diff --git a/CMakeLists.txt b/CMakeLists.txt index fb65e32..00c51a6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.20) # Set toolchain before project() if using vcpkg -if(NOT DEFINED CMAKE_TOOLCHAIN_FILE) +if(NOT DEFINED CMAKE_TOOLCHAIN_FILE AND NOT EMSCRIPTEN) set(CMAKE_TOOLCHAIN_FILE "$ENV{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake" CACHE STRING "Vcpkg toolchain") endif() @@ -10,6 +10,10 @@ project(rive_tests C CXX) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) +# Tell CMake where to find our custom FindTMXLITE.cmake module. +# set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake ${CMAKE_MODULE_PATH}) +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") + # Enable folders in IDEs like Visual Studio set_property(GLOBAL PROPERTY USE_FOLDERS ON) @@ -42,35 +46,25 @@ if(PLATFORM_WEB) # For Emscripten, we'll use the built-in SDL support # No need to find SDL3 package else() - # For other platforms, use vcpkg SDL3 + # For other platforms, use vcpkg packages find_package(SDL3 CONFIG REQUIRED) + find_package(harfbuzz CONFIG REQUIRED) + find_package(PNG REQUIRED) + find_package(WebP CONFIG REQUIRED) + find_package(yoga CONFIG REQUIRED) + find_package(SheenBidi REQUIRED) + find_package(glad CONFIG REQUIRED) endif() -# Add glad manually (since it's not installed via vcpkg) -add_library(glad STATIC - third_party/glad/src/gl.c -) +find_package(RIVE REQUIRED) # Platform-specific OpenGL setup if(PLATFORM_DESKTOP) find_package(OpenGL REQUIRED) set(GL_LIBS OpenGL::GL) - target_compile_definitions(glad PUBLIC GLAD_GL) elseif(PLATFORM_MOBILE OR PLATFORM_WEB) # Mobile and Web use OpenGL ES set(GL_LIBS "") # GLES is handled by platform - target_compile_definitions(glad PUBLIC GLAD_GLES2) - - if(PLATFORM_WEB) - # Emscripten-specific settings - target_compile_definitions(glad PUBLIC GLAD_GLES2_IMPLEMENTATION) - endif() -endif() - -# Add EGL source only for platforms that need it -if(PLATFORM_MOBILE) - target_sources(glad PRIVATE third_party/glad/src/egl.c) - target_compile_definitions(glad PUBLIC GLAD_EGL) endif() add_executable(rive_tests src/main.cpp) @@ -82,11 +76,10 @@ if(PLATFORM_WEB) SUFFIX ".html" OUTPUT_NAME "index" ) - target_compile_options(rive_tests PRIVATE + target_compile_options(rive_tests PRIVATE "SHELL:-s USE_SDL=3" - "SHELL:-s USE_WEBGL2=1" ) - target_link_options(rive_tests PRIVATE + target_link_options(rive_tests PRIVATE "SHELL:-s USE_SDL=3" "SHELL:-s USE_WEBGL2=1" "SHELL:-s FULL_ES3=1" @@ -94,7 +87,7 @@ if(PLATFORM_WEB) "SHELL:-s ALLOW_MEMORY_GROWTH=1" "SHELL:-s EXPORTED_FUNCTIONS=['_main']" "SHELL:-s EXPORTED_RUNTIME_METHODS=['ccall','cwrap']" - "SHELL:--shell-file ${CMAKE_SOURCE_DIR}/web/shell.html" + "SHELL:--shell-file=${CMAKE_SOURCE_DIR}/web/shell.html" ) elseif(PLATFORM_MOBILE) if(IOS) @@ -107,10 +100,6 @@ elseif(PLATFORM_MOBILE) endif() endif() -# Include directories -target_include_directories(glad PUBLIC third_party/glad/include) -set_target_properties(glad PROPERTIES LINKER_LANGUAGE C) - # Platform-specific preprocessor definitions if(PLATFORM_WEB) target_compile_definitions(rive_tests PRIVATE PLATFORM_WEB) @@ -130,14 +119,25 @@ if(PLATFORM_WEB) # For Emscripten, SDL is handled via link options target_link_libraries(rive_tests PRIVATE - glad + RIVE::rive + RIVE::renderer + RIVE::decoders + SheenBidi::SheenBidi ) else() target_link_libraries(rive_tests PRIVATE SDL3::SDL3 ${GL_LIBS} - glad + glad::glad + harfbuzz::harfbuzz + PNG::PNG + WebP::webp + yoga::yogacore + RIVE::rive + RIVE::renderer + RIVE::decoders + SheenBidi::SheenBidi ) endif() diff --git a/assets/rive_files/alien.rev b/assets/rive_files/alien.rev new file mode 100644 index 0000000..8ea9ecb Binary files /dev/null and b/assets/rive_files/alien.rev differ diff --git a/assets/rive_files/alien.riv b/assets/rive_files/alien.riv new file mode 100644 index 0000000..27cadf0 Binary files /dev/null and b/assets/rive_files/alien.riv differ diff --git a/assets/rive_files/arcade_controls.rev b/assets/rive_files/arcade_controls.rev new file mode 100644 index 0000000..bec40ca Binary files /dev/null and b/assets/rive_files/arcade_controls.rev differ diff --git a/assets/rive_files/arcade_controls.riv b/assets/rive_files/arcade_controls.riv new file mode 100644 index 0000000..4b246ad Binary files /dev/null and b/assets/rive_files/arcade_controls.riv differ diff --git a/assets/rive_files/audio_sampler.rev b/assets/rive_files/audio_sampler.rev new file mode 100644 index 0000000..8b80c85 Binary files /dev/null and b/assets/rive_files/audio_sampler.rev differ diff --git a/assets/rive_files/audio_sampler.riv b/assets/rive_files/audio_sampler.riv new file mode 100644 index 0000000..da1dcda Binary files /dev/null and b/assets/rive_files/audio_sampler.riv differ diff --git a/assets/rive_files/car_interface.rev b/assets/rive_files/car_interface.rev new file mode 100644 index 0000000..86e0cfc Binary files /dev/null and b/assets/rive_files/car_interface.rev differ diff --git a/assets/rive_files/car_interface.riv b/assets/rive_files/car_interface.riv new file mode 100644 index 0000000..007ad15 Binary files /dev/null and b/assets/rive_files/car_interface.riv differ diff --git a/assets/rive_files/charge.riv b/assets/rive_files/charge.riv new file mode 100644 index 0000000..28387db Binary files /dev/null and b/assets/rive_files/charge.riv differ diff --git a/assets/rive_files/seasynth.rev b/assets/rive_files/seasynth.rev new file mode 100644 index 0000000..9a8cc26 Binary files /dev/null and b/assets/rive_files/seasynth.rev differ diff --git a/assets/rive_files/seasynth.riv b/assets/rive_files/seasynth.riv new file mode 100644 index 0000000..cd9cbbf Binary files /dev/null and b/assets/rive_files/seasynth.riv differ diff --git a/assets/rive_files/toymachine_3.rev b/assets/rive_files/toymachine_3.rev new file mode 100644 index 0000000..2b82732 Binary files /dev/null and b/assets/rive_files/toymachine_3.rev differ diff --git a/assets/rive_files/toymachine_3.riv b/assets/rive_files/toymachine_3.riv new file mode 100644 index 0000000..7fde0b5 Binary files /dev/null and b/assets/rive_files/toymachine_3.riv differ diff --git a/assets/rive_files/ui_elements.rev b/assets/rive_files/ui_elements.rev new file mode 100644 index 0000000..8f3ea88 Binary files /dev/null and b/assets/rive_files/ui_elements.rev differ diff --git a/assets/rive_files/ui_elements.riv b/assets/rive_files/ui_elements.riv new file mode 100644 index 0000000..cff590a Binary files /dev/null and b/assets/rive_files/ui_elements.riv differ diff --git a/cmake/FindRIVE.cmake b/cmake/FindRIVE.cmake new file mode 100644 index 0000000..b6f4111 --- /dev/null +++ b/cmake/FindRIVE.cmake @@ -0,0 +1,538 @@ +# FindRIVE.cmake +# ============================================================================ +# CMake Find Module for Rive +# This module finds and configures the Rive animation library +# +# Usage: +# find_package(RIVE REQUIRED) +# target_link_libraries(your_target PRIVATE RIVE::rive RIVE::renderer RIVE::decoders) +# +# This module defines the following IMPORTED targets: +# RIVE::rive - Core Rive library +# RIVE::renderer - Rive OpenGL renderer +# RIVE::decoders - Rive image decoders +# +# Variables: +# RIVE_FOUND - True if Rive is found +# RIVE_INCLUDE_DIRS - Include directories for Rive +# RIVE_LIBRARIES - Libraries to link against +# RIVE_THIRDPARTY_DIR - Directory containing Rive source (can be set by user) +# ============================================================================ + +# Allow user to specify the thirdparty directory +if(NOT RIVE_THIRDPARTY_DIR) + # Try to find it relative to common locations + set(_rive_search_paths + "${CMAKE_CURRENT_SOURCE_DIR}/thirdparty" + "${CMAKE_CURRENT_SOURCE_DIR}/../thirdparty" + "${CMAKE_SOURCE_DIR}/thirdparty" + "${CMAKE_SOURCE_DIR}/third_party" + "${CMAKE_SOURCE_DIR}/extern" + "${CMAKE_SOURCE_DIR}/external" + ) + + foreach(_path ${_rive_search_paths}) + if(EXISTS "${_path}/rive/rive.h") + set(RIVE_THIRDPARTY_DIR "${_path}") + break() + endif() + endforeach() +endif() + +# Check if we found the source +if(NOT RIVE_THIRDPARTY_DIR OR NOT EXISTS "${RIVE_THIRDPARTY_DIR}/rive/rive.h") + if(RIVE_FIND_REQUIRED) + message(FATAL_ERROR "Could not find Rive source directory. Please set RIVE_THIRDPARTY_DIR to the directory containing the rive folder.") + else() + set(RIVE_FOUND FALSE) + return() + endif() +endif() + +# Platform detection (same as before) +if(WIN32) + set(RIVE_PLATFORM_WINDOWS TRUE) + set(RIVE_PLATFORM_DESKTOP TRUE) +elseif(APPLE) + set(RIVE_PLATFORM_APPLE TRUE) + set(RIVE_PLATFORM_DESKTOP TRUE) + if(IOS) + set(RIVE_PLATFORM_IOS TRUE) + set(RIVE_PLATFORM_MOBILE TRUE) + else() + set(RIVE_PLATFORM_MACOS TRUE) + endif() +elseif(UNIX) + set(RIVE_PLATFORM_LINUX TRUE) + set(RIVE_PLATFORM_DESKTOP TRUE) +elseif(EMSCRIPTEN) + set(RIVE_PLATFORM_WEB TRUE) +endif() + +# Function to collect source files (same as before) +function(_rive_collect_sources base_path output_var) + file(GLOB_RECURSE all_sources + "${base_path}/*.cpp" + "${base_path}/*.c" + "${base_path}/*.mm" + "${base_path}/*.m" + ) + + set(filtered_sources "") + foreach(source ${all_sources}) + set(include_file TRUE) + + # Platform-specific filtering + if(NOT RIVE_PLATFORM_WINDOWS AND source MATCHES "_windows\\.(cpp|c|mm|m)$") + set(include_file FALSE) + endif() + if(NOT RIVE_PLATFORM_APPLE AND source MATCHES "_apple\\.(cpp|c|mm|m)$") + set(include_file FALSE) + endif() + if(NOT RIVE_PLATFORM_MACOS AND source MATCHES "_osx\\.(cpp|c|mm|m)$") + set(include_file FALSE) + endif() + if(NOT RIVE_PLATFORM_MACOS AND source MATCHES "_mac\\.(cpp|c|mm|m)$") + set(include_file FALSE) + endif() + if(NOT RIVE_PLATFORM_IOS AND source MATCHES "_ios\\.(cpp|c|mm|m)$") + set(include_file FALSE) + endif() + if(NOT RIVE_PLATFORM_LINUX AND source MATCHES "_linux\\.(cpp|c|mm|m)$") + set(include_file FALSE) + endif() + if(NOT RIVE_PLATFORM_MOBILE AND source MATCHES "_mobile\\.(cpp|c|mm|m)$") + set(include_file FALSE) + endif() + if(NOT RIVE_PLATFORM_WEB AND source MATCHES "_emscripten\\.(cpp|c|mm|m)$") + set(include_file FALSE) + endif() + if(NOT RIVE_PLATFORM_WEB AND source MATCHES "_wasm\\.(cpp|c|mm|m)$") + set(include_file FALSE) + endif() + + # Skip test files + if(source MATCHES "/test/" OR source MATCHES "_test\\.(cpp|c|mm|m)$") + set(include_file FALSE) + endif() + + if(include_file) + list(APPEND filtered_sources ${source}) + endif() + endforeach() + + set(${output_var} ${filtered_sources} PARENT_SCOPE) +endfunction() + +# Only create targets if they don't already exist +if(NOT TARGET RIVE::rive) + # Core Rive Library + set(rive_dir "${RIVE_THIRDPARTY_DIR}/rive") + _rive_collect_sources("${rive_dir}/source" rive_sources) + + add_library(RIVE_rive STATIC ${rive_sources}) + add_library(RIVE::rive ALIAS RIVE_rive) + + target_compile_features(RIVE_rive PUBLIC cxx_std_17) + + target_include_directories(RIVE_rive PUBLIC + "${rive_dir}/include" + "${rive_dir}" + ) + + target_compile_definitions(RIVE_rive PUBLIC + WITH_RIVE_TEXT=1 + WITH_RIVE_YOGA=1 + WITH_RIVE_LAYOUT=1 + _RIVE_INTERNAL_=1 + ) + + # Platform-specific settings + if(RIVE_PLATFORM_APPLE) + target_link_libraries(RIVE_rive PUBLIC "-framework CoreText") + if(RIVE_PLATFORM_MACOS) + set_target_properties(RIVE_rive PROPERTIES + XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC YES + ) + endif() + endif() + + # Dependencies + find_package(harfbuzz CONFIG REQUIRED) + target_link_libraries(RIVE_rive PUBLIC harfbuzz::harfbuzz) + + # SheenBidi - try to find it + find_package(SheenBidi QUIET) + if(SheenBidi_FOUND) + target_link_libraries(RIVE_rive PUBLIC SheenBidi::SheenBidi) + else() + # Try pkg-config as fallback + find_package(PkgConfig QUIET) + if(PkgConfig_FOUND) + pkg_check_modules(SHEENBIDI QUIET sheenbidi) + if(SHEENBIDI_FOUND) + target_link_libraries(RIVE_rive PUBLIC ${SHEENBIDI_LIBRARIES}) + target_include_directories(RIVE_rive PUBLIC ${SHEENBIDI_INCLUDE_DIRS}) + else() + message(WARNING "SheenBidi not found. Text bidirectional support may be limited.") + endif() + endif() + endif() + + # Yoga - try to find it with different target names + find_package(yoga QUIET) + if(yoga_FOUND) + # Check which target is available + if(TARGET yoga::yogacore) + target_link_libraries(RIVE_rive PUBLIC yoga::yogacore) + elseif(TARGET yoga::yoga) + target_link_libraries(RIVE_rive PUBLIC yoga::yoga) + else() + message(WARNING "Yoga found but no recognized target available.") + endif() + else() + message(WARNING "Yoga layout engine not found. Layout features may be limited.") + endif() +endif() + +if(NOT TARGET RIVE::decoders) + # Rive Decoders + set(rive_decoders_dir "${RIVE_THIRDPARTY_DIR}/rive_decoders") + _rive_collect_sources("${rive_decoders_dir}/source" rive_decoders_sources) + + add_library(RIVE_decoders STATIC ${rive_decoders_sources}) + add_library(RIVE::decoders ALIAS RIVE_decoders) + + target_include_directories(RIVE_decoders PUBLIC + "${rive_decoders_dir}/include" + "${rive_decoders_dir}" + ) + + # Add this section to handle libpng compatibility: + # Create a compatibility header for libpng + set(LIBPNG_COMPAT_DIR "${CMAKE_CURRENT_BINARY_DIR}/libpng_compat") + file(MAKE_DIRECTORY "${LIBPNG_COMPAT_DIR}/libpng") + file(WRITE "${LIBPNG_COMPAT_DIR}/libpng/libpng.h" "#include \n") + target_include_directories(RIVE_decoders PRIVATE "${LIBPNG_COMPAT_DIR}") + + # Create a compatibility header for libwebp + set(LIBWEBP_COMPAT_DIR "${CMAKE_CURRENT_BINARY_DIR}/libwebp_compat") + file(MAKE_DIRECTORY "${LIBWEBP_COMPAT_DIR}/libwebp") + file(WRITE "${LIBWEBP_COMPAT_DIR}/libwebp/libwebp.h" +"#include +#include +#include +#include +") + target_include_directories(RIVE_decoders PRIVATE "${LIBWEBP_COMPAT_DIR}") + + # Base compiler definitions for decoders + target_compile_definitions(RIVE_decoders PUBLIC + _RIVE_INTERNAL_=1 + ) + + # Optional image format support + find_package(PNG QUIET) + find_package(WebP QUIET) + + if(PNG_FOUND) + target_compile_definitions(RIVE_decoders PUBLIC RIVE_PNG=1) + target_link_libraries(RIVE_decoders PUBLIC PNG::PNG) + endif() + + if(WebP_FOUND) + target_compile_definitions(RIVE_decoders PUBLIC RIVE_WEBP=1) + target_link_libraries(RIVE_decoders PUBLIC WebP::webp) + endif() + + # Platform-specific settings + if(RIVE_PLATFORM_APPLE) + target_link_libraries(RIVE_decoders PUBLIC "-framework ImageIO") + set_target_properties(RIVE_decoders PROPERTIES + XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC YES + ) + endif() + + # Add this missing dependency: + target_link_libraries(RIVE_decoders PUBLIC RIVE::rive) +endif() + +if(NOT TARGET RIVE::renderer) + # Rive Renderer + set(rive_renderer_dir "${RIVE_THIRDPARTY_DIR}/rive_renderer") + _rive_collect_sources("${rive_renderer_dir}/source" rive_renderer_sources) + + # Platform-specific filtering for renderer backends + set(filtered_renderer_sources "") + foreach(source ${rive_renderer_sources}) + set(include_source TRUE) + + # Platform-specific backend filtering + if(RIVE_PLATFORM_WINDOWS) + # On Windows: exclude Metal, WebGPU (keep D3D, OpenGL, Vulkan) + if(source MATCHES "/metal/" OR source MATCHES "/webgpu/") + set(include_source FALSE) + endif() + elseif(RIVE_PLATFORM_APPLE) + # On Apple: exclude D3D, Vulkan, WebGPU (keep Metal, OpenGL) + if(source MATCHES "/d3d/" OR source MATCHES "/d3d11/" OR source MATCHES "/d3d12/" OR + source MATCHES "/vulkan/" OR source MATCHES "/webgpu/") + set(include_source FALSE) + endif() + elseif(RIVE_PLATFORM_LINUX) + # On Linux: exclude D3D, Metal, WebGPU (keep OpenGL, Vulkan) + if(source MATCHES "/d3d/" OR source MATCHES "/d3d11/" OR source MATCHES "/d3d12/" OR + source MATCHES "/metal/" OR source MATCHES "/webgpu/") + set(include_source FALSE) + endif() + elseif(RIVE_PLATFORM_WEB) + # On Web: exclude D3D, Metal, Vulkan (keep WebGPU, OpenGL ES) + if(source MATCHES "/d3d/" OR source MATCHES "/d3d11/" OR source MATCHES "/d3d12/" OR + source MATCHES "/metal/" OR source MATCHES "/vulkan/") + set(include_source FALSE) + endif() + endif() + + # Include if not excluded + if(include_source) + list(APPEND filtered_renderer_sources ${source}) + endif() + endforeach() + + add_library(RIVE_renderer STATIC ${filtered_renderer_sources}) + add_library(RIVE::renderer ALIAS RIVE_renderer) + + target_compile_features(RIVE_renderer PUBLIC cxx_std_17) + + target_include_directories(RIVE_renderer PUBLIC + "${rive_renderer_dir}/include" + "${rive_renderer_dir}/source" + "${rive_renderer_dir}/source/generated/shaders" + "${rive_renderer_dir}" + ) + + # Create glad_custom.h compatibility header for ALL desktop platforms + if(RIVE_PLATFORM_DESKTOP) + set(GLAD_COMPAT_DIR "${CMAKE_CURRENT_BINARY_DIR}/glad_compat") + file(MAKE_DIRECTORY "${GLAD_COMPAT_DIR}") + file(WRITE "${GLAD_COMPAT_DIR}/glad_custom.h" +"#pragma once +#include + +// Ensure we have the same defines that Rive expects +#ifndef GLAPIENTRY +#define GLAPIENTRY APIENTRY +#endif + +#ifndef GL_APIENTRY +#define GL_APIENTRY GLAPIENTRY +#endif + +// Define missing ANGLE provoking vertex extension +#ifndef GL_ANGLE_provoking_vertex +#define GL_ANGLE_provoking_vertex 1 +#define GL_FIRST_VERTEX_CONVENTION_ANGLE 0x8E4D +#define GL_LAST_VERTEX_CONVENTION_ANGLE 0x8E4E +#define GL_PROVOKING_VERTEX_ANGLE 0x8E4F +// Declare the function as a no-op for desktop GL +static inline void glProvokingVertexANGLE(GLenum provokeMode) { (void)provokeMode; } +#endif + +// Define missing ANGLE polygon mode extension +#ifndef GL_ANGLE_polygon_mode +#define GL_ANGLE_polygon_mode 1 +#define GL_FILL_ANGLE 0x1B02 +#define GL_LINE_ANGLE 0x1B01 +#define GL_POINT_ANGLE 0x1B00 +static inline void glPolygonModeANGLE(GLenum face, GLenum mode) { (void)face; (void)mode; } +#endif + +// Define missing EXT clip cull distance extension +#ifndef GL_EXT_clip_cull_distance +#define GL_EXT_clip_cull_distance 1 +#define GL_CLIP_DISTANCE0_EXT 0x3000 +#define GL_CLIP_DISTANCE1_EXT 0x3001 +#define GL_CLIP_DISTANCE2_EXT 0x3002 +#define GL_CLIP_DISTANCE3_EXT 0x3003 +#define GL_CLIP_DISTANCE4_EXT 0x3004 +#define GL_CLIP_DISTANCE5_EXT 0x3005 +#define GL_CLIP_DISTANCE6_EXT 0x3006 +#define GL_CLIP_DISTANCE7_EXT 0x3007 +#endif + +// Define missing ANGLE shader pixel local storage extension +#ifndef GL_ANGLE_shader_pixel_local_storage +#define GL_ANGLE_shader_pixel_local_storage 1 +#define GL_MAX_PIXEL_LOCAL_STORAGE_PLANES_ANGLE 0x96E0 +#define GL_MAX_COMBINED_DRAW_BUFFERS_AND_PIXEL_LOCAL_STORAGE_PLANES_ANGLE 0x96E1 +#define GL_PIXEL_LOCAL_STORAGE_ACTIVE_PLANES_ANGLE 0x96E2 +#define GL_LOAD_OP_ZERO_ANGLE 0x96E3 +#define GL_LOAD_OP_CLEAR_ANGLE 0x96E4 +#define GL_LOAD_OP_LOAD_ANGLE 0x96E5 +#define GL_STORE_OP_STORE_ANGLE 0x96E6 +#define GL_PIXEL_LOCAL_FORMAT_ANGLE 0x96E7 +#define GL_PIXEL_LOCAL_TEXTURE_NAME_ANGLE 0x96E8 +#define GL_PIXEL_LOCAL_TEXTURE_LEVEL_ANGLE 0x96E9 +#define GL_PIXEL_LOCAL_TEXTURE_LAYER_ANGLE 0x96EA +#define GL_PIXEL_LOCAL_CLEAR_VALUE_FLOAT_ANGLE 0x96EB +#define GL_PIXEL_LOCAL_CLEAR_VALUE_INT_ANGLE 0x96EC +#define GL_PIXEL_LOCAL_CLEAR_VALUE_UNSIGNED_INT_ANGLE 0x96ED + +// Declare no-op functions for desktop GL +static inline void glFramebufferTexturePixelLocalStorageANGLE(GLint plane, GLuint backingtexture, GLint level, GLint layer) { + (void)plane; (void)backingtexture; (void)level; (void)layer; +} +static inline void glFramebufferPixelLocalClearValuefvANGLE(GLint plane, const GLfloat value[4]) { + (void)plane; (void)value; +} +static inline void glBeginPixelLocalStorageANGLE(GLsizei n, const GLenum loadops[]) { + (void)n; (void)loadops; +} +static inline void glEndPixelLocalStorageANGLE(GLsizei n, const GLenum storeops[]) { + (void)n; (void)storeops; +} +static inline void glGetFramebufferPixelLocalStorageParameterivANGLE(GLint plane, GLenum pname, GLint* param) { + (void)plane; (void)pname; if(param) *param = 0; +} +#endif + +// Define missing KHR blend equation advanced constants +#ifndef GL_KHR_blend_equation_advanced +#define GL_KHR_blend_equation_advanced 1 +#define GL_MULTIPLY_KHR 0x9294 +#define GL_SCREEN_KHR 0x9295 +#define GL_OVERLAY_KHR 0x9296 +#define GL_DARKEN_KHR 0x9297 +#define GL_LIGHTEN_KHR 0x9298 +#define GL_COLORDODGE_KHR 0x9299 +#define GL_COLORBURN_KHR 0x929A +#define GL_HARDLIGHT_KHR 0x929B +#define GL_SOFTLIGHT_KHR 0x929C +#define GL_DIFFERENCE_KHR 0x929E +#define GL_EXCLUSION_KHR 0x92A0 +#define GL_HSL_HUE_KHR 0x92AD +#define GL_HSL_SATURATION_KHR 0x92AE +#define GL_HSL_COLOR_KHR 0x92AF +#define GL_HSL_LUMINOSITY_KHR 0x92B0 +#define GL_BLEND_ADVANCED_COHERENT_KHR 0x9285 +#endif + +// Define other missing constants that might be needed +#ifndef GL_SHADER_PIXEL_LOCAL_STORAGE_EXT +#define GL_SHADER_PIXEL_LOCAL_STORAGE_EXT 0x8F64 +#endif + +#ifndef GL_FRAMEBUFFER_FETCH_NONCOHERENT_QCOM +#define GL_FRAMEBUFFER_FETCH_NONCOHERENT_QCOM 0x96A2 +#endif + +// Only define this if Rive hasn't already defined it +#ifndef glFramebufferFetchBarrierQCOM +static inline void glFramebufferFetchBarrierQCOM(void) {} +#endif + +// Map EXT function names to standard glad functions if available +#ifndef glDrawElementsInstancedBaseInstanceEXT +#define glDrawElementsInstancedBaseInstanceEXT glDrawElementsInstancedBaseInstance +#endif + +#ifndef glRenderbufferStorageMultisampleEXT +#define glRenderbufferStorageMultisampleEXT glRenderbufferStorageMultisample +#endif + +#ifndef glFramebufferTexture2DMultisampleEXT +static inline void glFramebufferTexture2DMultisampleEXT(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples) { + // This is a mobile-specific extension, provide no-op for desktop + (void)target; (void)attachment; (void)textarget; (void)texture; (void)level; (void)samples; +} +#endif + +// Define GLAD extension detection variables that Rive expects +// Set to 0 for desktop GL since these are mobile/WebGL extensions +#ifndef GLAD_GL_version_major +extern int GLAD_GL_VERSION_MAJOR; +#define GLAD_GL_version_major GLAD_GL_VERSION_MAJOR +#endif + +#ifndef GLAD_GL_version_minor +extern int GLAD_GL_VERSION_MINOR; +#define GLAD_GL_version_minor GLAD_GL_VERSION_MINOR +#endif + +#ifndef GLAD_GL_version_es +#define GLAD_GL_version_es 0 +#endif + +#ifndef GLAD_GL_ANGLE_base_vertex_base_instance_shader_builtin +#define GLAD_GL_ANGLE_base_vertex_base_instance_shader_builtin 0 +#endif + +#ifndef GLAD_GL_ANGLE_polygon_mode +#define GLAD_GL_ANGLE_polygon_mode 0 +#endif + +#ifndef GLAD_GL_EXT_base_instance +#define GLAD_GL_EXT_base_instance 0 +#endif +") + target_include_directories(RIVE_renderer PRIVATE "${GLAD_COMPAT_DIR}") + endif() + + # OpenGL dependency - prioritize vcpkg glad + find_package(glad CONFIG QUIET) + if(glad_FOUND AND TARGET glad::glad) + target_link_libraries(RIVE_renderer PUBLIC glad::glad) + message(STATUS "Using glad::glad from vcpkg") + elseif(TARGET glad) + # Fallback to manual glad target if it exists + target_link_libraries(RIVE_renderer PUBLIC glad) + message(STATUS "Using existing manual glad target") + else() + message(WARNING "glad not found. Please install via vcpkg or ensure glad is available") + endif() + + target_compile_definitions(RIVE_renderer PUBLIC + WITH_RIVE_TEXT=1 + RIVE_DECODERS=1 + YUP_RIVE_USE_OPENGL=1 + _RIVE_INTERNAL_=1 + ) + + # Platform-specific OpenGL definitions + if(RIVE_PLATFORM_DESKTOP) + target_compile_definitions(RIVE_renderer PUBLIC RIVE_DESKTOP_GL=1) + elseif(RIVE_PLATFORM_WEB) + target_compile_definitions(RIVE_renderer PUBLIC RIVE_WEBGL=1) + endif() + + # Link dependencies + target_link_libraries(RIVE_renderer PUBLIC + RIVE::rive + RIVE::decoders + ) +endif() + +# Set up the standard CMake variables +set(RIVE_INCLUDE_DIRS + "${RIVE_THIRDPARTY_DIR}/rive/include" + "${RIVE_THIRDPARTY_DIR}/rive_renderer/include" + "${RIVE_THIRDPARTY_DIR}/rive_decoders/include" +) + +set(RIVE_LIBRARIES RIVE::rive RIVE::renderer RIVE::decoders) + +# Use FindPackageHandleStandardArgs to set RIVE_FOUND +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(RIVE + REQUIRED_VARS RIVE_THIRDPARTY_DIR + VERSION_VAR "1.0" # You can extract this from Rive headers if needed +) + +# Set variables in parent scope if found and parent scope exists +if(RIVE_FOUND AND CMAKE_CURRENT_FUNCTION) + set(RIVE_INCLUDE_DIRS ${RIVE_INCLUDE_DIRS} PARENT_SCOPE) + set(RIVE_LIBRARIES ${RIVE_LIBRARIES} PARENT_SCOPE) + set(RIVE_THIRDPARTY_DIR ${RIVE_THIRDPARTY_DIR} PARENT_SCOPE) +endif() + +mark_as_advanced(RIVE_THIRDPARTY_DIR) diff --git a/cmake/FindSheenBidi.cmake b/cmake/FindSheenBidi.cmake new file mode 100644 index 0000000..73a0fe5 --- /dev/null +++ b/cmake/FindSheenBidi.cmake @@ -0,0 +1,134 @@ +# FindSheenBidi.cmake +# ============================================================================ +# CMake Find Module for SheenBidi +# This module finds and configures the SheenBidi bidirectional text library +# +# Usage: +# find_package(SheenBidi REQUIRED) +# target_link_libraries(your_target PRIVATE SheenBidi::SheenBidi) +# +# This module defines the following IMPORTED targets: +# SheenBidi::SheenBidi - SheenBidi library +# +# Variables: +# SheenBidi_FOUND - True if SheenBidi is found +# SheenBidi_INCLUDE_DIRS - Include directories for SheenBidi +# SheenBidi_LIBRARIES - Libraries to link against +# SHEENBIDI_ROOT_DIR - Directory containing SheenBidi source (can be set by user) +# ============================================================================ + +# Allow user to specify the SheenBidi directory +if(NOT SHEENBIDI_ROOT_DIR) + # Try to find it relative to common locations + set(_sheenbidi_search_paths + "${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/sheenbidi" + "${CMAKE_CURRENT_SOURCE_DIR}/third_party/sheenbidi" + "${CMAKE_CURRENT_SOURCE_DIR}/extern/sheenbidi" + "${CMAKE_CURRENT_SOURCE_DIR}/external/sheenbidi" + "${CMAKE_SOURCE_DIR}/thirdparty/sheenbidi" + "${CMAKE_SOURCE_DIR}/third_party/sheenbidi" + "${CMAKE_SOURCE_DIR}/extern/sheenbidi" + "${CMAKE_SOURCE_DIR}/external/sheenbidi" + ) + + foreach(_path ${_sheenbidi_search_paths}) + if(EXISTS "${_path}/Headers/SheenBidi.h" OR EXISTS "${_path}/include/SheenBidi.h") + set(SHEENBIDI_ROOT_DIR "${_path}") + break() + endif() + endforeach() +endif() + +# Check if we found the source +set(_sheenbidi_header_found FALSE) +if(SHEENBIDI_ROOT_DIR) + if(EXISTS "${SHEENBIDI_ROOT_DIR}/Headers/SheenBidi.h") + set(SHEENBIDI_INCLUDE_DIR "${SHEENBIDI_ROOT_DIR}/Headers") + set(_sheenbidi_header_found TRUE) + elseif(EXISTS "${SHEENBIDI_ROOT_DIR}/include/SheenBidi.h") + set(SHEENBIDI_INCLUDE_DIR "${SHEENBIDI_ROOT_DIR}/include") + set(_sheenbidi_header_found TRUE) + endif() +endif() + +if(NOT _sheenbidi_header_found) + if(SheenBidi_FIND_REQUIRED) + message(FATAL_ERROR "Could not find SheenBidi source directory. Please set SHEENBIDI_ROOT_DIR to the directory containing SheenBidi source.") + else() + set(SheenBidi_FOUND FALSE) + return() + endif() +endif() + +# Only create target if it doesn't already exist +if(NOT TARGET SheenBidi::SheenBidi) + # Collect source files + file(GLOB_RECURSE sheenbidi_sources + "${SHEENBIDI_ROOT_DIR}/Source/*.c" + "${SHEENBIDI_ROOT_DIR}/source/*.c" + "${SHEENBIDI_ROOT_DIR}/src/*.c" + ) + + # Filter out any test files + set(filtered_sources "") + foreach(source ${sheenbidi_sources}) + if(NOT source MATCHES "/test/" AND NOT source MATCHES "_test\\.(c|cpp)$") + list(APPEND filtered_sources ${source}) + endif() + endforeach() + + if(NOT filtered_sources) + if(SheenBidi_FIND_REQUIRED) + message(FATAL_ERROR "Could not find SheenBidi source files in ${SHEENBIDI_ROOT_DIR}") + else() + set(SheenBidi_FOUND FALSE) + return() + endif() + endif() + + # Create the library + add_library(SheenBidi_SheenBidi STATIC ${filtered_sources}) + add_library(SheenBidi::SheenBidi ALIAS SheenBidi_SheenBidi) + + # Set include directories + target_include_directories(SheenBidi_SheenBidi PUBLIC + "${SHEENBIDI_INCLUDE_DIR}" + ) + + # Set C standard (SheenBidi is a C library) + target_compile_features(SheenBidi_SheenBidi PUBLIC c_std_99) + + # Platform-specific compiler flags + if(MSVC) + target_compile_options(SheenBidi_SheenBidi PRIVATE /W3) + else() + target_compile_options(SheenBidi_SheenBidi PRIVATE -Wall -Wextra) + endif() + + # Set properties + set_target_properties(SheenBidi_SheenBidi PROPERTIES + C_VISIBILITY_PRESET hidden + VISIBILITY_INLINES_HIDDEN ON + POSITION_INDEPENDENT_CODE ON + ) +endif() + +# Set up standard CMake variables +set(SheenBidi_INCLUDE_DIRS "${SHEENBIDI_INCLUDE_DIR}") +set(SheenBidi_LIBRARIES SheenBidi::SheenBidi) + +# Use FindPackageHandleStandardArgs to set SheenBidi_FOUND +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(SheenBidi + REQUIRED_VARS SHEENBIDI_ROOT_DIR SHEENBIDI_INCLUDE_DIR + VERSION_VAR "2.6" # Current version as of 2024 +) + +# Set variables in parent scope if found and parent scope exists +if(SheenBidi_FOUND AND CMAKE_CURRENT_FUNCTION) + set(SheenBidi_INCLUDE_DIRS ${SheenBidi_INCLUDE_DIRS} PARENT_SCOPE) + set(SheenBidi_LIBRARIES ${SheenBidi_LIBRARIES} PARENT_SCOPE) + set(SHEENBIDI_ROOT_DIR ${SHEENBIDI_ROOT_DIR} PARENT_SCOPE) +endif() + +mark_as_advanced(SHEENBIDI_ROOT_DIR SHEENBIDI_INCLUDE_DIR) diff --git a/scripts/build_web.sh b/scripts/build_web.sh index 3979265..28f381b 100755 --- a/scripts/build_web.sh +++ b/scripts/build_web.sh @@ -35,8 +35,7 @@ echo "Configuring project for WebAssembly..." emcmake cmake -B "${BUILD_DIR}" -S . \ -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \ -DEMSCRIPTEN=ON \ - -DVCPKG_TARGET_TRIPLET=wasm32-emscripten \ - -DCMAKE_TOOLCHAIN_FILE="${VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake" + -DVCPKG_TARGET_TRIPLET=wasm32-emscripten # Build echo "Building project..." diff --git a/src/main.cpp b/src/main.cpp index d6e77d6..c1a80a6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,6 +1,6 @@ #define SDL_MAIN_USE_CALLBACKS 1 /* use the callbacks instead of main() */ -#include +#include #include #include #include @@ -8,12 +8,15 @@ /* We will use this renderer to draw into this window every frame. */ static SDL_Window *window = nullptr; static SDL_GLContext glContext = nullptr; -static GladGLContext gladContext = {}; static bool isPaused = false; /* This function runs once at startup. */ SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[]) { + (void)appstate; // Suppress unused parameter warning + (void)argc; // Suppress unused parameter warning + (void)argv; // Suppress unused parameter warning + SDL_SetAppMetadata("SDL3 OpenGL Example", "1.0", "cl.staytrue.rive"); if (!SDL_Init(SDL_INIT_VIDEO)) { @@ -33,31 +36,33 @@ SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[]) return SDL_APP_FAILURE; } - // Initialize GLAD with the context + // Initialize GLAD with the loader function #if defined(__ANDROID__) || defined(__IPHONEOS__) || defined(__EMSCRIPTEN__) - // Use OpenGL ES on mobile platforms and WebAssembly - if (!gladLoadGLES2Context(&gladContext, (GLADloadfunc)SDL_GL_GetProcAddress)) { - SDL_Log("Failed to initialize GLAD (OpenGL ES)"); + // Use OpenGL ES on mobile platforms and WebAssembly - for now use desktop GL + if (!gladLoadGLLoader((GLADloadproc)SDL_GL_GetProcAddress)) { + SDL_Log("Failed to initialize GLAD (OpenGL)"); return SDL_APP_FAILURE; } #else // Use desktop OpenGL on other platforms - if (!gladLoadGLContext(&gladContext, (GLADloadfunc)SDL_GL_GetProcAddress)) { + if (!gladLoadGLLoader((GLADloadproc)SDL_GL_GetProcAddress)) { SDL_Log("Failed to initialize GLAD (OpenGL)"); return SDL_APP_FAILURE; } #endif - SDL_Log("OpenGL Version: %s", gladContext.GetString(GL_VERSION)); - SDL_Log("OpenGL Renderer: %s", gladContext.GetString(GL_RENDERER)); + SDL_Log("OpenGL Version: %s", glGetString(GL_VERSION)); + SDL_Log("OpenGL Renderer: %s", glGetString(GL_RENDERER)); - gladContext.ClearColor(0.1f, 0.1f, 0.1f, 1.0f); + glClearColor(0.1f, 0.1f, 0.1f, 1.0f); return SDL_APP_CONTINUE; } /* This function runs when a new event (mouse input, keypresses, etc) occurs. */ SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event) { + (void)appstate; // Suppress unused parameter warning + if (event->type == SDL_EVENT_QUIT) { return SDL_APP_SUCCESS; /* end the program, reporting success to the OS. */ } @@ -67,6 +72,8 @@ SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event) /* This function runs once per frame, and is the heart of the program. */ SDL_AppResult SDL_AppIterate(void *appstate) { + (void)appstate; // Suppress unused parameter warning + if (!isPaused) { const double now = ((double)SDL_GetTicks()) / 1000.0; /* convert from milliseconds to seconds. */ /* choose the color for the frame we will draw. The sine wave trick makes it fade between colors smoothly. */ @@ -74,8 +81,8 @@ SDL_AppResult SDL_AppIterate(void *appstate) const float green = (float) (0.5 + 0.5 * SDL_sin(now + SDL_PI_D * 2 / 3)); const float blue = (float) (0.5 + 0.5 * SDL_sin(now + SDL_PI_D * 4 / 3)); - gladContext.ClearColor(red, green, blue, 1.0f); - gladContext.Clear(GL_COLOR_BUFFER_BIT); + glClearColor(red, green, blue, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); SDL_GL_SwapWindow(window); } @@ -85,6 +92,9 @@ SDL_AppResult SDL_AppIterate(void *appstate) /* This function runs once at shutdown. */ void SDL_AppQuit(void *appstate, SDL_AppResult result) { + (void)appstate; // Suppress unused parameter warning + (void)result; // Suppress unused parameter warning + if (glContext) { SDL_GL_DestroyContext(glContext); glContext = nullptr; diff --git a/third_party/rive/include/rive/advance_flags.hpp b/third_party/rive/include/rive/advance_flags.hpp new file mode 100644 index 0000000..912f6b9 --- /dev/null +++ b/third_party/rive/include/rive/advance_flags.hpp @@ -0,0 +1,26 @@ +#ifndef _RIVE_ADVANCE_FLAGS_HPP_ +#define _RIVE_ADVANCE_FLAGS_HPP_ + +#include "rive/enum_bitset.hpp" + +namespace rive +{ +enum class AdvanceFlags : unsigned short +{ + None = 0, + + /// Whether NestedArtboards should advance + AdvanceNested = 1 << 0, + + /// Whether the Component should animate when advancing + Animate = 1 << 1, + + /// Whether this Component is on the root artboard + IsRoot = 1 << 2, + + /// Whether we are advancing to a new frame + NewFrame = 1 << 3, +}; +RIVE_MAKE_ENUM_BITSET(AdvanceFlags) +} // namespace rive +#endif diff --git a/third_party/rive/include/rive/advancing_component.hpp b/third_party/rive/include/rive/advancing_component.hpp new file mode 100644 index 0000000..7f9dd9f --- /dev/null +++ b/third_party/rive/include/rive/advancing_component.hpp @@ -0,0 +1,20 @@ +#ifndef _RIVE_ADVANCING_COMPONENT_HPP_ +#define _RIVE_ADVANCING_COMPONENT_HPP_ + +#include "rive/advance_flags.hpp" + +namespace rive +{ +class Component; +class AdvancingComponent +{ +public: + virtual bool advanceComponent( + float elapsedSeconds, + AdvanceFlags flags = AdvanceFlags::Animate | + AdvanceFlags::NewFrame) = 0; + static AdvancingComponent* from(Component* component); +}; +} // namespace rive + +#endif diff --git a/third_party/rive/include/rive/animation/advanceable_state.hpp b/third_party/rive/include/rive/animation/advanceable_state.hpp new file mode 100644 index 0000000..58008fe --- /dev/null +++ b/third_party/rive/include/rive/animation/advanceable_state.hpp @@ -0,0 +1,13 @@ +#ifndef _RIVE_ADVANCEABLE_STATE_HPP_ +#define _RIVE_ADVANCEABLE_STATE_HPP_ +#include "rive/generated/animation/advanceable_state_base.hpp" +#include +namespace rive +{ +class AdvanceableState : public AdvanceableStateBase +{ +public: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/animation.hpp b/third_party/rive/include/rive/animation/animation.hpp new file mode 100644 index 0000000..757bca8 --- /dev/null +++ b/third_party/rive/include/rive/animation/animation.hpp @@ -0,0 +1,10 @@ +#ifndef _RIVE_ANIMATION_HPP_ +#define _RIVE_ANIMATION_HPP_ +#include "rive/generated/animation/animation_base.hpp" +namespace rive +{ +class Animation : public AnimationBase +{}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/animation_reset.hpp b/third_party/rive/include/rive/animation/animation_reset.hpp new file mode 100644 index 0000000..2828da3 --- /dev/null +++ b/third_party/rive/include/rive/animation/animation_reset.hpp @@ -0,0 +1,32 @@ +#ifndef _RIVE_ANIMATION_RESET_HPP_ +#define _RIVE_ANIMATION_RESET_HPP_ + +#include +#include "rive/artboard.hpp" +#include "rive/animation/animation_reset.hpp" +#include "rive/core/binary_writer.hpp" +#include "rive/core/vector_binary_writer.hpp" +#include "rive/core/binary_data_reader.hpp" + +namespace rive +{ + +class AnimationReset +{ +private: + VectorBinaryWriter m_binaryWriter; + BinaryDataReader m_binaryReader; + std::vector m_WriteBuffer; + +public: + AnimationReset(); + void writeObjectId(uint32_t objectId); + void writeTotalProperties(uint32_t value); + void writePropertyKey(uint32_t value); + void writePropertyValue(float value); + void apply(Artboard* artboard); + void complete(); + void clear(); +}; +} // namespace rive +#endif diff --git a/third_party/rive/include/rive/animation/animation_reset_factory.hpp b/third_party/rive/include/rive/animation/animation_reset_factory.hpp new file mode 100644 index 0000000..3665f53 --- /dev/null +++ b/third_party/rive/include/rive/animation/animation_reset_factory.hpp @@ -0,0 +1,44 @@ +#ifndef _RIVE_ANIMATION_RESET_FACTORY_HPP_ +#define _RIVE_ANIMATION_RESET_FACTORY_HPP_ + +#include +#include +#include "rive/animation/animation_reset.hpp" +#include "rive/animation/state_instance.hpp" +#include "rive/animation/linear_animation.hpp" +#include "rive/artboard.hpp" + +namespace rive +{ + +class AnimationResetFactory +{ + static std::vector> m_resources; + static std::mutex m_mutex; + +private: + static void fromState(StateInstance* stateInstance, + std::vector& animations); + +public: + static std::unique_ptr getInstance(); + static std::unique_ptr fromStates( + StateInstance* stateFrom, + StateInstance* currentState, + ArtboardInstance* artboard); + static std::unique_ptr fromAnimations( + std::vector& animations, + ArtboardInstance* artboard, + bool useFirstAsBaseline); + static void release(std::unique_ptr value); +#ifdef TESTING + // Used in testing to check pooled resources; + static int resourcesCount() + { + return static_cast(m_resources.size()); + }; + static void releaseResources() { m_resources.clear(); }; +#endif +}; +} // namespace rive +#endif diff --git a/third_party/rive/include/rive/animation/animation_state.hpp b/third_party/rive/include/rive/animation/animation_state.hpp new file mode 100644 index 0000000..8ed3cc2 --- /dev/null +++ b/third_party/rive/include/rive/animation/animation_state.hpp @@ -0,0 +1,30 @@ +#ifndef _RIVE_ANIMATION_STATE_HPP_ +#define _RIVE_ANIMATION_STATE_HPP_ +#include "rive/generated/animation/animation_state_base.hpp" +#include +namespace rive +{ +class LinearAnimation; +class ArtboardInstance; +class StateMachineLayerImporter; + +class AnimationState : public AnimationStateBase +{ + friend class StateMachineLayerImporter; + +private: + LinearAnimation* m_Animation = nullptr; + +public: + const LinearAnimation* animation() const { return m_Animation; } + +#ifdef TESTING + void animation(LinearAnimation* animation); +#endif + + std::unique_ptr makeInstance( + ArtboardInstance*) const override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/animation_state_instance.hpp b/third_party/rive/include/rive/animation/animation_state_instance.hpp new file mode 100644 index 0000000..bab0ade --- /dev/null +++ b/third_party/rive/include/rive/animation/animation_state_instance.hpp @@ -0,0 +1,41 @@ +#ifndef _RIVE_ANIMATION_STATE_INSTANCE_HPP_ +#define _RIVE_ANIMATION_STATE_INSTANCE_HPP_ + +#include +#include "rive/animation/state_instance.hpp" +#include "rive/animation/linear_animation_instance.hpp" + +namespace rive +{ +class AnimationState; + +/// Represents an instance of an animation state. +class AnimationStateInstance : public StateInstance +{ +private: + LinearAnimationInstance m_AnimationInstance; + bool m_KeepGoing; + +public: + AnimationStateInstance(const AnimationState* animationState, + ArtboardInstance* instance); + + void advance(float seconds, + StateMachineInstance* stateMachineInstance) override; + void apply(ArtboardInstance* instance, float mix) override; + + bool keepGoing() const override; + void clearSpilledTime() override; + + const LinearAnimationInstance* animationInstance() const + { + return &m_AnimationInstance; + } + + LinearAnimationInstance* animationInstance() + { + return &m_AnimationInstance; + } +}; +} // namespace rive +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/any_state.hpp b/third_party/rive/include/rive/animation/any_state.hpp new file mode 100644 index 0000000..bd07c14 --- /dev/null +++ b/third_party/rive/include/rive/animation/any_state.hpp @@ -0,0 +1,13 @@ +#ifndef _RIVE_ANY_STATE_HPP_ +#define _RIVE_ANY_STATE_HPP_ +#include "rive/generated/animation/any_state_base.hpp" +#include +namespace rive +{ +class AnyState : public AnyStateBase +{ +public: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/arithmetic_operation.hpp b/third_party/rive/include/rive/animation/arithmetic_operation.hpp new file mode 100644 index 0000000..f551e29 --- /dev/null +++ b/third_party/rive/include/rive/animation/arithmetic_operation.hpp @@ -0,0 +1,30 @@ +#ifndef _RIVE_ARITHMETIC_OPERATION_HPP_ +#define _RIVE_ARITHMETIC_OPERATION_HPP_ + +namespace rive +{ +enum class ArithmeticOperation : int +{ + add = 0, + subtract = 1, + multiply = 2, + divide = 3, + modulo = 4, + squareRoot = 5, + power = 6, + exp = 7, + log = 8, + cosine = 9, + sine = 10, + tangent = 11, + acosine = 12, + asine = 13, + atangent = 14, + atangent2 = 15, + round = 16, + floor = 17, + ceil = 18, +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/artboard_property.hpp b/third_party/rive/include/rive/animation/artboard_property.hpp new file mode 100644 index 0000000..0a4d606 --- /dev/null +++ b/third_party/rive/include/rive/animation/artboard_property.hpp @@ -0,0 +1,14 @@ +#ifndef _RIVE_ARTBOARD_PROPERTY_HPP_ +#define _RIVE_ARTBOARD_PROPERTY_HPP_ + +namespace rive +{ +enum class ArtboardProperty : int +{ + width = 0, + height = 1, + ratio = 2, +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/blend_animation.hpp b/third_party/rive/include/rive/animation/blend_animation.hpp new file mode 100644 index 0000000..1e0b88a --- /dev/null +++ b/third_party/rive/include/rive/animation/blend_animation.hpp @@ -0,0 +1,22 @@ +#ifndef _RIVE_BLEND_ANIMATION_HPP_ +#define _RIVE_BLEND_ANIMATION_HPP_ +#include "rive/generated/animation/blend_animation_base.hpp" +namespace rive +{ +class LinearAnimation; +class BlendAnimation : public BlendAnimationBase +{ +private: + static LinearAnimation m_EmptyAnimation; + LinearAnimation* m_Animation = nullptr; + +public: + const LinearAnimation* animation() const + { + return m_Animation == nullptr ? &m_EmptyAnimation : m_Animation; + } + StatusCode import(ImportStack& importStack) override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/blend_animation_1d.hpp b/third_party/rive/include/rive/animation/blend_animation_1d.hpp new file mode 100644 index 0000000..42b77e1 --- /dev/null +++ b/third_party/rive/include/rive/animation/blend_animation_1d.hpp @@ -0,0 +1,15 @@ +#ifndef _RIVE_BLEND_ANIMATION1_D_HPP_ +#define _RIVE_BLEND_ANIMATION1_D_HPP_ +#include "rive/generated/animation/blend_animation_1d_base.hpp" +#include +namespace rive +{ +class BlendAnimation1D : public BlendAnimation1DBase +{ +public: + StatusCode onAddedDirty(CoreContext* context) override; + StatusCode onAddedClean(CoreContext* context) override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/blend_animation_direct.hpp b/third_party/rive/include/rive/animation/blend_animation_direct.hpp new file mode 100644 index 0000000..4c8433e --- /dev/null +++ b/third_party/rive/include/rive/animation/blend_animation_direct.hpp @@ -0,0 +1,33 @@ +#ifndef _RIVE_BLEND_ANIMATION_DIRECT_HPP_ +#define _RIVE_BLEND_ANIMATION_DIRECT_HPP_ +#include "rive/generated/animation/blend_animation_direct_base.hpp" +#include +namespace rive +{ +class BindableProperty; +enum class DirectBlendSource : unsigned int +{ + inputId = 0, + mixValue = 1, + dataBindId = 2, +}; + +class BlendAnimationDirect : public BlendAnimationDirectBase +{ +public: + StatusCode onAddedDirty(CoreContext* context) override; + StatusCode onAddedClean(CoreContext* context) override; + StatusCode import(ImportStack& importStack) override; + void bindableProperty(BindableProperty* value) + { + m_bindableProperty = value; + }; + BindableProperty* bindableProperty() const { return m_bindableProperty; }; + +private: + BindableProperty* m_bindableProperty; +}; + +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/blend_state.hpp b/third_party/rive/include/rive/animation/blend_state.hpp new file mode 100644 index 0000000..d6cba1e --- /dev/null +++ b/third_party/rive/include/rive/animation/blend_state.hpp @@ -0,0 +1,35 @@ +#ifndef _RIVE_BLEND_STATE_HPP_ +#define _RIVE_BLEND_STATE_HPP_ +#include "rive/generated/animation/blend_state_base.hpp" +#include +#include +#include + +namespace rive +{ +class BlendAnimation; +class LayerStateImporter; + +class BlendState : public BlendStateBase +{ + friend class LayerStateImporter; + +private: + std::vector m_Animations; + void addAnimation(BlendAnimation* animation); + +public: + ~BlendState() override; + inline const std::vector& animations() const + { + return m_Animations; + } + +#ifdef TESTING + size_t animationCount() { return m_Animations.size(); } + BlendAnimation* animation(size_t index) { return m_Animations[index]; } +#endif +}; +} // namespace rive + +#endif diff --git a/third_party/rive/include/rive/animation/blend_state_1d.hpp b/third_party/rive/include/rive/animation/blend_state_1d.hpp new file mode 100644 index 0000000..5694ea3 --- /dev/null +++ b/third_party/rive/include/rive/animation/blend_state_1d.hpp @@ -0,0 +1,15 @@ +#ifndef _RIVE_BLEND_STATE1_D_HPP_ +#define _RIVE_BLEND_STATE1_D_HPP_ +#include "rive/generated/animation/blend_state_1d_base.hpp" + +namespace rive +{ +class BlendState1D : public BlendState1DBase +{ +public: + std::unique_ptr makeInstance( + ArtboardInstance*) const override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/blend_state_1d_input.hpp b/third_party/rive/include/rive/animation/blend_state_1d_input.hpp new file mode 100644 index 0000000..e5226d0 --- /dev/null +++ b/third_party/rive/include/rive/animation/blend_state_1d_input.hpp @@ -0,0 +1,16 @@ +#ifndef _RIVE_BLEND_STATE1_DINPUT_HPP_ +#define _RIVE_BLEND_STATE1_DINPUT_HPP_ +#include "rive/generated/animation/blend_state_1d_input_base.hpp" +#include +namespace rive +{ +class BlendState1DInput : public BlendState1DInputBase +{ +public: + bool hasValidInputId() const { return inputId() != Core::emptyId; } + + StatusCode import(ImportStack& importStack) override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/blend_state_1d_instance.hpp b/third_party/rive/include/rive/animation/blend_state_1d_instance.hpp new file mode 100644 index 0000000..3f44fe5 --- /dev/null +++ b/third_party/rive/include/rive/animation/blend_state_1d_instance.hpp @@ -0,0 +1,30 @@ +#ifndef _RIVE_BLEND_STATE_1D_INSTANCE_HPP_ +#define _RIVE_BLEND_STATE_1D_INSTANCE_HPP_ + +#include "rive/animation/blend_state_instance.hpp" +#include "rive/animation/blend_state_1d.hpp" +#include "rive/animation/blend_animation_1d.hpp" +#include "rive/animation/animation_reset.hpp" +#include "rive/animation/animation_reset_factory.hpp" + +namespace rive +{ +class BlendState1DInstance + : public BlendStateInstance +{ +private: + BlendStateAnimationInstance* m_From = nullptr; + BlendStateAnimationInstance* m_To = nullptr; + std::unique_ptr m_AnimationReset; + int animationIndex(float value); + +public: + BlendState1DInstance(const BlendState1D* blendState, + ArtboardInstance* instance); + ~BlendState1DInstance(); + void advance(float seconds, + StateMachineInstance* stateMachineInstance) override; + void apply(ArtboardInstance* instance, float mix) override; +}; +} // namespace rive +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/blend_state_1d_viewmodel.hpp b/third_party/rive/include/rive/animation/blend_state_1d_viewmodel.hpp new file mode 100644 index 0000000..4e753b0 --- /dev/null +++ b/third_party/rive/include/rive/animation/blend_state_1d_viewmodel.hpp @@ -0,0 +1,21 @@ +#ifndef _RIVE_BLEND_STATE1_DVIEW_MODEL_HPP_ +#define _RIVE_BLEND_STATE1_DVIEW_MODEL_HPP_ +#include "rive/generated/animation/blend_state_1d_viewmodel_base.hpp" +#include "rive/data_bind/bindable_property.hpp" +#include +namespace rive +{ +class BlendState1DViewModel : public BlendState1DViewModelBase +{ +public: + ~BlendState1DViewModel(); + StatusCode import(ImportStack& importStack) override; + + BindableProperty* bindableProperty() const { return m_bindableProperty; }; + +protected: + BindableProperty* m_bindableProperty; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/blend_state_direct.hpp b/third_party/rive/include/rive/animation/blend_state_direct.hpp new file mode 100644 index 0000000..6d4c12c --- /dev/null +++ b/third_party/rive/include/rive/animation/blend_state_direct.hpp @@ -0,0 +1,15 @@ +#ifndef _RIVE_BLEND_STATE_DIRECT_HPP_ +#define _RIVE_BLEND_STATE_DIRECT_HPP_ +#include "rive/generated/animation/blend_state_direct_base.hpp" +#include +namespace rive +{ +class BlendStateDirect : public BlendStateDirectBase +{ +public: + std::unique_ptr makeInstance( + ArtboardInstance*) const override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/blend_state_direct_instance.hpp b/third_party/rive/include/rive/animation/blend_state_direct_instance.hpp new file mode 100644 index 0000000..95143bc --- /dev/null +++ b/third_party/rive/include/rive/animation/blend_state_direct_instance.hpp @@ -0,0 +1,20 @@ +#ifndef _RIVE_BLEND_STATE_DIRECT_INSTANCE_HPP_ +#define _RIVE_BLEND_STATE_DIRECT_INSTANCE_HPP_ + +#include "rive/animation/blend_state_instance.hpp" +#include "rive/animation/blend_state_direct.hpp" +#include "rive/animation/blend_animation_direct.hpp" + +namespace rive +{ +class BlendStateDirectInstance + : public BlendStateInstance +{ +public: + BlendStateDirectInstance(const BlendStateDirect* blendState, + ArtboardInstance* instance); + void advance(float seconds, + StateMachineInstance* stateMachineInstance) override; +}; +} // namespace rive +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/blend_state_instance.hpp b/third_party/rive/include/rive/animation/blend_state_instance.hpp new file mode 100644 index 0000000..dcaa1ba --- /dev/null +++ b/third_party/rive/include/rive/animation/blend_state_instance.hpp @@ -0,0 +1,123 @@ +#ifndef _RIVE_BLEND_STATE_INSTANCE_HPP_ +#define _RIVE_BLEND_STATE_INSTANCE_HPP_ + +#include +#include +#include "rive/animation/state_instance.hpp" +#include "rive/animation/blend_state.hpp" +#include "rive/animation/layer_state_flags.hpp" +#include "rive/animation/linear_animation_instance.hpp" +#include "rive/animation/state_machine_instance.hpp" +#include "rive/animation/animation_reset.hpp" +#include "rive/animation/animation_reset_factory.hpp" + +namespace rive +{ +class AnimationState; + +template class BlendStateInstance; +template class BlendStateAnimationInstance +{ + template friend class BlendStateInstance; + +private: + const T* m_BlendAnimation; + LinearAnimationInstance m_AnimationInstance; + float m_Mix = 0.0f; + +public: + const T* blendAnimation() const { return m_BlendAnimation; } + const LinearAnimationInstance* animationInstance() const + { + return &m_AnimationInstance; + } + + BlendStateAnimationInstance(const T* blendAnimation, + ArtboardInstance* instance) : + m_BlendAnimation(blendAnimation), + m_AnimationInstance(blendAnimation->animation(), instance) + {} + + void mix(float value) { m_Mix = value; } +}; + +template class BlendStateInstance : public StateInstance +{ +protected: + std::vector> m_AnimationInstances; + bool m_KeepGoing = true; + +public: + BlendStateInstance(const K* blendState, ArtboardInstance* instance) : + StateInstance(blendState) + { + m_AnimationInstances.reserve(blendState->animations().size()); + + for (auto blendAnimation : blendState->animations()) + { + m_AnimationInstances.emplace_back( + BlendStateAnimationInstance(static_cast(blendAnimation), + instance)); + } + if ((static_cast(blendState->flags()) & + LayerStateFlags::Reset) == LayerStateFlags::Reset) + { + auto animations = std::vector(); + for (auto blendAnimation : blendState->animations()) + { + animations.push_back(blendAnimation->animation()); + } + } + } + + bool keepGoing() const override { return m_KeepGoing; } + + void advance(float seconds, + StateMachineInstance* stateMachineInstance) override + { + // NOTE: we are intentionally ignoring the animationInstances' keepGoing + // return value. + // Blend states need to keep blending forever, as even if the animation + // does not change the mix values may + for (auto& animation : m_AnimationInstances) + { + if (animation.m_AnimationInstance.keepGoing()) + { + // Should animations with m_Mix == 0.0 advance? They will + // trigger events and the event properties (if any) will not be + // updated by animationInstance.apply + animation.m_AnimationInstance.advance(seconds, + stateMachineInstance); + } + } + } + + void apply(ArtboardInstance* instance, float mix) override + { + for (auto& animation : m_AnimationInstances) + { + float m = mix * animation.m_Mix; + if (m == 0.0f) + { + continue; + } + animation.m_AnimationInstance.apply(m); + } + } + + // Find the animationInstance that corresponds to the blendAnimation. + const LinearAnimationInstance* animationInstance( + const BlendAnimation* blendAnimation) const + { + for (auto& animation : m_AnimationInstances) + { + if (animation.m_BlendAnimation == blendAnimation) + { + return animation.animationInstance(); + } + } + return nullptr; + } +}; +} // namespace rive +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/blend_state_transition.hpp b/third_party/rive/include/rive/animation/blend_state_transition.hpp new file mode 100644 index 0000000..3c0f553 --- /dev/null +++ b/third_party/rive/include/rive/animation/blend_state_transition.hpp @@ -0,0 +1,28 @@ +#ifndef _RIVE_BLEND_STATE_TRANSITION_HPP_ +#define _RIVE_BLEND_STATE_TRANSITION_HPP_ +#include "rive/generated/animation/blend_state_transition_base.hpp" +#include +namespace rive +{ +class BlendAnimation; +class LayerStateImporter; +class BlendStateTransition : public BlendStateTransitionBase +{ + friend class LayerStateImporter; + +private: + BlendAnimation* m_ExitBlendAnimation = nullptr; + +public: + BlendAnimation* exitBlendAnimation() const { return m_ExitBlendAnimation; } + + const LinearAnimationInstance* exitTimeAnimationInstance( + const StateInstance* from) const override; + + const LinearAnimation* exitTimeAnimation( + const LayerState* from) const override; +}; + +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/cubic_ease_interpolator.hpp b/third_party/rive/include/rive/animation/cubic_ease_interpolator.hpp new file mode 100644 index 0000000..ce68f53 --- /dev/null +++ b/third_party/rive/include/rive/animation/cubic_ease_interpolator.hpp @@ -0,0 +1,15 @@ +#ifndef _RIVE_CUBIC_EASE_INTERPOLATOR_HPP_ +#define _RIVE_CUBIC_EASE_INTERPOLATOR_HPP_ +#include "rive/generated/animation/cubic_ease_interpolator_base.hpp" +#include +namespace rive +{ +class CubicEaseInterpolator : public CubicEaseInterpolatorBase +{ +public: + float transformValue(float valueFrom, float valueTo, float factor) override; + float transform(float factor) const override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/cubic_interpolator.hpp b/third_party/rive/include/rive/animation/cubic_interpolator.hpp new file mode 100644 index 0000000..1737f18 --- /dev/null +++ b/third_party/rive/include/rive/animation/cubic_interpolator.hpp @@ -0,0 +1,19 @@ +#ifndef _RIVE_CUBIC_INTERPOLATOR_HPP_ +#define _RIVE_CUBIC_INTERPOLATOR_HPP_ +#include "rive/generated/animation/cubic_interpolator_base.hpp" +#include "rive/animation/cubic_interpolator_solver.hpp" + +namespace rive +{ +class CubicInterpolator : public CubicInterpolatorBase +{ +public: + StatusCode onAddedDirty(CoreContext* context) override; + void initialize() override; + +protected: + CubicInterpolatorSolver m_solver; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/cubic_interpolator_component.hpp b/third_party/rive/include/rive/animation/cubic_interpolator_component.hpp new file mode 100644 index 0000000..89aefda --- /dev/null +++ b/third_party/rive/include/rive/animation/cubic_interpolator_component.hpp @@ -0,0 +1,19 @@ +#ifndef _RIVE_CUBIC_INTERPOLATOR_COMPONENT_HPP_ +#define _RIVE_CUBIC_INTERPOLATOR_COMPONENT_HPP_ +#include "rive/generated/animation/cubic_interpolator_component_base.hpp" +#include "rive/animation/cubic_interpolator_solver.hpp" + +namespace rive +{ +class CubicInterpolatorComponent : public CubicInterpolatorComponentBase +{ +public: + StatusCode onAddedDirty(CoreContext* context) override; + float transform(float factor) const; + +private: + CubicInterpolatorSolver m_solver; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/cubic_interpolator_solver.hpp b/third_party/rive/include/rive/animation/cubic_interpolator_solver.hpp new file mode 100644 index 0000000..5aeebe8 --- /dev/null +++ b/third_party/rive/include/rive/animation/cubic_interpolator_solver.hpp @@ -0,0 +1,23 @@ +#ifndef _RIVE_CUBIC_INTERPOLATOR_SOLVER_HPP_ +#define _RIVE_CUBIC_INTERPOLATOR_SOLVER_HPP_ + +namespace rive +{ +// A helper for finding T based on X value. +class CubicInterpolatorSolver +{ +public: + void build(float x1, float x2); + float getT(float x) const; + static float calcBezier(float aT, float aA1, float aA2); + +private: + static constexpr int SplineTableSize = 11; + static constexpr float SampleStepSize = 1.0f / (SplineTableSize - 1.0f); + float m_values[SplineTableSize]; + float m_x1; + float m_x2; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/cubic_value_interpolator.hpp b/third_party/rive/include/rive/animation/cubic_value_interpolator.hpp new file mode 100644 index 0000000..bbd724b --- /dev/null +++ b/third_party/rive/include/rive/animation/cubic_value_interpolator.hpp @@ -0,0 +1,26 @@ +#ifndef _RIVE_CUBIC_VALUE_INTERPOLATOR_HPP_ +#define _RIVE_CUBIC_VALUE_INTERPOLATOR_HPP_ +#include "rive/generated/animation/cubic_value_interpolator_base.hpp" +#include +namespace rive +{ +class CubicValueInterpolator : public CubicValueInterpolatorBase +{ +private: + float m_A; + float m_B; + float m_C; + float m_D; + float m_ValueTo; + + void computeParameters(); + +public: + CubicValueInterpolator(); + float transformValue(float valueFrom, float valueTo, float factor) override; + float transform(float factor) const override; + StatusCode onAddedDirty(CoreContext* context) override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/data_converter_range_mapper_flags.hpp b/third_party/rive/include/rive/animation/data_converter_range_mapper_flags.hpp new file mode 100644 index 0000000..a76da2d --- /dev/null +++ b/third_party/rive/include/rive/animation/data_converter_range_mapper_flags.hpp @@ -0,0 +1,27 @@ +#ifndef _RIVE_DATA_CONVERTER_RANGE_MAPPER_FLAGS_HPP_ +#define _RIVE_DATA_CONVERTER_RANGE_MAPPER_FLAGS_HPP_ + +#include "rive/enum_bitset.hpp" + +namespace rive +{ +enum class DataConverterRangeMapperFlags : unsigned short +{ + + /// Whether the lower bound should be clamped + ClampLower = 1 << 0, + + /// Whether the upper bound should be clamped + ClampUpper = 1 << 1, + + /// Whether the value should wrap if it exceeds the range + Modulo = 1 << 2, + + /// Whether to reverse the mapping + Reverse = 1 << 3, + +}; + +RIVE_MAKE_ENUM_BITSET(DataConverterRangeMapperFlags) +} // namespace rive +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/data_converter_to_string_flags.hpp b/third_party/rive/include/rive/animation/data_converter_to_string_flags.hpp new file mode 100644 index 0000000..b970f9f --- /dev/null +++ b/third_party/rive/include/rive/animation/data_converter_to_string_flags.hpp @@ -0,0 +1,21 @@ +#ifndef _RIVE_DATA_CONVERTER_TO_STRING_FLAGS_HPP_ +#define _RIVE_DATA_CONVERTER_TO_STRING_FLAGS_HPP_ + +#include "rive/enum_bitset.hpp" + +namespace rive +{ +enum class DataConverterToStringFlags : unsigned short +{ + + /// Whether to round to decimals + Round = 1 << 0, + + /// Whether to remove trailing zeros + TrailingZeros = 1 << 1, + +}; + +RIVE_MAKE_ENUM_BITSET(DataConverterToStringFlags) +} // namespace rive +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/easing.hpp b/third_party/rive/include/rive/animation/easing.hpp new file mode 100644 index 0000000..46fd973 --- /dev/null +++ b/third_party/rive/include/rive/animation/easing.hpp @@ -0,0 +1,14 @@ +#ifndef _RIVE_EASING_HPP_ +#define _RIVE_EASING_HPP_ +#include + +namespace rive +{ +enum class Easing : uint8_t +{ + easeIn = 0, + easeOut = 1, + easeInOut = 2 +}; +} +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/elastic_ease.hpp b/third_party/rive/include/rive/animation/elastic_ease.hpp new file mode 100644 index 0000000..bee5a66 --- /dev/null +++ b/third_party/rive/include/rive/animation/elastic_ease.hpp @@ -0,0 +1,26 @@ +#ifndef _RIVE_ELASTIC_EASE_HPP_ +#define _RIVE_ELASTIC_EASE_HPP_ + +namespace rive +{ +class ElasticEase +{ +public: + ElasticEase(float amplitude, float period); + float easeOut(float factor) const; + float easeIn(float factor) const; + float easeInOut(float factor) const; + +#ifndef TESTING +private: +#endif + float computeActualAmplitude(float time) const; + float m_amplitude; + float m_period; + + // Computed phase shift for starting the sin function at 0 at factor 0. + float m_s; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/elastic_interpolator.hpp b/third_party/rive/include/rive/animation/elastic_interpolator.hpp new file mode 100644 index 0000000..6708d77 --- /dev/null +++ b/third_party/rive/include/rive/animation/elastic_interpolator.hpp @@ -0,0 +1,25 @@ +#ifndef _RIVE_ELASTIC_INTERPOLATOR_HPP_ +#define _RIVE_ELASTIC_INTERPOLATOR_HPP_ +#include "rive/generated/animation/elastic_interpolator_base.hpp" +#include "rive/animation/elastic_ease.hpp" +#include "rive/animation/easing.hpp" + +namespace rive +{ +class ElasticInterpolator : public ElasticInterpolatorBase +{ +public: + ElasticInterpolator(); + StatusCode onAddedDirty(CoreContext* context) override; + float transformValue(float valueFrom, float valueTo, float factor) override; + float transform(float factor) const override; + + Easing easing() const { return (Easing)easingValue(); } + void initialize() override; + +private: + ElasticEase m_elastic; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/entry_state.hpp b/third_party/rive/include/rive/animation/entry_state.hpp new file mode 100644 index 0000000..e9bbfa2 --- /dev/null +++ b/third_party/rive/include/rive/animation/entry_state.hpp @@ -0,0 +1,13 @@ +#ifndef _RIVE_ENTRY_STATE_HPP_ +#define _RIVE_ENTRY_STATE_HPP_ +#include "rive/generated/animation/entry_state_base.hpp" +#include +namespace rive +{ +class EntryState : public EntryStateBase +{ +public: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/exit_state.hpp b/third_party/rive/include/rive/animation/exit_state.hpp new file mode 100644 index 0000000..607526d --- /dev/null +++ b/third_party/rive/include/rive/animation/exit_state.hpp @@ -0,0 +1,13 @@ +#ifndef _RIVE_EXIT_STATE_HPP_ +#define _RIVE_EXIT_STATE_HPP_ +#include "rive/generated/animation/exit_state_base.hpp" +#include +namespace rive +{ +class ExitState : public ExitStateBase +{ +public: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/hittable.hpp b/third_party/rive/include/rive/animation/hittable.hpp new file mode 100644 index 0000000..be4d888 --- /dev/null +++ b/third_party/rive/include/rive/animation/hittable.hpp @@ -0,0 +1,22 @@ +#ifndef _RIVE_HITTABLE_HPP_ +#define _RIVE_HITTABLE_HPP_ + +#include "rive/math/aabb.hpp" + +namespace rive +{ +class Component; + +// A Component that can be hit-tested via two passes: a faster AABB pass, and a +// more accurate HiFi pass. +class Hittable +{ +public: + static Hittable* from(Component* component); + virtual bool hitTestAABB(const Vec2D& position) = 0; + virtual bool hitTestHiFi(const Vec2D& position, float hitRadius) = 0; + virtual ~Hittable() {} +}; +} // namespace rive + +#endif diff --git a/third_party/rive/include/rive/animation/interpolating_keyframe.hpp b/third_party/rive/include/rive/animation/interpolating_keyframe.hpp new file mode 100644 index 0000000..a2d31f6 --- /dev/null +++ b/third_party/rive/include/rive/animation/interpolating_keyframe.hpp @@ -0,0 +1,25 @@ +#ifndef _RIVE_INTERPOLATING_KEY_FRAME_HPP_ +#define _RIVE_INTERPOLATING_KEY_FRAME_HPP_ +#include "rive/generated/animation/interpolating_keyframe_base.hpp" + +namespace rive +{ +class KeyFrameInterpolator; +class InterpolatingKeyFrame : public InterpolatingKeyFrameBase +{ +public: + inline KeyFrameInterpolator* interpolator() const { return m_interpolator; } + virtual void apply(Core* object, int propertyKey, float mix) = 0; + virtual void applyInterpolation(Core* object, + int propertyKey, + float seconds, + const KeyFrame* nextFrame, + float mix) = 0; + StatusCode onAddedDirty(CoreContext* context) override; + +private: + KeyFrameInterpolator* m_interpolator = nullptr; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/keyed_callback_reporter.hpp b/third_party/rive/include/rive/animation/keyed_callback_reporter.hpp new file mode 100644 index 0000000..7f691a3 --- /dev/null +++ b/third_party/rive/include/rive/animation/keyed_callback_reporter.hpp @@ -0,0 +1,16 @@ +#ifndef _RIVE_KEYED_CALLBACK_REPORTER_HPP_ +#define _RIVE_KEYED_CALLBACK_REPORTER_HPP_ + +namespace rive +{ +class KeyedCallbackReporter +{ +public: + virtual ~KeyedCallbackReporter() {} + virtual void reportKeyedCallback(uint32_t objectId, + uint32_t propertyKey, + float elapsedSeconds) = 0; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/keyed_object.hpp b/third_party/rive/include/rive/animation/keyed_object.hpp new file mode 100644 index 0000000..3aba7b9 --- /dev/null +++ b/third_party/rive/include/rive/animation/keyed_object.hpp @@ -0,0 +1,46 @@ +#ifndef _RIVE_KEYED_OBJECT_HPP_ +#define _RIVE_KEYED_OBJECT_HPP_ +#include "rive/generated/animation/keyed_object_base.hpp" +#include +namespace rive +{ +class Artboard; +class KeyedProperty; +class KeyedCallbackReporter; +class KeyedObject : public KeyedObjectBase +{ +public: + KeyedObject(); + ~KeyedObject() override; + void addKeyedProperty(std::unique_ptr); + + StatusCode onAddedDirty(CoreContext* context) override; + StatusCode onAddedClean(CoreContext* context) override; + void reportKeyedCallbacks(KeyedCallbackReporter* reporter, + float secondsFrom, + float secondsTo, + bool isAtStartFrame) const; + void apply(Artboard* coreContext, float time, float mix); + + StatusCode import(ImportStack& importStack) override; + + const KeyedProperty* getProperty(size_t index) const + { + if (index < m_keyedProperties.size()) + { + return m_keyedProperties[index].get(); + } + else + { + return nullptr; + } + } + + size_t numKeyedProperties() const { return m_keyedProperties.size(); } + +private: + std::vector> m_keyedProperties; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/keyed_property.hpp b/third_party/rive/include/rive/animation/keyed_property.hpp new file mode 100644 index 0000000..d9d0425 --- /dev/null +++ b/third_party/rive/include/rive/animation/keyed_property.hpp @@ -0,0 +1,44 @@ +#ifndef _RIVE_KEYED_PROPERTY_HPP_ +#define _RIVE_KEYED_PROPERTY_HPP_ +#include "rive/generated/animation/keyed_property_base.hpp" +#include +namespace rive +{ +class KeyFrame; +class KeyedCallbackReporter; +class KeyedProperty : public KeyedPropertyBase +{ +public: + KeyedProperty(); + ~KeyedProperty() override; + void addKeyFrame(std::unique_ptr); + StatusCode onAddedClean(CoreContext* context) override; + StatusCode onAddedDirty(CoreContext* context) override; + + /// Report any keyframes that occured between secondsFrom and secondsTo. + void reportKeyedCallbacks(KeyedCallbackReporter* reporter, + uint32_t objectId, + float secondsFrom, + float secondsTo, + bool isAtStartFrame) const; + + /// Apply interpolating key frames. + void apply(Core* object, float time, float mix); + + StatusCode import(ImportStack& importStack) override; + KeyFrame* first() const + { + if (m_keyFrames.size() > 0) + { + return m_keyFrames.front().get(); + } + return nullptr; + } + +private: + int closestFrameIndex(float seconds, int exactOffset = 0) const; + std::vector> m_keyFrames; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/keyframe.hpp b/third_party/rive/include/rive/animation/keyframe.hpp new file mode 100644 index 0000000..b1621c8 --- /dev/null +++ b/third_party/rive/include/rive/animation/keyframe.hpp @@ -0,0 +1,20 @@ +#ifndef _RIVE_KEY_FRAME_HPP_ +#define _RIVE_KEY_FRAME_HPP_ +#include "rive/generated/animation/keyframe_base.hpp" +namespace rive +{ +class KeyFrame : public KeyFrameBase +{ +public: + inline float seconds() const { return m_seconds; } + + void computeSeconds(int fps); + + StatusCode import(ImportStack& importStack) override; + +private: + float m_seconds; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/keyframe_bool.hpp b/third_party/rive/include/rive/animation/keyframe_bool.hpp new file mode 100644 index 0000000..226fd87 --- /dev/null +++ b/third_party/rive/include/rive/animation/keyframe_bool.hpp @@ -0,0 +1,19 @@ +#ifndef _RIVE_KEY_FRAME_BOOL_HPP_ +#define _RIVE_KEY_FRAME_BOOL_HPP_ +#include "rive/generated/animation/keyframe_bool_base.hpp" + +namespace rive +{ +class KeyFrameBool : public KeyFrameBoolBase +{ +public: + void apply(Core* object, int propertyKey, float mix) override; + void applyInterpolation(Core* object, + int propertyKey, + float seconds, + const KeyFrame* nextFrame, + float mix) override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/keyframe_callback.hpp b/third_party/rive/include/rive/animation/keyframe_callback.hpp new file mode 100644 index 0000000..9c8c344 --- /dev/null +++ b/third_party/rive/include/rive/animation/keyframe_callback.hpp @@ -0,0 +1,13 @@ +#ifndef _RIVE_KEY_FRAME_CALLBACK_HPP_ +#define _RIVE_KEY_FRAME_CALLBACK_HPP_ +#include "rive/generated/animation/keyframe_callback_base.hpp" + +namespace rive +{ +class KeyFrameCallback : public KeyFrameCallbackBase +{ +public: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/keyframe_color.hpp b/third_party/rive/include/rive/animation/keyframe_color.hpp new file mode 100644 index 0000000..82c8bd9 --- /dev/null +++ b/third_party/rive/include/rive/animation/keyframe_color.hpp @@ -0,0 +1,18 @@ +#ifndef _RIVE_KEY_FRAME_COLOR_HPP_ +#define _RIVE_KEY_FRAME_COLOR_HPP_ +#include "rive/generated/animation/keyframe_color_base.hpp" +namespace rive +{ +class KeyFrameColor : public KeyFrameColorBase +{ +public: + void apply(Core* object, int propertyKey, float mix) override; + void applyInterpolation(Core* object, + int propertyKey, + float seconds, + const KeyFrame* nextFrame, + float mix) override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/keyframe_double.hpp b/third_party/rive/include/rive/animation/keyframe_double.hpp new file mode 100644 index 0000000..2bdff78 --- /dev/null +++ b/third_party/rive/include/rive/animation/keyframe_double.hpp @@ -0,0 +1,18 @@ +#ifndef _RIVE_KEY_FRAME_DOUBLE_HPP_ +#define _RIVE_KEY_FRAME_DOUBLE_HPP_ +#include "rive/generated/animation/keyframe_double_base.hpp" +namespace rive +{ +class KeyFrameDouble : public KeyFrameDoubleBase +{ +public: + void apply(Core* object, int propertyKey, float mix) override; + void applyInterpolation(Core* object, + int propertyKey, + float seconds, + const KeyFrame* nextFrame, + float mix) override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/keyframe_id.hpp b/third_party/rive/include/rive/animation/keyframe_id.hpp new file mode 100644 index 0000000..5182c6e --- /dev/null +++ b/third_party/rive/include/rive/animation/keyframe_id.hpp @@ -0,0 +1,19 @@ +#ifndef _RIVE_KEY_FRAME_ID_HPP_ +#define _RIVE_KEY_FRAME_ID_HPP_ +#include "rive/generated/animation/keyframe_id_base.hpp" + +namespace rive +{ +class KeyFrameId : public KeyFrameIdBase +{ +public: + void apply(Core* object, int propertyKey, float mix) override; + void applyInterpolation(Core* object, + int propertyKey, + float seconds, + const KeyFrame* nextFrame, + float mix) override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/keyframe_interpolator.hpp b/third_party/rive/include/rive/animation/keyframe_interpolator.hpp new file mode 100644 index 0000000..af0a7ca --- /dev/null +++ b/third_party/rive/include/rive/animation/keyframe_interpolator.hpp @@ -0,0 +1,33 @@ +#ifndef _RIVE_KEY_FRAME_INTERPOLATOR_HPP_ +#define _RIVE_KEY_FRAME_INTERPOLATOR_HPP_ +#include "rive/generated/animation/keyframe_interpolator_base.hpp" +#include +namespace rive +{ + +class InterpolatorHost +{ +public: + virtual ~InterpolatorHost() {} + virtual bool overridesKeyedInterpolation(int propertyKey) = 0; + static InterpolatorHost* from(Core* component); +}; + +class KeyFrameInterpolator : public KeyFrameInterpolatorBase +{ +public: + /// Convert a linear interpolation value to an eased one. + virtual float transformValue(float valueFrom, + float valueTo, + float factor) = 0; + + /// Convert a linear interpolation factor to an eased one. + virtual float transform(float factor) const = 0; + + StatusCode import(ImportStack& importStack) override; + + virtual void initialize(){}; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/keyframe_string.hpp b/third_party/rive/include/rive/animation/keyframe_string.hpp new file mode 100644 index 0000000..4749dc2 --- /dev/null +++ b/third_party/rive/include/rive/animation/keyframe_string.hpp @@ -0,0 +1,19 @@ +#ifndef _RIVE_KEY_FRAME_STRING_HPP_ +#define _RIVE_KEY_FRAME_STRING_HPP_ +#include "rive/generated/animation/keyframe_string_base.hpp" + +namespace rive +{ +class KeyFrameString : public KeyFrameStringBase +{ +public: + void apply(Core* object, int propertyKey, float mix) override; + void applyInterpolation(Core* object, + int propertyKey, + float seconds, + const KeyFrame* nextFrame, + float mix) override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/keyframe_uint.hpp b/third_party/rive/include/rive/animation/keyframe_uint.hpp new file mode 100644 index 0000000..2b398de --- /dev/null +++ b/third_party/rive/include/rive/animation/keyframe_uint.hpp @@ -0,0 +1,19 @@ +#ifndef _RIVE_KEY_FRAME_UINT_HPP_ +#define _RIVE_KEY_FRAME_UINT_HPP_ +#include "rive/generated/animation/keyframe_uint_base.hpp" +#include +namespace rive +{ +class KeyFrameUint : public KeyFrameUintBase +{ +public: + void apply(Core* object, int propertyKey, float mix) override; + void applyInterpolation(Core* object, + int propertyKey, + float seconds, + const KeyFrame* nextFrame, + float mix) override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/layer_state.hpp b/third_party/rive/include/rive/animation/layer_state.hpp new file mode 100644 index 0000000..989ccec --- /dev/null +++ b/third_party/rive/include/rive/animation/layer_state.hpp @@ -0,0 +1,48 @@ +#ifndef _RIVE_LAYER_STATE_HPP_ +#define _RIVE_LAYER_STATE_HPP_ +#include "rive/generated/animation/layer_state_base.hpp" +#include +#include + +namespace rive +{ +class ArtboardInstance; +class StateTransition; +class LayerStateImporter; +class StateMachineLayerImporter; +class StateInstance; + +class LayerState : public LayerStateBase +{ + friend class LayerStateImporter; + friend class StateMachineLayerImporter; + +private: + std::vector m_Transitions; + void addTransition(StateTransition* transition); + +public: + ~LayerState() override; + StatusCode onAddedDirty(CoreContext* context) override; + StatusCode onAddedClean(CoreContext* context) override; + + StatusCode import(ImportStack& importStack) override; + + size_t transitionCount() const { return m_Transitions.size(); } + StateTransition* transition(size_t index) const + { + if (index < m_Transitions.size()) + { + return m_Transitions[index]; + } + return nullptr; + } + + /// Make an instance of this state that can be advanced and applied by + /// the state machine when it is active or being transitioned from. + virtual std::unique_ptr makeInstance( + ArtboardInstance* instance) const; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/layer_state_flags.hpp b/third_party/rive/include/rive/animation/layer_state_flags.hpp new file mode 100644 index 0000000..97ff294 --- /dev/null +++ b/third_party/rive/include/rive/animation/layer_state_flags.hpp @@ -0,0 +1,27 @@ +#ifndef _RIVE_LAYER_STATE_FLAGS_HPP_ +#define _RIVE_LAYER_STATE_FLAGS_HPP_ + +#include + +namespace rive +{ +enum class LayerStateFlags : unsigned char +{ + None = 0, + + /// Whether the transition is disabled. + Random = 1 << 0, + + /// Whether the blend should include an instance to reset values on apply + Reset = 1 << 1, +}; + +inline constexpr LayerStateFlags operator&(LayerStateFlags lhs, + LayerStateFlags rhs) +{ + return static_cast( + static_cast::type>(lhs) & + static_cast::type>(rhs)); +} +} // namespace rive +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/linear_animation.hpp b/third_party/rive/include/rive/animation/linear_animation.hpp new file mode 100644 index 0000000..5550547 --- /dev/null +++ b/third_party/rive/include/rive/animation/linear_animation.hpp @@ -0,0 +1,73 @@ +#ifndef _RIVE_LINEAR_ANIMATION_HPP_ +#define _RIVE_LINEAR_ANIMATION_HPP_ +#include "rive/animation/loop.hpp" +#include "rive/generated/animation/linear_animation_base.hpp" +#include +namespace rive +{ +class Artboard; +class KeyedObject; +class KeyedCallbackReporter; + +class LinearAnimation : public LinearAnimationBase +{ +private: + std::vector> m_KeyedObjects; + + friend class Artboard; + +public: + LinearAnimation(); + ~LinearAnimation() override; + StatusCode onAddedDirty(CoreContext* context) override; + StatusCode onAddedClean(CoreContext* context) override; + void addKeyedObject(std::unique_ptr); + void apply(Artboard* artboard, float time, float mix = 1.0f) const; + + Loop loop() const { return (Loop)loopValue(); } + + StatusCode import(ImportStack& importStack) override; + + float durationSeconds() const; + /// Returns the start time/ end time of the animation in seconds + float startSeconds() const; + float endSeconds() const; + + /// Returns the start time/ end time of the animation in seconds, + /// considering speed + float startTime() const; + float startTime(float multiplier) const; + float endTime() const; + + /// Convert a global clock to local seconds (takes into consideration + /// work area start/end, speed, looping). + float globalToLocalSeconds(float seconds) const; + + const KeyedObject* getObject(size_t index) const + { + if (index < m_KeyedObjects.size()) + { + return m_KeyedObjects[index].get(); + } + else + { + return nullptr; + } + } + + size_t numKeyedObjects() const { return m_KeyedObjects.size(); } + +#ifdef TESTING + // Used in testing to check how many animations gets deleted. + static int deleteCount; +#endif + + void reportKeyedCallbacks(KeyedCallbackReporter* reporter, + float secondsFrom, + float secondsTo, + float speedDirection, + bool fromPong) const; +}; +} // namespace rive + +#endif diff --git a/third_party/rive/include/rive/animation/linear_animation_instance.hpp b/third_party/rive/include/rive/animation/linear_animation_instance.hpp new file mode 100644 index 0000000..751ac3a --- /dev/null +++ b/third_party/rive/include/rive/animation/linear_animation_instance.hpp @@ -0,0 +1,125 @@ +#ifndef _RIVE_LINEAR_ANIMATION_INSTANCE_HPP_ +#define _RIVE_LINEAR_ANIMATION_INSTANCE_HPP_ + +#include "rive/artboard.hpp" +#include "rive/core/field_types/core_callback_type.hpp" +#include "rive/nested_animation.hpp" +#include "rive/scene.hpp" + +namespace rive +{ +class LinearAnimation; +class NestedEventNotifier; + +class LinearAnimationInstance : public Scene, public NestedEventNotifier +{ +public: + LinearAnimationInstance(const LinearAnimation*, + ArtboardInstance*, + float speedMultiplier = 1.0); + LinearAnimationInstance(LinearAnimationInstance const&); + ~LinearAnimationInstance() override; + + // Advance the animation by the specified time. Returns true if the + // animation will continue to animate after this advance. + bool advance(float seconds, KeyedCallbackReporter* reporter); + bool advance(float seconds) { return advance(seconds, nullptr); } + + void clearSpilledTime() { m_spilledTime = 0; } + + // Returns a pointer to the instance's animation + const LinearAnimation* animation() const { return m_animation; } + + // Returns the current point in time at which this instance has advance + // to + float time() const { return m_time; } + + // Returns the direction that we are currently playing in + float direction() const { return m_direction; } + + // Returns speed in the current direction of the animation. + float directedSpeed() const { return m_direction * speed(); } + + // Update the direction of the animation instance, positive value for + // forwards Negative for backwards + void direction(int direction) + { + if (direction > 0) + { + m_direction = 1; + } + else + { + m_direction = -1; + } + } + + // Sets the animation's point in time. + void time(float value); + + // Applies the animation instance to its artboard instance. The mix (a value + // between 0 and 1) is the strength at which the animation is mixed with + // other animations applied to the artboard. + void apply(float mix = 1.0f) const + { + m_animation->apply(m_artboardInstance, m_time, mix); + } + + // Set when the animation is advanced, true if the animation has stopped + // (oneShot), reached the end (loop), or changed direction (pingPong) + bool didLoop() const { return m_didLoop; } + + bool keepGoing() const + { + return this->loopValue() != static_cast(rive::Loop::oneShot) || + (directedSpeed() > 0 && m_time < m_animation->endSeconds()) || + (directedSpeed() < 0 && m_time > m_animation->startSeconds()); + } + + bool keepGoing(float speedMultiplier) const + { + return this->loopValue() != static_cast(rive::Loop::oneShot) || + (directedSpeed() * speedMultiplier > 0 && + m_time < m_animation->endSeconds()) || + (directedSpeed() * speedMultiplier < 0 && + m_time > m_animation->startSeconds()); + } + + float totalTime() const { return m_totalTime; } + float lastTotalTime() const { return m_lastTotalTime; } + float spilledTime() const { return m_spilledTime; } + float durationSeconds() const override; + + // Forwarded from animation + uint32_t fps() const; + uint32_t duration() const; + float speed() const; + float startTime() const; + + // Returns either the animation's default or overridden loop values + Loop loop() const override { return (Loop)loopValue(); } + int loopValue() const; + // Override the animation's default loop + void loopValue(int value); + + bool isTranslucent() const override; + bool advanceAndApply(float seconds) override; + std::string name() const override; + void reset(float speedMultiplier); + void reportEvent(Event* event, float secondsDelay = 0.0f) override; + +private: + const LinearAnimation* m_animation = nullptr; + float m_time; + float m_speedDirection; + float m_totalTime; + float m_lastTotalTime; + float m_spilledTime; + + // float because it gets multiplied with other floats + float m_direction; + bool m_didLoop; + int m_loopValue = -1; +}; +} // namespace rive +#endif diff --git a/third_party/rive/include/rive/animation/listener_action.hpp b/third_party/rive/include/rive/animation/listener_action.hpp new file mode 100644 index 0000000..691ab0f --- /dev/null +++ b/third_party/rive/include/rive/animation/listener_action.hpp @@ -0,0 +1,19 @@ +#ifndef _RIVE_LISTENER_ACTION_HPP_ +#define _RIVE_LISTENER_ACTION_HPP_ +#include "rive/generated/animation/listener_action_base.hpp" +#include "rive/math/vec2d.hpp" + +namespace rive +{ +class StateMachineInstance; +class ListenerAction : public ListenerActionBase +{ +public: + StatusCode import(ImportStack& importStack) override; + virtual void perform(StateMachineInstance* stateMachineInstance, + Vec2D position, + Vec2D previousPosition) const = 0; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/listener_align_target.hpp b/third_party/rive/include/rive/animation/listener_align_target.hpp new file mode 100644 index 0000000..2a150d6 --- /dev/null +++ b/third_party/rive/include/rive/animation/listener_align_target.hpp @@ -0,0 +1,16 @@ +#ifndef _RIVE_LISTENER_ALIGN_TARGET_HPP_ +#define _RIVE_LISTENER_ALIGN_TARGET_HPP_ +#include "rive/generated/animation/listener_align_target_base.hpp" +#include +namespace rive +{ +class ListenerAlignTarget : public ListenerAlignTargetBase +{ +public: + void perform(StateMachineInstance* stateMachineInstance, + Vec2D position, + Vec2D previousPosition) const override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/listener_bool_change.hpp b/third_party/rive/include/rive/animation/listener_bool_change.hpp new file mode 100644 index 0000000..a6f25c2 --- /dev/null +++ b/third_party/rive/include/rive/animation/listener_bool_change.hpp @@ -0,0 +1,19 @@ +#ifndef _RIVE_LISTENER_BOOL_CHANGE_HPP_ +#define _RIVE_LISTENER_BOOL_CHANGE_HPP_ +#include "rive/generated/animation/listener_bool_change_base.hpp" + +namespace rive +{ +class NestedInput; +class ListenerBoolChange : public ListenerBoolChangeBase +{ +public: + bool validateInputType(const StateMachineInput* input) const override; + bool validateNestedInputType(const NestedInput* input) const override; + void perform(StateMachineInstance* stateMachineInstance, + Vec2D position, + Vec2D previousPosition) const override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/listener_fire_event.hpp b/third_party/rive/include/rive/animation/listener_fire_event.hpp new file mode 100644 index 0000000..4e4a7d2 --- /dev/null +++ b/third_party/rive/include/rive/animation/listener_fire_event.hpp @@ -0,0 +1,16 @@ +#ifndef _RIVE_LISTENER_FIRE_EVENT_HPP_ +#define _RIVE_LISTENER_FIRE_EVENT_HPP_ +#include "rive/generated/animation/listener_fire_event_base.hpp" + +namespace rive +{ +class ListenerFireEvent : public ListenerFireEventBase +{ +public: + void perform(StateMachineInstance* stateMachineInstance, + Vec2D position, + Vec2D previousPosition) const override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/listener_input_change.hpp b/third_party/rive/include/rive/animation/listener_input_change.hpp new file mode 100644 index 0000000..9a2a5ba --- /dev/null +++ b/third_party/rive/include/rive/animation/listener_input_change.hpp @@ -0,0 +1,24 @@ +#ifndef _RIVE_LISTENER_INPUT_CHANGE_HPP_ +#define _RIVE_LISTENER_INPUT_CHANGE_HPP_ +#include "rive/generated/animation/listener_input_change_base.hpp" + +namespace rive +{ +class NestedInput; +class StateMachineInput; +class ListenerInputChange : public ListenerInputChangeBase +{ +public: + StatusCode import(ImportStack& importStack) override; + virtual bool validateInputType(const StateMachineInput* input) const + { + return true; + } + virtual bool validateNestedInputType(const NestedInput* input) const + { + return true; + } +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/listener_number_change.hpp b/third_party/rive/include/rive/animation/listener_number_change.hpp new file mode 100644 index 0000000..613d7d3 --- /dev/null +++ b/third_party/rive/include/rive/animation/listener_number_change.hpp @@ -0,0 +1,19 @@ +#ifndef _RIVE_LISTENER_NUMBER_CHANGE_HPP_ +#define _RIVE_LISTENER_NUMBER_CHANGE_HPP_ +#include "rive/generated/animation/listener_number_change_base.hpp" + +namespace rive +{ +class NestedInput; +class ListenerNumberChange : public ListenerNumberChangeBase +{ +public: + bool validateInputType(const StateMachineInput* input) const override; + bool validateNestedInputType(const NestedInput* input) const override; + void perform(StateMachineInstance* stateMachineInstance, + Vec2D position, + Vec2D previousPosition) const override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/listener_trigger_change.hpp b/third_party/rive/include/rive/animation/listener_trigger_change.hpp new file mode 100644 index 0000000..005f472 --- /dev/null +++ b/third_party/rive/include/rive/animation/listener_trigger_change.hpp @@ -0,0 +1,19 @@ +#ifndef _RIVE_LISTENER_TRIGGER_CHANGE_HPP_ +#define _RIVE_LISTENER_TRIGGER_CHANGE_HPP_ +#include "rive/generated/animation/listener_trigger_change_base.hpp" + +namespace rive +{ +class NestedInput; +class ListenerTriggerChange : public ListenerTriggerChangeBase +{ +public: + bool validateInputType(const StateMachineInput* input) const override; + bool validateNestedInputType(const NestedInput* input) const override; + void perform(StateMachineInstance* stateMachineInstance, + Vec2D position, + Vec2D previousPosition) const override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/listener_viewmodel_change.hpp b/third_party/rive/include/rive/animation/listener_viewmodel_change.hpp new file mode 100644 index 0000000..a58ef49 --- /dev/null +++ b/third_party/rive/include/rive/animation/listener_viewmodel_change.hpp @@ -0,0 +1,22 @@ +#ifndef _RIVE_LISTENER_VIEW_MODEL_CHANGE_HPP_ +#define _RIVE_LISTENER_VIEW_MODEL_CHANGE_HPP_ +#include "rive/generated/animation/listener_viewmodel_change_base.hpp" +#include "rive/data_bind/bindable_property.hpp" +#include +namespace rive +{ +class ListenerViewModelChange : public ListenerViewModelChangeBase +{ +public: + ~ListenerViewModelChange(); + void perform(StateMachineInstance* stateMachineInstance, + Vec2D position, + Vec2D previousPosition) const override; + StatusCode import(ImportStack& importStack) override; + +private: + BindableProperty* m_bindableProperty; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/loop.hpp b/third_party/rive/include/rive/animation/loop.hpp new file mode 100644 index 0000000..d4f0d53 --- /dev/null +++ b/third_party/rive/include/rive/animation/loop.hpp @@ -0,0 +1,19 @@ +#ifndef _RIVE_LOOP_HPP_ +#define _RIVE_LOOP_HPP_ +namespace rive +{ +/// Loop options for linear animations. +enum class Loop : unsigned int +{ + /// Play until the duration or end of work area of the animation. + oneShot = 0, + + /// Play until the duration or end of work area of the animation and + /// then go back to the start (0 seconds). + loop = 1, + + /// Play to the end of the duration/work area and then play back. + pingPong = 2 +}; +} // namespace rive +#endif diff --git a/third_party/rive/include/rive/animation/nested_bool.hpp b/third_party/rive/include/rive/animation/nested_bool.hpp new file mode 100644 index 0000000..6421069 --- /dev/null +++ b/third_party/rive/include/rive/animation/nested_bool.hpp @@ -0,0 +1,19 @@ +#ifndef _RIVE_NESTED_BOOL_HPP_ +#define _RIVE_NESTED_BOOL_HPP_ +#include "rive/generated/animation/nested_bool_base.hpp" +#include +namespace rive +{ +class NestedBool : public NestedBoolBase +{ +public: + void nestedValue(bool value) override; + bool nestedValue() const override; + + void applyValue() override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/nested_input.hpp b/third_party/rive/include/rive/animation/nested_input.hpp new file mode 100644 index 0000000..a5d5c10 --- /dev/null +++ b/third_party/rive/include/rive/animation/nested_input.hpp @@ -0,0 +1,54 @@ +#ifndef _RIVE_NESTED_INPUT_HPP_ +#define _RIVE_NESTED_INPUT_HPP_ +#include "rive/animation/nested_state_machine.hpp" +#include "rive/animation/state_machine_input_instance.hpp" +#include "rive/generated/animation/nested_input_base.hpp" +#include +namespace rive +{ +class NestedInput : public NestedInputBase +{ +public: + StatusCode onAddedDirty(CoreContext* context) override + { + StatusCode result = Super::onAddedDirty(context); + auto parent = this->parent(); + if (parent != nullptr && parent->is()) + { + parent->as()->addNestedInput(this); + } + return result; + } + + virtual void applyValue() {} + + SMIInput* input() const + { + auto parent = this->parent(); + if (parent != nullptr && parent->is()) + { + StateMachineInstance* smInstance = + parent->as()->stateMachineInstance(); + if (smInstance == nullptr) + { + return nullptr; + } + auto inputInstance = smInstance->input(this->inputId()); + return inputInstance; + } + return nullptr; + } + + const std::string name() const + { + auto smi = input(); + if (smi != nullptr) + { + return smi->name(); + } + return std::string(); + } +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/nested_linear_animation.hpp b/third_party/rive/include/rive/animation/nested_linear_animation.hpp new file mode 100644 index 0000000..0864e2b --- /dev/null +++ b/third_party/rive/include/rive/animation/nested_linear_animation.hpp @@ -0,0 +1,25 @@ +#ifndef _RIVE_NESTED_LINEAR_ANIMATION_HPP_ +#define _RIVE_NESTED_LINEAR_ANIMATION_HPP_ +#include "rive/generated/animation/nested_linear_animation_base.hpp" +#include +namespace rive +{ +class LinearAnimationInstance; +class NestedLinearAnimation : public NestedLinearAnimationBase +{ +protected: + std::unique_ptr m_AnimationInstance; + +public: + NestedLinearAnimation(); + ~NestedLinearAnimation() override; + + void initializeAnimation(ArtboardInstance*) override; + LinearAnimationInstance* animationInstance() + { + return m_AnimationInstance.get(); + } +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/nested_number.hpp b/third_party/rive/include/rive/animation/nested_number.hpp new file mode 100644 index 0000000..f965126 --- /dev/null +++ b/third_party/rive/include/rive/animation/nested_number.hpp @@ -0,0 +1,18 @@ +#ifndef _RIVE_NESTED_NUMBER_HPP_ +#define _RIVE_NESTED_NUMBER_HPP_ +#include "rive/generated/animation/nested_number_base.hpp" +#include +namespace rive +{ +class NestedNumber : public NestedNumberBase +{ +public: + void nestedValue(float value) override; + float nestedValue() const override; + void applyValue() override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/nested_remap_animation.hpp b/third_party/rive/include/rive/animation/nested_remap_animation.hpp new file mode 100644 index 0000000..c50bf9f --- /dev/null +++ b/third_party/rive/include/rive/animation/nested_remap_animation.hpp @@ -0,0 +1,16 @@ +#ifndef _RIVE_NESTED_REMAP_ANIMATION_HPP_ +#define _RIVE_NESTED_REMAP_ANIMATION_HPP_ +#include "rive/generated/animation/nested_remap_animation_base.hpp" +#include +namespace rive +{ +class NestedRemapAnimation : public NestedRemapAnimationBase +{ +public: + void timeChanged() override; + bool advance(float elapsedSeconds, bool newFrame) override; + void initializeAnimation(ArtboardInstance*) override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/nested_simple_animation.hpp b/third_party/rive/include/rive/animation/nested_simple_animation.hpp new file mode 100644 index 0000000..6288e6f --- /dev/null +++ b/third_party/rive/include/rive/animation/nested_simple_animation.hpp @@ -0,0 +1,14 @@ +#ifndef _RIVE_NESTED_SIMPLE_ANIMATION_HPP_ +#define _RIVE_NESTED_SIMPLE_ANIMATION_HPP_ +#include "rive/generated/animation/nested_simple_animation_base.hpp" +#include +namespace rive +{ +class NestedSimpleAnimation : public NestedSimpleAnimationBase +{ +public: + bool advance(float elapsedSeconds, bool newFrame) override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/nested_state_machine.hpp b/third_party/rive/include/rive/animation/nested_state_machine.hpp new file mode 100644 index 0000000..339fede --- /dev/null +++ b/third_party/rive/include/rive/animation/nested_state_machine.hpp @@ -0,0 +1,43 @@ +#ifndef _RIVE_NESTED_STATE_MACHINE_HPP_ +#define _RIVE_NESTED_STATE_MACHINE_HPP_ +#include "rive/animation/state_machine_instance.hpp" +#include "rive/generated/animation/nested_state_machine_base.hpp" +#include "rive/hit_result.hpp" +#include "rive/math/vec2d.hpp" +#include + +namespace rive +{ +class ArtboardInstance; +class NestedInput; +class StateMachineInstance; +class NestedStateMachine : public NestedStateMachineBase +{ +private: + std::unique_ptr m_StateMachineInstance; + std::vector m_nestedInputs; + +public: + NestedStateMachine(); + ~NestedStateMachine() override; + bool advance(float elapsedSeconds, bool newFrame) override; + void initializeAnimation(ArtboardInstance*) override; + StateMachineInstance* stateMachineInstance(); + + HitResult pointerMove(Vec2D position); + HitResult pointerDown(Vec2D position); + HitResult pointerUp(Vec2D position); + HitResult pointerExit(Vec2D position); + bool tryChangeState(); + bool hitTest(Vec2D position) const; + + void addNestedInput(NestedInput* input); + size_t inputCount() { return m_nestedInputs.size(); } + NestedInput* input(size_t index); + NestedInput* input(std::string name); + void bindViewModelInstance(rcp viewModelInstance); + void dataContext(DataContext* dataContext); +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/nested_trigger.hpp b/third_party/rive/include/rive/animation/nested_trigger.hpp new file mode 100644 index 0000000..989eac8 --- /dev/null +++ b/third_party/rive/include/rive/animation/nested_trigger.hpp @@ -0,0 +1,15 @@ +#ifndef _RIVE_NESTED_TRIGGER_HPP_ +#define _RIVE_NESTED_TRIGGER_HPP_ +#include "rive/generated/animation/nested_trigger_base.hpp" +#include +namespace rive +{ +class NestedTrigger : public NestedTriggerBase +{ +public: + void applyValue() override; + void fire(const CallbackData& value) override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/state_instance.hpp b/third_party/rive/include/rive/animation/state_instance.hpp new file mode 100644 index 0000000..064ca6d --- /dev/null +++ b/third_party/rive/include/rive/animation/state_instance.hpp @@ -0,0 +1,36 @@ +#ifndef _RIVE_STATE_INSTANCE_HPP_ +#define _RIVE_STATE_INSTANCE_HPP_ + +#include +#include +#include "rive/rive_types.hpp" +#include "rive/span.hpp" + +namespace rive +{ +class LayerState; +class StateMachineInstance; +class ArtboardInstance; + +/// Represents an instance of a state tracked by the State Machine. +class StateInstance +{ +private: + const LayerState* m_LayerState; + +public: + StateInstance(const LayerState* layerState); + virtual ~StateInstance(); + virtual void advance(float seconds, + StateMachineInstance* stateMachineInstance) = 0; + virtual void apply(ArtboardInstance* instance, float mix) = 0; + + /// Returns true when the State Machine needs to keep advancing this + /// state. + virtual bool keepGoing() const = 0; + virtual void clearSpilledTime() {} + + const LayerState* state() const; +}; +} // namespace rive +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/state_machine.hpp b/third_party/rive/include/rive/animation/state_machine.hpp new file mode 100644 index 0000000..258fe61 --- /dev/null +++ b/third_party/rive/include/rive/animation/state_machine.hpp @@ -0,0 +1,52 @@ +#ifndef _RIVE_STATE_MACHINE_HPP_ +#define _RIVE_STATE_MACHINE_HPP_ +#include "rive/generated/animation/state_machine_base.hpp" +#include +#include + +namespace rive +{ +class StateMachineLayer; +class StateMachineInput; +class StateMachineListener; +class StateMachineImporter; +class DataBind; +class StateMachine : public StateMachineBase +{ + friend class StateMachineImporter; + +private: + std::vector> m_Layers; + std::vector> m_Inputs; + std::vector> m_Listeners; + std::vector> m_dataBinds; + + void addLayer(std::unique_ptr); + void addInput(std::unique_ptr); + void addListener(std::unique_ptr); + void addDataBind(std::unique_ptr); + +public: + StateMachine(); + ~StateMachine() override; + + StatusCode import(ImportStack& importStack) override; + + size_t layerCount() const { return m_Layers.size(); } + size_t inputCount() const { return m_Inputs.size(); } + size_t listenerCount() const { return m_Listeners.size(); } + size_t dataBindCount() const { return m_dataBinds.size(); } + + const StateMachineInput* input(std::string name) const; + const StateMachineInput* input(size_t index) const; + const StateMachineLayer* layer(std::string name) const; + const StateMachineLayer* layer(size_t index) const; + const DataBind* dataBind(size_t index) const; + const StateMachineListener* listener(size_t index) const; + + StatusCode onAddedDirty(CoreContext* context) override; + StatusCode onAddedClean(CoreContext* context) override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/state_machine_bool.hpp b/third_party/rive/include/rive/animation/state_machine_bool.hpp new file mode 100644 index 0000000..a441e55 --- /dev/null +++ b/third_party/rive/include/rive/animation/state_machine_bool.hpp @@ -0,0 +1,13 @@ +#ifndef _RIVE_STATE_MACHINE_BOOL_HPP_ +#define _RIVE_STATE_MACHINE_BOOL_HPP_ +#include "rive/generated/animation/state_machine_bool_base.hpp" +#include +namespace rive +{ +class StateMachineBool : public StateMachineBoolBase +{ +public: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/state_machine_component.hpp b/third_party/rive/include/rive/animation/state_machine_component.hpp new file mode 100644 index 0000000..8f6e340 --- /dev/null +++ b/third_party/rive/include/rive/animation/state_machine_component.hpp @@ -0,0 +1,13 @@ +#ifndef _RIVE_STATE_MACHINE_COMPONENT_HPP_ +#define _RIVE_STATE_MACHINE_COMPONENT_HPP_ +#include "rive/generated/animation/state_machine_component_base.hpp" +#include +namespace rive +{ +class StateMachineComponent : public StateMachineComponentBase +{ +public: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/state_machine_fire_event.hpp b/third_party/rive/include/rive/animation/state_machine_fire_event.hpp new file mode 100644 index 0000000..9927cfd --- /dev/null +++ b/third_party/rive/include/rive/animation/state_machine_fire_event.hpp @@ -0,0 +1,26 @@ +#ifndef _RIVE_STATE_MACHINE_FIRE_EVENT_HPP_ +#define _RIVE_STATE_MACHINE_FIRE_EVENT_HPP_ +#include "rive/generated/animation/state_machine_fire_event_base.hpp" + +namespace rive +{ +class StateMachineInstance; +enum class StateMachineFireOccurance : int +{ + atStart = 0, + atEnd = 1 +}; + +class StateMachineFireEvent : public StateMachineFireEventBase +{ +public: + StatusCode import(ImportStack& importStack) override; + StateMachineFireOccurance occurs() const + { + return (StateMachineFireOccurance)occursValue(); + } + void perform(StateMachineInstance* stateMachineInstance) const; +}; + +} // namespace rive +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/state_machine_input.hpp b/third_party/rive/include/rive/animation/state_machine_input.hpp new file mode 100644 index 0000000..d7d29ae --- /dev/null +++ b/third_party/rive/include/rive/animation/state_machine_input.hpp @@ -0,0 +1,16 @@ +#ifndef _RIVE_STATE_MACHINE_INPUT_HPP_ +#define _RIVE_STATE_MACHINE_INPUT_HPP_ +#include "rive/generated/animation/state_machine_input_base.hpp" +#include +namespace rive +{ +class StateMachineInput : public StateMachineInputBase +{ +public: + StatusCode onAddedDirty(CoreContext* context) override; + StatusCode onAddedClean(CoreContext* context) override; + StatusCode import(ImportStack& importStack) override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/state_machine_input_instance.hpp b/third_party/rive/include/rive/animation/state_machine_input_instance.hpp new file mode 100644 index 0000000..23958f2 --- /dev/null +++ b/third_party/rive/include/rive/animation/state_machine_input_instance.hpp @@ -0,0 +1,126 @@ +#ifndef _RIVE_STATE_MACHINE_INPUT_INSTANCE_HPP_ +#define _RIVE_STATE_MACHINE_INPUT_INSTANCE_HPP_ + +#include +#include +#include +#include + +namespace rive +{ +class StateMachineInstance; +class StateMachineInput; +class StateMachineBool; +class StateMachineNumber; +class StateMachineTrigger; +class TransitionTriggerCondition; +class StateMachineLayerInstance; + +class SMIInput +{ + friend class StateMachineInstance; + friend class StateMachineLayerInstance; + +private: + virtual void advanced() {} + +protected: + void valueChanged(); + + SMIInput(const StateMachineInput* input, + StateMachineInstance* machineInstance); + +public: + virtual ~SMIInput() {} + const StateMachineInput* input() const { return m_input; } + + const std::string& name() const; + uint16_t inputCoreType() const; + +private: + StateMachineInstance* m_machineInstance; + const StateMachineInput* m_input; +#ifdef WITH_RIVE_TOOLS + uint64_t m_index = 0; +#endif +}; + +class SMIBool : public SMIInput +{ + friend class StateMachineInstance; + +private: + bool m_Value; + + SMIBool(const StateMachineBool* input, + StateMachineInstance* machineInstance); + +public: + bool value() const { return m_Value; } + void value(bool newValue); +}; + +class SMINumber : public SMIInput +{ + friend class StateMachineInstance; + +private: + float m_Value; + + SMINumber(const StateMachineNumber* input, + StateMachineInstance* machineInstance); + +public: + float value() const { return m_Value; } + void value(float newValue); +}; + +class Triggerable +{ + +public: + bool isUsedInLayer(StateMachineLayerInstance* layer) const + { + auto it = std::find(m_usedLayers.begin(), m_usedLayers.end(), layer); + if (it == m_usedLayers.end()) + { + return false; + } + return true; + } + void useInLayer(StateMachineLayerInstance* layer) const + { + auto it = std::find(m_usedLayers.begin(), m_usedLayers.end(), layer); + if (it == m_usedLayers.end()) + { + m_usedLayers.push_back(layer); + } + } + +protected: + mutable std::vector m_usedLayers; +}; + +class SMITrigger : public SMIInput, public Triggerable +{ + friend class StateMachineInstance; + friend class TransitionTriggerCondition; + bool m_fired = false; + + SMITrigger(const StateMachineTrigger* input, + StateMachineInstance* machineInstance); + void advanced() override + { + m_fired = false; + m_usedLayers.clear(); + } + +public: + void fire(); + +#ifdef TESTING + bool didFire() { return m_fired; } +#endif +}; +} // namespace rive +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/state_machine_instance.hpp b/third_party/rive/include/rive/animation/state_machine_instance.hpp new file mode 100644 index 0000000..290674b --- /dev/null +++ b/third_party/rive/include/rive/animation/state_machine_instance.hpp @@ -0,0 +1,244 @@ +#ifndef _RIVE_STATE_MACHINE_INSTANCE_HPP_ +#define _RIVE_STATE_MACHINE_INSTANCE_HPP_ + +#include +#include +#include +#include +#include "rive/animation/linear_animation_instance.hpp" +#include "rive/animation/state_instance.hpp" +#include "rive/animation/state_transition.hpp" +#include "rive/core/field_types/core_callback_type.hpp" +#include "rive/hit_result.hpp" +#include "rive/listener_type.hpp" +#include "rive/nested_animation.hpp" +#include "rive/scene.hpp" + +namespace rive +{ +class StateMachine; +class LayerState; +class SMIInput; +class ArtboardInstance; +class SMIBool; +class SMINumber; +class SMITrigger; +class Shape; +class StateMachineLayerInstance; +class HitComponent; +class HitShape; +class ListenerGroup; +class NestedArtboard; +class NestedEventListener; +class NestedEventNotifier; +class Event; +class KeyedProperty; +class EventReport; +class DataBind; +class BindableProperty; +class HitDrawable; + +#ifdef WITH_RIVE_TOOLS +class StateMachineInstance; +typedef void (*InputChanged)(StateMachineInstance*, uint64_t); +#endif + +class StateMachineInstance : public Scene, + public NestedEventNotifier, + public NestedEventListener +{ + friend class SMIInput; + friend class KeyedProperty; + friend class HitComponent; + friend class StateMachineLayerInstance; + +private: + /// Provide a hitListener if you want to process a down or an up for the + /// pointer position too. + HitResult updateListeners(Vec2D position, ListenerType hitListener); + + template + InstType* getNamedInput(const std::string& name) const; + void notifyEventListeners(const std::vector& events, + NestedArtboard* source); + void sortHitComponents(); + double randomValue(); + StateTransition* findRandomTransition( + StateInstance* stateFromInstance, + StateMachineLayerInstance* layerInstance); + StateTransition* findAllowedTransition( + StateInstance* stateFromInstance, + StateMachineLayerInstance* layerInstance); + + bool m_ownsDataContext = false; + DataContext* m_DataContext = nullptr; + void addToHitLookup(Component* target, + bool isLayoutComponent, + std::unordered_map& hitLookup, + ListenerGroup* listenerGroup, + bool isOpaque); + +public: + StateMachineInstance(const StateMachine* machine, + ArtboardInstance* instance); + StateMachineInstance(StateMachineInstance const&) = delete; + ~StateMachineInstance() override; + + void markNeedsAdvance(); + // Advance the state machine by the specified time. Returns true if the + // state machine will continue to animate after this advance. + bool advance(float seconds, bool newFrame); + + bool advance(float seconds) { return advance(seconds, true); } + + // Returns true when the StateMachineInstance has more data to process. + bool needsAdvance() const; + + // Returns a pointer to the instance's stateMachine + const StateMachine* stateMachine() const { return m_machine; } + + size_t inputCount() const override { return m_inputInstances.size(); } + SMIInput* input(size_t index) const override; + SMIBool* getBool(const std::string& name) const override; + SMINumber* getNumber(const std::string& name) const override; + SMITrigger* getTrigger(const std::string& name) const override; + void bindViewModelInstance( + rcp viewModelInstance) override; + void dataContext(DataContext* dataContext); + + size_t currentAnimationCount() const; + const LinearAnimationInstance* currentAnimationByIndex(size_t index) const; + + // The number of state changes that occurred across all layers on the + // previous advance. + std::size_t stateChangedCount() const; + + // Returns the state name for states that changed in layers on the + // previously called advance. If the index of out of range, it returns + // the empty string. + const LayerState* stateChangedByIndex(size_t index) const; + + bool advanceAndApply(float secs) override; + void advancedDataContext(); + std::string name() const override; + HitResult pointerMove(Vec2D position) override; + HitResult pointerDown(Vec2D position) override; + HitResult pointerUp(Vec2D position) override; + HitResult pointerExit(Vec2D position) override; + bool tryChangeState(); + bool hitTest(Vec2D position) const; + + float durationSeconds() const override { return -1; } + Loop loop() const override { return Loop::oneShot; } + bool isTranslucent() const override { return true; } + + /// Allow anything referencing a concrete StateMachineInstace access to + /// the backing artboard (explicitly not allowed on Scenes). + Artboard* artboard() const { return m_artboardInstance; } + + void setParentStateMachineInstance(StateMachineInstance* instance) + { + m_parentStateMachineInstance = instance; + } + StateMachineInstance* parentStateMachineInstance() + { + return m_parentStateMachineInstance; + } + + void setParentNestedArtboard(NestedArtboard* artboard) + { + m_parentNestedArtboard = artboard; + } + NestedArtboard* parentNestedArtboard() { return m_parentNestedArtboard; } + void notify(const std::vector& events, + NestedArtboard* context) override; + + /// Tracks an event that reported, will be cleared at the end of the next + /// advance. + void reportEvent(Event* event, float secondsDelay = 0.0f) override; + + /// Gets the number of events that reported since the last advance. + std::size_t reportedEventCount() const; + + /// Gets a reported event at an index < reportedEventCount(). + const EventReport reportedEventAt(std::size_t index) const; + bool playsAudio() override { return true; } + BindableProperty* bindablePropertyInstance( + BindableProperty* bindableProperty) const; + DataBind* bindableDataBindToSource( + BindableProperty* bindableProperty) const; + DataBind* bindableDataBindToTarget( + BindableProperty* bindableProperty) const; + bool hasListeners() { return m_hitComponents.size() > 0; } +#ifdef TESTING + size_t hitComponentsCount() { return m_hitComponents.size(); }; + HitComponent* hitComponent(size_t index) + { + if (index < m_hitComponents.size()) + { + return m_hitComponents[index].get(); + } + return nullptr; + } + const LayerState* layerState(size_t index); +#endif + void updateDataBinds(); + +private: + std::vector m_reportedEvents; + const StateMachine* m_machine; + bool m_needsAdvance = false; + std::vector m_inputInstances; // we own each pointer + size_t m_layerCount; + StateMachineLayerInstance* m_layers; + std::vector> m_hitComponents; + std::vector> m_listenerGroups; + StateMachineInstance* m_parentStateMachineInstance = nullptr; + NestedArtboard* m_parentNestedArtboard = nullptr; + std::vector m_dataBinds; + std::unordered_map + m_bindablePropertyInstances; + std::unordered_map + m_bindableDataBindsToTarget; + std::unordered_map + m_bindableDataBindsToSource; + uint8_t m_drawOrderChangeCounter = 0; + void internalDataContext(DataContext* dataContext); + void clearDataContext(); + +#ifdef WITH_RIVE_TOOLS +public: + void onInputChanged(InputChanged callback) + { + m_inputChangedCallback = callback; + } + void onDataBindChanged(DataBindChanged callback); + InputChanged m_inputChangedCallback = nullptr; +#endif +}; + +class HitComponent +{ +public: + Component* component() const { return m_component; } + HitComponent(Component* component, + StateMachineInstance* stateMachineInstance) : + m_component(component), m_stateMachineInstance(stateMachineInstance) + {} + virtual ~HitComponent() {} + virtual HitResult processEvent(Vec2D position, + ListenerType hitType, + bool canHit) = 0; + virtual void prepareEvent(Vec2D position, ListenerType hitType) = 0; + virtual bool hitTest(Vec2D position) const = 0; +#ifdef TESTING + int earlyOutCount = 0; +#endif + +protected: + Component* m_component; + StateMachineInstance* m_stateMachineInstance; +}; + +} // namespace rive +#endif diff --git a/third_party/rive/include/rive/animation/state_machine_layer.hpp b/third_party/rive/include/rive/animation/state_machine_layer.hpp new file mode 100644 index 0000000..74ba7e3 --- /dev/null +++ b/third_party/rive/include/rive/animation/state_machine_layer.hpp @@ -0,0 +1,51 @@ +#ifndef _RIVE_STATE_MACHINE_LAYER_HPP_ +#define _RIVE_STATE_MACHINE_LAYER_HPP_ +#include "rive/generated/animation/state_machine_layer_base.hpp" +#include +#include + +namespace rive +{ +class LayerState; +class StateMachineLayerImporter; +class AnyState; +class EntryState; +class ExitState; +class StateMachineLayer : public StateMachineLayerBase +{ + friend class StateMachineLayerImporter; + +private: + std::vector m_States; + AnyState* m_Any = nullptr; + EntryState* m_Entry = nullptr; + ExitState* m_Exit = nullptr; + + void addState(LayerState* state); + +public: + ~StateMachineLayer() override; + StatusCode onAddedDirty(CoreContext* context) override; + StatusCode onAddedClean(CoreContext* context) override; + + StatusCode import(ImportStack& importStack) override; + + const AnyState* anyState() const { return m_Any; } + const EntryState* entryState() const { return m_Entry; } + const ExitState* exitState() const { return m_Exit; } + +#ifdef TESTING + size_t stateCount() const { return m_States.size(); } + LayerState* state(size_t index) const + { + if (index < m_States.size()) + { + return m_States[index]; + } + return nullptr; + } +#endif +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/state_machine_layer_component.hpp b/third_party/rive/include/rive/animation/state_machine_layer_component.hpp new file mode 100644 index 0000000..d94266d --- /dev/null +++ b/third_party/rive/include/rive/animation/state_machine_layer_component.hpp @@ -0,0 +1,25 @@ +#ifndef _RIVE_STATE_MACHINE_LAYER_COMPONENT_HPP_ +#define _RIVE_STATE_MACHINE_LAYER_COMPONENT_HPP_ +#include "rive/generated/animation/state_machine_layer_component_base.hpp" +#include + +namespace rive +{ +class StateMachineFireEvent; +class StateMachineLayerComponent : public StateMachineLayerComponentBase +{ + friend class StateMachineLayerComponentImporter; + +public: + const std::vector& events() const + { + return m_events; + } + ~StateMachineLayerComponent() override; + +private: + std::vector m_events; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/state_machine_listener.hpp b/third_party/rive/include/rive/animation/state_machine_listener.hpp new file mode 100644 index 0000000..051bc7a --- /dev/null +++ b/third_party/rive/include/rive/animation/state_machine_listener.hpp @@ -0,0 +1,40 @@ +#ifndef _RIVE_STATE_MACHINE_LISTENER_HPP_ +#define _RIVE_STATE_MACHINE_LISTENER_HPP_ +#include "rive/generated/animation/state_machine_listener_base.hpp" +#include "rive/listener_type.hpp" +#include "rive/math/vec2d.hpp" + +namespace rive +{ +class Shape; +class StateMachineListenerImporter; +class ListenerAction; +class StateMachineInstance; +class StateMachineListener : public StateMachineListenerBase +{ + friend class StateMachineListenerImporter; + +public: + StateMachineListener(); + ~StateMachineListener() override; + + ListenerType listenerType() const + { + return (ListenerType)listenerTypeValue(); + } + size_t actionCount() const { return m_actions.size(); } + + const ListenerAction* action(size_t index) const; + StatusCode import(ImportStack& importStack) override; + + void performChanges(StateMachineInstance* stateMachineInstance, + Vec2D position, + Vec2D previousPosition) const; + +private: + void addAction(std::unique_ptr); + std::vector> m_actions; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/state_machine_number.hpp b/third_party/rive/include/rive/animation/state_machine_number.hpp new file mode 100644 index 0000000..ca3e4e1 --- /dev/null +++ b/third_party/rive/include/rive/animation/state_machine_number.hpp @@ -0,0 +1,13 @@ +#ifndef _RIVE_STATE_MACHINE_NUMBER_HPP_ +#define _RIVE_STATE_MACHINE_NUMBER_HPP_ +#include "rive/generated/animation/state_machine_number_base.hpp" +#include +namespace rive +{ +class StateMachineNumber : public StateMachineNumberBase +{ +public: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/state_machine_trigger.hpp b/third_party/rive/include/rive/animation/state_machine_trigger.hpp new file mode 100644 index 0000000..c556c57 --- /dev/null +++ b/third_party/rive/include/rive/animation/state_machine_trigger.hpp @@ -0,0 +1,11 @@ +#ifndef _RIVE_STATE_MACHINE_TRIGGER_HPP_ +#define _RIVE_STATE_MACHINE_TRIGGER_HPP_ +#include "rive/generated/animation/state_machine_trigger_base.hpp" +#include +namespace rive +{ +class StateMachineTrigger : public StateMachineTriggerBase +{}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/state_transition.hpp b/third_party/rive/include/rive/animation/state_transition.hpp new file mode 100644 index 0000000..79b9fff --- /dev/null +++ b/third_party/rive/include/rive/animation/state_transition.hpp @@ -0,0 +1,144 @@ +#ifndef _RIVE_STATE_TRANSITION_HPP_ +#define _RIVE_STATE_TRANSITION_HPP_ +#include "rive/animation/keyframe_interpolator.hpp" +#include "rive/animation/state_transition_flags.hpp" +#include "rive/generated/animation/state_transition_base.hpp" +#include +#include + +namespace rive +{ +class LayerState; +class StateMachineLayerImporter; +class StateTransitionImporter; +class TransitionCondition; +class StateInstance; +class StateMachineInstance; +class StateMachineLayerInstance; +class LinearAnimation; +class LinearAnimationInstance; + +enum class AllowTransition : unsigned char +{ + no, + waitingForExit, + yes +}; + +class StateTransition : public StateTransitionBase +{ + friend class StateMachineLayerImporter; + friend class StateTransitionImporter; + +private: + StateTransitionFlags transitionFlags() const + { + return static_cast(flags()); + } + LayerState* m_StateTo = nullptr; + uint32_t m_EvaluatedRandomWeight = 1; + KeyFrameInterpolator* m_Interpolator = nullptr; + + std::vector m_Conditions; + void addCondition(TransitionCondition* condition); + +public: + ~StateTransition() override; + const LayerState* stateTo() const { return m_StateTo; } + inline KeyFrameInterpolator* interpolator() const { return m_Interpolator; } + + inline uint32_t evaluatedRandomWeight() const + { + return m_EvaluatedRandomWeight; + } + void evaluatedRandomWeight(uint32_t value) + { + m_EvaluatedRandomWeight = value; + } + + StatusCode onAddedDirty(CoreContext* context) override; + StatusCode onAddedClean(CoreContext* context) override; + + /// Whether the transition is marked disabled (usually done in the + /// editor). + bool isDisabled() const + { + return (transitionFlags() & StateTransitionFlags::Disabled) == + StateTransitionFlags::Disabled; + } + + /// Returns AllowTransition::yes when this transition can be taken from + /// stateFrom with the given inputs. + AllowTransition allowed(StateInstance* stateFrom, + StateMachineInstance* stateMachineInstance, + StateMachineLayerInstance* layerInstance) const; + + /// Whether the animation is held at exit or if it keeps advancing + /// during mixing. + bool pauseOnExit() const + { + return (transitionFlags() & StateTransitionFlags::PauseOnExit) == + StateTransitionFlags::PauseOnExit; + } + + /// Whether exit time is enabled. All other conditions still apply, the + /// exit time is effectively an AND with the rest of the conditions. + bool enableExitTime() const + { + return (transitionFlags() & StateTransitionFlags::EnableExitTime) == + StateTransitionFlags::EnableExitTime; + } + + /// Whether the transition can be interrupted. + bool enableEarlyExit() const + { + return (transitionFlags() & StateTransitionFlags::EnableEarlyExit) == + StateTransitionFlags::EnableEarlyExit; + } + + StatusCode import(ImportStack& importStack) override; + + size_t conditionCount() const { return m_Conditions.size(); } + TransitionCondition* condition(size_t index) const + { + if (index < m_Conditions.size()) + { + return m_Conditions[index]; + } + return nullptr; + } + + /// The amount of time to mix the outgoing animation onto the incoming + /// one when changing state. Only applies when going out from an + /// AnimationState. + float mixTime(const LayerState* stateFrom) const; + + /// Computes the exit time in seconds of the stateFrom. Set absolute to + /// true if you want the returned time to be relative to the entire + /// animation. Set absolute to false if you want it relative to the work + /// area. + float exitTimeSeconds(const LayerState* stateFrom, + bool absolute = false) const; + + /// Provide the animation instance to use for computing percentage + /// durations for exit time. + virtual const LinearAnimationInstance* exitTimeAnimationInstance( + const StateInstance* from) const; + + /// Provide the animation to use for computing percentage durations for + /// exit time. + virtual const LinearAnimation* exitTimeAnimation( + const LayerState* from) const; + + /// Retruns true when we need to hold the exit time, also applies the + /// correct time to the animation instance in the stateFrom, when + /// applicable (when it's an AnimationState). + bool applyExitCondition(StateInstance* stateFrom) const; + + /// Marks any trigger based condition as used for this layer + void useLayerInConditions(StateMachineInstance* stateMachineInstance, + StateMachineLayerInstance* layerInstance) const; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/state_transition_flags.hpp b/third_party/rive/include/rive/animation/state_transition_flags.hpp new file mode 100644 index 0000000..730df60 --- /dev/null +++ b/third_party/rive/include/rive/animation/state_transition_flags.hpp @@ -0,0 +1,93 @@ +#ifndef _RIVE_STATE_TRANSITION_FLAGS_HPP_ +#define _RIVE_STATE_TRANSITION_FLAGS_HPP_ + +#include + +namespace rive +{ +enum class StateTransitionFlags : unsigned char +{ + None = 0, + + /// Whether the transition is disabled. + Disabled = 1 << 0, + + /// Whether the transition duration is a percentage or time in ms. + DurationIsPercentage = 1 << 1, + + /// Whether exit time is enabled. + EnableExitTime = 1 << 2, + + /// Whether the exit time is a percentage or time in ms. + ExitTimeIsPercentage = 1 << 3, + + /// Whether the animation is held at exit or if it keeps advancing + /// during mixing. + PauseOnExit = 1 << 4, + + /// Whether the transition can exit before it is complete. + EnableEarlyExit = 1 << 5 + +}; + +inline constexpr StateTransitionFlags operator&(StateTransitionFlags lhs, + StateTransitionFlags rhs) +{ + return static_cast( + static_cast::type>(lhs) & + static_cast::type>(rhs)); +} + +inline constexpr StateTransitionFlags operator^(StateTransitionFlags lhs, + StateTransitionFlags rhs) +{ + return static_cast( + static_cast::type>(lhs) ^ + static_cast::type>(rhs)); +} + +inline constexpr StateTransitionFlags operator|(StateTransitionFlags lhs, + StateTransitionFlags rhs) +{ + return static_cast( + static_cast::type>(lhs) | + static_cast::type>(rhs)); +} + +inline constexpr StateTransitionFlags operator~(StateTransitionFlags rhs) +{ + return static_cast( + ~static_cast::type>(rhs)); +} + +inline StateTransitionFlags& operator|=(StateTransitionFlags& lhs, + StateTransitionFlags rhs) +{ + lhs = static_cast( + static_cast::type>(lhs) | + static_cast::type>(rhs)); + + return lhs; +} + +inline StateTransitionFlags& operator&=(StateTransitionFlags& lhs, + StateTransitionFlags rhs) +{ + lhs = static_cast( + static_cast::type>(lhs) & + static_cast::type>(rhs)); + + return lhs; +} + +inline StateTransitionFlags& operator^=(StateTransitionFlags& lhs, + StateTransitionFlags rhs) +{ + lhs = static_cast( + static_cast::type>(lhs) ^ + static_cast::type>(rhs)); + + return lhs; +} +} // namespace rive +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/system_state_instance.hpp b/third_party/rive/include/rive/animation/system_state_instance.hpp new file mode 100644 index 0000000..d3215e1 --- /dev/null +++ b/third_party/rive/include/rive/animation/system_state_instance.hpp @@ -0,0 +1,27 @@ +#ifndef _RIVE_SYSTEM_STATE_INSTANCE_HPP_ +#define _RIVE_SYSTEM_STATE_INSTANCE_HPP_ + +#include +#include "rive/animation/state_instance.hpp" + +namespace rive +{ +class StateMachineInstance; + +/// Represents an instance of a system state machine. Basically a +/// placeholder that may have meaning to the state machine itself, or is +/// just a no-op state (perhaps an unknown to this runtime state-type). +class SystemStateInstance : public StateInstance +{ +public: + SystemStateInstance(const LayerState* layerState, + ArtboardInstance* instance); + + void advance(float seconds, + StateMachineInstance* stateMachineInstance) override; + void apply(ArtboardInstance* artboard, float mix) override; + + bool keepGoing() const override; +}; +} // namespace rive +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/transition_artboard_condition.hpp b/third_party/rive/include/rive/animation/transition_artboard_condition.hpp new file mode 100644 index 0000000..7892537 --- /dev/null +++ b/third_party/rive/include/rive/animation/transition_artboard_condition.hpp @@ -0,0 +1,13 @@ +#ifndef _RIVE_TRANSITION_ARTBOARD_CONDITION_HPP_ +#define _RIVE_TRANSITION_ARTBOARD_CONDITION_HPP_ +#include "rive/generated/animation/transition_artboard_condition_base.hpp" +#include +namespace rive +{ +class TransitionArtboardCondition : public TransitionArtboardConditionBase +{ +public: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/transition_bool_condition.hpp b/third_party/rive/include/rive/animation/transition_bool_condition.hpp new file mode 100644 index 0000000..a93dc59 --- /dev/null +++ b/third_party/rive/include/rive/animation/transition_bool_condition.hpp @@ -0,0 +1,18 @@ +#ifndef _RIVE_TRANSITION_BOOL_CONDITION_HPP_ +#define _RIVE_TRANSITION_BOOL_CONDITION_HPP_ +#include "rive/generated/animation/transition_bool_condition_base.hpp" +#include +namespace rive +{ +class TransitionBoolCondition : public TransitionBoolConditionBase +{ +public: + bool evaluate(const StateMachineInstance* stateMachineInstance, + StateMachineLayerInstance* layerInstance) const override; + +protected: + bool validateInputType(const StateMachineInput* input) const override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/transition_comparator.hpp b/third_party/rive/include/rive/animation/transition_comparator.hpp new file mode 100644 index 0000000..b791373 --- /dev/null +++ b/third_party/rive/include/rive/animation/transition_comparator.hpp @@ -0,0 +1,39 @@ +#ifndef _RIVE_TRANSITION_COMPARATOR_HPP_ +#define _RIVE_TRANSITION_COMPARATOR_HPP_ +#include "rive/generated/animation/transition_comparator_base.hpp" +#include "rive/animation/transition_condition_op.hpp" +#include "rive/viewmodel/viewmodel_instance.hpp" +#include "rive/viewmodel/viewmodel_instance_value.hpp" +#include +namespace rive +{ +class StateMachineInstance; +class StateMachineLayerInstance; +class TransitionComparator : public TransitionComparatorBase +{ +public: + StatusCode import(ImportStack& importStack) override; + virtual bool compare(TransitionComparator* comparand, + TransitionConditionOp operation, + const StateMachineInstance* stateMachineInstance, + StateMachineLayerInstance* layerInstance); + + virtual void useInLayer(const StateMachineInstance* stateMachineInstance, + StateMachineLayerInstance* layerInstance) const + {} + +protected: + bool compareNumbers(float left, float right, TransitionConditionOp op); + bool compareBooleans(bool left, bool right, TransitionConditionOp op); + bool compareEnums(uint16_t left, uint16_t right, TransitionConditionOp op); + bool compareColors(int left, int right, TransitionConditionOp op); + bool compareStrings(std::string left, + std::string right, + TransitionConditionOp op); + bool compareTriggers(uint32_t left, + uint32_t right, + TransitionConditionOp op); +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/transition_condition.hpp b/third_party/rive/include/rive/animation/transition_condition.hpp new file mode 100644 index 0000000..138a530 --- /dev/null +++ b/third_party/rive/include/rive/animation/transition_condition.hpp @@ -0,0 +1,37 @@ +#ifndef _RIVE_TRANSITION_CONDITION_HPP_ +#define _RIVE_TRANSITION_CONDITION_HPP_ +#include "rive/generated/animation/transition_condition_base.hpp" +#include "rive/animation/state_machine_instance.hpp" + +namespace rive +{ +class StateMachineInput; +class SMIInput; + +class TransitionCondition : public TransitionConditionBase +{ +public: + StatusCode onAddedDirty(CoreContext* context) override; + StatusCode onAddedClean(CoreContext* context) override; + + StatusCode import(ImportStack& importStack) override; + + virtual bool evaluate(const StateMachineInstance* stateMachineInstance, + StateMachineLayerInstance* layerInstance) const + { + return true; + } + + virtual void useInLayer(const StateMachineInstance* stateMachineInstance, + StateMachineLayerInstance* layerInstance) const + {} + +protected: + virtual bool validateInputType(const StateMachineInput* input) const + { + return true; + } +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/transition_condition_op.hpp b/third_party/rive/include/rive/animation/transition_condition_op.hpp new file mode 100644 index 0000000..cf2ef7c --- /dev/null +++ b/third_party/rive/include/rive/animation/transition_condition_op.hpp @@ -0,0 +1,17 @@ +#ifndef _RIVE_TRANSITION_CONDITION_OP_HPP_ +#define _RIVE_TRANSITION_CONDITION_OP_HPP_ + +namespace rive +{ +enum class TransitionConditionOp : int +{ + equal = 0, + notEqual = 1, + lessThanOrEqual = 2, + greaterThanOrEqual = 3, + lessThan = 4, + greaterThan = 5 +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/transition_input_condition.hpp b/third_party/rive/include/rive/animation/transition_input_condition.hpp new file mode 100644 index 0000000..90ab05a --- /dev/null +++ b/third_party/rive/include/rive/animation/transition_input_condition.hpp @@ -0,0 +1,14 @@ +#ifndef _RIVE_TRANSITION_INPUT_CONDITION_HPP_ +#define _RIVE_TRANSITION_INPUT_CONDITION_HPP_ +#include "rive/generated/animation/transition_input_condition_base.hpp" +#include +namespace rive +{ +class TransitionInputCondition : public TransitionInputConditionBase +{ +public: + StatusCode import(ImportStack& importStack) override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/transition_number_condition.hpp b/third_party/rive/include/rive/animation/transition_number_condition.hpp new file mode 100644 index 0000000..7a3a372 --- /dev/null +++ b/third_party/rive/include/rive/animation/transition_number_condition.hpp @@ -0,0 +1,18 @@ +#ifndef _RIVE_TRANSITION_NUMBER_CONDITION_HPP_ +#define _RIVE_TRANSITION_NUMBER_CONDITION_HPP_ +#include "rive/generated/animation/transition_number_condition_base.hpp" +#include +namespace rive +{ +class TransitionNumberCondition : public TransitionNumberConditionBase +{ +protected: + bool validateInputType(const StateMachineInput* input) const override; + +public: + bool evaluate(const StateMachineInstance* stateMachineInstance, + StateMachineLayerInstance* layerInstance) const override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/transition_property_artboard_comparator.hpp b/third_party/rive/include/rive/animation/transition_property_artboard_comparator.hpp new file mode 100644 index 0000000..448f498 --- /dev/null +++ b/third_party/rive/include/rive/animation/transition_property_artboard_comparator.hpp @@ -0,0 +1,22 @@ +#ifndef _RIVE_TRANSITION_PROPERTY_ARTBOARD_COMPARATOR_HPP_ +#define _RIVE_TRANSITION_PROPERTY_ARTBOARD_COMPARATOR_HPP_ +#include "rive/generated/animation/transition_property_artboard_comparator_base.hpp" +#include +namespace rive +{ +class Artboard; +class TransitionPropertyArtboardComparator + : public TransitionPropertyArtboardComparatorBase +{ +public: + bool compare(TransitionComparator* comparand, + TransitionConditionOp operation, + const StateMachineInstance* stateMachineInstance, + StateMachineLayerInstance* layerInstance) override; + +private: + float propertyValue(const StateMachineInstance* stateMachineInstance); +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/transition_property_comparator.hpp b/third_party/rive/include/rive/animation/transition_property_comparator.hpp new file mode 100644 index 0000000..e2d9914 --- /dev/null +++ b/third_party/rive/include/rive/animation/transition_property_comparator.hpp @@ -0,0 +1,13 @@ +#ifndef _RIVE_TRANSITION_PROPERTY_COMPARATOR_HPP_ +#define _RIVE_TRANSITION_PROPERTY_COMPARATOR_HPP_ +#include "rive/generated/animation/transition_property_comparator_base.hpp" +#include +namespace rive +{ +class TransitionPropertyComparator : public TransitionPropertyComparatorBase +{ +public: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/transition_property_viewmodel_comparator.hpp b/third_party/rive/include/rive/animation/transition_property_viewmodel_comparator.hpp new file mode 100644 index 0000000..87fe6d1 --- /dev/null +++ b/third_party/rive/include/rive/animation/transition_property_viewmodel_comparator.hpp @@ -0,0 +1,44 @@ +#ifndef _RIVE_TRANSITION_PROPERTY_VIEW_MODEL_COMPARATOR_HPP_ +#define _RIVE_TRANSITION_PROPERTY_VIEW_MODEL_COMPARATOR_HPP_ +#include "rive/generated/animation/transition_property_viewmodel_comparator_base.hpp" +#include "rive/data_bind/bindable_property.hpp" +#include "rive/animation/state_machine_instance.hpp" +#include +namespace rive +{ +class TransitionPropertyViewModelComparator + : public TransitionPropertyViewModelComparatorBase +{ +public: + ~TransitionPropertyViewModelComparator(); + StatusCode import(ImportStack& importStack) override; + bool compare(TransitionComparator* comparand, + TransitionConditionOp operation, + const StateMachineInstance* stateMachineInstance, + StateMachineLayerInstance* layerInstance) override; + template + U value(const StateMachineInstance* stateMachineInstance) + { + if (m_bindableProperty != nullptr && m_bindableProperty->is()) + { + auto bindableInstance = + stateMachineInstance->bindablePropertyInstance( + m_bindableProperty); + if (bindableInstance != nullptr) + { + return bindableInstance->as()->propertyValue(); + } + } + return T::defaultValue; + }; + float valueToFloat(const StateMachineInstance* stateMachineInstance); + void useInLayer(const StateMachineInstance* stateMachineInstance, + StateMachineLayerInstance* layerInstance) const override; + DataType instanceDataType(const StateMachineInstance* stateMachineInstance); + +protected: + BindableProperty* m_bindableProperty; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/transition_trigger_condition.hpp b/third_party/rive/include/rive/animation/transition_trigger_condition.hpp new file mode 100644 index 0000000..9bd6dd6 --- /dev/null +++ b/third_party/rive/include/rive/animation/transition_trigger_condition.hpp @@ -0,0 +1,20 @@ +#ifndef _RIVE_TRANSITION_TRIGGER_CONDITION_HPP_ +#define _RIVE_TRANSITION_TRIGGER_CONDITION_HPP_ +#include "rive/generated/animation/transition_trigger_condition_base.hpp" +#include +namespace rive +{ +class TransitionTriggerCondition : public TransitionTriggerConditionBase +{ +public: + bool evaluate(const StateMachineInstance* stateMachineInstance, + StateMachineLayerInstance* layerInstance) const override; + void useInLayer(const StateMachineInstance* stateMachineInstance, + StateMachineLayerInstance* layerInstance) const override; + +protected: + bool validateInputType(const StateMachineInput* input) const override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/transition_value_boolean_comparator.hpp b/third_party/rive/include/rive/animation/transition_value_boolean_comparator.hpp new file mode 100644 index 0000000..9bc9f5d --- /dev/null +++ b/third_party/rive/include/rive/animation/transition_value_boolean_comparator.hpp @@ -0,0 +1,18 @@ +#ifndef _RIVE_TRANSITION_VALUE_BOOLEAN_COMPARATOR_HPP_ +#define _RIVE_TRANSITION_VALUE_BOOLEAN_COMPARATOR_HPP_ +#include "rive/generated/animation/transition_value_boolean_comparator_base.hpp" +#include +namespace rive +{ +class TransitionValueBooleanComparator + : public TransitionValueBooleanComparatorBase +{ +public: + bool compare(TransitionComparator* comparand, + TransitionConditionOp operation, + const StateMachineInstance* stateMachineInstance, + StateMachineLayerInstance* layerInstance) override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/transition_value_color_comparator.hpp b/third_party/rive/include/rive/animation/transition_value_color_comparator.hpp new file mode 100644 index 0000000..389979f --- /dev/null +++ b/third_party/rive/include/rive/animation/transition_value_color_comparator.hpp @@ -0,0 +1,17 @@ +#ifndef _RIVE_TRANSITION_VALUE_COLOR_COMPARATOR_HPP_ +#define _RIVE_TRANSITION_VALUE_COLOR_COMPARATOR_HPP_ +#include "rive/generated/animation/transition_value_color_comparator_base.hpp" +#include +namespace rive +{ +class TransitionValueColorComparator : public TransitionValueColorComparatorBase +{ +public: + bool compare(TransitionComparator* comparand, + TransitionConditionOp operation, + const StateMachineInstance* stateMachineInstance, + StateMachineLayerInstance* layerInstance) override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/transition_value_comparator.hpp b/third_party/rive/include/rive/animation/transition_value_comparator.hpp new file mode 100644 index 0000000..4ebba61 --- /dev/null +++ b/third_party/rive/include/rive/animation/transition_value_comparator.hpp @@ -0,0 +1,13 @@ +#ifndef _RIVE_TRANSITION_VALUE_COMPARATOR_HPP_ +#define _RIVE_TRANSITION_VALUE_COMPARATOR_HPP_ +#include "rive/generated/animation/transition_value_comparator_base.hpp" +#include +namespace rive +{ +class TransitionValueComparator : public TransitionValueComparatorBase +{ +public: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/transition_value_condition.hpp b/third_party/rive/include/rive/animation/transition_value_condition.hpp new file mode 100644 index 0000000..34c4253 --- /dev/null +++ b/third_party/rive/include/rive/animation/transition_value_condition.hpp @@ -0,0 +1,18 @@ +#ifndef _RIVE_TRANSITION_VALUE_CONDITION_HPP_ +#define _RIVE_TRANSITION_VALUE_CONDITION_HPP_ +#include "rive/generated/animation/transition_value_condition_base.hpp" +#include "rive/animation/transition_condition_op.hpp" + +namespace rive +{ +class TransitionValueCondition : public TransitionValueConditionBase +{ +public: + TransitionConditionOp op() const + { + return (TransitionConditionOp)opValue(); + } +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/transition_value_enum_comparator.hpp b/third_party/rive/include/rive/animation/transition_value_enum_comparator.hpp new file mode 100644 index 0000000..62bd13d --- /dev/null +++ b/third_party/rive/include/rive/animation/transition_value_enum_comparator.hpp @@ -0,0 +1,11 @@ +#ifndef _RIVE_TRANSITION_VALUE_ENUM_COMPARATOR_HPP_ +#define _RIVE_TRANSITION_VALUE_ENUM_COMPARATOR_HPP_ +#include "rive/generated/animation/transition_value_enum_comparator_base.hpp" +#include +namespace rive +{ +class TransitionValueEnumComparator : public TransitionValueEnumComparatorBase +{}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/transition_value_number_comparator.hpp b/third_party/rive/include/rive/animation/transition_value_number_comparator.hpp new file mode 100644 index 0000000..649768f --- /dev/null +++ b/third_party/rive/include/rive/animation/transition_value_number_comparator.hpp @@ -0,0 +1,18 @@ +#ifndef _RIVE_TRANSITION_VALUE_NUMBER_COMPARATOR_HPP_ +#define _RIVE_TRANSITION_VALUE_NUMBER_COMPARATOR_HPP_ +#include "rive/generated/animation/transition_value_number_comparator_base.hpp" +#include +namespace rive +{ +class TransitionValueNumberComparator + : public TransitionValueNumberComparatorBase +{ +public: + bool compare(TransitionComparator* comparand, + TransitionConditionOp operation, + const StateMachineInstance* stateMachineInstance, + StateMachineLayerInstance* layerInstance) override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/transition_value_string_comparator.hpp b/third_party/rive/include/rive/animation/transition_value_string_comparator.hpp new file mode 100644 index 0000000..4288c7e --- /dev/null +++ b/third_party/rive/include/rive/animation/transition_value_string_comparator.hpp @@ -0,0 +1,18 @@ +#ifndef _RIVE_TRANSITION_VALUE_STRING_COMPARATOR_HPP_ +#define _RIVE_TRANSITION_VALUE_STRING_COMPARATOR_HPP_ +#include "rive/generated/animation/transition_value_string_comparator_base.hpp" +#include +namespace rive +{ +class TransitionValueStringComparator + : public TransitionValueStringComparatorBase +{ +public: + bool compare(TransitionComparator* comparand, + TransitionConditionOp operation, + const StateMachineInstance* stateMachineInstance, + StateMachineLayerInstance* layerInstance) override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/transition_value_trigger_comparator.hpp b/third_party/rive/include/rive/animation/transition_value_trigger_comparator.hpp new file mode 100644 index 0000000..311c95b --- /dev/null +++ b/third_party/rive/include/rive/animation/transition_value_trigger_comparator.hpp @@ -0,0 +1,14 @@ +#ifndef _RIVE_TRANSITION_VALUE_TRIGGER_COMPARATOR_HPP_ +#define _RIVE_TRANSITION_VALUE_TRIGGER_COMPARATOR_HPP_ +#include "rive/generated/animation/transition_value_trigger_comparator_base.hpp" +#include +namespace rive +{ +class TransitionValueTriggerComparator + : public TransitionValueTriggerComparatorBase +{ +public: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/animation/transition_viewmodel_condition.hpp b/third_party/rive/include/rive/animation/transition_viewmodel_condition.hpp new file mode 100644 index 0000000..8891407 --- /dev/null +++ b/third_party/rive/include/rive/animation/transition_viewmodel_condition.hpp @@ -0,0 +1,42 @@ +#ifndef _RIVE_TRANSITION_VIEW_MODEL_CONDITION_HPP_ +#define _RIVE_TRANSITION_VIEW_MODEL_CONDITION_HPP_ +#include "rive/generated/animation/transition_viewmodel_condition_base.hpp" +#include "rive/animation/transition_comparator.hpp" +#include "rive/animation/transition_condition_op.hpp" +#include "rive/animation/state_machine_instance.hpp" +#include +namespace rive +{ +class TransitionViewModelCondition : public TransitionViewModelConditionBase +{ +protected: + TransitionComparator* m_leftComparator; + TransitionComparator* m_rightComparator; + +public: + ~TransitionViewModelCondition(); + bool evaluate(const StateMachineInstance* stateMachineInstance, + StateMachineLayerInstance* layerInstance) const override; + void useInLayer(const StateMachineInstance* stateMachineInstance, + StateMachineLayerInstance* layerInstance) const override; + TransitionComparator* leftComparator() const { return m_leftComparator; }; + TransitionComparator* rightComparator() const { return m_rightComparator; }; + void comparator(TransitionComparator* value) + { + if (m_leftComparator == nullptr) + { + m_leftComparator = value; + } + else + { + m_rightComparator = value; + } + }; + TransitionConditionOp op() const + { + return (TransitionConditionOp)opValue(); + } +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/artboard.hpp b/third_party/rive/include/rive/artboard.hpp new file mode 100644 index 0000000..3e98109 --- /dev/null +++ b/third_party/rive/include/rive/artboard.hpp @@ -0,0 +1,472 @@ +#ifndef _RIVE_ARTBOARD_HPP_ +#define _RIVE_ARTBOARD_HPP_ + +#include "rive/advance_flags.hpp" +#include "rive/animation/linear_animation.hpp" +#include "rive/animation/state_machine.hpp" +#include "rive/core_context.hpp" +#include "rive/data_bind/data_bind.hpp" +#include "rive/data_bind/data_context.hpp" +#include "rive/data_bind/data_bind_context.hpp" +#include "rive/viewmodel/viewmodel_instance_value.hpp" +#include "rive/viewmodel/viewmodel_instance_viewmodel.hpp" +#include "rive/generated/artboard_base.hpp" +#include "rive/hit_info.hpp" +#include "rive/math/aabb.hpp" +#include "rive/renderer.hpp" +#include "rive/text/text_value_run.hpp" +#include "rive/event.hpp" +#include "rive/audio/audio_engine.hpp" +#include "rive/math/raw_path.hpp" +#include "rive/typed_children.hpp" + +#include +#include +#include + +namespace rive +{ +class ArtboardComponentList; +class ArtboardHost; +class File; +class Drawable; +class Factory; +class Node; +class DrawTarget; +class ArtboardImporter; +class NestedArtboard; +class ArtboardInstance; +class LinearAnimationInstance; +class Scene; +class StateMachineInstance; +class Joystick; +class TextValueRun; +class Event; +class SMIBool; +class SMIInput; +class SMINumber; +class SMITrigger; + +#ifdef WITH_RIVE_TOOLS +typedef void (*ArtboardCallback)(void*); +#endif + +class Artboard : public ArtboardBase, public CoreContext +{ + friend class File; + friend class ArtboardImporter; + friend class Component; + +private: + std::vector m_Objects; + std::vector m_Animations; + std::vector m_StateMachines; + std::vector m_DependencyOrder; + std::vector m_Drawables; + std::vector m_DrawTargets; + std::vector m_NestedArtboards; + std::vector m_ComponentLists; + std::vector m_ArtboardHosts; + std::vector m_Joysticks; + std::vector m_DataBinds; + std::vector m_AllDataBinds; + DataContext* m_DataContext = nullptr; + bool m_ownsDataContext = false; + bool m_JoysticksApplyBeforeUpdate = true; + + unsigned int m_DirtDepth = 0; + Factory* m_Factory = nullptr; + Drawable* m_FirstDrawable = nullptr; + bool m_IsInstance = false; + bool m_FrameOrigin = true; + std::unordered_set m_dirtyLayout; + bool m_isCleaningDirtyLayouts = false; + float m_originalWidth = 0; + float m_originalHeight = 0; + bool m_updatesOwnLayout = true; + Artboard* parentArtboard() const; + ArtboardHost* m_host = nullptr; + bool sharesLayoutWithHost() const; + void cloneObjectDataBinds(const Core* object, + Core* clone, + Artboard* artboard) const; + + // Variable that tracks whenever the draw order changes. It is used by the + // state machine controllers to sort their hittable components when they are + // out of sync + uint8_t m_drawOrderChangeCounter = 0; + +#ifdef EXTERNAL_RIVE_AUDIO_ENGINE + rcp m_audioEngine; +#endif + + void sortDependencies(); + void sortDrawOrder(); + void updateDataBinds(); + void updateRenderPath() override; + void update(ComponentDirt value) override; + +public: + void host(ArtboardHost* artboardHost); + ArtboardHost* host() const; + + // Implemented for ShapePaintContainer. + const Mat2D& shapeWorldTransform() const override + { + return worldTransform(); + } + +private: +#ifdef TESTING +public: + Artboard(Factory* factory) : m_Factory(factory) { m_Clip = true; } +#endif + void addObject(Core* object); + void addAnimation(LinearAnimation* object); + void addStateMachine(StateMachine* object); + +public: + Artboard(); + ~Artboard() override; + bool validateObjects(); + StatusCode initialize(); + + Core* resolve(uint32_t id) const override; + + /// Find the id of a component in the artboard the object in the artboard. + /// The artboard itself has id 0 so we use that as a flag for not found. + uint32_t idOf(Core* object) const; + + Factory* factory() const { return m_Factory; } + + // EXPERIMENTAL -- for internal testing only for now. + // DO NOT RELY ON THIS as it may change/disappear in the future. + Core* hitTest(HitInfo*, const Mat2D&) override; + + void onComponentDirty(Component* component); + + /// Update components that depend on each other in DAG order. + bool updateComponents(); + + // Update layouts and components. Returns true if it updated something. + bool updatePass(bool isRoot); + + void onDirty(ComponentDirt dirt) override; + + // Artboards don't update their world transforms in the same way + // as other TransformComponents so we override this. + // This is because LayoutComponent extends Drawable, but + // Artboard is a special type of LayoutComponent + void updateWorldTransform() override {} + + void markLayoutDirty(LayoutComponent* layoutComponent); + void cleanLayout(LayoutComponent* layoutComponent); + + LayoutData* takeLayoutData(); + bool syncStyleChanges() override; + bool canHaveOverrides() override { return true; } + + bool advance(float elapsedSeconds, + AdvanceFlags flags = AdvanceFlags::AdvanceNested | + AdvanceFlags::Animate | + AdvanceFlags::NewFrame); + bool advanceInternal(float elapsedSeconds, + AdvanceFlags flags = AdvanceFlags::AdvanceNested | + AdvanceFlags::Animate | + AdvanceFlags::NewFrame); + uint8_t drawOrderChangeCounter() { return m_drawOrderChangeCounter; } + Drawable* firstDrawable() { return m_FirstDrawable; }; + + enum class DrawOption + { + kNormal, + kHideBG, + kHideFG, + }; + void draw(Renderer* renderer, DrawOption option); + void draw(Renderer* renderer) override; + void addToRenderPath(RenderPath* path, const Mat2D& transform); + +#ifdef TESTING + ShapePaintPath* clipPath() { return &m_worldPath; } + ShapePaintPath* backgroundPath() { return &m_localPath; } +#endif + + const std::vector& objects() const { return m_Objects; } + template TypedChildren objects() + { + return TypedChildren( + Span(m_Objects.data(), m_Objects.size())); + } + + const std::vector nestedArtboards() const + { + return m_NestedArtboards; + } + const std::vector artboardComponentLists() const + { + return m_ComponentLists; + } + const std::vector dataBinds() const { return m_DataBinds; } + const std::vector allDataBinds() const { return m_AllDataBinds; } + DataContext* dataContext() { return m_DataContext; } + NestedArtboard* nestedArtboard(const std::string& name) const; + NestedArtboard* nestedArtboardAtPath(const std::string& path) const; + + float originalWidth() const { return m_originalWidth; } + float originalHeight() const { return m_originalHeight; } + float layoutWidth() const; + float layoutHeight() const; + float layoutX() const; + float layoutY() const; + AABB bounds() const; + Vec2D origin() const; + + // Can we hide these from the public? (they use playable) + bool isTranslucent() const; + bool isTranslucent(const LinearAnimation*) const; + bool isTranslucent(const LinearAnimationInstance*) const; + void dataContext(DataContext* dataContext); + void internalDataContext(DataContext* dataContext, bool isRoot); + void clearDataContext(); + void bindViewModelInstance(rcp viewModelInstance, + DataContext* parent); + void bindViewModelInstance(rcp viewModelInstance, + DataContext* parent, + bool isRoot); + void bindViewModelInstance(rcp viewModelInstance); + void addDataBind(DataBind* dataBind); + void populateDataBinds(std::vector* dataBinds); + void sortDataBinds(); + void collectDataBinds(); + + bool hasAudio() const; + + template T* find(const std::string& name) + { + for (auto object : m_Objects) + { + if (object != nullptr && object->is() && + object->as()->name() == name) + { + return static_cast(object); + } + } + return nullptr; + } + + template size_t count() + { + size_t count = 0; + for (auto object : m_Objects) + { + if (object != nullptr && object->is()) + { + count++; + } + } + return count; + } + + template T* objectAt(size_t index) + { + size_t count = 0; + for (auto object : m_Objects) + { + if (object != nullptr && object->is()) + { + if (count++ == index) + { + return static_cast(object); + } + } + } + return nullptr; + } + + template std::vector find() + { + std::vector results; + for (auto object : m_Objects) + { + if (object != nullptr && object->is()) + { + results.push_back(static_cast(object)); + } + } + return results; + } + + size_t animationCount() const { return m_Animations.size(); } + std::string animationNameAt(size_t index) const; + + size_t stateMachineCount() const { return m_StateMachines.size(); } + std::string stateMachineNameAt(size_t index) const; + + LinearAnimation* firstAnimation() const { return animation(0); } + LinearAnimation* animation(const std::string& name) const; + LinearAnimation* animation(size_t index) const; + + StateMachine* firstStateMachine() const { return stateMachine(0); } + StateMachine* stateMachine(const std::string& name) const; + StateMachine* stateMachine(size_t index) const; + + /// When provided, the designer has specified that this artboard should + /// always autoplay this StateMachine. Returns -1 if it was not + // provided. + int defaultStateMachineIndex() const; + + /// Make an instance of this artboard. + template std::unique_ptr instance() const + { + std::unique_ptr artboardClone(new T); + artboardClone->copy(*this); + + artboardClone->m_Factory = m_Factory; + artboardClone->m_FrameOrigin = m_FrameOrigin; + artboardClone->m_DataContext = m_DataContext; + artboardClone->m_IsInstance = true; + artboardClone->m_originalWidth = m_originalWidth; + artboardClone->m_originalHeight = m_originalHeight; + cloneObjectDataBinds(this, artboardClone.get(), artboardClone.get()); + + std::vector& cloneObjects = artboardClone->m_Objects; + cloneObjects.push_back(artboardClone.get()); + + if (!m_Objects.empty()) + { + // Skip first object (artboard). + auto itr = m_Objects.begin(); + while (++itr != m_Objects.end()) + { + auto object = *itr; + cloneObjects.push_back(object == nullptr ? nullptr + : object->clone()); + // For each object, clone its data bind objects and target their + // clones + cloneObjectDataBinds(object, + cloneObjects.back(), + artboardClone.get()); + } + } + + for (auto animation : m_Animations) + { + artboardClone->m_Animations.push_back(animation); + } + for (auto stateMachine : m_StateMachines) + { + artboardClone->m_StateMachines.push_back(stateMachine); + } + + if (artboardClone->initialize() != StatusCode::Ok) + { + artboardClone = nullptr; + } + + assert(artboardClone->isInstance()); + return artboardClone; + } + + /// Returns true if the artboard is an instance of another + bool isInstance() const { return m_IsInstance; } + + /// Returns true when the artboard will shift the origin from the top + /// left to the relative width/height of the artboard itself. This is + /// what the editor does visually when you change the origin value to + /// give context as to where the origin lies within the framed bounds. + bool frameOrigin() const { return m_FrameOrigin; } + /// When composing multiple artboards together in a common world-space, + /// it may be desireable to have them share the same space regardless of + /// origin offset from the bounding artboard. Set frameOrigin to false + /// to move the bounds relative to the origin instead of the origin + /// relative to the bounds. + void frameOrigin(bool value); + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + bool result = ArtboardBase::deserialize(propertyKey, reader); + switch (propertyKey) + { + case widthPropertyKey: + m_originalWidth = width(); + break; + case heightPropertyKey: + m_originalHeight = height(); + break; + default: + break; + } + return result; + } + + StatusCode import(ImportStack& importStack) override; + + float volume() const; + void volume(float value); + +#ifdef EXTERNAL_RIVE_AUDIO_ENGINE + rcp audioEngine() const; + void audioEngine(rcp audioEngine); +#endif + +#ifdef WITH_RIVE_LAYOUT + void propagateSize() override; +#endif +private: + float m_volume = 1.0f; +#ifdef WITH_RIVE_TOOLS + ArtboardCallback m_layoutChangedCallback = nullptr; + ArtboardCallback m_layoutDirtyCallback = nullptr; + +public: + void* callbackUserData; + void onLayoutChanged(ArtboardCallback callback) + { + m_layoutChangedCallback = callback; + } + void onLayoutDirty(ArtboardCallback callback) + { + m_layoutDirtyCallback = callback; + addDirt(ComponentDirt::Components); + } +#endif +}; + +class ArtboardInstance : public Artboard +{ +public: + ArtboardInstance(); + ~ArtboardInstance() override; + + std::unique_ptr animationAt(size_t index); + std::unique_ptr animationNamed( + const std::string& name); + + std::unique_ptr stateMachineAt(size_t index); + std::unique_ptr stateMachineNamed( + const std::string& name); + + /// When provided, the designer has specified that this artboard should + /// always autoplay this StateMachine instance. If it was not specified, + /// this returns nullptr. + std::unique_ptr defaultStateMachine(); + + // This attemps to always return *something*, in this search order: + // 1. default statemachine instance + // 2. first statemachine instance + // 3. first animation instance + // 4. nullptr + std::unique_ptr defaultScene(); + + SMIInput* input(const std::string& name, const std::string& path); + template + InstType* getNamedInput(const std::string& name, const std::string& path); + SMIBool* getBool(const std::string& name, const std::string& path); + SMINumber* getNumber(const std::string& name, const std::string& path); + SMITrigger* getTrigger(const std::string& name, const std::string& path); + TextValueRun* getTextRun(const std::string& name, const std::string& path); +}; +} // namespace rive + +#endif diff --git a/third_party/rive/include/rive/artboard_component_list.hpp b/third_party/rive/include/rive/artboard_component_list.hpp new file mode 100644 index 0000000..d189a93 --- /dev/null +++ b/third_party/rive/include/rive/artboard_component_list.hpp @@ -0,0 +1,112 @@ +#ifndef _RIVE_ARTBOARD_COMPONENT_LIST_HPP_ +#define _RIVE_ARTBOARD_COMPONENT_LIST_HPP_ +#include "rive/generated/artboard_component_list_base.hpp" +#include "rive/advancing_component.hpp" +#include "rive/animation/state_machine_instance.hpp" +#include "rive/artboard.hpp" +#include "rive/artboard_host.hpp" +#include "rive/data_bind/data_bind_list_item_consumer.hpp" +#include "rive/layout/layout_node_provider.hpp" +#include "rive/viewmodel/viewmodel_instance_list_item.hpp" +#include +#include +namespace rive +{ +class File; + +class ArtboardComponentList : public ArtboardComponentListBase, + public ArtboardHost, + public AdvancingComponent, + public LayoutNodeProvider, + public DataBindListItemConsumer +{ +private: + std::vector m_listItems; + +public: + ArtboardComponentList(); + ~ArtboardComponentList() override; +#ifdef WITH_RIVE_LAYOUT + void* layoutNode(int index) override; +#endif + size_t artboardCount() override { return m_listItems.size(); } + ViewModelInstanceListItem* listItem(int index) + { + if (index < m_listItems.size()) + { + return m_listItems[index]; + } + return nullptr; + } + ArtboardInstance* artboardInstance(int index = 0) override + { + if (index < m_listItems.size()) + { + return m_artboardInstancesMap[listItem(index)].get(); + } + return nullptr; + } + StateMachineInstance* stateMachineInstance(int index = 0) + { + if (index < m_listItems.size()) + { + return m_stateMachinesMap[listItem(index)].get(); + } + return nullptr; + } + bool worldToLocal(Vec2D world, Vec2D* local, int index); + bool advanceComponent(float elapsedSeconds, + AdvanceFlags flags = AdvanceFlags::Animate | + AdvanceFlags::NewFrame) override; + AABB layoutBounds() override; + AABB layoutBoundsForNode(int index) override; + void markHostingLayoutDirty(ArtboardInstance* artboardInstance) override; + TransformComponent* transformComponent() override + { + return this->as(); + } + void updateList(int propertyKey, + std::vector* list) override; + void draw(Renderer* renderer) override; + Core* hitTest(HitInfo*, const Mat2D&) override; + void update(ComponentDirt value) override; + void updateConstraints() override; + void populateDataBinds(std::vector* dataBinds) override; + void internalDataContext(DataContext* dataContext) override; + void bindViewModelInstance(rcp viewModelInstance, + DataContext* parent) override; + void clearDataContext() override; + Artboard* parentArtboard() override { return artboard(); } + void markHostTransformDirty() override { markTransformDirty(); } + bool syncStyleChanges() override; + void updateLayoutBounds(bool animate = true) override; + void markLayoutNodeDirty( + bool shouldForceUpdateLayoutBounds = false) override; + bool isLayoutProvider() override { return true; } + size_t numLayoutNodes() override { return m_listItems.size(); } + void reset(); + void file(File*); + File* file() const; + Core* clone() const override; + +private: + void disposeListItem(ViewModelInstanceListItem* listItem); + std::unique_ptr createArtboard( + Component* target, + ViewModelInstanceListItem* listItem) const; + Artboard* findArtboard(ViewModelInstanceListItem* listItem) const; + std::unique_ptr createStateMachineInstance( + Component* target, + ArtboardInstance* artboard); + mutable std::unordered_map m_artboardsMap; + std::unordered_map> + m_artboardInstancesMap; + std::unordered_map> + m_stateMachinesMap; + File* m_file; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/artboard_host.hpp b/third_party/rive/include/rive/artboard_host.hpp new file mode 100644 index 0000000..88da3bf --- /dev/null +++ b/third_party/rive/include/rive/artboard_host.hpp @@ -0,0 +1,31 @@ +#ifndef _RIVE_ARTBOARD_HOST_HPP_ +#define _RIVE_ARTBOARD_HOST_HPP_ +#include "rive/refcnt.hpp" +#include +namespace rive +{ +class ArtboardInstance; +class DataBind; +class DataContext; +class ViewModelInstance; + +class ArtboardHost +{ +public: + virtual size_t artboardCount() = 0; + virtual ArtboardInstance* artboardInstance(int index = 0) = 0; + virtual std::vector dataBindPathIds() { return {}; } + virtual void populateDataBinds(std::vector* dataBinds) = 0; + virtual void internalDataContext(DataContext* dataContext) = 0; + virtual void bindViewModelInstance(rcp viewModelInstance, + DataContext* parent) = 0; + virtual void clearDataContext() = 0; + virtual void markHostingLayoutDirty(ArtboardInstance* artboardInstance) {} + // The artboard that contains this ArtboardHost + virtual Artboard* parentArtboard() = 0; + virtual void markHostTransformDirty() = 0; + virtual bool isLayoutProvider() { return false; } +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/assets/asset.hpp b/third_party/rive/include/rive/assets/asset.hpp new file mode 100644 index 0000000..16f8cef --- /dev/null +++ b/third_party/rive/include/rive/assets/asset.hpp @@ -0,0 +1,13 @@ +#ifndef _RIVE_ASSET_HPP_ +#define _RIVE_ASSET_HPP_ +#include "rive/generated/assets/asset_base.hpp" +#include +namespace rive +{ +class Asset : public AssetBase +{ +public: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/assets/audio_asset.hpp b/third_party/rive/include/rive/assets/audio_asset.hpp new file mode 100644 index 0000000..bc8d89a --- /dev/null +++ b/third_party/rive/include/rive/assets/audio_asset.hpp @@ -0,0 +1,30 @@ +#ifndef _RIVE_AUDIO_ASSET_HPP_ +#define _RIVE_AUDIO_ASSET_HPP_ +#include "rive/generated/assets/audio_asset_base.hpp" +#include "rive/audio/audio_source.hpp" +#include "rive/audio/audio_engine.hpp" + +namespace rive +{ +class AudioAsset : public AudioAssetBase +{ +public: + AudioAsset(); + ~AudioAsset() override; + bool decode(SimpleArray&, Factory*) override; + std::string fileExtension() const override; + +#ifdef TESTING + bool hasAudioSource() { return m_audioSource != nullptr; } +#endif + + rcp audioSource() { return m_audioSource; } + void audioSource(rcp source) { m_audioSource = source; } + void stop(rcp engine); + +private: + rcp m_audioSource; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/assets/drawable_asset.hpp b/third_party/rive/include/rive/assets/drawable_asset.hpp new file mode 100644 index 0000000..ce2ddaf --- /dev/null +++ b/third_party/rive/include/rive/assets/drawable_asset.hpp @@ -0,0 +1,13 @@ +#ifndef _RIVE_DRAWABLE_ASSET_HPP_ +#define _RIVE_DRAWABLE_ASSET_HPP_ +#include "rive/generated/assets/drawable_asset_base.hpp" +#include +namespace rive +{ +class DrawableAsset : public DrawableAssetBase +{ +public: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/assets/export_audio.hpp b/third_party/rive/include/rive/assets/export_audio.hpp new file mode 100644 index 0000000..7642863 --- /dev/null +++ b/third_party/rive/include/rive/assets/export_audio.hpp @@ -0,0 +1,13 @@ +#ifndef _RIVE_EXPORT_AUDIO_HPP_ +#define _RIVE_EXPORT_AUDIO_HPP_ +#include "rive/generated/assets/export_audio_base.hpp" +#include +namespace rive +{ +class ExportAudio : public ExportAudioBase +{ +public: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/assets/file_asset.hpp b/third_party/rive/include/rive/assets/file_asset.hpp new file mode 100644 index 0000000..781d9fb --- /dev/null +++ b/third_party/rive/include/rive/assets/file_asset.hpp @@ -0,0 +1,58 @@ +#ifndef _RIVE_FILE_ASSET_HPP_ +#define _RIVE_FILE_ASSET_HPP_ +#include "rive/assets/file_asset_referencer.hpp" +#include "rive/generated/assets/file_asset_base.hpp" +#include "rive/span.hpp" +#include "rive/simple_array.hpp" +#include + +namespace rive +{ +class Factory; +class FileAsset : public FileAssetBase +{ +private: + std::vector m_cdnUuid; + std::vector m_fileAssetReferencers; + +public: + Span cdnUuid() const; + std::string cdnUuidStr() const; + + void decodeCdnUuid(Span value) override; + void copyCdnUuid(const FileAssetBase& object) override; + virtual bool decode(SimpleArray&, Factory*) = 0; + virtual std::string fileExtension() const = 0; + StatusCode import(ImportStack& importStack) override; + const std::vector& fileAssetReferencers() + { + return m_fileAssetReferencers; + } + + void addFileAssetReferencer(FileAssetReferencer* referencer) + { + m_fileAssetReferencers.push_back(referencer); + } + + void removeFileAssetReferencer(FileAssetReferencer* referencer) + { + auto itr = m_fileAssetReferencers.begin(); + while (itr != m_fileAssetReferencers.end()) + { + if (*itr == referencer) + { + itr = m_fileAssetReferencers.erase(itr); + } + else + { + itr++; + } + } + } + + std::string uniqueName() const; + std::string uniqueFilename() const; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/assets/file_asset_contents.hpp b/third_party/rive/include/rive/assets/file_asset_contents.hpp new file mode 100644 index 0000000..67457c0 --- /dev/null +++ b/third_party/rive/include/rive/assets/file_asset_contents.hpp @@ -0,0 +1,22 @@ +#ifndef _RIVE_FILE_ASSET_CONTENTS_HPP_ +#define _RIVE_FILE_ASSET_CONTENTS_HPP_ +#include "rive/generated/assets/file_asset_contents_base.hpp" +#include +#include "rive/simple_array.hpp" + +namespace rive +{ +class FileAssetContents : public FileAssetContentsBase +{ +public: + SimpleArray& bytes(); + StatusCode import(ImportStack& importStack) override; + void decodeBytes(Span value) override; + void copyBytes(const FileAssetContentsBase& object) override; + +private: + SimpleArray m_bytes; +}; +} // namespace rive + +#endif diff --git a/third_party/rive/include/rive/assets/file_asset_referencer.hpp b/third_party/rive/include/rive/assets/file_asset_referencer.hpp new file mode 100644 index 0000000..1b2be34 --- /dev/null +++ b/third_party/rive/include/rive/assets/file_asset_referencer.hpp @@ -0,0 +1,24 @@ +#ifndef _RIVE_FILE_ASSET_REFERENCER_HPP_ +#define _RIVE_FILE_ASSET_REFERENCER_HPP_ + +#include +#include "rive/importers/import_stack.hpp" + +namespace rive +{ +class FileAsset; +class FileAssetReferencer +{ +protected: + FileAsset* m_fileAsset = nullptr; + +public: + virtual ~FileAssetReferencer() = 0; + virtual void setAsset(FileAsset* asset); + virtual uint32_t assetId() = 0; + StatusCode registerReferencer(ImportStack& importStack); + virtual void assetUpdated() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/assets/folder.hpp b/third_party/rive/include/rive/assets/folder.hpp new file mode 100644 index 0000000..d51c359 --- /dev/null +++ b/third_party/rive/include/rive/assets/folder.hpp @@ -0,0 +1,13 @@ +#ifndef _RIVE_FOLDER_HPP_ +#define _RIVE_FOLDER_HPP_ +#include "rive/generated/assets/folder_base.hpp" +#include +namespace rive +{ +class Folder : public FolderBase +{ +public: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/assets/font_asset.hpp b/third_party/rive/include/rive/assets/font_asset.hpp new file mode 100644 index 0000000..29fad8d --- /dev/null +++ b/third_party/rive/include/rive/assets/font_asset.hpp @@ -0,0 +1,22 @@ +#ifndef _RIVE_FONT_ASSET_HPP_ +#define _RIVE_FONT_ASSET_HPP_ +#include "rive/generated/assets/font_asset_base.hpp" +#include "rive/text_engine.hpp" +#include "rive/refcnt.hpp" + +namespace rive +{ +class FontAsset : public FontAssetBase +{ +public: + bool decode(SimpleArray&, Factory*) override; + std::string fileExtension() const override; + const rcp font() const { return m_font; } + void font(rcp font); + +private: + rcp m_font; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/assets/image_asset.hpp b/third_party/rive/include/rive/assets/image_asset.hpp new file mode 100644 index 0000000..f258847 --- /dev/null +++ b/third_party/rive/include/rive/assets/image_asset.hpp @@ -0,0 +1,38 @@ +#ifndef _RIVE_IMAGE_ASSET_HPP_ +#define _RIVE_IMAGE_ASSET_HPP_ + +#include "rive/generated/assets/image_asset_base.hpp" +#include "rive/renderer.hpp" +#include "rive/simple_array.hpp" +#include +#include + +namespace rive +{ +class ImageAsset : public ImageAssetBase +#if defined(__EMSCRIPTEN__) + , + public RenderImageDelegate +#endif +{ +private: + rcp m_RenderImage; + +public: + ImageAsset() {} + ~ImageAsset() override; + +#ifdef TESTING + std::size_t decodedByteSize = 0; +#endif + bool decode(SimpleArray&, Factory*) override; + std::string fileExtension() const override; + RenderImage* renderImage() const { return m_RenderImage.get(); } + void renderImage(rcp renderImage); +#if defined(__EMSCRIPTEN__) + void decodedAsync() override; +#endif +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/audio/audio_engine.hpp b/third_party/rive/include/rive/audio/audio_engine.hpp new file mode 100644 index 0000000..3d9ef88 --- /dev/null +++ b/third_party/rive/include/rive/audio/audio_engine.hpp @@ -0,0 +1,98 @@ +#ifdef WITH_RIVE_AUDIO +#ifndef _RIVE_AUDIO_ENGINE_HPP_ +#define _RIVE_AUDIO_ENGINE_HPP_ + +#include "rive/refcnt.hpp" +#include "rive/span.hpp" +#include +#include +#include +#include + +typedef struct ma_engine ma_engine; +typedef struct ma_sound ma_sound; +typedef struct ma_device ma_device; +typedef struct ma_node_base ma_node_base; +typedef struct ma_context ma_context; + +namespace rive +{ +class AudioSound; +class AudioSource; +class LevelsNode; +class Artboard; +class AudioEngine : public RefCnt +{ + friend class AudioSound; + friend class AudioSource; + friend class LevelsNode; + +public: + static const uint32_t defaultNumChannels = 2; + static const uint32_t defaultSampleRate = 48000; + + static rcp Make(uint32_t numChannels, uint32_t sampleRate); + + ma_device* device() { return m_device; } + ma_engine* engine() { return m_engine; } + + uint32_t channels() const; + uint32_t sampleRate() const; + uint64_t timeInFrames(); + + ~AudioEngine(); + rcp play(rcp source, + uint64_t startTime, + uint64_t endTime, + uint64_t soundStartTime, + Artboard* artboard = nullptr); + + static rcp RuntimeEngine(bool makeWhenNecessary = true); + +#ifdef EXTERNAL_RIVE_AUDIO_ENGINE + bool readAudioFrames(float* frames, + uint64_t numFrames, + uint64_t* framesRead = nullptr); + bool sumAudioFrames(float* frames, uint64_t numFrames); +#endif + +#ifdef WITH_RIVE_AUDIO_TOOLS + void initLevelMonitor(); + void levels(Span levels); + float level(uint32_t channel); +#endif + + void start(); + void stop(); + void stop(Artboard* artboard); + +#ifdef TESTING + size_t playingSoundCount(); +#endif +private: + AudioEngine(ma_engine* engine, ma_context* context); + ma_device* m_device; + ma_engine* m_engine; + ma_context* m_context; + std::mutex m_mutex; + + void soundCompleted(rcp sound); + void unlinkSound(rcp sound); + + std::vector> m_completedSounds; + rcp m_playingSoundsHead; + static void SoundCompleted(void* pUserData, ma_sound* pSound); + +#ifdef WITH_RIVE_AUDIO_TOOLS + void measureLevels(const float* frames, uint32_t frameCount); + std::vector m_levels; + LevelsNode* m_levelMonitor = nullptr; +#endif +#ifdef EXTERNAL_RIVE_AUDIO_ENGINE + std::vector m_readFrames; +#endif +}; +} // namespace rive + +#endif +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/audio/audio_format.hpp b/third_party/rive/include/rive/audio/audio_format.hpp new file mode 100644 index 0000000..330dffe --- /dev/null +++ b/third_party/rive/include/rive/audio/audio_format.hpp @@ -0,0 +1,15 @@ +#ifndef _RIVE_AUDIO_FORMAT_HPP_ +#define _RIVE_AUDIO_FORMAT_HPP_ +namespace rive +{ +enum class AudioFormat : unsigned int +{ + unknown = 0, + wav, + flac, + mp3, + vorbis, + buffered +}; +} +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/audio/audio_reader.hpp b/third_party/rive/include/rive/audio/audio_reader.hpp new file mode 100644 index 0000000..6243fd7 --- /dev/null +++ b/third_party/rive/include/rive/audio/audio_reader.hpp @@ -0,0 +1,37 @@ +#ifdef WITH_RIVE_AUDIO +#ifndef _RIVE_AUDIO_READER_HPP_ +#define _RIVE_AUDIO_READER_HPP_ + +#include "miniaudio.h" +#include "rive/refcnt.hpp" +#include "rive/span.hpp" +#include + +namespace rive +{ +class AudioSource; +class AudioReader : public RefCnt +{ + friend class AudioSource; + +public: + uint64_t lengthInFrames(); + Span read(uint64_t frameCount); + ~AudioReader(); + uint32_t channels() const; + uint32_t sampleRate() const; + +private: + AudioReader(rcp audioSource, uint32_t channels); + ma_decoder* decoder(); + + rcp m_source; + uint32_t m_channels; + ma_decoder m_decoder; + std::vector m_readBuffer; +}; + +} // namespace rive + +#endif +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/audio/audio_sound.hpp b/third_party/rive/include/rive/audio/audio_sound.hpp new file mode 100644 index 0000000..754008e --- /dev/null +++ b/third_party/rive/include/rive/audio/audio_sound.hpp @@ -0,0 +1,142 @@ +#ifdef WITH_RIVE_AUDIO +#ifndef _RIVE_AUDIO_SOUND_HPP_ +#define _RIVE_AUDIO_SOUND_HPP_ + +#include "miniaudio.h" +#include "rive/refcnt.hpp" +#include "rive/audio/audio_source.hpp" + +namespace rive +{ +class AudioEngine; +class Artboard; + +struct ma_end_clipped_decoder +{ + ma_data_source_base base; + ma_decoder decoder; + ma_uint64 frameCursor; + ma_uint64 endFrame; +}; + +static ma_result ma_end_clipped_decoder_read(ma_data_source* pDataSource, + void* pFramesOut, + ma_uint64 frameCount, + ma_uint64* pFramesRead) +{ + ma_end_clipped_decoder* clipped = (ma_end_clipped_decoder*)pDataSource; + + ma_result result = ma_decoder_read_pcm_frames(&clipped->decoder, + pFramesOut, + frameCount, + pFramesRead); + + clipped->frameCursor += *pFramesRead; + if (clipped->frameCursor >= clipped->endFrame) + { + ma_uint64 overflow = clipped->frameCursor - clipped->endFrame; + if (*pFramesRead > overflow) + { + *pFramesRead -= overflow; + } + else + { + *pFramesRead = 0; + return MA_AT_END; + } + } + + return result; +} + +static ma_result ma_end_clipped_decoder_seek(ma_data_source* pDataSource, + ma_uint64 frameIndex) +{ + ma_end_clipped_decoder* clipped = (ma_end_clipped_decoder*)pDataSource; + ma_result result = + ma_decoder_seek_to_pcm_frame(&clipped->decoder, frameIndex); + if (result != MA_SUCCESS) + { + return result; + } + + clipped->frameCursor = frameIndex; + return result; +} + +static ma_result ma_end_clipped_decoder_get_data_format( + ma_data_source* pDataSource, + ma_format* pFormat, + ma_uint32* pChannels, + ma_uint32* pSampleRate, + ma_channel* pChannelMap, + size_t channelMapCap) +{ + ma_end_clipped_decoder* clipped = (ma_end_clipped_decoder*)pDataSource; + return ma_decoder_get_data_format(&clipped->decoder, + pFormat, + pChannels, + pSampleRate, + pChannelMap, + channelMapCap); +} + +static ma_result ma_end_clipped_decoder_get_cursor(ma_data_source* pDataSource, + ma_uint64* pCursor) +{ + ma_end_clipped_decoder* clipped = (ma_end_clipped_decoder*)pDataSource; + *pCursor = clipped->frameCursor; + return MA_SUCCESS; +} + +static ma_result ma_end_clipped_decoder_get_length(ma_data_source* pDataSource, + ma_uint64* pLength) +{ + ma_end_clipped_decoder* clipped = (ma_end_clipped_decoder*)pDataSource; + return ma_decoder_get_length_in_pcm_frames(&clipped->decoder, pLength); +} + +static ma_data_source_vtable g_ma_end_clipped_decoder_vtable = { + ma_end_clipped_decoder_read, + ma_end_clipped_decoder_seek, + ma_end_clipped_decoder_get_data_format, + ma_end_clipped_decoder_get_cursor, + ma_end_clipped_decoder_get_length}; + +class AudioSound : public RefCnt +{ + friend class AudioEngine; + +public: + bool seek(uint64_t timeInFrames); + ~AudioSound(); + void stop(uint64_t fadeTimeInFrames = 0); + float volume(); + void volume(float value); + bool completed() const; + +private: + AudioSound(AudioEngine* engine, + rcp source, + Artboard* artboard); + ma_end_clipped_decoder* clippedDecoder() { return &m_decoder; } + ma_audio_buffer* buffer() { return &m_buffer; } + ma_sound* sound() { return &m_sound; } + void dispose(); + + ma_end_clipped_decoder m_decoder; + ma_audio_buffer m_buffer; + ma_sound m_sound; + rcp m_source; + + // This is storage used by the AudioEngine. + bool m_isDisposed; + rcp m_nextPlaying; + rcp m_prevPlaying; + AudioEngine* m_engine; + Artboard* m_artboard; +}; +} // namespace rive + +#endif +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/audio/audio_source.hpp b/third_party/rive/include/rive/audio/audio_source.hpp new file mode 100644 index 0000000..9ddf49a --- /dev/null +++ b/third_party/rive/include/rive/audio/audio_source.hpp @@ -0,0 +1,67 @@ +#ifndef _RIVE_AUDIO_SOURCE_HPP_ +#define _RIVE_AUDIO_SOURCE_HPP_ + +#include "rive/refcnt.hpp" +#include "rive/span.hpp" +#include "rive/simple_array.hpp" +#include "rive/audio/audio_format.hpp" + +namespace rive +{ +class AudioEngine; +class AudioReader; +class AudioSound; +class AudioSource : public RefCnt +{ +public: + // Makes an audio source that does not own it's backing bytes. + AudioSource(rive::Span fileBytes); + + // Makes an audio source whose backing bytes will be deleted when the + // AudioSource deletes. + AudioSource(rive::SimpleArray fileBytes); + + // Makes a buffered audio source whose backing bytes will be deleted when + // the AudioSource deletes. + AudioSource(rive::Span samples, + uint32_t numChannels, + uint32_t sampleRate); + +#ifdef WITH_RIVE_AUDIO + rcp makeReader(uint32_t numChannels, uint32_t sampleRate); +#endif + + uint32_t channels(); + uint32_t sampleRate(); + AudioFormat format() const; + const rive::Span bytes() const + { +#ifdef WITH_RIVE_AUDIO + return m_fileBytes; +#else + return rive::Span(nullptr, 0); +#endif + } + + const rive::Span bufferedSamples() const; + bool isBuffered() const + { +#ifdef WITH_RIVE_AUDIO + return m_isBuffered; +#else + return false; +#endif + } + +private: +#ifdef WITH_RIVE_AUDIO + bool m_isBuffered; + uint32_t m_channels; + uint32_t m_sampleRate; + rive::Span m_fileBytes; + rive::SimpleArray m_ownedBytes; +#endif +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/audio_event.hpp b/third_party/rive/include/rive/audio_event.hpp new file mode 100644 index 0000000..2844e9c --- /dev/null +++ b/third_party/rive/include/rive/audio_event.hpp @@ -0,0 +1,25 @@ +#ifndef _RIVE_AUDIO_EVENT_HPP_ +#define _RIVE_AUDIO_EVENT_HPP_ +#include "rive/generated/audio_event_base.hpp" +#include "rive/assets/file_asset_referencer.hpp" + +namespace rive +{ +class AudioAsset; +class AudioEvent : public AudioEventBase, public FileAssetReferencer +{ +public: + StatusCode import(ImportStack& importStack) override; + void setAsset(FileAsset* asset) override; + uint32_t assetId() override; + void trigger(const CallbackData& value) override; + void play(); + +#ifdef TESTING + AudioAsset* asset() const { return (AudioAsset*)m_fileAsset; } +#endif + Core* clone() const override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/backboard.hpp b/third_party/rive/include/rive/backboard.hpp new file mode 100644 index 0000000..475011c --- /dev/null +++ b/third_party/rive/include/rive/backboard.hpp @@ -0,0 +1,10 @@ +#ifndef _RIVE_BACKBOARD_HPP_ +#define _RIVE_BACKBOARD_HPP_ +#include "rive/generated/backboard_base.hpp" +namespace rive +{ +class Backboard : public BackboardBase +{}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/bones/bone.hpp b/third_party/rive/include/rive/bones/bone.hpp new file mode 100644 index 0000000..b5cfb96 --- /dev/null +++ b/third_party/rive/include/rive/bones/bone.hpp @@ -0,0 +1,37 @@ +#ifndef _RIVE_BONE_HPP_ +#define _RIVE_BONE_HPP_ +#include "rive/generated/bones/bone_base.hpp" +#include +#include + +namespace rive +{ +class Constraint; +class Bone : public BoneBase +{ + +private: + std::vector m_ChildBones; + std::vector m_PeerConstraints; + +public: + StatusCode onAddedClean(CoreContext* context) override; + float x() const override; + float y() const override; + + inline const std::vector childBones() { return m_ChildBones; } + + void addChildBone(Bone* bone); + Vec2D tipWorldTranslation() const; + void addPeerConstraint(Constraint* peer); + const std::vector& peerConstraints() const + { + return m_PeerConstraints; + } + +private: + void lengthChanged() override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/bones/cubic_weight.hpp b/third_party/rive/include/rive/bones/cubic_weight.hpp new file mode 100644 index 0000000..23af090 --- /dev/null +++ b/third_party/rive/include/rive/bones/cubic_weight.hpp @@ -0,0 +1,19 @@ +#ifndef _RIVE_CUBIC_WEIGHT_HPP_ +#define _RIVE_CUBIC_WEIGHT_HPP_ +#include "rive/generated/bones/cubic_weight_base.hpp" +#include +namespace rive +{ +class CubicWeight : public CubicWeightBase +{ +private: + Vec2D m_InTranslation; + Vec2D m_OutTranslation; + +public: + Vec2D& inTranslation() { return m_InTranslation; } + Vec2D& outTranslation() { return m_OutTranslation; } +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/bones/root_bone.hpp b/third_party/rive/include/rive/bones/root_bone.hpp new file mode 100644 index 0000000..b6f4aeb --- /dev/null +++ b/third_party/rive/include/rive/bones/root_bone.hpp @@ -0,0 +1,18 @@ +#ifndef _RIVE_ROOT_BONE_HPP_ +#define _RIVE_ROOT_BONE_HPP_ +#include "rive/generated/bones/root_bone_base.hpp" +#include +namespace rive +{ +class RootBone : public RootBoneBase +{ +public: + StatusCode onAddedClean(CoreContext* context) override; + +protected: + void xChanged() override; + void yChanged() override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/bones/skeletal_component.hpp b/third_party/rive/include/rive/bones/skeletal_component.hpp new file mode 100644 index 0000000..03b49ef --- /dev/null +++ b/third_party/rive/include/rive/bones/skeletal_component.hpp @@ -0,0 +1,13 @@ +#ifndef _RIVE_SKELETAL_COMPONENT_HPP_ +#define _RIVE_SKELETAL_COMPONENT_HPP_ +#include "rive/generated/bones/skeletal_component_base.hpp" +#include +namespace rive +{ +class SkeletalComponent : public SkeletalComponentBase +{ +public: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/bones/skin.hpp b/third_party/rive/include/rive/bones/skin.hpp new file mode 100644 index 0000000..862b60e --- /dev/null +++ b/third_party/rive/include/rive/bones/skin.hpp @@ -0,0 +1,44 @@ +#ifndef _RIVE_SKIN_HPP_ +#define _RIVE_SKIN_HPP_ +#include "rive/generated/bones/skin_base.hpp" +#include "rive/math/mat2d.hpp" +#include "rive/span.hpp" +#include +#include + +namespace rive +{ +class Tendon; +class Vertex; +class Skinnable; + +class Skin : public SkinBase +{ + friend class Tendon; + +public: + ~Skin() override; + +private: + Mat2D m_WorldTransform; + std::vector m_Tendons; + float* m_BoneTransforms = nullptr; + Skinnable* m_Skinnable; + +protected: + void addTendon(Tendon* tendon); + +public: + StatusCode onAddedDirty(CoreContext* context) override; + void buildDependencies() override; + void deform(Span vertices); + void onDirty(ComponentDirt dirt) override; + void update(ComponentDirt value) override; + +#ifdef TESTING + std::vector& tendons() { return m_Tendons; } +#endif +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/bones/skinnable.hpp b/third_party/rive/include/rive/bones/skinnable.hpp new file mode 100644 index 0000000..345dbf9 --- /dev/null +++ b/third_party/rive/include/rive/bones/skinnable.hpp @@ -0,0 +1,31 @@ +#ifndef _RIVE_SKINNABLE_HPP_ +#define _RIVE_SKINNABLE_HPP_ + +#include "rive/rive_types.hpp" + +namespace rive +{ +class Skin; +class Component; + +class Skinnable +{ + friend class Skin; + +private: + Skin* m_Skin = nullptr; + +protected: + void skin(Skin* skin); + +public: + virtual ~Skinnable() {} + + Skin* skin() const { return m_Skin; } + virtual void markSkinDirty() = 0; + + static Skinnable* from(Component* component); +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/bones/tendon.hpp b/third_party/rive/include/rive/bones/tendon.hpp new file mode 100644 index 0000000..6a8f456 --- /dev/null +++ b/third_party/rive/include/rive/bones/tendon.hpp @@ -0,0 +1,25 @@ +#ifndef _RIVE_TENDON_HPP_ +#define _RIVE_TENDON_HPP_ + +#include "rive/generated/bones/tendon_base.hpp" +#include "rive/math/mat2d.hpp" +#include + +namespace rive +{ +class Bone; +class Tendon : public TendonBase +{ +private: + Mat2D m_InverseBind; + Bone* m_Bone = nullptr; + +public: + Bone* bone() const { return m_Bone; } + const Mat2D& inverseBind() const { return m_InverseBind; } + StatusCode onAddedDirty(CoreContext* context) override; + StatusCode onAddedClean(CoreContext* context) override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/bones/weight.hpp b/third_party/rive/include/rive/bones/weight.hpp new file mode 100644 index 0000000..4b8658f --- /dev/null +++ b/third_party/rive/include/rive/bones/weight.hpp @@ -0,0 +1,27 @@ +#ifndef _RIVE_WEIGHT_HPP_ +#define _RIVE_WEIGHT_HPP_ +#include "rive/generated/bones/weight_base.hpp" +#include "rive/math/vec2d.hpp" +#include + +namespace rive +{ +class Weight : public WeightBase +{ +private: + Vec2D m_Translation; + +public: + Vec2D& translation() { return m_Translation; } + + StatusCode onAddedDirty(CoreContext* context) override; + + static Vec2D deform(Vec2D inPoint, + unsigned int indices, + unsigned int weights, + const Mat2D& world, + const float* boneTransforms); +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/bounds_provider.hpp b/third_party/rive/include/rive/bounds_provider.hpp new file mode 100644 index 0000000..7f3ca83 --- /dev/null +++ b/third_party/rive/include/rive/bounds_provider.hpp @@ -0,0 +1,17 @@ +#ifndef _RIVE_BOUNDS_PROVIDER_HPP_ +#define _RIVE_BOUNDS_PROVIDER_HPP_ + +#include "rive/math/aabb.hpp" +#include "rive/math/mat2d.hpp" + +namespace rive +{ + +class BoundsProvider +{ +public: + virtual ~BoundsProvider() {} + virtual AABB computeBounds(Mat2D toParent); +}; +} // namespace rive +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/clip_result.hpp b/third_party/rive/include/rive/clip_result.hpp new file mode 100644 index 0000000..7b9b7dc --- /dev/null +++ b/third_party/rive/include/rive/clip_result.hpp @@ -0,0 +1,12 @@ +#ifndef _RIVE_CLIP_RESULT_HPP_ +#define _RIVE_CLIP_RESULT_HPP_ +namespace rive +{ +enum class ClipResult : unsigned char +{ + noClip = 0, + clip = 1, + emptyClip = 2 +}; +} +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/command_path.hpp b/third_party/rive/include/rive/command_path.hpp new file mode 100644 index 0000000..52e54ec --- /dev/null +++ b/third_party/rive/include/rive/command_path.hpp @@ -0,0 +1,53 @@ +#ifndef _RIVE_COMMAND_PATH_HPP_ +#define _RIVE_COMMAND_PATH_HPP_ + +#include "rive/math/mat2d.hpp" +#include "rive/math/path_types.hpp" +#include "rive/refcnt.hpp" + +namespace rive +{ +class RenderPath; + +/// Abstract path used to build up commands used for rendering. +class CommandPath : public RefCnt +{ +public: + virtual ~CommandPath() {} + virtual void rewind() = 0; + virtual void fillRule(FillRule value) = 0; + virtual void addPath(CommandPath* path, const Mat2D& transform) = 0; + + virtual void moveTo(float x, float y) = 0; + virtual void lineTo(float x, float y) = 0; + virtual void cubicTo(float ox, + float oy, + float ix, + float iy, + float x, + float y) = 0; + virtual void close() = 0; + + virtual RenderPath* renderPath() = 0; + virtual const RenderPath* renderPath() const = 0; + + // non-virtual helpers + + void addRect(float x, float y, float width, float height) + { + moveTo(x, y); + lineTo(x + width, y); + lineTo(x + width, y + height); + lineTo(x, y + height); + close(); + } + + void move(Vec2D v) { this->moveTo(v.x, v.y); } + void line(Vec2D v) { this->lineTo(v.x, v.y); } + void cubic(Vec2D a, Vec2D b, Vec2D c) + { + this->cubicTo(a.x, a.y, b.x, b.y, c.x, c.y); + } +}; +} // namespace rive +#endif diff --git a/third_party/rive/include/rive/command_queue.hpp b/third_party/rive/include/rive/command_queue.hpp new file mode 100644 index 0000000..b69e4a3 --- /dev/null +++ b/third_party/rive/include/rive/command_queue.hpp @@ -0,0 +1,332 @@ +/* + * Copyright 2025 Rive + */ + +#pragma once + +#include "rive/object_stream.hpp" +#include "rive/refcnt.hpp" +#include "rive/math/vec2d.hpp" + +#include +#include +#include +#include +#include +#include +#include +#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; + +RIVE_DEFINE_HANDLE(FileHandle); +RIVE_DEFINE_HANDLE(ArtboardHandle); +RIVE_DEFINE_HANDLE(StateMachineHandle); +RIVE_DEFINE_HANDLE(DrawKey); + +// Function poimter that gets called back from the server thread. +using CommandServerCallback = std::function; +using CommandServerDrawCallback = std::function; + +// Client-side recorder for commands that will be executed by a +// CommandServer. +class CommandQueue : public RefCnt +{ +public: + template 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(&other)); + m_owningQueue->registerListener( + m_handle, + static_cast(this)); + } + } + ~ListenerBase() + { + if (m_owningQueue) + m_owningQueue->unregisterListener( + m_handle, + static_cast(this)); + } + ListenerBase() : m_handle(RIVE_NULL_HANDLE) {} + + private: + rcp m_owningQueue; + HandleType m_handle; + }; + + class FileListener + : public CommandQueue::ListenerBase + { + public: + virtual void onFileDeleted(const FileHandle, uint64_t requestId) {} + + virtual void onArtboardsListed(const FileHandle, + uint64_t requestId, + std::vector artboardNames) + {} + }; + + class ArtboardListener + : public CommandQueue::ListenerBase + { + public: + virtual void onArtboardDeleted(const ArtboardHandle, uint64_t requestId) + {} + + virtual void onStateMachinesListed( + const ArtboardHandle, + uint64_t requestId, + std::vector stateMachineNames) + {} + }; + + class StateMachineListener + : public CommandQueue::ListenerBase + { + public: + 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) + {} + }; + + CommandQueue(); + ~CommandQueue(); + + FileHandle loadFile(std::vector rivBytes, + rcp, + FileListener* listener = nullptr, + uint64_t requestId = 0); + + FileHandle loadFile(std::vector rivBytes, + FileListener* listener = nullptr, + uint64_t requestId = 0) + { + return loadFile(std::move(rivBytes), nullptr, listener, requestId); + } + + void deleteFile(FileHandle, 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 deleteArtboard(ArtboardHandle, 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 advanceStateMachine(StateMachineHandle, + float timeToAdvance, + uint64_t requestId = 0); + + // Pointer events + void pointerMove(StateMachineHandle, Vec2D position); + void pointerDown(StateMachineHandle, Vec2D position); + void pointerUp(StateMachineHandle, Vec2D position); + void pointerExit(StateMachineHandle, Vec2D position); + + void deleteStateMachine(StateMachineHandle, uint64_t requestId = 0); + + // Create unique draw key for draw. + DrawKey createDrawKey(); + + // Executes a one-time callback on the server. This may eventualy become a + // testing-only method. + void runOnce(CommandServerCallback); + + // Run draw function for given draw key, only the latest function passed + // will be run per pollCommands. + void draw(DrawKey, CommandServerDrawCallback); + +#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 requestArtboardNames(FileHandle, uint64_t requestId = 0); + void requestStateMachineNames(ArtboardHandle, uint64_t requestId = 0); + + // Consume all messages received from the server. + void processMessages(); + +private: + void registerListener(FileHandle handle, FileListener* listener) + { + assert(listener); + assert(m_fileListeners.find(handle) == m_fileListeners.end()); + m_fileListeners.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(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(ArtboardHandle handle, ArtboardListener* listener) + { + m_artboardListeners.erase(handle); + } + + void unregisterListener(StateMachineHandle handle, + StateMachineListener* listener) + { + m_stateMachineListeners.erase(handle); + } + + enum class Command + { + loadFile, + deleteFile, + instantiateArtboard, + deleteArtboard, + instantiateStateMachine, + deleteStateMachine, + advanceStateMachine, + runOnce, + draw, + 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 + listArtboards, + listStateMachines + }; + + enum class Message + { + // Same as commandLoopBreak for processMessages + messageLoopBreak, + artboardsListed, + stateMachinesListed, + fileDeleted, + artboardDeleted, + stateMachineDeleted, + stateMachineSettled + }; + + friend class CommandServer; + + uint64_t m_currentFileHandleIdx = 0; + uint64_t m_currentArtboardHandleIdx = 0; + uint64_t m_currentStateMachineHandleIdx = 0; + uint64_t m_currentDrawKeyIdx = 0; + + std::mutex m_commandMutex; + std::condition_variable m_commandConditionVariable; + PODStream m_commandStream; + ObjectStream> m_byteVectors; + ObjectStream m_names; + ObjectStream m_callbacks; + ObjectStream m_drawCallbacks; + + // Messages streams + std::mutex m_messageMutex; + PODStream m_messageStream; + ObjectStream m_messageNames; + + // Listeners + std::unordered_map m_fileListeners; + std::unordered_map m_artboardListeners; + std::unordered_map + m_stateMachineListeners; +}; + +}; // namespace rive diff --git a/third_party/rive/include/rive/command_server.hpp b/third_party/rive/include/rive/command_server.hpp new file mode 100644 index 0000000..9212e8c --- /dev/null +++ b/third_party/rive/include/rive/command_server.hpp @@ -0,0 +1,54 @@ +/* + * Copyright 2025 Rive + */ + +#pragma once + +#include "rive/command_queue.hpp" +#include +#include + +namespace rive +{ +// Server-side worker that executes commands from a CommandQueue. +class CommandServer +{ +public: + CommandServer(rcp, Factory*); + virtual ~CommandServer(); + + Factory* factory() const { return m_factory; } + + File* getFile(FileHandle) const; + bool getWasDisconnected() const { return m_wasDisconnectReceived; } + + ArtboardInstance* getArtboardInstance(ArtboardHandle) const; + StateMachineInstance* getStateMachineInstance(StateMachineHandle) const; + // Wait for queue to not be empty, then returns pollMessages. + bool waitCommands(); + // Returns imidiatly after checking messages. If there are none just returns + // returns !m_wasDisconnectReceived. + bool processCommands(); + // Blocks and runs waitMessages until disconnect is received. + void serveUntilDisconnect(); + +private: + friend class CommandQueue; + + bool m_wasDisconnectReceived = false; + const rcp m_commandQueue; + Factory* const m_factory; +#ifndef NDEBUG + const std::thread::id m_threadID; +#endif + + std::unordered_map> m_files; + std::unordered_map> + m_artboards; + std::unordered_map> + m_stateMachines; + + std::unordered_map m_uniqueDraws; +}; +}; // namespace rive diff --git a/third_party/rive/include/rive/component.hpp b/third_party/rive/include/rive/component.hpp new file mode 100644 index 0000000..9e1be4f --- /dev/null +++ b/third_party/rive/include/rive/component.hpp @@ -0,0 +1,70 @@ +#ifndef _RIVE_COMPONENT_HPP_ +#define _RIVE_COMPONENT_HPP_ +#include "rive/component_dirt.hpp" +#include "rive/generated/component_base.hpp" +#include "rive/dependency_helper.hpp" + +#include +#include + +namespace rive +{ +class ContainerComponent; +class Artboard; + +class Component : public ComponentBase +{ + friend class Artboard; + +private: + ContainerComponent* m_Parent = nullptr; + + unsigned int m_GraphOrder; + Artboard* m_Artboard = nullptr; + +protected: + ComponentDirt m_Dirt = ComponentDirt::Filthy; + +public: + DependencyHelper m_DependencyHelper; + virtual bool collapse(bool value); + inline Artboard* artboard() const { return m_Artboard; } + bool validate(CoreContext* context) override; + StatusCode onAddedDirty(CoreContext* context) override; + inline ContainerComponent* parent() const { return m_Parent; } + const std::vector& dependents() const + { + return m_DependencyHelper.dependents(); + } + + void addDependent(Component* component); + + // TODO: re-evaluate when more of the lib is complete... + // These could be pure virtual but we define them empty here to avoid + // having to implement them in a bunch of concrete classes that + // currently don't use this logic. + virtual void buildDependencies() {} + virtual void onDirty(ComponentDirt dirt) {} + virtual void update(ComponentDirt value) {} + + unsigned int graphOrder() const { return m_GraphOrder; } + bool addDirt(ComponentDirt value, bool recurse = false); + inline bool hasDirt(ComponentDirt flag) const + { + return (m_Dirt & flag) == flag; + } + static inline bool hasDirt(ComponentDirt value, ComponentDirt flag) + { + return (value & flag) != ComponentDirt::None; + } + + StatusCode import(ImportStack& importStack) override; + + virtual bool isCollapsed() const + { + return (m_Dirt & ComponentDirt::Collapsed) == ComponentDirt::Collapsed; + } +}; +} // namespace rive + +#endif diff --git a/third_party/rive/include/rive/component_dirt.hpp b/third_party/rive/include/rive/component_dirt.hpp new file mode 100644 index 0000000..68e5d6f --- /dev/null +++ b/third_party/rive/include/rive/component_dirt.hpp @@ -0,0 +1,77 @@ +#ifndef _RIVE_DIRTY_FLAGS_HPP_ +#define _RIVE_DIRTY_FLAGS_HPP_ + +#include "rive/enum_bitset.hpp" + +namespace rive +{ +enum class ComponentDirt : unsigned short +{ + None = 0, + + /// Used to mark that a component (and subsequently it's children) do not + /// update with the Artboard update cycle and that any drawable should also + /// be hidden. Used by Solos. + Collapsed = 1 << 0, + + Dependents = 1 << 1, + + /// General flag for components are dirty (if this is up, the update + /// cycle runs). It gets automatically applied with any other dirt. + Components = 1 << 2, + + /// Draw order needs to be re-computed. + DrawOrder = 1 << 3, + + /// Path is dirty and needs to be rebuilt. + Path = 1 << 4, + + /// TextShape is dirty and needs to be rebuilt. + TextShape = 1 << 4, + + /// Skin needs to recompute bone transformations. + Skin = 1 << 4, + + /// Vertices have changed, re-order cached lists. + Vertices = 1 << 5, + + /// Text modifier coverage is dirty and needs to be rebuilt. + TextCoverage = 1 << 5, + + /// Used by any component that needs to recompute their local transform. + /// Usually components that have their transform dirty will also have + /// their worldTransform dirty. + Transform = 1 << 6, + + /// Used by any component that needs to update its world transform. + WorldTransform = 1 << 7, + + /// Marked when the stored render opacity needs to be updated. + RenderOpacity = 1 << 8, + + /// Dirt used to mark some stored paint needs to be rebuilt or that we + /// just want to trigger an update cycle so painting occurs. + Paint = 1 << 9, + + /// Used by the gradients track when the stops need to be re-ordered. + Stops = 1 << 10, + + /// Blend modes need to be updated + // TODO: do we need this? + // BlendMode = 1 << 9, + + LayoutStyle = 1 << 11, + + /// Used by data binds to track the value has changed. + Bindings = 1 << 12, + + /// Set when components deformed by an NSlicer need to recalculate + /// their render paths, mesh, points, etc. + NSlicer = 1 << 13, + + /// All dirty. Every flag (apart from Collapsed) is set. + Filthy = 0xFFFE +}; +RIVE_MAKE_ENUM_BITSET(ComponentDirt) +} // namespace rive +#endif diff --git a/third_party/rive/include/rive/constraints/constraint.hpp b/third_party/rive/include/rive/constraints/constraint.hpp new file mode 100644 index 0000000..bb29fb2 --- /dev/null +++ b/third_party/rive/include/rive/constraints/constraint.hpp @@ -0,0 +1,24 @@ +#ifndef _RIVE_CONSTRAINT_HPP_ +#define _RIVE_CONSTRAINT_HPP_ +#include "rive/generated/constraints/constraint_base.hpp" +#include +namespace rive +{ +class TransformComponent; +class Mat2D; + +class Constraint : public ConstraintBase +{ +public: + void strengthChanged() override; + StatusCode onAddedClean(CoreContext* context) override; + virtual void markConstraintDirty(); + virtual void constrain(TransformComponent* component) = 0; + void buildDependencies() override; + void onDirty(ComponentDirt dirt) override; +}; + +const Mat2D& getParentWorld(const TransformComponent& component); +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/constraints/distance_constraint.hpp b/third_party/rive/include/rive/constraints/distance_constraint.hpp new file mode 100644 index 0000000..5af1a70 --- /dev/null +++ b/third_party/rive/include/rive/constraints/distance_constraint.hpp @@ -0,0 +1,16 @@ +#ifndef _RIVE_DISTANCE_CONSTRAINT_HPP_ +#define _RIVE_DISTANCE_CONSTRAINT_HPP_ +#include "rive/generated/constraints/distance_constraint_base.hpp" +#include +namespace rive +{ +class DistanceConstraint : public DistanceConstraintBase +{ +public: + void constrain(TransformComponent* component) override; + void distanceChanged() override; + void modeValueChanged() override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/constraints/draggable_constraint.hpp b/third_party/rive/include/rive/constraints/draggable_constraint.hpp new file mode 100644 index 0000000..778d998 --- /dev/null +++ b/third_party/rive/include/rive/constraints/draggable_constraint.hpp @@ -0,0 +1,55 @@ +#ifndef _RIVE_DRAGGABLE_CONSTRAINT_HPP_ +#define _RIVE_DRAGGABLE_CONSTRAINT_HPP_ +#include "rive/generated/constraints/draggable_constraint_base.hpp" +#include "rive/drawable.hpp" +#include "rive/math/vec2d.hpp" +#include +namespace rive +{ +enum class DraggableConstraintDirection : uint8_t +{ + horizontal, + vertical, + all +}; + +class DraggableProxy +{ +protected: + Drawable* m_hittable; + +public: + virtual ~DraggableProxy() {} + virtual bool isOpaque() { return false; } + virtual void startDrag(Vec2D mousePosition) = 0; + virtual void drag(Vec2D mousePosition) = 0; + virtual void endDrag(Vec2D mousePosition) = 0; + Drawable* hittable() { return m_hittable; } +}; + +class DraggableConstraint : public DraggableConstraintBase +{ +public: + DraggableConstraint() {} + virtual std::vector draggables() = 0; + + DraggableConstraintDirection direction() + { + return DraggableConstraintDirection(directionValue()); + } + bool constrainsHorizontal() + { + auto dir = direction(); + return dir == DraggableConstraintDirection::horizontal || + dir == DraggableConstraintDirection::all; + } + bool constrainsVertical() + { + auto dir = direction(); + return dir == DraggableConstraintDirection::vertical || + dir == DraggableConstraintDirection::all; + } +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/constraints/follow_path_constraint.hpp b/third_party/rive/include/rive/constraints/follow_path_constraint.hpp new file mode 100644 index 0000000..8c4344f --- /dev/null +++ b/third_party/rive/include/rive/constraints/follow_path_constraint.hpp @@ -0,0 +1,27 @@ +#ifndef _RIVE_FOLLOW_PATH_CONSTRAINT_HPP_ +#define _RIVE_FOLLOW_PATH_CONSTRAINT_HPP_ +#include "rive/generated/constraints/follow_path_constraint_base.hpp" +#include "rive/math/transform_components.hpp" +#include "rive/math/path_measure.hpp" +namespace rive +{ +class FollowPathConstraint : public FollowPathConstraintBase +{ +public: + void distanceChanged() override; + void orientChanged() override; + StatusCode onAddedClean(CoreContext* context) override; + const Mat2D targetTransform() const; + void constrain(TransformComponent* component) override; + void update(ComponentDirt value) override; + void buildDependencies() override; + +private: + RawPath m_rawPath; + PathMeasure m_pathMeasure; + TransformComponents m_ComponentsA; + TransformComponents m_ComponentsB; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/constraints/ik_constraint.hpp b/third_party/rive/include/rive/constraints/ik_constraint.hpp new file mode 100644 index 0000000..191c7de --- /dev/null +++ b/third_party/rive/include/rive/constraints/ik_constraint.hpp @@ -0,0 +1,38 @@ +#ifndef _RIVE_I_KCONSTRAINT_HPP_ +#define _RIVE_I_KCONSTRAINT_HPP_ +#include "rive/generated/constraints/ik_constraint_base.hpp" +#include "rive/math/mat2d.hpp" +#include "rive/math/transform_components.hpp" +#include + +namespace rive +{ +class Bone; +class IKConstraint : public IKConstraintBase +{ +private: + struct BoneChainLink + { + int index; + Bone* bone; + float angle; + TransformComponents transformComponents; + Mat2D parentWorldInverse; + }; + std::vector m_FkChain; + void solve1(BoneChainLink* fk1, const Vec2D& worldTargetTranslation); + void solve2(BoneChainLink* fk1, + BoneChainLink* fk2, + const Vec2D& worldTargetTranslation); + void constrainRotation(BoneChainLink& fk, float rotation); + +public: + void markConstraintDirty() override; + StatusCode onAddedClean(CoreContext* context) override; + void constrain(TransformComponent* component) override; + void buildDependencies() override; + void invertDirectionChanged() override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/constraints/layout_constraint.hpp b/third_party/rive/include/rive/constraints/layout_constraint.hpp new file mode 100644 index 0000000..96b885b --- /dev/null +++ b/third_party/rive/include/rive/constraints/layout_constraint.hpp @@ -0,0 +1,15 @@ +#ifndef _RIVE_LAYOUT_CONSTRAINT_HPP_ +#define _RIVE_LAYOUT_CONSTRAINT_HPP_ +#include +namespace rive +{ +class LayoutNodeProvider; + +class LayoutConstraint +{ +public: + virtual void constrainChild(LayoutNodeProvider* child) {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/constraints/rotation_constraint.hpp b/third_party/rive/include/rive/constraints/rotation_constraint.hpp new file mode 100644 index 0000000..ed69d29 --- /dev/null +++ b/third_party/rive/include/rive/constraints/rotation_constraint.hpp @@ -0,0 +1,22 @@ +#ifndef _RIVE_ROTATION_CONSTRAINT_HPP_ +#define _RIVE_ROTATION_CONSTRAINT_HPP_ +#include "rive/generated/constraints/rotation_constraint_base.hpp" +#include "rive/math/transform_components.hpp" +#include +namespace rive +{ +class RotationConstraint : public RotationConstraintBase +{ +private: + TransformComponents m_ComponentsA; + TransformComponents m_ComponentsB; + +protected: + bool requiresTarget() override { return false; } + +public: + void constrain(TransformComponent* component) override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/constraints/scale_constraint.hpp b/third_party/rive/include/rive/constraints/scale_constraint.hpp new file mode 100644 index 0000000..e9b27dc --- /dev/null +++ b/third_party/rive/include/rive/constraints/scale_constraint.hpp @@ -0,0 +1,22 @@ +#ifndef _RIVE_SCALE_CONSTRAINT_HPP_ +#define _RIVE_SCALE_CONSTRAINT_HPP_ +#include "rive/generated/constraints/scale_constraint_base.hpp" +#include "rive/math/transform_components.hpp" +#include +namespace rive +{ +class ScaleConstraint : public ScaleConstraintBase +{ +private: + TransformComponents m_ComponentsA; + TransformComponents m_ComponentsB; + +protected: + bool requiresTarget() override { return false; } + +public: + void constrain(TransformComponent* component) override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/constraints/scrolling/clamped_scroll_physics.hpp b/third_party/rive/include/rive/constraints/scrolling/clamped_scroll_physics.hpp new file mode 100644 index 0000000..f4ae3b8 --- /dev/null +++ b/third_party/rive/include/rive/constraints/scrolling/clamped_scroll_physics.hpp @@ -0,0 +1,21 @@ +#ifndef _RIVE_CLAMPED_SCROLL_PHYSICS_HPP_ +#define _RIVE_CLAMPED_SCROLL_PHYSICS_HPP_ +#include "rive/generated/constraints/scrolling/clamped_scroll_physics_base.hpp" +#include +namespace rive +{ +class ClampedScrollPhysics : public ClampedScrollPhysicsBase +{ +private: + Vec2D m_value; + +public: + Vec2D advance(float elapsedSeconds) override; + void run(Vec2D range, + Vec2D value, + std::vector snappingPoints) override; + Vec2D clamp(Vec2D range, Vec2D value) override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/constraints/scrolling/elastic_scroll_physics.hpp b/third_party/rive/include/rive/constraints/scrolling/elastic_scroll_physics.hpp new file mode 100644 index 0000000..f69da85 --- /dev/null +++ b/third_party/rive/include/rive/constraints/scrolling/elastic_scroll_physics.hpp @@ -0,0 +1,66 @@ +#ifndef _RIVE_ELASTIC_SCROLL_PHYSICS_HPP_ +#define _RIVE_ELASTIC_SCROLL_PHYSICS_HPP_ +#include "rive/generated/constraints/scrolling/elastic_scroll_physics_base.hpp" +#include +namespace rive +{ + +class ElasticScrollPhysicsHelper +{ +private: + float m_friction = 8.0f; + float m_speedMultiplier = 1.0f; + float m_elasticFactor = 0.66f; + float m_target = 0; + float m_current = 0; + float m_speed = 0; + float m_runRange = 0; + bool m_isRunning = false; + +public: + ElasticScrollPhysicsHelper(float friction, + float speedMultiplier, + float elasticFactor) + { + m_friction = friction; + m_speedMultiplier = speedMultiplier; + m_elasticFactor = elasticFactor; + } + + bool isRunning() { return m_isRunning; } + float clamp(float range, float value); + void run(float acceleration, + float range, + float value, + std::vector snappingPoints); + float advance(float elapsedSeconds); +}; + +class ElasticScrollPhysics : public ElasticScrollPhysicsBase +{ +private: + ElasticScrollPhysicsHelper* m_physicsX; + ElasticScrollPhysicsHelper* m_physicsY; + +public: + ~ElasticScrollPhysics(); + bool enabled() override + { + return m_physicsX != nullptr || m_physicsY != nullptr; + } + bool isRunning() override + { + return (m_physicsX != nullptr && m_physicsX->isRunning()) || + (m_physicsY != nullptr && m_physicsY->isRunning()); + } + Vec2D advance(float elapsedSeconds) override; + Vec2D clamp(Vec2D range, Vec2D value) override; + void run(Vec2D range, + Vec2D value, + std::vector snappingPoints) override; + void prepare(DraggableConstraintDirection dir) override; + void reset() override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/constraints/scrolling/scroll_bar_constraint.hpp b/third_party/rive/include/rive/constraints/scrolling/scroll_bar_constraint.hpp new file mode 100644 index 0000000..f02c0ec --- /dev/null +++ b/third_party/rive/include/rive/constraints/scrolling/scroll_bar_constraint.hpp @@ -0,0 +1,43 @@ +#ifndef _RIVE_SCROLL_BAR_CONSTRAINT_HPP_ +#define _RIVE_SCROLL_BAR_CONSTRAINT_HPP_ +#include "rive/constraints/scrolling/scroll_constraint.hpp" +#include "rive/math/transform_components.hpp" +#include "rive/generated/constraints/scrolling/scroll_bar_constraint_base.hpp" +#include +namespace rive +{ +class DraggableProxy; +class TransformComponent; +class TransformComponents; + +class ScrollBarConstraint : public ScrollBarConstraintBase +{ +private: + TransformComponents m_componentsA; + TransformComponents m_componentsB; + ScrollConstraint* m_scrollConstraint; + +public: + void constrain(TransformComponent* component) override; + std::vector draggables() override; + ScrollConstraint* scrollConstraint() { return m_scrollConstraint; } + void scrollConstraint(ScrollConstraint* constraint) + { + m_scrollConstraint = constraint; + } + void buildDependencies() override; + StatusCode onAddedDirty(CoreContext* context) override; + void dragThumb(Vec2D delta); + void hitTrack(Vec2D worldPosition); + LayoutComponent* thumb() { return parent()->as(); } + LayoutComponent* track() + { + return parent()->parent()->as(); + } + float computedThumbWidth(); + float computedThumbHeight(); + bool validate(CoreContext* context) override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/constraints/scrolling/scroll_bar_constraint_proxy.hpp b/third_party/rive/include/rive/constraints/scrolling/scroll_bar_constraint_proxy.hpp new file mode 100644 index 0000000..bffaa66 --- /dev/null +++ b/third_party/rive/include/rive/constraints/scrolling/scroll_bar_constraint_proxy.hpp @@ -0,0 +1,48 @@ +#ifndef _RIVE_SCROLL_BAR_CONSTRAINT_PROXY_HPP_ +#define _RIVE_SCROLL_BAR_CONSTRAINT_PROXY_HPP_ +#include +#include "rive/constraints/draggable_constraint.hpp" +namespace rive +{ +class ScrollBarConstraint; +class Drawable; + +class ThumbDraggableProxy : public DraggableProxy +{ +private: + ScrollBarConstraint* m_constraint; + Vec2D m_lastPosition; + +public: + ThumbDraggableProxy(ScrollBarConstraint* constraint, Drawable* hittable) : + m_constraint(constraint) + { + m_hittable = hittable; + } + ~ThumbDraggableProxy() {} + bool isOpaque() override { return true; } + void startDrag(Vec2D mousePosition) override; + void drag(Vec2D mousePosition) override; + void endDrag(Vec2D mousePosition) override {} +}; + +class TrackDraggableProxy : public DraggableProxy +{ +private: + ScrollBarConstraint* m_constraint; + +public: + TrackDraggableProxy(ScrollBarConstraint* constraint, Drawable* hittable) : + m_constraint(constraint) + { + m_hittable = hittable; + } + ~TrackDraggableProxy() {} + bool isOpaque() override { return true; } + void startDrag(Vec2D mousePosition) override; + void drag(Vec2D mousePosition) override {} + void endDrag(Vec2D mousePosition) override {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/constraints/scrolling/scroll_constraint.hpp b/third_party/rive/include/rive/constraints/scrolling/scroll_constraint.hpp new file mode 100644 index 0000000..4033768 --- /dev/null +++ b/third_party/rive/include/rive/constraints/scrolling/scroll_constraint.hpp @@ -0,0 +1,173 @@ +#ifndef _RIVE_SCROLL_CONSTRAINT_HPP_ +#define _RIVE_SCROLL_CONSTRAINT_HPP_ +#include "rive/generated/constraints/scrolling/scroll_constraint_base.hpp" +#include "rive/advance_flags.hpp" +#include "rive/advancing_component.hpp" +#include "rive/constraints/layout_constraint.hpp" +#include "rive/constraints/scrolling/scroll_physics.hpp" +#include "rive/layout_component.hpp" +#include "rive/math/math_types.hpp" +#include "rive/math/transform_components.hpp" +#include +namespace rive +{ +class LayoutNodeProvider; + +class ScrollConstraint : public ScrollConstraintBase, + public AdvancingComponent, + public LayoutConstraint +{ +private: + TransformComponents m_componentsA; + TransformComponents m_componentsB; + float m_offsetX = 0; + float m_offsetY = 0; + ScrollPhysics* m_physics; + Mat2D m_scrollTransform; + bool m_isDragging = false; + + Vec2D positionAtIndex(float index); + float indexAtPosition(Vec2D pos); + +public: + ~ScrollConstraint(); + void constrain(TransformComponent* component) override; + std::vector draggables() override; + void buildDependencies() override; + StatusCode import(ImportStack& importStack) override; + StatusCode onAddedDirty(CoreContext* context) override; + Core* clone() const override; + void dragView(Vec2D delta); + void runPhysics(); + void constrainChild(LayoutNodeProvider* child) override; + bool advanceComponent(float elapsedSeconds, + AdvanceFlags flags = AdvanceFlags::Animate | + AdvanceFlags::NewFrame) override; + + ScrollPhysics* physics() const { return m_physics; } + void physics(ScrollPhysics* physics) { m_physics = physics; } + void initPhysics(); + void stopPhysics(); + + ScrollPhysicsType physicsType() const + { + return ScrollPhysicsType(physicsTypeValue()); + } + + LayoutComponent* content() { return parent()->as(); } + LayoutComponent* viewport() + { + return parent()->parent()->as(); + } + float contentWidth() { return content()->layoutWidth(); } + float contentHeight() { return content()->layoutHeight(); } + float viewportWidth() + { + return direction() == DraggableConstraintDirection::vertical + ? viewport()->layoutWidth() + : std::max(0.0f, + viewport()->layoutWidth() - content()->layoutX()); + } + float viewportHeight() + { + return direction() == DraggableConstraintDirection::horizontal + ? viewport()->layoutHeight() + : std::max(0.0f, + viewport()->layoutHeight() - + content()->layoutY()); + } + float visibleWidthRatio() + { + if (contentWidth() == 0) + { + return 1; + } + return std::min(1.0f, viewportWidth() / contentWidth()); + } + float visibleHeightRatio() + { + if (contentHeight() == 0) + { + return 1; + } + return std::min(1.0f, viewportHeight() / contentHeight()); + } + float maxOffsetX() + { + return std::min(0.0f, + viewportWidth() - contentWidth() - + viewport()->paddingRight()); + } + float maxOffsetY() + { + return std::min(0.0f, + viewportHeight() - contentHeight() - + viewport()->paddingBottom()); + } + float clampedOffsetX() + { + if (maxOffsetX() > 0) + { + return 0; + } + if (m_physics != nullptr && m_physics->enabled()) + { + return m_physics + ->clamp(Vec2D(maxOffsetX(), maxOffsetY()), + Vec2D(m_offsetX, m_offsetY)) + .x; + } + return math::clamp(m_offsetX, maxOffsetX(), 0); + } + float clampedOffsetY() + { + if (maxOffsetY() > 0) + { + return 0; + } + if (m_physics != nullptr && m_physics->enabled()) + { + return m_physics + ->clamp(Vec2D(maxOffsetX(), maxOffsetY()), + Vec2D(m_offsetX, m_offsetY)) + .y; + } + return math::clamp(m_offsetY, maxOffsetY(), 0); + } + + float offsetX() { return m_offsetX; } + float offsetY() { return m_offsetY; } + void offsetX(float value) + { + if (m_offsetX == value) + { + return; + } + m_offsetX = value; + content()->markWorldTransformDirty(); + } + void offsetY(float value) + { + if (m_offsetY == value) + { + return; + } + m_offsetY = value; + content()->markWorldTransformDirty(); + } + + void scrollOffsetXChanged() override { offsetX(scrollOffsetX()); } + void scrollOffsetYChanged() override { offsetY(scrollOffsetY()); } + + float scrollPercentX() override; + float scrollPercentY() override; + float scrollIndex() override; + void setScrollPercentX(float value) override; + void setScrollPercentY(float value) override; + void setScrollIndex(float value) override; + size_t scrollItemCount(); + Vec2D gap(); +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/constraints/scrolling/scroll_constraint_proxy.hpp b/third_party/rive/include/rive/constraints/scrolling/scroll_constraint_proxy.hpp new file mode 100644 index 0000000..965724f --- /dev/null +++ b/third_party/rive/include/rive/constraints/scrolling/scroll_constraint_proxy.hpp @@ -0,0 +1,30 @@ +#ifndef _RIVE_SCROLL_CONSTRAINT_PROXY_HPP_ +#define _RIVE_SCROLL_CONSTRAINT_PROXY_HPP_ +#include +#include "rive/constraints/draggable_constraint.hpp" +namespace rive +{ +class ScrollConstraint; +class Drawable; + +class ViewportDraggableProxy : public DraggableProxy +{ +private: + ScrollConstraint* m_constraint; + Vec2D m_lastPosition; + +public: + ViewportDraggableProxy(ScrollConstraint* constraint, Drawable* hittable) : + m_constraint(constraint) + { + m_hittable = hittable; + } + ~ViewportDraggableProxy() {} + bool isOpaque() override { return false; } + void startDrag(Vec2D mousePosition) override; + void drag(Vec2D mousePosition) override; + void endDrag(Vec2D mousePosition) override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/constraints/scrolling/scroll_physics.hpp b/third_party/rive/include/rive/constraints/scrolling/scroll_physics.hpp new file mode 100644 index 0000000..62f535c --- /dev/null +++ b/third_party/rive/include/rive/constraints/scrolling/scroll_physics.hpp @@ -0,0 +1,65 @@ +#ifndef _RIVE_SCROLL_PHYSICS_HPP_ +#define _RIVE_SCROLL_PHYSICS_HPP_ +#include "rive/artboard.hpp" +#include "rive/backboard.hpp" +#include "rive/constraints/draggable_constraint.hpp" +#include "rive/generated/constraints/scrolling/scroll_physics_base.hpp" +#include "rive/importers/artboard_importer.hpp" +#include "rive/importers/backboard_importer.hpp" +#include "rive/importers/import_stack.hpp" +#include "rive/math/math_types.hpp" +#include "rive/math/vec2d.hpp" +#include +#include +#include +namespace rive +{ +class ScrollConstraint; + +enum class ScrollPhysicsType : uint8_t +{ + elastic, + clamped +}; + +class ScrollPhysics : public ScrollPhysicsBase +{ +private: + bool m_isRunning = false; + long long m_lastTime = + std::chrono::duration_cast( + std::chrono::high_resolution_clock::now().time_since_epoch()) + .count(); + +protected: + DraggableConstraintDirection m_direction; + Vec2D m_speed; + Vec2D m_acceleration; + +public: + virtual bool enabled() { return isRunning(); } + virtual bool isRunning() { return m_isRunning; } + virtual void prepare(DraggableConstraintDirection dir) + { + m_direction = dir; + } + virtual Vec2D clamp(Vec2D range, Vec2D value) { return Vec2D(); }; + virtual Vec2D advance(float elapsedSeconds) { return Vec2D(); }; + virtual void accumulate(Vec2D delta); + virtual void run(Vec2D range, + Vec2D value, + std::vector snappingPoints) + { + m_isRunning = true; + } + virtual void stop() { m_isRunning = false; } + virtual void reset() + { + m_acceleration = Vec2D(); + stop(); + } + StatusCode import(ImportStack& importStack) override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/constraints/targeted_constraint.hpp b/third_party/rive/include/rive/constraints/targeted_constraint.hpp new file mode 100644 index 0000000..dcfef42 --- /dev/null +++ b/third_party/rive/include/rive/constraints/targeted_constraint.hpp @@ -0,0 +1,22 @@ +#ifndef _RIVE_TARGETED_CONSTRAINT_HPP_ +#define _RIVE_TARGETED_CONSTRAINT_HPP_ +#include "rive/generated/constraints/targeted_constraint_base.hpp" +#include +namespace rive +{ +class TransformComponent; +class TargetedConstraint : public TargetedConstraintBase +{ +protected: + TransformComponent* m_Target = nullptr; + virtual bool requiresTarget() { return true; }; + +public: + void buildDependencies() override; + + bool validate(CoreContext* context) override; + StatusCode onAddedDirty(CoreContext* context) override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/constraints/transform_component_constraint.hpp b/third_party/rive/include/rive/constraints/transform_component_constraint.hpp new file mode 100644 index 0000000..dfd26c7 --- /dev/null +++ b/third_party/rive/include/rive/constraints/transform_component_constraint.hpp @@ -0,0 +1,18 @@ +#ifndef _RIVE_TRANSFORM_COMPONENT_CONSTRAINT_HPP_ +#define _RIVE_TRANSFORM_COMPONENT_CONSTRAINT_HPP_ +#include "rive/generated/constraints/transform_component_constraint_base.hpp" +#include "rive/transform_space.hpp" +#include +namespace rive +{ +class TransformComponentConstraint : public TransformComponentConstraintBase +{ +public: + TransformSpace minMaxSpace() const + { + return (TransformSpace)minMaxSpaceValue(); + } +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/constraints/transform_component_constraint_y.hpp b/third_party/rive/include/rive/constraints/transform_component_constraint_y.hpp new file mode 100644 index 0000000..05aaf3d --- /dev/null +++ b/third_party/rive/include/rive/constraints/transform_component_constraint_y.hpp @@ -0,0 +1,13 @@ +#ifndef _RIVE_TRANSFORM_COMPONENT_CONSTRAINT_Y_HPP_ +#define _RIVE_TRANSFORM_COMPONENT_CONSTRAINT_Y_HPP_ +#include "rive/generated/constraints/transform_component_constraint_y_base.hpp" +#include +namespace rive +{ +class TransformComponentConstraintY : public TransformComponentConstraintYBase +{ +public: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/constraints/transform_constraint.hpp b/third_party/rive/include/rive/constraints/transform_constraint.hpp new file mode 100644 index 0000000..054381b --- /dev/null +++ b/third_party/rive/include/rive/constraints/transform_constraint.hpp @@ -0,0 +1,30 @@ +#ifndef _RIVE_TRANSFORM_CONSTRAINT_HPP_ +#define _RIVE_TRANSFORM_CONSTRAINT_HPP_ +#include "rive/generated/constraints/transform_constraint_base.hpp" +#include "rive/math/transform_components.hpp" + +#include +namespace rive +{ +class TransformConstraint : public TransformConstraintBase +{ +private: + TransformComponents m_ComponentsA; + TransformComponents m_ComponentsB; + +public: + virtual const Mat2D targetTransform() const; + void constrain(TransformComponent* component) override; + void originXChanged() override; + void originYChanged() override; + + static void constrainWorld(TransformComponent* component, + Mat2D from, + TransformComponents componentsFrom, + Mat2D to, + TransformComponents componentsTo, + float strength); +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/constraints/transform_space_constraint.hpp b/third_party/rive/include/rive/constraints/transform_space_constraint.hpp new file mode 100644 index 0000000..2bd7806 --- /dev/null +++ b/third_party/rive/include/rive/constraints/transform_space_constraint.hpp @@ -0,0 +1,22 @@ +#ifndef _RIVE_TRANSFORM_SPACE_CONSTRAINT_HPP_ +#define _RIVE_TRANSFORM_SPACE_CONSTRAINT_HPP_ +#include "rive/generated/constraints/transform_space_constraint_base.hpp" +#include "rive/transform_space.hpp" +#include +namespace rive +{ +class TransformSpaceConstraint : public TransformSpaceConstraintBase +{ +public: + TransformSpace sourceSpace() const + { + return (TransformSpace)sourceSpaceValue(); + } + TransformSpace destSpace() const + { + return (TransformSpace)destSpaceValue(); + } +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/constraints/translation_constraint.hpp b/third_party/rive/include/rive/constraints/translation_constraint.hpp new file mode 100644 index 0000000..a8864a7 --- /dev/null +++ b/third_party/rive/include/rive/constraints/translation_constraint.hpp @@ -0,0 +1,17 @@ +#ifndef _RIVE_TRANSLATION_CONSTRAINT_HPP_ +#define _RIVE_TRANSLATION_CONSTRAINT_HPP_ +#include "rive/generated/constraints/translation_constraint_base.hpp" +#include +namespace rive +{ +class TranslationConstraint : public TranslationConstraintBase +{ +protected: + bool requiresTarget() override { return false; } + +public: + void constrain(TransformComponent* component) override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/container_component.hpp b/third_party/rive/include/rive/container_component.hpp new file mode 100644 index 0000000..1a91f39 --- /dev/null +++ b/third_party/rive/include/rive/container_component.hpp @@ -0,0 +1,37 @@ +#ifndef _RIVE_CONTAINER_COMPONENT_HPP_ +#define _RIVE_CONTAINER_COMPONENT_HPP_ +#include "rive/generated/container_component_base.hpp" +#include "rive/typed_children.hpp" +#include +#include + +namespace rive +{ + +class ContainerComponent : public ContainerComponentBase +{ +public: + template TypedChildren children() + { + return TypedChildren( + Span((Core**)m_children.data(), m_children.size())); + } + + const std::vector& children() const { return m_children; } + virtual void addChild(Component* component); + bool collapse(bool value) override; + + // Returns whether predicate returns true for the current Component. + bool forAll(std::function predicate); + + // Recursively descend onto all the children in the hierarchy tree. + // If predicate returns false, it won't recurse down a particular + // branch. + void forEachChild(std::function predicate); + +private: + std::vector m_children; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/core.hpp b/third_party/rive/include/rive/core.hpp new file mode 100644 index 0000000..4d5b198 --- /dev/null +++ b/third_party/rive/include/rive/core.hpp @@ -0,0 +1,77 @@ +#ifndef _RIVE_CORE_HPP_ +#define _RIVE_CORE_HPP_ + +#include "rive/rive_types.hpp" +#include "rive/core/binary_reader.hpp" +#include "rive/status_code.hpp" + +#ifdef DEBUG +#define DEBUG_PRINT(msg) fprintf(stderr, msg "\n"); +#else +#define DEBUG_PRINT(msg) +#endif + +namespace rive +{ +class CoreContext; +class ImportStack; +class Core +{ +public: + Core() = default; + Core(const Core&) = default; + const uint32_t emptyId = -1; + static const int invalidPropertyKey = 0; + virtual ~Core() {} + virtual uint16_t coreType() const = 0; + virtual bool isTypeOf(uint16_t typeKey) const = 0; + virtual bool deserialize(uint16_t propertyKey, BinaryReader& reader) = 0; + + template inline bool is() const + { + return isTypeOf(T::typeKey); + } + template inline T* as() + { + assert(is()); + return static_cast(this); + } + + /// Make a shallow copy of the object. + virtual Core* clone() const { return nullptr; } + + template inline const T* as() const + { + assert(is()); + return static_cast(this); + } + + /// Called to validate the object can be used at runtime. + virtual bool validate(CoreContext* context) { return true; } + + /// Called when the object is first added to the context, other objects + /// may not have resolved their dependencies yet. This is an opportunity + /// to look up objects referenced by id, but not assume that they in + /// turn have resolved their references yet. Called during + /// load/instance. + virtual StatusCode onAddedDirty(CoreContext* context) + { + return StatusCode::Ok; + } + + /// Called when all the objects in the context have had onAddedDirty + /// called. This is an opportunity to reference things referenced by + /// dependencies. (A path should be able to find a Shape somewhere in + /// its hierarchy, which may be multiple levels up). + virtual StatusCode onAddedClean(CoreContext* context) + { + return StatusCode::Ok; + } + + virtual StatusCode import(ImportStack& importStack) + { + return StatusCode::Ok; + } +}; +} // namespace rive +#endif diff --git a/third_party/rive/include/rive/core/binary_data_reader.hpp b/third_party/rive/include/rive/core/binary_data_reader.hpp new file mode 100644 index 0000000..beae449 --- /dev/null +++ b/third_party/rive/include/rive/core/binary_data_reader.hpp @@ -0,0 +1,38 @@ +#ifndef _RIVE_CORE_BINARY_DATA_READER_HPP_ +#define _RIVE_CORE_BINARY_DATA_READER_HPP_ + +#include +#include + +namespace rive +{ +class BinaryDataReader +{ +private: + uint8_t* m_Position; + uint8_t* m_End; + bool m_Overflowed; + size_t m_Length; + + void overflow(); + +public: + BinaryDataReader(uint8_t* bytes, size_t length); + bool didOverflow() const; + bool isEOF() const { return m_Position >= m_End; } + const uint8_t* position() const { return m_Position; } + + size_t lengthInBytes() const; + + uint64_t readVarUint(); + uint32_t readVarUint32(); + double readFloat64(); + float readFloat32(); + uint8_t readByte(); + uint32_t readUint32(); + void complete(uint8_t* bytes, size_t length); + void reset(uint8_t* bytes); +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/core/binary_reader.hpp b/third_party/rive/include/rive/core/binary_reader.hpp new file mode 100644 index 0000000..0d77cb6 --- /dev/null +++ b/third_party/rive/include/rive/core/binary_reader.hpp @@ -0,0 +1,57 @@ + +#ifndef _RIVE_CORE_BINARY_READER_HPP_ +#define _RIVE_CORE_BINARY_READER_HPP_ + +#include +#include +#include "rive/span.hpp" +#include "rive/core/type_conversions.hpp" + +namespace rive +{ +class BinaryReader +{ +private: + Span m_Bytes; + const uint8_t* m_Position; + bool m_Overflowed; + bool m_IntRangeError; + + void overflow(); + void intRangeError(); + +public: + explicit BinaryReader(Span); + bool didOverflow() const; + bool didIntRangeError() const; + bool hasError() const { return m_Overflowed || m_IntRangeError; } + bool reachedEnd() const; + + size_t lengthInBytes() const; + const uint8_t* position() const; + + std::string readString(); + Span readBytes(); + float readFloat32(); + uint8_t readByte(); + uint16_t readUint16(); + uint32_t readUint32(); + uint64_t readVarUint64(); // Reads a LEB128 encoded uint64_t + + // This will cast the uint read to the requested size, but if the + // raw value was out-of-range, instead returns 0 and sets the IntRangeError. + template T readVarUintAs() + { + auto value = this->readVarUint64(); + if (!fitsIn(value)) + { + value = 0; + this->intRangeError(); + } + return static_cast(value); + } + void reset(); +}; +} // namespace rive + +#endif diff --git a/third_party/rive/include/rive/core/binary_stream.hpp b/third_party/rive/include/rive/core/binary_stream.hpp new file mode 100644 index 0000000..f582ccf --- /dev/null +++ b/third_party/rive/include/rive/core/binary_stream.hpp @@ -0,0 +1,20 @@ +#ifndef _RIVE_CORE_BINARY_STREAM_HPP_ +#define _RIVE_CORE_BINARY_STREAM_HPP_ + +#include +#include + +namespace rive +{ +// Used to write binary chunks to an underlying stream, makes no assumptions +// regarding storage/streaming it can flush the contents as it needs. +class BinaryStream +{ +public: + virtual void write(const uint8_t* bytes, std::size_t length) = 0; + virtual void flush() = 0; + virtual void clear() = 0; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/core/binary_writer.hpp b/third_party/rive/include/rive/core/binary_writer.hpp new file mode 100644 index 0000000..92ae1c3 --- /dev/null +++ b/third_party/rive/include/rive/core/binary_writer.hpp @@ -0,0 +1,34 @@ +#ifndef _RIVE_CORE_BINARY_WRITER_HPP_ +#define _RIVE_CORE_BINARY_WRITER_HPP_ + +#include +#include +#include + +namespace rive +{ +class BinaryStream; +class BinaryWriter +{ +private: + BinaryStream* m_Stream; + +public: + BinaryWriter(BinaryStream* stream); + ~BinaryWriter(); + void write(float value); + void writeFloat(float value); + void write(double value); + void writeVarUint(uint64_t value); + void writeVarUint(uint32_t value); + void write(const uint8_t* bytes, std::size_t length); + void write(uint8_t value); + void writeDouble(double value); + void write(uint16_t value); + void write(uint32_t value); + void write(std::string value); + void clear(); +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/core/field_types/core_bool_type.hpp b/third_party/rive/include/rive/core/field_types/core_bool_type.hpp new file mode 100644 index 0000000..c6b0fcc --- /dev/null +++ b/third_party/rive/include/rive/core/field_types/core_bool_type.hpp @@ -0,0 +1,14 @@ +#ifndef _RIVE_CORE_BOOL_TYPE_HPP_ +#define _RIVE_CORE_BOOL_TYPE_HPP_ + +namespace rive +{ +class BinaryReader; +class CoreBoolType +{ +public: + static const int id = 0; + static bool deserialize(BinaryReader& reader); +}; +} // namespace rive +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/core/field_types/core_bytes_type.hpp b/third_party/rive/include/rive/core/field_types/core_bytes_type.hpp new file mode 100644 index 0000000..90f1886 --- /dev/null +++ b/third_party/rive/include/rive/core/field_types/core_bytes_type.hpp @@ -0,0 +1,17 @@ +#ifndef _RIVE_CORE_BYTES_TYPE_HPP_ +#define _RIVE_CORE_BYTES_TYPE_HPP_ + +#include "rive/span.hpp" +#include + +namespace rive +{ +class BinaryReader; +class CoreBytesType +{ +public: + static const int id = 1; + static Span deserialize(BinaryReader& reader); +}; +} // namespace rive +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/core/field_types/core_callback_type.hpp b/third_party/rive/include/rive/core/field_types/core_callback_type.hpp new file mode 100644 index 0000000..a6bb93f --- /dev/null +++ b/third_party/rive/include/rive/core/field_types/core_callback_type.hpp @@ -0,0 +1,29 @@ +#ifndef _RIVE_CORE_CALLBACK_TYPE_HPP_ +#define _RIVE_CORE_CALLBACK_TYPE_HPP_ + +namespace rive +{ +class Event; +class CallbackContext +{ +public: + virtual ~CallbackContext() {} + virtual void reportEvent(Event* event, float secondsDelay = 0.0f) {} + virtual bool playsAudio() { return false; } +}; + +class CallbackData +{ +public: + CallbackContext* context() const { return m_context; } + float delaySeconds() const { return m_delaySeconds; } + CallbackData(CallbackContext* context, float delaySeconds) : + m_context(context), m_delaySeconds(delaySeconds) + {} + +private: + CallbackContext* m_context; + float m_delaySeconds; +}; +} // namespace rive +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/core/field_types/core_color_type.hpp b/third_party/rive/include/rive/core/field_types/core_color_type.hpp new file mode 100644 index 0000000..afacba9 --- /dev/null +++ b/third_party/rive/include/rive/core/field_types/core_color_type.hpp @@ -0,0 +1,14 @@ +#ifndef _RIVE_CORE_COLOR_TYPE_HPP_ +#define _RIVE_CORE_COLOR_TYPE_HPP_ + +namespace rive +{ +class BinaryReader; +class CoreColorType +{ +public: + static const int id = 3; + static int deserialize(BinaryReader& reader); +}; +} // namespace rive +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/core/field_types/core_double_type.hpp b/third_party/rive/include/rive/core/field_types/core_double_type.hpp new file mode 100644 index 0000000..6351572 --- /dev/null +++ b/third_party/rive/include/rive/core/field_types/core_double_type.hpp @@ -0,0 +1,14 @@ +#ifndef _RIVE_CORE_DOUBLE_TYPE_HPP_ +#define _RIVE_CORE_DOUBLE_TYPE_HPP_ + +namespace rive +{ +class BinaryReader; +class CoreDoubleType +{ +public: + static const int id = 2; + static float deserialize(BinaryReader& reader); +}; +} // namespace rive +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/core/field_types/core_string_type.hpp b/third_party/rive/include/rive/core/field_types/core_string_type.hpp new file mode 100644 index 0000000..5962545 --- /dev/null +++ b/third_party/rive/include/rive/core/field_types/core_string_type.hpp @@ -0,0 +1,16 @@ +#ifndef _RIVE_CORE_STRING_TYPE_HPP_ +#define _RIVE_CORE_STRING_TYPE_HPP_ + +#include + +namespace rive +{ +class BinaryReader; +class CoreStringType +{ +public: + static const int id = 1; + static std::string deserialize(BinaryReader& reader); +}; +} // namespace rive +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/core/field_types/core_uint_type.hpp b/third_party/rive/include/rive/core/field_types/core_uint_type.hpp new file mode 100644 index 0000000..af9c399 --- /dev/null +++ b/third_party/rive/include/rive/core/field_types/core_uint_type.hpp @@ -0,0 +1,14 @@ +#ifndef _RIVE_CORE_UINT_TYPE_HPP_ +#define _RIVE_CORE_UINT_TYPE_HPP_ + +namespace rive +{ +class BinaryReader; +class CoreUintType +{ +public: + static const int id = 0; + static unsigned int deserialize(BinaryReader& reader); +}; +} // namespace rive +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/core/reader.h b/third_party/rive/include/rive/core/reader.h new file mode 100644 index 0000000..fa9196d --- /dev/null +++ b/third_party/rive/include/rive/core/reader.h @@ -0,0 +1,193 @@ +#pragma once + +#include +#include + +static bool is_big_endian(void) +{ + union + { + uint32_t i; + char c[4]; + } bint = {0x01020304}; + + return bint.c[0] == 1; +} + +/* Decode an unsigned int LEB128 at buf into r, returning the nr of bytes read. + */ +inline size_t decode_uint_leb(const uint8_t* buf, + const uint8_t* buf_end, + uint64_t* r) +{ + const uint8_t* p = buf; + uint8_t shift = 0; + uint64_t result = 0; + uint8_t byte; + + do + { + if (p >= buf_end) + { + return 0; + } + byte = *p++; + result |= ((uint64_t)(byte & 0x7f)) << shift; + shift += 7; + } while ((byte & 0x80) != 0); + *r = result; + return p - buf; +} + +/* Decode an unsigned int LEB128 at buf into r, returning the nr of bytes read. + */ +inline size_t decode_uint_leb32(const uint8_t* buf, + const uint8_t* buf_end, + uint32_t* r) +{ + const uint8_t* p = buf; + uint8_t shift = 0; + uint32_t result = 0; + uint8_t byte; + + do + { + if (p >= buf_end) + { + return 0; + } + byte = *p++; + result |= ((uint32_t)(byte & 0x7f)) << shift; + shift += 7; + } while ((byte & 0x80) != 0); + *r = result; + return p - buf; +} + +/* Decodes a string + */ +inline uint64_t decode_string(uint64_t str_len, + const uint8_t* buf, + const uint8_t* buf_end, + char* char_buf) +{ + // Return zero bytes read on buffer overflow + if (buf_end < buf + str_len) + { + return 0; + } + const uint8_t* p = buf; + for (int i = 0; i < str_len; i++) + { + char_buf[i] = *p++; + } + // Add the null terminator + char_buf[str_len] = '\0'; + return str_len; +} + +/* Decodes a double (8 bytes) + */ +inline size_t decode_double(const uint8_t* buf, + const uint8_t* buf_end, + double* r) +{ + // Return zero bytes read on buffer overflow + if (buf_end - buf < sizeof(double)) + { + return 0; + } + if (is_big_endian()) + { + uint8_t inverted[8] = + {buf[7], buf[6], buf[5], buf[4], buf[3], buf[2], buf[1], buf[0]}; + memcpy(r, inverted, sizeof(double)); + } + else + { + memcpy(r, buf, sizeof(double)); + } + return sizeof(double); +} + +/* Decodes a float (4 bytes) + */ +inline size_t decode_float(const uint8_t* buf, const uint8_t* buf_end, float* r) +{ + // Return zero bytes read on buffer overflow + if (buf_end - buf < (unsigned)sizeof(float)) + { + return 0; + } + if (is_big_endian()) + { + uint8_t inverted[4] = {buf[3], buf[2], buf[1], buf[0]}; + memcpy(r, inverted, sizeof(float)); + } + else + { + memcpy(r, buf, sizeof(float)); + } + return sizeof(float); +} + +/* Decodes a single byte + */ +inline size_t decode_uint_8(const uint8_t* buf, + const uint8_t* buf_end, + uint8_t* r) +{ + // Return zero bytes read on buffer overflow + if (buf_end - buf < (unsigned)sizeof(uint8_t)) + { + return 0; + } + memcpy(r, buf, sizeof(uint8_t)); + return sizeof(uint8_t); +} + +/* Decodes a 16 bit unsigned integer. + */ +inline size_t decode_uint_16(const uint8_t* buf, + const uint8_t* buf_end, + uint16_t* r) +{ + // Return zero bytes read on buffer overflow + if (buf_end - buf < (unsigned)sizeof(uint16_t)) + { + return 0; + } + if (is_big_endian()) + { + uint8_t inverted[2] = {buf[1], buf[0]}; + memcpy(r, inverted, sizeof(uint16_t)); + } + else + { + memcpy(r, buf, sizeof(uint16_t)); + } + return sizeof(uint16_t); +} + +/* Decodes a 32 bit unsigned integer. + */ +inline size_t decode_uint_32(const uint8_t* buf, + const uint8_t* buf_end, + uint32_t* r) +{ + // Return zero bytes read on buffer overflow + if (buf_end - buf < (unsigned)sizeof(uint32_t)) + { + return 0; + } + if (is_big_endian()) + { + uint8_t inverted[4] = {buf[3], buf[2], buf[1], buf[0]}; + memcpy(r, inverted, sizeof(uint32_t)); + } + else + { + memcpy(r, buf, sizeof(uint32_t)); + } + return sizeof(uint32_t); +} diff --git a/third_party/rive/include/rive/core/type_conversions.hpp b/third_party/rive/include/rive/core/type_conversions.hpp new file mode 100644 index 0000000..f8cc2b4 --- /dev/null +++ b/third_party/rive/include/rive/core/type_conversions.hpp @@ -0,0 +1,29 @@ +/* + * Copyright 2022 Rive + */ + +#ifndef _RIVE_TYPE_CONVERSIONS_HPP_ +#define _RIVE_TYPE_CONVERSIONS_HPP_ + +#include "rive/rive_types.hpp" +#include + +namespace rive +{ + +template bool fitsIn(intmax_t x) +{ + return x >= std::numeric_limits::min() && + x <= std::numeric_limits::max(); +} + +template T castTo(intmax_t x) +{ + assert(sizeof(T) <= 4); // don't cast to 64bit types + assert(fitsIn(x)); + return static_cast(x); +} + +} // namespace rive + +#endif diff --git a/third_party/rive/include/rive/core/vector_binary_writer.hpp b/third_party/rive/include/rive/core/vector_binary_writer.hpp new file mode 100644 index 0000000..93663de --- /dev/null +++ b/third_party/rive/include/rive/core/vector_binary_writer.hpp @@ -0,0 +1,45 @@ +#ifndef _RIVE_CORE_VECTOR_BINARY_WRITER_HPP_ +#define _RIVE_CORE_VECTOR_BINARY_WRITER_HPP_ + +#include "rive/core/binary_stream.hpp" +#include "rive/core/binary_writer.hpp" +#include + +namespace rive +{ +class VectorBinaryWriter : public BinaryStream, public BinaryWriter +{ +private: + std::vector* m_WriteBuffer; + std::size_t m_Start; + size_t m_pos = 0; + +public: + VectorBinaryWriter(std::vector* buffer) : + BinaryWriter(this), + m_WriteBuffer(buffer), + m_Start(m_WriteBuffer->size()) + {} + + uint8_t* buffer() const { return &(*m_WriteBuffer)[m_Start]; } + std::size_t bufferSize() const { return m_WriteBuffer->size() - m_Start; } + + std::size_t start() const { return m_Start; } + size_t size() const { return m_pos; } + + using BinaryWriter::write; + void write(const uint8_t* bytes, std::size_t length) override + { + auto end = m_pos; + if (m_WriteBuffer->size() < end + length) + { + m_WriteBuffer->resize(end + length); + } + std::memcpy(&((*m_WriteBuffer)[end]), bytes, length); + m_pos += length; + } + void flush() override {} + void clear() override { m_pos = 0; } +}; +} // namespace rive +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/core_context.hpp b/third_party/rive/include/rive/core_context.hpp new file mode 100644 index 0000000..655c751 --- /dev/null +++ b/third_party/rive/include/rive/core_context.hpp @@ -0,0 +1,17 @@ +#ifndef _RIVE_CORE_CONTEXT_HPP_ +#define _RIVE_CORE_CONTEXT_HPP_ + +#include "rive/rive_types.hpp" + +namespace rive +{ +class Artboard; +class Core; +class CoreContext +{ +public: + virtual ~CoreContext() {} + virtual Core* resolve(uint32_t id) const = 0; +}; +} // namespace rive +#endif diff --git a/third_party/rive/include/rive/custom_property.hpp b/third_party/rive/include/rive/custom_property.hpp new file mode 100644 index 0000000..2863962 --- /dev/null +++ b/third_party/rive/include/rive/custom_property.hpp @@ -0,0 +1,13 @@ +#ifndef _RIVE_CUSTOM_PROPERTY_HPP_ +#define _RIVE_CUSTOM_PROPERTY_HPP_ +#include "rive/generated/custom_property_base.hpp" +#include +namespace rive +{ +class CustomProperty : public CustomPropertyBase +{ +public: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/custom_property_boolean.hpp b/third_party/rive/include/rive/custom_property_boolean.hpp new file mode 100644 index 0000000..260bc0f --- /dev/null +++ b/third_party/rive/include/rive/custom_property_boolean.hpp @@ -0,0 +1,13 @@ +#ifndef _RIVE_CUSTOM_PROPERTY_BOOLEAN_HPP_ +#define _RIVE_CUSTOM_PROPERTY_BOOLEAN_HPP_ +#include "rive/generated/custom_property_boolean_base.hpp" +#include +namespace rive +{ +class CustomPropertyBoolean : public CustomPropertyBooleanBase +{ +public: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/custom_property_group.hpp b/third_party/rive/include/rive/custom_property_group.hpp new file mode 100644 index 0000000..80115e3 --- /dev/null +++ b/third_party/rive/include/rive/custom_property_group.hpp @@ -0,0 +1,13 @@ +#ifndef _RIVE_CUSTOM_PROPERTY_GROUP_HPP_ +#define _RIVE_CUSTOM_PROPERTY_GROUP_HPP_ +#include "rive/generated/custom_property_group_base.hpp" +#include +namespace rive +{ +class CustomPropertyGroup : public CustomPropertyGroupBase +{ +public: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/custom_property_number.hpp b/third_party/rive/include/rive/custom_property_number.hpp new file mode 100644 index 0000000..192351b --- /dev/null +++ b/third_party/rive/include/rive/custom_property_number.hpp @@ -0,0 +1,13 @@ +#ifndef _RIVE_CUSTOM_PROPERTY_NUMBER_HPP_ +#define _RIVE_CUSTOM_PROPERTY_NUMBER_HPP_ +#include "rive/generated/custom_property_number_base.hpp" +#include +namespace rive +{ +class CustomPropertyNumber : public CustomPropertyNumberBase +{ +public: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/custom_property_string.hpp b/third_party/rive/include/rive/custom_property_string.hpp new file mode 100644 index 0000000..7efc20e --- /dev/null +++ b/third_party/rive/include/rive/custom_property_string.hpp @@ -0,0 +1,13 @@ +#ifndef _RIVE_CUSTOM_PROPERTY_STRING_HPP_ +#define _RIVE_CUSTOM_PROPERTY_STRING_HPP_ +#include "rive/generated/custom_property_string_base.hpp" +#include +namespace rive +{ +class CustomPropertyString : public CustomPropertyStringBase +{ +public: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/data_bind/bindable_property.hpp b/third_party/rive/include/rive/data_bind/bindable_property.hpp new file mode 100644 index 0000000..cbfb148 --- /dev/null +++ b/third_party/rive/include/rive/data_bind/bindable_property.hpp @@ -0,0 +1,12 @@ +#ifndef _RIVE_BINDABLE_PROPERTY_HPP_ +#define _RIVE_BINDABLE_PROPERTY_HPP_ +#include "rive/generated/data_bind/bindable_property_base.hpp" +#include "rive/data_bind/data_bind.hpp" +#include +namespace rive +{ +class BindableProperty : public BindablePropertyBase +{}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/data_bind/bindable_property_asset.hpp b/third_party/rive/include/rive/data_bind/bindable_property_asset.hpp new file mode 100644 index 0000000..58b89ff --- /dev/null +++ b/third_party/rive/include/rive/data_bind/bindable_property_asset.hpp @@ -0,0 +1,14 @@ +#ifndef _RIVE_BINDABLE_PROPERTY_ASSET_HPP_ +#define _RIVE_BINDABLE_PROPERTY_ASSET_HPP_ +#include "rive/generated/data_bind/bindable_property_asset_base.hpp" +#include +namespace rive +{ +class BindablePropertyAsset : public BindablePropertyAssetBase +{ +public: + constexpr static uint32_t defaultValue = -1; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/data_bind/bindable_property_boolean.hpp b/third_party/rive/include/rive/data_bind/bindable_property_boolean.hpp new file mode 100644 index 0000000..df773b9 --- /dev/null +++ b/third_party/rive/include/rive/data_bind/bindable_property_boolean.hpp @@ -0,0 +1,14 @@ +#ifndef _RIVE_BINDABLE_PROPERTY_BOOLEAN_HPP_ +#define _RIVE_BINDABLE_PROPERTY_BOOLEAN_HPP_ +#include "rive/generated/data_bind/bindable_property_boolean_base.hpp" +#include +namespace rive +{ +class BindablePropertyBoolean : public BindablePropertyBooleanBase +{ +public: + constexpr static bool defaultValue = false; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/data_bind/bindable_property_color.hpp b/third_party/rive/include/rive/data_bind/bindable_property_color.hpp new file mode 100644 index 0000000..4440591 --- /dev/null +++ b/third_party/rive/include/rive/data_bind/bindable_property_color.hpp @@ -0,0 +1,14 @@ +#ifndef _RIVE_BINDABLE_PROPERTY_COLOR_HPP_ +#define _RIVE_BINDABLE_PROPERTY_COLOR_HPP_ +#include "rive/generated/data_bind/bindable_property_color_base.hpp" +#include +namespace rive +{ +class BindablePropertyColor : public BindablePropertyColorBase +{ +public: + constexpr static int defaultValue = 0; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/data_bind/bindable_property_enum.hpp b/third_party/rive/include/rive/data_bind/bindable_property_enum.hpp new file mode 100644 index 0000000..49c8058 --- /dev/null +++ b/third_party/rive/include/rive/data_bind/bindable_property_enum.hpp @@ -0,0 +1,14 @@ +#ifndef _RIVE_BINDABLE_PROPERTY_ENUM_HPP_ +#define _RIVE_BINDABLE_PROPERTY_ENUM_HPP_ +#include "rive/generated/data_bind/bindable_property_enum_base.hpp" +#include +namespace rive +{ +class BindablePropertyEnum : public BindablePropertyEnumBase +{ +public: + constexpr static uint16_t defaultValue = 0; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/data_bind/bindable_property_integer.hpp b/third_party/rive/include/rive/data_bind/bindable_property_integer.hpp new file mode 100644 index 0000000..0631fc8 --- /dev/null +++ b/third_party/rive/include/rive/data_bind/bindable_property_integer.hpp @@ -0,0 +1,14 @@ +#ifndef _RIVE_BINDABLE_PROPERTY_INTEGER_HPP_ +#define _RIVE_BINDABLE_PROPERTY_INTEGER_HPP_ +#include "rive/generated/data_bind/bindable_property_integer_base.hpp" +#include +namespace rive +{ +class BindablePropertyInteger : public BindablePropertyIntegerBase +{ +public: + constexpr static uint32_t defaultValue = 0; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/data_bind/bindable_property_number.hpp b/third_party/rive/include/rive/data_bind/bindable_property_number.hpp new file mode 100644 index 0000000..87d3fbc --- /dev/null +++ b/third_party/rive/include/rive/data_bind/bindable_property_number.hpp @@ -0,0 +1,14 @@ +#ifndef _RIVE_BINDABLE_PROPERTY_NUMBER_HPP_ +#define _RIVE_BINDABLE_PROPERTY_NUMBER_HPP_ +#include "rive/generated/data_bind/bindable_property_number_base.hpp" +#include +namespace rive +{ +class BindablePropertyNumber : public BindablePropertyNumberBase +{ +public: + constexpr static float defaultValue = 0; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/data_bind/bindable_property_string.hpp b/third_party/rive/include/rive/data_bind/bindable_property_string.hpp new file mode 100644 index 0000000..9f7e953 --- /dev/null +++ b/third_party/rive/include/rive/data_bind/bindable_property_string.hpp @@ -0,0 +1,15 @@ +#ifndef _RIVE_BINDABLE_PROPERTY_STRING_HPP_ +#define _RIVE_BINDABLE_PROPERTY_STRING_HPP_ +#include "rive/generated/data_bind/bindable_property_string_base.hpp" +#include +#include +namespace rive +{ +class BindablePropertyString : public BindablePropertyStringBase +{ +public: + static constexpr const char* defaultValue = ""; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/data_bind/bindable_property_trigger.hpp b/third_party/rive/include/rive/data_bind/bindable_property_trigger.hpp new file mode 100644 index 0000000..be69b15 --- /dev/null +++ b/third_party/rive/include/rive/data_bind/bindable_property_trigger.hpp @@ -0,0 +1,14 @@ +#ifndef _RIVE_BINDABLE_PROPERTY_TRIGGER_HPP_ +#define _RIVE_BINDABLE_PROPERTY_TRIGGER_HPP_ +#include "rive/generated/data_bind/bindable_property_trigger_base.hpp" +#include +namespace rive +{ +class BindablePropertyTrigger : public BindablePropertyTriggerBase +{ +public: + constexpr static uint32_t defaultValue = 0; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/data_bind/context/context_value.hpp b/third_party/rive/include/rive/data_bind/context/context_value.hpp new file mode 100644 index 0000000..c4626d9 --- /dev/null +++ b/third_party/rive/include/rive/data_bind/context/context_value.hpp @@ -0,0 +1,97 @@ +#ifndef _RIVE_DATA_BIND_CONTEXT_VALUE_HPP_ +#define _RIVE_DATA_BIND_CONTEXT_VALUE_HPP_ +#include "rive/viewmodel/viewmodel_instance_value.hpp" +#include "rive/data_bind/converters/data_converter.hpp" +#include "rive/data_bind/data_bind.hpp" +#include "rive/data_bind/data_values/data_value_number.hpp" +#include +namespace rive +{ +class DataBindContextValue +{ +protected: + DataBind* m_dataBind = nullptr; + DataValue* m_dataValue = nullptr; + bool m_isValid = false; + virtual DataValue* targetValue() { return nullptr; }; + +public: + DataBindContextValue(DataBind* dataBind); + virtual ~DataBindContextValue() + { + if (m_dataValue != nullptr) + { + delete m_dataValue; + } + }; + virtual void applyToSource(Core* component, + uint32_t propertyKey, + bool isMainDirection); + virtual void apply(Core* component, + uint32_t propertyKey, + bool isMainDirection){}; + void invalidate() { m_isValid = false; }; + virtual bool syncTargetValue(Core* target, uint32_t propertyKey) + { + return false; + }; + void syncSourceValue(); + template + U getDataValue(DataValue* input, DataBind* dataBind) + { + auto converter = dataBind->converter(); + auto dataValue = + converter != nullptr ? converter->convert(input, dataBind) : input; + if (dataValue->is()) + { + return dataValue->as()->value(); + } + return T::defaultValue; + }; + template + U getReverseDataValue(DataValue* input, DataBind* dataBind) + { + auto converter = dataBind->converter(); + auto dataValue = converter != nullptr + ? converter->reverseConvert(input, dataBind) + : input; + if (dataValue->is()) + { + return dataValue->as()->value(); + } + return T::defaultValue; + }; + template + U calculateValue(DataValue* input, bool isMainDirection, DataBind* dataBind) + { + auto value = isMainDirection + ? getDataValue(input, dataBind) + : getReverseDataValue(input, dataBind); + return value; + }; + template + void calculateValueAndApply(DataValue* input, + bool isMainDirection, + DataBind* dataBind, + Core* component, + uint32_t propertyKey) + { + // Check if target value changed or binding has been invalidated + if (syncTargetValue(component, propertyKey) || !m_isValid) + { + // Calculate new value after converters are applied + auto value = calculateValue(input, isMainDirection, dataBind); + // Apply value to source + dataBind->suppressDirt(true); + auto source = dataBind->source(); + source->as()->propertyValue(value); + dataBind->suppressDirt(false); + m_isValid = true; + } + }; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/data_bind/context/context_value_asset_image.hpp b/third_party/rive/include/rive/data_bind/context/context_value_asset_image.hpp new file mode 100644 index 0000000..d3dac46 --- /dev/null +++ b/third_party/rive/include/rive/data_bind/context/context_value_asset_image.hpp @@ -0,0 +1,28 @@ +#ifndef _RIVE_DATA_BIND_CONTEXT_VALUE_ASSET_IMAGE_HPP_ +#define _RIVE_DATA_BIND_CONTEXT_VALUE_ASSET_IMAGE_HPP_ +#include "rive/data_bind/context/context_value.hpp" +#include "rive/data_bind/data_values/data_value_asset_image.hpp" +namespace rive +{ +class ImageAsset; +class DataBindContextValueAssetImage : public DataBindContextValue +{ + +public: + DataBindContextValueAssetImage(DataBind* m_dataBind); + void apply(Core* component, + uint32_t propertyKey, + bool isMainDirection) override; + bool syncTargetValue(Core* target, uint32_t propertyKey) override; + ImageAsset* fileAsset(); + +protected: + DataValue* targetValue() override { return &m_targetDataValue; } + +private: + uint32_t m_previousValue = -1; + DataValueAssetImage m_targetDataValue; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/data_bind/context/context_value_boolean.hpp b/third_party/rive/include/rive/data_bind/context/context_value_boolean.hpp new file mode 100644 index 0000000..e8702c1 --- /dev/null +++ b/third_party/rive/include/rive/data_bind/context/context_value_boolean.hpp @@ -0,0 +1,25 @@ +#ifndef _RIVE_DATA_BIND_CONTEXT_VALUE_BOOLEAN_HPP_ +#define _RIVE_DATA_BIND_CONTEXT_VALUE_BOOLEAN_HPP_ +#include "rive/data_bind/context/context_value.hpp" +#include "rive/data_bind/data_values/data_value_boolean.hpp" +namespace rive +{ +class DataBindContextValueBoolean : public DataBindContextValue +{ +public: + DataBindContextValueBoolean(DataBind* m_dataBind); + void apply(Core* component, + uint32_t propertyKey, + bool isMainDirection) override; + bool syncTargetValue(Core* target, uint32_t propertyKey) override; + +private: + bool m_previousValue = false; + DataValueBoolean m_targetDataValue; + +protected: + DataValue* targetValue() override { return &m_targetDataValue; } +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/data_bind/context/context_value_color.hpp b/third_party/rive/include/rive/data_bind/context/context_value_color.hpp new file mode 100644 index 0000000..5590640 --- /dev/null +++ b/third_party/rive/include/rive/data_bind/context/context_value_color.hpp @@ -0,0 +1,26 @@ +#ifndef _RIVE_DATA_BIND_CONTEXT_VALUE_COLOR_HPP_ +#define _RIVE_DATA_BIND_CONTEXT_VALUE_COLOR_HPP_ +#include "rive/data_bind/context/context_value.hpp" +#include "rive/data_bind/data_values/data_value_color.hpp" +namespace rive +{ +class DataBindContextValueColor : public DataBindContextValue +{ + +public: + DataBindContextValueColor(DataBind* m_dataBind); + void apply(Core* component, + uint32_t propertyKey, + bool isMainDirection) override; + bool syncTargetValue(Core* target, uint32_t propertyKey) override; + +private: + int m_previousValue = 0; + DataValueColor m_targetDataValue; + +protected: + DataValue* targetValue() override { return &m_targetDataValue; } +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/data_bind/context/context_value_enum.hpp b/third_party/rive/include/rive/data_bind/context/context_value_enum.hpp new file mode 100644 index 0000000..1ae2dd3 --- /dev/null +++ b/third_party/rive/include/rive/data_bind/context/context_value_enum.hpp @@ -0,0 +1,26 @@ +#ifndef _RIVE_DATA_BIND_CONTEXT_VALUE_ENUM_HPP_ +#define _RIVE_DATA_BIND_CONTEXT_VALUE_ENUM_HPP_ +#include "rive/data_bind/context/context_value.hpp" +#include "rive/data_bind/data_values/data_value_enum.hpp" +namespace rive +{ +class DataBindContextValueEnum : public DataBindContextValue +{ + +public: + DataBindContextValueEnum(DataBind* m_dataBind); + void apply(Core* component, + uint32_t propertyKey, + bool isMainDirection) override; + bool syncTargetValue(Core* target, uint32_t propertyKey) override; + +private: + uint32_t m_previousValue = 0; + DataValueEnum m_targetDataValue; + +protected: + DataValue* targetValue() override { return &m_targetDataValue; } +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/data_bind/context/context_value_list.hpp b/third_party/rive/include/rive/data_bind/context/context_value_list.hpp new file mode 100644 index 0000000..b5fcb67 --- /dev/null +++ b/third_party/rive/include/rive/data_bind/context/context_value_list.hpp @@ -0,0 +1,22 @@ +#ifndef _RIVE_DATA_BIND_CONTEXT_VALUE_LIST_HPP_ +#define _RIVE_DATA_BIND_CONTEXT_VALUE_LIST_HPP_ +#include "rive/data_bind/context/context_value.hpp" +#include "rive/data_bind/data_values/data_value_list.hpp" + +namespace rive +{ +class DataBindContextValueList : public DataBindContextValue +{ + +public: + DataBindContextValueList(DataBind* m_dataBind); + void apply(Core* component, + uint32_t propertyKey, + bool isMainDirection) override; + virtual void applyToSource(Core* component, + uint32_t propertyKey, + bool isMainDirection) override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/data_bind/context/context_value_number.hpp b/third_party/rive/include/rive/data_bind/context/context_value_number.hpp new file mode 100644 index 0000000..2e158bd --- /dev/null +++ b/third_party/rive/include/rive/data_bind/context/context_value_number.hpp @@ -0,0 +1,26 @@ +#ifndef _RIVE_DATA_BIND_CONTEXT_VALUE_NUMBER_HPP_ +#define _RIVE_DATA_BIND_CONTEXT_VALUE_NUMBER_HPP_ +#include "rive/data_bind/context/context_value.hpp" +#include "rive/data_bind/data_values/data_value_number.hpp" +namespace rive +{ +class DataBindContextValueNumber : public DataBindContextValue +{ + +public: + DataBindContextValueNumber(DataBind* m_dataBind); + void apply(Core* component, + uint32_t propertyKey, + bool isMainDirection) override; + bool syncTargetValue(Core* target, uint32_t propertyKey) override; + +private: + float m_previousValue = 0; + DataValueNumber m_targetDataValue; + +protected: + DataValue* targetValue() override { return &m_targetDataValue; } +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/data_bind/context/context_value_string.hpp b/third_party/rive/include/rive/data_bind/context/context_value_string.hpp new file mode 100644 index 0000000..ec81713 --- /dev/null +++ b/third_party/rive/include/rive/data_bind/context/context_value_string.hpp @@ -0,0 +1,26 @@ +#ifndef _RIVE_DATA_BIND_CONTEXT_VALUE_STRING_HPP_ +#define _RIVE_DATA_BIND_CONTEXT_VALUE_STRING_HPP_ +#include "rive/data_bind/context/context_value.hpp" +#include "rive/data_bind/data_values/data_value_string.hpp" +namespace rive +{ +class DataBindContextValueString : public DataBindContextValue +{ + +public: + DataBindContextValueString(DataBind* m_dataBind); + void apply(Core* component, + uint32_t propertyKey, + bool isMainDirection) override; + bool syncTargetValue(Core* target, uint32_t propertyKey) override; + +private: + std::string m_previousValue = ""; + DataValueString m_targetDataValue; + +protected: + DataValue* targetValue() override { return &m_targetDataValue; } +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/data_bind/context/context_value_symbol_list_index.hpp b/third_party/rive/include/rive/data_bind/context/context_value_symbol_list_index.hpp new file mode 100644 index 0000000..a98f656 --- /dev/null +++ b/third_party/rive/include/rive/data_bind/context/context_value_symbol_list_index.hpp @@ -0,0 +1,26 @@ +#ifndef _RIVE_DATA_BIND_CONTEXT_VALUE_SYMBOL_LIST_INDEX_HPP_ +#define _RIVE_DATA_BIND_CONTEXT_VALUE_SYMBOL_LIST_INDEX_HPP_ +#include "rive/data_bind/context/context_value.hpp" +#include "rive/data_bind/data_values/data_value_symbol_list_index.hpp" +namespace rive +{ +class DataBindContextValueSymbolListIndex : public DataBindContextValue +{ + +public: + DataBindContextValueSymbolListIndex(DataBind* m_dataBind); + void apply(Core* component, + uint32_t propertyKey, + bool isMainDirection) override; + bool syncTargetValue(Core* target, uint32_t propertyKey) override; + +private: + uint32_t m_previousValue = 0; + DataValueSymbolListIndex m_targetDataValue; + +protected: + DataValue* targetValue() override { return &m_targetDataValue; } +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/data_bind/context/context_value_trigger.hpp b/third_party/rive/include/rive/data_bind/context/context_value_trigger.hpp new file mode 100644 index 0000000..b66e41f --- /dev/null +++ b/third_party/rive/include/rive/data_bind/context/context_value_trigger.hpp @@ -0,0 +1,26 @@ +#ifndef _RIVE_DATA_BIND_CONTEXT_VALUE_TRIGGER_HPP_ +#define _RIVE_DATA_BIND_CONTEXT_VALUE_TRIGGER_HPP_ +#include "rive/data_bind/context/context_value.hpp" +#include "rive/data_bind/data_values/data_value_trigger.hpp" +namespace rive +{ +class DataBindContextValueTrigger : public DataBindContextValue +{ + +public: + DataBindContextValueTrigger(DataBind* m_dataBind); + void apply(Core* component, + uint32_t propertyKey, + bool isMainDirection) override; + bool syncTargetValue(Core* target, uint32_t propertyKey) override; + +private: + uint32_t m_previousValue = 0; + DataValueTrigger m_targetDataValue; + +protected: + DataValue* targetValue() override { return &m_targetDataValue; } +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/data_bind/converters/data_converter.hpp b/third_party/rive/include/rive/data_bind/converters/data_converter.hpp new file mode 100644 index 0000000..158aa1d --- /dev/null +++ b/third_party/rive/include/rive/data_bind/converters/data_converter.hpp @@ -0,0 +1,39 @@ +#ifndef _RIVE_DATA_CONVERTER_HPP_ +#define _RIVE_DATA_CONVERTER_HPP_ +#include "rive/generated/data_bind/converters/data_converter_base.hpp" +#include "rive/data_bind/data_values/data_value.hpp" +#include "rive/data_bind/data_context.hpp" +#include +namespace rive +{ +class DataBind; +class DataConverter : public DataConverterBase +{ +public: + ~DataConverter(); + virtual DataValue* convert(DataValue* value, DataBind* dataBind) + { + return value; + }; + virtual DataValue* reverseConvert(DataValue* value, DataBind* dataBind) + { + return value; + }; + virtual DataType outputType() { return DataType::none; }; + virtual void bindFromContext(DataContext* dataContext, DataBind* dataBind); + virtual void unbind(); + StatusCode import(ImportStack& importStack) override; + void addDataBind(DataBind* dataBind); + std::vector dataBinds() const { return m_dataBinds; } + void markConverterDirty(); + virtual void update(); + void copy(const DataConverter& object); + virtual bool advance(float elapsedTime); + +private: + std::vector m_dataBinds; + DataBind* m_parentDataBind; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/data_bind/converters/data_converter_boolean_negate.hpp b/third_party/rive/include/rive/data_bind/converters/data_converter_boolean_negate.hpp new file mode 100644 index 0000000..a4b92cc --- /dev/null +++ b/third_party/rive/include/rive/data_bind/converters/data_converter_boolean_negate.hpp @@ -0,0 +1,22 @@ +#ifndef _RIVE_DATA_CONVERTER_BOOLEAN_NEGATE_HPP_ +#define _RIVE_DATA_CONVERTER_BOOLEAN_NEGATE_HPP_ +#include "rive/generated/data_bind/converters/data_converter_boolean_negate_base.hpp" +#include "rive/data_bind/data_values/data_value.hpp" +#include "rive/data_bind/data_values/data_value_boolean.hpp" +#include "rive/data_bind/data_bind.hpp" +#include +namespace rive +{ +class DataConverterBooleanNegate : public DataConverterBooleanNegateBase +{ +public: + DataType outputType() override { return DataType::boolean; }; + DataValue* convert(DataValue* value, DataBind* dataBind) override; + DataValue* reverseConvert(DataValue* value, DataBind* dataBind) override; + +private: + DataValueBoolean m_output; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/data_bind/converters/data_converter_formula.hpp b/third_party/rive/include/rive/data_bind/converters/data_converter_formula.hpp new file mode 100644 index 0000000..feedf49 --- /dev/null +++ b/third_party/rive/include/rive/data_bind/converters/data_converter_formula.hpp @@ -0,0 +1,46 @@ +#ifndef _RIVE_DATA_CONVERTER_FORMULA_HPP_ +#define _RIVE_DATA_CONVERTER_FORMULA_HPP_ +#include "rive/generated/data_bind/converters/data_converter_formula_base.hpp" +#include "rive/data_bind/converters/formula/formula_token.hpp" +#include "rive/data_bind/data_bind.hpp" +#include "rive/data_bind/data_values/data_value_number.hpp" +#include +#include +namespace rive +{ + +class DataConverterFormula : public DataConverterFormulaBase +{ +public: + ~DataConverterFormula(); + DataType outputType() override { return DataType::number; }; + void addToken(FormulaToken*); + void addOutputToken(FormulaToken*, int); + void initialize(); + void isInstance(bool value) { m_isInstance = value; } + +protected: + DataValue* convert(DataValue* value, DataBind* dataBind) override; + DataValue* reverseConvert(DataValue* value, DataBind* dataBind) override; + DataValueNumber m_output; + Core* clone() const override; + void bindFromContext(DataContext* dataContext, DataBind* dataBind) override; + void unbind() override; + void update() override; + +private: + int getPrecedence(FormulaToken*); + float getRandom(int); + float applyOperation(float left, float right, int operationType); + float applyFunction(std::vector& stack, + int functionTypeIndex, + int totalArguments); + std::vector m_tokens; + std::vector m_outputQueue; + std::vector m_randoms; + std::unordered_map m_argumentsCount; + bool m_isInstance = false; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/data_bind/converters/data_converter_group.hpp b/third_party/rive/include/rive/data_bind/converters/data_converter_group.hpp new file mode 100644 index 0000000..9b8e70f --- /dev/null +++ b/third_party/rive/include/rive/data_bind/converters/data_converter_group.hpp @@ -0,0 +1,36 @@ +#ifndef _RIVE_DATA_CONVERTER_GROUP_HPP_ +#define _RIVE_DATA_CONVERTER_GROUP_HPP_ +#include "rive/generated/data_bind/converters/data_converter_group_base.hpp" +#include "rive/data_bind/converters/data_converter_group_item.hpp" +#include "rive/data_bind/data_bind.hpp" +#include +namespace rive +{ +class DataConverterGroup : public DataConverterGroupBase +{ +public: + ~DataConverterGroup(); + DataValue* convert(DataValue* value, DataBind* dataBind) override; + DataValue* reverseConvert(DataValue* value, DataBind* dataBind) override; + void addItem(DataConverterGroupItem* item); + DataType outputType() override + { + if (m_items.size() > 0) + { + return m_items.back()->converter()->outputType(); + }; + return Super::outputType(); + } + const std::vector& items() { return m_items; } + Core* clone() const override; + void bindFromContext(DataContext* dataContext, DataBind* dataBind) override; + void unbind() override; + void update() override; + bool advance(float elapsedSeconds) override; + +private: + std::vector m_items; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/data_bind/converters/data_converter_group_item.hpp b/third_party/rive/include/rive/data_bind/converters/data_converter_group_item.hpp new file mode 100644 index 0000000..6f410f5 --- /dev/null +++ b/third_party/rive/include/rive/data_bind/converters/data_converter_group_item.hpp @@ -0,0 +1,24 @@ +#ifndef _RIVE_DATA_CONVERTER_GROUP_ITEM_HPP_ +#define _RIVE_DATA_CONVERTER_GROUP_ITEM_HPP_ +#include "rive/generated/data_bind/converters/data_converter_group_item_base.hpp" +#include "rive/data_bind/converters/data_converter.hpp" +#include +namespace rive +{ +class DataConverterGroupItem : public DataConverterGroupItemBase +{ +public: + ~DataConverterGroupItem(); + StatusCode import(ImportStack& importStack) override; + DataConverter* converter() const { return m_dataConverter; }; + void converter(DataConverter* value) { m_dataConverter = value; }; + void ownsConverter(bool value) { m_ownsConverter = value; }; + Core* clone() const override; + +protected: + DataConverter* m_dataConverter = nullptr; + bool m_ownsConverter = false; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/data_bind/converters/data_converter_interpolator.hpp b/third_party/rive/include/rive/data_bind/converters/data_converter_interpolator.hpp new file mode 100644 index 0000000..ac7c067 --- /dev/null +++ b/third_party/rive/include/rive/data_bind/converters/data_converter_interpolator.hpp @@ -0,0 +1,53 @@ +#ifndef _RIVE_DATA_CONVERTER_INTERPOLATOR_HPP_ +#define _RIVE_DATA_CONVERTER_INTERPOLATOR_HPP_ +#include "rive/generated/data_bind/converters/data_converter_interpolator_base.hpp" +#include "rive/data_bind/data_values/data_value_number.hpp" +#include "rive/data_bind/data_values/data_value.hpp" +#include "rive/animation/keyframe_interpolator.hpp" +#include +namespace rive +{ + +struct InterpolatorAnimationData +{ + float elapsedSeconds = 0.0f; + float from; + float to; + float interpolate(float f) const + { + float fi = 1.0f - f; + return to * f + from * fi; + } + void copy(const InterpolatorAnimationData& source); +}; +class DataConverterInterpolator : public DataConverterInterpolatorBase +{ +protected: + KeyFrameInterpolator* m_interpolator = nullptr; + +public: + void interpolator(KeyFrameInterpolator* interpolator); + KeyFrameInterpolator* interpolator() const { return m_interpolator; }; + DataType outputType() override { return DataType::number; }; + DataValue* convert(DataValue* value, DataBind* dataBind) override; + DataValue* reverseConvert(DataValue* value, DataBind* dataBind) override; + bool advance(float elapsedTime) override; + void copy(const DataConverterInterpolatorBase& object); + void durationChanged() override; + +private: + DataValueNumber m_output; + float m_currentValue; + bool m_isFirstRun = true; + + InterpolatorAnimationData m_animationDataA; + InterpolatorAnimationData m_animationDataB; + bool m_isSmoothingAnimation = false; + InterpolatorAnimationData* currentAnimationData(); + void advanceAnimationData(float elapsedTime); + +public: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/data_bind/converters/data_converter_number_to_list.hpp b/third_party/rive/include/rive/data_bind/converters/data_converter_number_to_list.hpp new file mode 100644 index 0000000..25baba9 --- /dev/null +++ b/third_party/rive/include/rive/data_bind/converters/data_converter_number_to_list.hpp @@ -0,0 +1,33 @@ +#ifndef _RIVE_DATA_CONVERTER_NUMBER_TO_LIST_HPP_ +#define _RIVE_DATA_CONVERTER_NUMBER_TO_LIST_HPP_ +#include "rive/generated/data_bind/converters/data_converter_number_to_list_base.hpp" +#include "rive/data_bind/data_bind.hpp" +#include "rive/data_bind/data_values/data_value_list.hpp" +#include "rive/refcnt.hpp" +#include "rive/viewmodel/viewmodel.hpp" +#include "rive/viewmodel/viewmodel_instance_list_item.hpp" +#include +namespace rive +{ +class File; + +class DataConverterNumberToList : public DataConverterNumberToListBase +{ +private: + File* m_file = nullptr; + DataValueList m_output; + std::vector m_listItems; + void clearItems(); + +public: + ~DataConverterNumberToList(); + DataValue* convert(DataValue* value, DataBind* dataBind) override; + DataType outputType() override { return DataType::list; }; + void file(File*); + File* file() const; + Core* clone() const override; + void viewModelIdChanged() override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/data_bind/converters/data_converter_operation.hpp b/third_party/rive/include/rive/data_bind/converters/data_converter_operation.hpp new file mode 100644 index 0000000..8013983 --- /dev/null +++ b/third_party/rive/include/rive/data_bind/converters/data_converter_operation.hpp @@ -0,0 +1,26 @@ +#ifndef _RIVE_DATA_CONVERTER_OPERATION_HPP_ +#define _RIVE_DATA_CONVERTER_OPERATION_HPP_ +#include "rive/generated/data_bind/converters/data_converter_operation_base.hpp" +#include "rive/animation/arithmetic_operation.hpp" +#include "rive/data_bind/data_bind.hpp" +#include "rive/data_bind/data_values/data_value_number.hpp" +#include +namespace rive +{ +class DataConverterOperation : public DataConverterOperationBase +{ +public: + DataType outputType() override { return DataType::number; }; + ArithmeticOperation op() const + { + return (ArithmeticOperation)operationType(); + } + +protected: + DataValue* convertValue(DataValue* input, float value); + DataValue* reverseConvertValue(DataValue* input, float value); + DataValueNumber m_output; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/data_bind/converters/data_converter_operation_value.hpp b/third_party/rive/include/rive/data_bind/converters/data_converter_operation_value.hpp new file mode 100644 index 0000000..2805187 --- /dev/null +++ b/third_party/rive/include/rive/data_bind/converters/data_converter_operation_value.hpp @@ -0,0 +1,16 @@ +#ifndef _RIVE_DATA_CONVERTER_OPERATION_VALUE_HPP_ +#define _RIVE_DATA_CONVERTER_OPERATION_VALUE_HPP_ +#include "rive/generated/data_bind/converters/data_converter_operation_value_base.hpp" +#include +namespace rive +{ +class DataConverterOperationValue : public DataConverterOperationValueBase +{ +public: + DataValue* convert(DataValue* value, DataBind* dataBind) override; + DataValue* reverseConvert(DataValue* value, DataBind* dataBind) override; + void operationValueChanged() override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/data_bind/converters/data_converter_operation_viewmodel.hpp b/third_party/rive/include/rive/data_bind/converters/data_converter_operation_viewmodel.hpp new file mode 100644 index 0000000..7680b3f --- /dev/null +++ b/third_party/rive/include/rive/data_bind/converters/data_converter_operation_viewmodel.hpp @@ -0,0 +1,33 @@ +#ifndef _RIVE_DATA_CONVERTER_OPERATION_VIEW_MODEL_HPP_ +#define _RIVE_DATA_CONVERTER_OPERATION_VIEW_MODEL_HPP_ +#include "rive/generated/data_bind/converters/data_converter_operation_viewmodel_base.hpp" +#include "rive/data_bind/data_context.hpp" +#include "rive/viewmodel/viewmodel_instance_number.hpp" +#include +namespace rive +{ +class DataConverterOperationViewModel + : public DataConverterOperationViewModelBase +{ +private: + float resolveValue(DataBind* dataBind); + ViewModelInstanceNumber* m_source = nullptr; + +protected: + std::vector m_SourcePathIdsBuffer; + +public: + DataValue* convert(DataValue* value, DataBind* dataBind) override; + DataValue* reverseConvert(DataValue* value, DataBind* dataBind) override; + void decodeSourcePathIds(Span value) override; + void copySourcePathIds( + const DataConverterOperationViewModelBase& object) override; + const std::vector& sourcePathIds() + { + return m_SourcePathIdsBuffer; + } + void bindFromContext(DataContext* dataContext, DataBind* dataBind) override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/data_bind/converters/data_converter_range_mapper.hpp b/third_party/rive/include/rive/data_bind/converters/data_converter_range_mapper.hpp new file mode 100644 index 0000000..8583351 --- /dev/null +++ b/third_party/rive/include/rive/data_bind/converters/data_converter_range_mapper.hpp @@ -0,0 +1,42 @@ +#ifndef _RIVE_DATA_CONVERTER_RANGE_MAPPER_HPP_ +#define _RIVE_DATA_CONVERTER_RANGE_MAPPER_HPP_ +#include "rive/generated/data_bind/converters/data_converter_range_mapper_base.hpp" +#include "rive/data_bind/data_values/data_value_number.hpp" +#include "rive/data_bind/data_values/data_value.hpp" +#include "rive/animation/keyframe_interpolator.hpp" +#include +namespace rive +{ +class DataConverterRangeMapper : public DataConverterRangeMapperBase +{ +protected: + KeyFrameInterpolator* m_interpolator; + DataValueNumber* calculateRange(DataValue* input, + float minInput, + float maxInput, + float minOutput, + float maxOutput); + DataValueNumber* calculateReverseRange(DataValue* input, + float minInput, + float maxInput, + float minOutput, + float maxOutput); + +public: + void interpolator(KeyFrameInterpolator* interpolator); + KeyFrameInterpolator* interpolator() const { return m_interpolator; }; + DataType outputType() override { return DataType::number; }; + DataValue* convert(DataValue* value, DataBind* dataBind) override; + DataValue* reverseConvert(DataValue* value, DataBind* dataBind) override; + void copy(const DataConverterRangeMapperBase& object); + void minInputChanged() override; + void maxInputChanged() override; + void minOutputChanged() override; + void maxOutputChanged() override; + +private: + DataValueNumber m_output; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/data_bind/converters/data_converter_rounder.hpp b/third_party/rive/include/rive/data_bind/converters/data_converter_rounder.hpp new file mode 100644 index 0000000..f7d948f --- /dev/null +++ b/third_party/rive/include/rive/data_bind/converters/data_converter_rounder.hpp @@ -0,0 +1,21 @@ +#ifndef _RIVE_DATA_CONVERTER_ROUND_HPP_ +#define _RIVE_DATA_CONVERTER_ROUND_HPP_ +#include "rive/generated/data_bind/converters/data_converter_rounder_base.hpp" +#include "rive/data_bind/data_values/data_value.hpp" +#include "rive/data_bind/data_bind.hpp" +#include "rive/data_bind/data_values/data_value_number.hpp" +#include +namespace rive +{ +class DataConverterRounder : public DataConverterRounderBase +{ +public: + DataValue* convert(DataValue* value, DataBind* dataBind) override; + DataType outputType() override { return DataType::number; }; + +private: + DataValueNumber m_output; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/data_bind/converters/data_converter_string_pad.hpp b/third_party/rive/include/rive/data_bind/converters/data_converter_string_pad.hpp new file mode 100644 index 0000000..0d93fcc --- /dev/null +++ b/third_party/rive/include/rive/data_bind/converters/data_converter_string_pad.hpp @@ -0,0 +1,23 @@ +#ifndef _RIVE_DATA_CONVERTER_STRING_PAD_HPP_ +#define _RIVE_DATA_CONVERTER_STRING_PAD_HPP_ +#include "rive/generated/data_bind/converters/data_converter_string_pad_base.hpp" +#include "rive/data_bind/data_bind.hpp" +#include "rive/data_bind/data_values/data_value_string.hpp" +#include +namespace rive +{ +class DataConverterStringPad : public DataConverterStringPadBase +{ +public: + DataValue* convert(DataValue* value, DataBind* dataBind) override; + DataType outputType() override { return DataType::string; }; + void lengthChanged() override; + void padTypeChanged() override; + void textChanged() override; + +private: + DataValueString m_output; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/data_bind/converters/data_converter_string_remove_zeros.hpp b/third_party/rive/include/rive/data_bind/converters/data_converter_string_remove_zeros.hpp new file mode 100644 index 0000000..98c0e61 --- /dev/null +++ b/third_party/rive/include/rive/data_bind/converters/data_converter_string_remove_zeros.hpp @@ -0,0 +1,21 @@ +#ifndef _RIVE_DATA_CONVERTER_STRING_REMOVE_ZEROS_HPP_ +#define _RIVE_DATA_CONVERTER_STRING_REMOVE_ZEROS_HPP_ +#include "rive/generated/data_bind/converters/data_converter_string_remove_zeros_base.hpp" +#include "rive/data_bind/data_bind.hpp" +#include "rive/data_bind/data_values/data_value_string.hpp" +#include +namespace rive +{ +class DataConverterStringRemoveZeros : public DataConverterStringRemoveZerosBase +{ +public: + static std::string removeZeros(std::string string); + DataValue* convert(DataValue* value, DataBind* dataBind) override; + DataType outputType() override { return DataType::string; }; + +private: + DataValueString m_output; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/data_bind/converters/data_converter_string_trim.hpp b/third_party/rive/include/rive/data_bind/converters/data_converter_string_trim.hpp new file mode 100644 index 0000000..2af4221 --- /dev/null +++ b/third_party/rive/include/rive/data_bind/converters/data_converter_string_trim.hpp @@ -0,0 +1,47 @@ +#ifndef _RIVE_DATA_CONVERTER_STRING_TRIM_HPP_ +#define _RIVE_DATA_CONVERTER_STRING_TRIM_HPP_ +#include "rive/generated/data_bind/converters/data_converter_string_trim_base.hpp" +#include "rive/data_bind/data_bind.hpp" +#include "rive/data_bind/data_values/data_value_string.hpp" +#include "rive/trim_type.hpp" +#include +#include +#include +#include +namespace rive +{ +class DataConverterStringTrim : public DataConverterStringTrimBase +{ +public: + DataValue* convert(DataValue* value, DataBind* dataBind) override; + DataType outputType() override { return DataType::string; }; + TrimType trimValue() { return (TrimType)trimType(); } + void trimTypeChanged() override; + +private: + DataValueString m_output; + inline void ltrim(std::string& s) + { + s.erase(s.begin(), + std::find_if(s.begin(), s.end(), [](unsigned char ch) { + return !std::isspace(ch); + })); + } + + inline void rtrim(std::string& s) + { + s.erase(std::find_if(s.rbegin(), + s.rend(), + [](unsigned char ch) { return !std::isspace(ch); }) + .base(), + s.end()); + } + inline void trim(std::string& s) + { + rtrim(s); + ltrim(s); + } +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/data_bind/converters/data_converter_system_degs_to_rads.hpp b/third_party/rive/include/rive/data_bind/converters/data_converter_system_degs_to_rads.hpp new file mode 100644 index 0000000..78b8d30 --- /dev/null +++ b/third_party/rive/include/rive/data_bind/converters/data_converter_system_degs_to_rads.hpp @@ -0,0 +1,17 @@ +#ifndef _RIVE_DATA_CONVERTER_SYSTEM_DEGS_TO_RADS_HPP_ +#define _RIVE_DATA_CONVERTER_SYSTEM_DEGS_TO_RADS_HPP_ +#include "rive/generated/data_bind/converters/data_converter_system_degs_to_rads_base.hpp" +#include "rive/data_bind/data_values/data_value.hpp" +#include "rive/data_bind/data_bind.hpp" +#include +namespace rive +{ +class DataConverterSystemDegsToRads : public DataConverterSystemDegsToRadsBase +{ +public: + DataValue* convert(DataValue* value, DataBind* dataBind) override; + DataValue* reverseConvert(DataValue* value, DataBind* dataBind) override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/data_bind/converters/data_converter_system_normalizer.hpp b/third_party/rive/include/rive/data_bind/converters/data_converter_system_normalizer.hpp new file mode 100644 index 0000000..98a21ea --- /dev/null +++ b/third_party/rive/include/rive/data_bind/converters/data_converter_system_normalizer.hpp @@ -0,0 +1,17 @@ +#ifndef _RIVE_DATA_CONVERTER_SYSTEM_NORMALIZER_HPP_ +#define _RIVE_DATA_CONVERTER_SYSTEM_NORMALIZER_HPP_ +#include "rive/generated/data_bind/converters/data_converter_system_normalizer_base.hpp" +#include "rive/data_bind/data_values/data_value.hpp" +#include "rive/data_bind/data_bind.hpp" +#include +namespace rive +{ +class DataConverterSystemNormalizer : public DataConverterSystemNormalizerBase +{ +public: + DataValue* convert(DataValue* value, DataBind* dataBind) override; + DataValue* reverseConvert(DataValue* value, DataBind* dataBind) override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/data_bind/converters/data_converter_to_string.hpp b/third_party/rive/include/rive/data_bind/converters/data_converter_to_string.hpp new file mode 100644 index 0000000..500dca9 --- /dev/null +++ b/third_party/rive/include/rive/data_bind/converters/data_converter_to_string.hpp @@ -0,0 +1,147 @@ +#ifndef _RIVE_DATA_CONVERTER_TO_STRING_HPP_ +#define _RIVE_DATA_CONVERTER_TO_STRING_HPP_ +#include "rive/generated/data_bind/converters/data_converter_to_string_base.hpp" +#include "rive/data_bind/data_bind.hpp" +#include "rive/data_bind/data_values/data_value_number.hpp" +#include "rive/data_bind/data_values/data_value_string.hpp" +#include "rive/data_bind/data_values/data_value_color.hpp" +#include +#include +#include +namespace rive +{ + +class _ColorConverter +{ +public: + _ColorConverter() {} + void color(int value) + { + if (m_color != value) + { + m_color = value; + h = -1; + l = -1; + s = -1; + } + } + int alphaComponent() { return (m_color >> 24) & 0xFF; }; + int redComponent() { return (m_color >> 16) & 0xFF; }; + int greenComponent() { return (m_color >> 8) & 0xFF; }; + int blueComponent() { return m_color & 0xFF; }; + std::string alpha() { return std::to_string(alphaComponent()); } + std::string red() { return std::to_string(redComponent()); } + std::string green() { return std::to_string(greenComponent()); } + std::string blue() { return std::to_string(blueComponent()); } + std::string hue() + { + if (h == -1) + { + calculateHSL(); + } + return std::to_string(h); + } + std::string luminance() + { + if (l == -1) + { + calculateHSL(); + } + return std::to_string(l); + } + std::string saturation() + { + if (s == -1) + { + calculateHSL(); + } + return std::to_string(s); + } + std::string toHex(int value) + { + std::stringstream ss; + ss << std::uppercase << std::hex << value; + std::string result = ss.str(); + if (result.length() < 2) + { + result.insert(0, 2 - result.length(), '0'); + } + return result; + } + void alphaHex(std::stringstream& stream) + { + stream << toHex(alphaComponent()); + } + void redHex(std::stringstream& stream) { stream << toHex(redComponent()); } + void greenHex(std::stringstream& stream) + { + stream << toHex(greenComponent()); + } + void blueHex(std::stringstream& stream) + { + stream << toHex(blueComponent()); + } + +private: + int h = 0; + int l = 0; + int s = 0; + int m_color = 0; + void calculateHSL() + { + float r = (float)redComponent() / 255.0f; + float g = (float)greenComponent() / 255.0f; + float b = (float)blueComponent() / 255.0f; + float maxComponent = std::max(std::max(r, g), b); + float minComponent = std::min(std::min(r, g), b); + float delta = maxComponent - minComponent; + float hue = 0; + float lum = 0; + float sat = 0; + if (delta != 0.0f) + { + if (maxComponent == r) + { + hue = fmodf(((g - b) / delta), 6); + } + else if (maxComponent == g) + { + hue = (b - r) / delta + 2; + } + else + { + hue = (r - g) / delta + 4; + } + } + + h = std::round((hue * 60)); + if (h < 0) + { + h = h + 360; + } + + lum = (maxComponent + minComponent) / 2; + sat = delta == 0 ? 0 : delta / (1 - std::abs(2 * lum - 1)); + + l = std::round(lum * 100); + s = std::round(sat * 100); + } +}; + +class DataConverterToString : public DataConverterToStringBase +{ +public: + DataValue* convert(DataValue* value, DataBind* dataBind) override; + DataType outputType() override { return DataType::string; }; + void decimalsChanged() override; + void colorFormatChanged() override; + +private: + DataValue* convertNumber(DataValueNumber* value); + DataValue* convertColor(DataValueColor* value); + DataValueString m_output; + _ColorConverter m_converter; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/data_bind/converters/data_converter_trigger.hpp b/third_party/rive/include/rive/data_bind/converters/data_converter_trigger.hpp new file mode 100644 index 0000000..b1fe2b5 --- /dev/null +++ b/third_party/rive/include/rive/data_bind/converters/data_converter_trigger.hpp @@ -0,0 +1,18 @@ +#ifndef _RIVE_DATA_CONVERTER_TRIGGER_HPP_ +#define _RIVE_DATA_CONVERTER_TRIGGER_HPP_ +#include "rive/generated/data_bind/converters/data_converter_trigger_base.hpp" +#include "rive/data_bind/data_bind.hpp" +#include "rive/data_bind/data_values/data_value_trigger.hpp" +#include +namespace rive +{ +class DataConverterTrigger : public DataConverterTriggerBase +{ +public: + DataValue* convert(DataValue* value, DataBind* dataBind) override; + DataType outputType() override { return DataType::trigger; }; + DataValueTrigger m_output; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/data_bind/converters/formula/formula_token.hpp b/third_party/rive/include/rive/data_bind/converters/formula/formula_token.hpp new file mode 100644 index 0000000..b648eb8 --- /dev/null +++ b/third_party/rive/include/rive/data_bind/converters/formula/formula_token.hpp @@ -0,0 +1,30 @@ +#ifndef _RIVE_FORMULA_TOKEN_HPP_ +#define _RIVE_FORMULA_TOKEN_HPP_ +#include "rive/generated/data_bind/converters/formula/formula_token_base.hpp" +#include "rive/data_bind/data_values/data_value.hpp" +#include "rive/data_bind/data_context.hpp" +#include "rive/data_bind/data_bind.hpp" +#include +namespace rive +{ +class FormulaToken : public FormulaTokenBase +{ +public: + ~FormulaToken(); + StatusCode import(ImportStack& importStack) override; + + virtual void bindFromContext(DataContext* dataContext, DataBind* dataBind); + virtual void unbind(); + virtual void update(); + void markDirty(); + void addDataBind(DataBind* dataBind); + void copy(const FormulaTokenBase& object); + std::vector dataBinds() const { return m_dataBinds; } + +private: + std::vector m_dataBinds; + DataBind* m_parentDataBind; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/data_bind/converters/formula/formula_token_argument_separator.hpp b/third_party/rive/include/rive/data_bind/converters/formula/formula_token_argument_separator.hpp new file mode 100644 index 0000000..9e662f7 --- /dev/null +++ b/third_party/rive/include/rive/data_bind/converters/formula/formula_token_argument_separator.hpp @@ -0,0 +1,13 @@ +#ifndef _RIVE_FORMULA_TOKEN_ARGUMENT_SEPARATOR_HPP_ +#define _RIVE_FORMULA_TOKEN_ARGUMENT_SEPARATOR_HPP_ +#include "rive/generated/data_bind/converters/formula/formula_token_argument_separator_base.hpp" +#include +namespace rive +{ +class FormulaTokenArgumentSeparator : public FormulaTokenArgumentSeparatorBase +{ +public: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/data_bind/converters/formula/formula_token_function.hpp b/third_party/rive/include/rive/data_bind/converters/formula/formula_token_function.hpp new file mode 100644 index 0000000..f4b0466 --- /dev/null +++ b/third_party/rive/include/rive/data_bind/converters/formula/formula_token_function.hpp @@ -0,0 +1,13 @@ +#ifndef _RIVE_FORMULA_TOKEN_FUNCTION_HPP_ +#define _RIVE_FORMULA_TOKEN_FUNCTION_HPP_ +#include "rive/generated/data_bind/converters/formula/formula_token_function_base.hpp" +#include +namespace rive +{ +class FormulaTokenFunction : public FormulaTokenFunctionBase +{ +public: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/data_bind/converters/formula/formula_token_input.hpp b/third_party/rive/include/rive/data_bind/converters/formula/formula_token_input.hpp new file mode 100644 index 0000000..d6c4d0c --- /dev/null +++ b/third_party/rive/include/rive/data_bind/converters/formula/formula_token_input.hpp @@ -0,0 +1,13 @@ +#ifndef _RIVE_FORMULA_TOKEN_INPUT_HPP_ +#define _RIVE_FORMULA_TOKEN_INPUT_HPP_ +#include "rive/generated/data_bind/converters/formula/formula_token_input_base.hpp" +#include +namespace rive +{ +class FormulaTokenInput : public FormulaTokenInputBase +{ +public: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/data_bind/converters/formula/formula_token_operation.hpp b/third_party/rive/include/rive/data_bind/converters/formula/formula_token_operation.hpp new file mode 100644 index 0000000..14db335 --- /dev/null +++ b/third_party/rive/include/rive/data_bind/converters/formula/formula_token_operation.hpp @@ -0,0 +1,13 @@ +#ifndef _RIVE_FORMULA_TOKEN_OPERATION_HPP_ +#define _RIVE_FORMULA_TOKEN_OPERATION_HPP_ +#include "rive/generated/data_bind/converters/formula/formula_token_operation_base.hpp" +#include +namespace rive +{ +class FormulaTokenOperation : public FormulaTokenOperationBase +{ +public: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/data_bind/converters/formula/formula_token_parenthesis.hpp b/third_party/rive/include/rive/data_bind/converters/formula/formula_token_parenthesis.hpp new file mode 100644 index 0000000..87effde --- /dev/null +++ b/third_party/rive/include/rive/data_bind/converters/formula/formula_token_parenthesis.hpp @@ -0,0 +1,13 @@ +#ifndef _RIVE_FORMULA_TOKEN_PARENTHESIS_HPP_ +#define _RIVE_FORMULA_TOKEN_PARENTHESIS_HPP_ +#include "rive/generated/data_bind/converters/formula/formula_token_parenthesis_base.hpp" +#include +namespace rive +{ +class FormulaTokenParenthesis : public FormulaTokenParenthesisBase +{ +public: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/data_bind/converters/formula/formula_token_parenthesis_close.hpp b/third_party/rive/include/rive/data_bind/converters/formula/formula_token_parenthesis_close.hpp new file mode 100644 index 0000000..94cf250 --- /dev/null +++ b/third_party/rive/include/rive/data_bind/converters/formula/formula_token_parenthesis_close.hpp @@ -0,0 +1,13 @@ +#ifndef _RIVE_FORMULA_TOKEN_PARENTHESIS_CLOSE_HPP_ +#define _RIVE_FORMULA_TOKEN_PARENTHESIS_CLOSE_HPP_ +#include "rive/generated/data_bind/converters/formula/formula_token_parenthesis_close_base.hpp" +#include +namespace rive +{ +class FormulaTokenParenthesisClose : public FormulaTokenParenthesisCloseBase +{ +public: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/data_bind/converters/formula/formula_token_parenthesis_open.hpp b/third_party/rive/include/rive/data_bind/converters/formula/formula_token_parenthesis_open.hpp new file mode 100644 index 0000000..a30ad28 --- /dev/null +++ b/third_party/rive/include/rive/data_bind/converters/formula/formula_token_parenthesis_open.hpp @@ -0,0 +1,13 @@ +#ifndef _RIVE_FORMULA_TOKEN_PARENTHESIS_OPEN_HPP_ +#define _RIVE_FORMULA_TOKEN_PARENTHESIS_OPEN_HPP_ +#include "rive/generated/data_bind/converters/formula/formula_token_parenthesis_open_base.hpp" +#include +namespace rive +{ +class FormulaTokenParenthesisOpen : public FormulaTokenParenthesisOpenBase +{ +public: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/data_bind/converters/formula/formula_token_value.hpp b/third_party/rive/include/rive/data_bind/converters/formula/formula_token_value.hpp new file mode 100644 index 0000000..d96aef3 --- /dev/null +++ b/third_party/rive/include/rive/data_bind/converters/formula/formula_token_value.hpp @@ -0,0 +1,13 @@ +#ifndef _RIVE_FORMULA_TOKEN_VALUE_HPP_ +#define _RIVE_FORMULA_TOKEN_VALUE_HPP_ +#include "rive/generated/data_bind/converters/formula/formula_token_value_base.hpp" +#include +namespace rive +{ +class FormulaTokenValue : public FormulaTokenValueBase +{ +public: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/data_bind/data_bind.hpp b/third_party/rive/include/rive/data_bind/data_bind.hpp new file mode 100644 index 0000000..f2049f8 --- /dev/null +++ b/third_party/rive/include/rive/data_bind/data_bind.hpp @@ -0,0 +1,64 @@ +#ifndef _RIVE_DATA_BIND_HPP_ +#define _RIVE_DATA_BIND_HPP_ +#include "rive/component_dirt.hpp" +#include "rive/generated/data_bind/data_bind_base.hpp" +#include "rive/viewmodel/viewmodel_instance_value.hpp" +#include "rive/data_bind/data_context.hpp" +#include "rive/data_bind/converters/data_converter.hpp" +#include "rive/data_bind/data_values/data_type.hpp" +#include "rive/dirtyable.hpp" +#include +namespace rive +{ +class File; +class DataBindContextValue; +#ifdef WITH_RIVE_TOOLS +class DataBind; +typedef void (*DataBindChanged)(); +#endif +class DataBind : public DataBindBase, public Dirtyable +{ +public: + ~DataBind(); + StatusCode onAddedDirty(CoreContext* context) override; + StatusCode import(ImportStack& importStack) override; + virtual void updateSourceBinding(bool invalidate = false); + virtual void update(ComponentDirt value); + Core* target() const { return m_target; }; + void target(Core* value) { m_target = value; }; + virtual void bind(); + virtual void unbind(); + ComponentDirt dirt() { return m_Dirt; }; + void dirt(ComponentDirt value) { m_Dirt = value; }; + void addDirt(ComponentDirt value, bool recurse) override; + DataConverter* converter() const { return m_dataConverter; }; + void converter(DataConverter* value) { m_dataConverter = value; }; + ViewModelInstanceValue* source() const { return m_Source; }; + void source(ViewModelInstanceValue* value); + void clearSource(); + bool toSource(); + bool toTarget(); + bool advance(float elapsedTime); + void suppressDirt(bool value) { m_suppressDirt = value; }; + void file(File* value) { m_file = value; }; + File* file() const { return m_file; }; + +protected: + ComponentDirt m_Dirt = ComponentDirt::Filthy; + Core* m_target = nullptr; + ViewModelInstanceValue* m_Source = nullptr; + DataBindContextValue* m_ContextValue = nullptr; + DataConverter* m_dataConverter = nullptr; + DataType outputType(); + bool bindsOnce(); + bool m_suppressDirt = false; + File* m_file; +#ifdef WITH_RIVE_TOOLS +public: + void onChanged(DataBindChanged callback) { m_changedCallback = callback; } + DataBindChanged m_changedCallback = nullptr; +#endif +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/data_bind/data_bind_context.hpp b/third_party/rive/include/rive/data_bind/data_bind_context.hpp new file mode 100644 index 0000000..45b069e --- /dev/null +++ b/third_party/rive/include/rive/data_bind/data_bind_context.hpp @@ -0,0 +1,23 @@ +#ifndef _RIVE_DATA_BIND_CONTEXT_HPP_ +#define _RIVE_DATA_BIND_CONTEXT_HPP_ +#include "rive/generated/data_bind/data_bind_context_base.hpp" +#include "rive/viewmodel/viewmodel_instance_value.hpp" +#include "rive/data_bind/context/context_value.hpp" +#include "rive/data_bind/data_context.hpp" +#include "rive/refcnt.hpp" +#include +namespace rive +{ +class DataBindContext : public DataBindContextBase +{ +protected: + std::vector m_SourcePathIdsBuffer; + +public: + void decodeSourcePathIds(Span value) override; + void copySourcePathIds(const DataBindContextBase& object) override; + void bindFromContext(DataContext* dataContext); +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/data_bind/data_bind_list_item_consumer.hpp b/third_party/rive/include/rive/data_bind/data_bind_list_item_consumer.hpp new file mode 100644 index 0000000..a1d576b --- /dev/null +++ b/third_party/rive/include/rive/data_bind/data_bind_list_item_consumer.hpp @@ -0,0 +1,17 @@ +#ifndef _RIVE_DATA_BIND_LIST_ITEM_PROVIDER_HPP_ +#define _RIVE_DATA_BIND_LIST_ITEM_PROVIDER_HPP_ +namespace rive +{ +class ViewModelInstanceListItem; + +class DataBindListItemConsumer +{ +public: + static DataBindListItemConsumer* from(Core* component); + + virtual void updateList(int propertyKey, + std::vector* list) = 0; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/data_bind/data_context.hpp b/third_party/rive/include/rive/data_bind/data_context.hpp new file mode 100644 index 0000000..9329bb7 --- /dev/null +++ b/third_party/rive/include/rive/data_bind/data_context.hpp @@ -0,0 +1,38 @@ +#ifndef _RIVE_DATA_CONTEXT_HPP_ +#define _RIVE_DATA_CONTEXT_HPP_ +#include "rive/viewmodel/viewmodel_instance_value.hpp" +#include "rive/viewmodel/viewmodel_instance.hpp" +#include "rive/refcnt.hpp" + +namespace rive +{ +class DataContext +{ +private: + DataContext* m_Parent = nullptr; + rcp m_ViewModelInstance; + +public: + DataContext(rcp viewModelInstance); + + DataContext* parent() { return m_Parent; } + void parent(DataContext* value) { m_Parent = value; } + ViewModelInstanceValue* getViewModelProperty( + const std::vector path) const; + rcp getViewModelInstance( + const std::vector path) const; + void viewModelInstance(rcp value); + void advanced(); + rcp viewModelInstance() { return m_ViewModelInstance; }; + + ViewModelInstanceValue* viewModelValue() + { + if (m_Parent) + { + return m_Parent->viewModelValue(); + } + return nullptr; + } +}; +} // namespace rive +#endif diff --git a/third_party/rive/include/rive/data_bind/data_values/data_type.hpp b/third_party/rive/include/rive/data_bind/data_values/data_type.hpp new file mode 100644 index 0000000..d24b6a1 --- /dev/null +++ b/third_party/rive/include/rive/data_bind/data_values/data_type.hpp @@ -0,0 +1,45 @@ +#ifndef _RIVE_DATA_TYPE_HPP_ +#define _RIVE_DATA_TYPE_HPP_ +namespace rive +{ +/// Data types used for converters. +enum class DataType : unsigned int +{ + /// None. + none = 0, + + /// String. + string = 1, + + /// Number. + number = 2, + + /// Bool. + boolean = 3, + + /// Color. + color = 4, + + /// List. + list = 5, + + /// Enum. + enumType = 6, + + /// Trigger. + trigger = 7, + + /// View Model. + viewModel = 8, + + /// Integer. + integer = 9, + + /// Symbol list index. + symbolListIndex = 10, + + /// Asset Image. + assetImage = 11 +}; +} // namespace rive +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/data_bind/data_values/data_value.hpp b/third_party/rive/include/rive/data_bind/data_values/data_value.hpp new file mode 100644 index 0000000..2023286 --- /dev/null +++ b/third_party/rive/include/rive/data_bind/data_values/data_value.hpp @@ -0,0 +1,25 @@ +#ifndef _RIVE_DATA_VALUE_HPP_ +#define _RIVE_DATA_VALUE_HPP_ +#include "rive/data_bind/data_values/data_type.hpp" + +#include +namespace rive +{ +class DataValue +{ +public: + virtual ~DataValue(){}; + virtual bool isTypeOf(DataType dataType) const { return false; } + template inline bool is() const + { + return isTypeOf(T::typeKey); + } + template inline T* as() + { + assert(is()); + return static_cast(this); + } +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/data_bind/data_values/data_value_asset_image.hpp b/third_party/rive/include/rive/data_bind/data_values/data_value_asset_image.hpp new file mode 100644 index 0000000..62b5090 --- /dev/null +++ b/third_party/rive/include/rive/data_bind/data_values/data_value_asset_image.hpp @@ -0,0 +1,26 @@ +#ifndef _RIVE_DATA_VALUE_ASSET_IMAGE_HPP_ +#define _RIVE_DATA_VALUE_ASSET_IMAGE_HPP_ +#include "rive/data_bind/data_values/data_value.hpp" + +#include +namespace rive +{ +class DataValueAssetImage : public DataValue +{ +private: + uint32_t m_value = -1; + +public: + DataValueAssetImage(uint32_t value) : m_value(value){}; + DataValueAssetImage(){}; + static const DataType typeKey = DataType::assetImage; + bool isTypeOf(DataType typeKey) const override + { + return typeKey == DataType::assetImage; + }; + uint32_t value() { return m_value; }; + void value(uint32_t value) { m_value = value; }; + constexpr static uint32_t defaultValue = -1; +}; +} // namespace rive +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/data_bind/data_values/data_value_boolean.hpp b/third_party/rive/include/rive/data_bind/data_values/data_value_boolean.hpp new file mode 100644 index 0000000..ba42e79 --- /dev/null +++ b/third_party/rive/include/rive/data_bind/data_values/data_value_boolean.hpp @@ -0,0 +1,27 @@ +#ifndef _RIVE_DATA_VALUE_BOOLEAN_HPP_ +#define _RIVE_DATA_VALUE_BOOLEAN_HPP_ +#include "rive/data_bind/data_values/data_value.hpp" + +#include +namespace rive +{ +class DataValueBoolean : public DataValue +{ +private: + bool m_value = false; + +public: + DataValueBoolean(bool value) : m_value(value){}; + DataValueBoolean(){}; + static const DataType typeKey = DataType::boolean; + bool isTypeOf(DataType typeKey) const override + { + return typeKey == DataType::boolean; + } + bool value() { return m_value; }; + void value(bool value) { m_value = value; }; + static const bool defaultValue = false; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/data_bind/data_values/data_value_color.hpp b/third_party/rive/include/rive/data_bind/data_values/data_value_color.hpp new file mode 100644 index 0000000..a809675 --- /dev/null +++ b/third_party/rive/include/rive/data_bind/data_values/data_value_color.hpp @@ -0,0 +1,27 @@ +#ifndef _RIVE_DATA_VALUE_COLOR_HPP_ +#define _RIVE_DATA_VALUE_COLOR_HPP_ +#include "rive/data_bind/data_values/data_value.hpp" + +#include +namespace rive +{ +class DataValueColor : public DataValue +{ +private: + int m_value = 0; + +public: + DataValueColor(int value) : m_value(value){}; + DataValueColor(){}; + static const DataType typeKey = DataType::color; + bool isTypeOf(DataType typeKey) const override + { + return typeKey == DataType::color; + } + int value() { return m_value; }; + void value(int value) { m_value = value; }; + static const int defaultValue = 0; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/data_bind/data_values/data_value_enum.hpp b/third_party/rive/include/rive/data_bind/data_values/data_value_enum.hpp new file mode 100644 index 0000000..d7b172e --- /dev/null +++ b/third_party/rive/include/rive/data_bind/data_values/data_value_enum.hpp @@ -0,0 +1,31 @@ +#ifndef _RIVE_DATA_VALUE_ENUM_HPP_ +#define _RIVE_DATA_VALUE_ENUM_HPP_ +#include "rive/data_bind/data_values/data_value.hpp" +#include "rive/viewmodel/data_enum.hpp" + +#include +namespace rive +{ +class DataValueEnum : public DataValue +{ +private: + uint32_t m_value = 0; + DataEnum* m_dataEnum; + +public: + DataValueEnum(uint32_t value, DataEnum* dataEnum) : + m_value(value), m_dataEnum(dataEnum){}; + DataValueEnum(){}; + static const DataType typeKey = DataType::enumType; + bool isTypeOf(DataType typeKey) const override + { + return typeKey == DataType::enumType; + }; + uint32_t value() { return m_value; }; + void value(uint32_t value) { m_value = value; }; + DataEnum* dataEnum() { return m_dataEnum; }; + void dataEnum(DataEnum* value) { m_dataEnum = value; }; + static const uint32_t defaultValue = 0; +}; +} // namespace rive +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/data_bind/data_values/data_value_integer.hpp b/third_party/rive/include/rive/data_bind/data_values/data_value_integer.hpp new file mode 100644 index 0000000..4e71ddf --- /dev/null +++ b/third_party/rive/include/rive/data_bind/data_values/data_value_integer.hpp @@ -0,0 +1,27 @@ +#ifndef _RIVE_DATA_VALUE_INTEGER_HPP_ +#define _RIVE_DATA_VALUE_INTEGER_HPP_ +#include "rive/data_bind/data_values/data_value.hpp" + +#include +namespace rive +{ +class DataValueInteger : public DataValue +{ +private: + uint32_t m_value = 0; + +public: + DataValueInteger(uint32_t value) : m_value(value){}; + DataValueInteger(){}; + static const DataType typeKey = DataType::trigger; + bool isTypeOf(DataType typeKey) const override + { + return typeKey == DataType::trigger; + } + uint32_t value() { return m_value; }; + void value(uint32_t value) { m_value = value; }; + constexpr static const uint32_t defaultValue = 0; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/data_bind/data_values/data_value_list.hpp b/third_party/rive/include/rive/data_bind/data_values/data_value_list.hpp new file mode 100644 index 0000000..b10068d --- /dev/null +++ b/third_party/rive/include/rive/data_bind/data_values/data_value_list.hpp @@ -0,0 +1,32 @@ +#ifndef _RIVE_DATA_VALUE_LIST_HPP_ +#define _RIVE_DATA_VALUE_LIST_HPP_ +#include "rive/data_bind/data_values/data_value.hpp" +#include "rive/viewmodel/viewmodel_instance_list.hpp" +#include "rive/viewmodel/viewmodel_instance_list_item.hpp" + +#include +namespace rive +{ +class DataValueList : public DataValue +{ +private: + std::vector m_value; + +public: + DataValueList(){}; + static const DataType typeKey = DataType::list; + bool isTypeOf(DataType typeKey) const override + { + return typeKey == DataType::list; + } + std::vector* value() { return &m_value; }; + void clear() { m_value.clear(); }; + void addItem(ViewModelInstanceListItem* item) { m_value.push_back(item); }; + // void value(std::vector* value) { m_value = + // value; }; + constexpr static std::vector* defaultValue = + nullptr; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/data_bind/data_values/data_value_number.hpp b/third_party/rive/include/rive/data_bind/data_values/data_value_number.hpp new file mode 100644 index 0000000..85e8f7c --- /dev/null +++ b/third_party/rive/include/rive/data_bind/data_values/data_value_number.hpp @@ -0,0 +1,27 @@ +#ifndef _RIVE_DATA_VALUE_NUMBER_HPP_ +#define _RIVE_DATA_VALUE_NUMBER_HPP_ +#include "rive/data_bind/data_values/data_value.hpp" + +#include +namespace rive +{ +class DataValueNumber : public DataValue +{ +private: + float m_value = 0; + +public: + DataValueNumber(float value) : m_value(value){}; + DataValueNumber(){}; + static const DataType typeKey = DataType::number; + bool isTypeOf(DataType typeKey) const override + { + return typeKey == DataType::number; + } + float value() { return m_value; }; + void value(float value) { m_value = value; }; + constexpr static const float defaultValue = 0; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/data_bind/data_values/data_value_string.hpp b/third_party/rive/include/rive/data_bind/data_values/data_value_string.hpp new file mode 100644 index 0000000..e572511 --- /dev/null +++ b/third_party/rive/include/rive/data_bind/data_values/data_value_string.hpp @@ -0,0 +1,26 @@ +#ifndef _RIVE_DATA_VALUE_STRING_HPP_ +#define _RIVE_DATA_VALUE_STRING_HPP_ +#include "rive/data_bind/data_values/data_value.hpp" + +#include +namespace rive +{ +class DataValueString : public DataValue +{ +private: + std::string m_value = ""; + +public: + DataValueString(std::string value) : m_value(value){}; + DataValueString(){}; + static const DataType typeKey = DataType::string; + bool isTypeOf(DataType typeKey) const override + { + return typeKey == DataType::string; + }; + std::string value() { return m_value; }; + void value(std::string value) { m_value = value; }; + constexpr static const char* defaultValue = ""; +}; +} // namespace rive +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/data_bind/data_values/data_value_symbol_list_index.hpp b/third_party/rive/include/rive/data_bind/data_values/data_value_symbol_list_index.hpp new file mode 100644 index 0000000..a08d24a --- /dev/null +++ b/third_party/rive/include/rive/data_bind/data_values/data_value_symbol_list_index.hpp @@ -0,0 +1,22 @@ +#ifndef _RIVE_DATA_VALUE_SYMBOL_LIST_INDEX_HPP_ +#define _RIVE_DATA_VALUE_SYMBOL_LIST_INDEX_HPP_ +#include "rive/data_bind/data_values/data_value_integer.hpp" + +#include +namespace rive +{ +class DataValueSymbolListIndex : public DataValueInteger +{ + +public: + DataValueSymbolListIndex(uint32_t value) : DataValueInteger(value){}; + DataValueSymbolListIndex(){}; + static const DataType typeKey = DataType::symbolListIndex; + bool isTypeOf(DataType typeKey) const override + { + return typeKey == DataType::symbolListIndex; + } +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/data_bind/data_values/data_value_trigger.hpp b/third_party/rive/include/rive/data_bind/data_values/data_value_trigger.hpp new file mode 100644 index 0000000..f7424c0 --- /dev/null +++ b/third_party/rive/include/rive/data_bind/data_values/data_value_trigger.hpp @@ -0,0 +1,22 @@ +#ifndef _RIVE_DATA_VALUE_TRIGGER_HPP_ +#define _RIVE_DATA_VALUE_TRIGGER_HPP_ +#include "rive/data_bind/data_values/data_value_integer.hpp" + +#include +namespace rive +{ +class DataValueTrigger : public DataValueInteger +{ + +public: + DataValueTrigger(uint32_t value) : DataValueInteger(value){}; + DataValueTrigger(){}; + static const DataType typeKey = DataType::trigger; + bool isTypeOf(DataType typeKey) const override + { + return typeKey == DataType::trigger; + } +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/data_bind_flags.hpp b/third_party/rive/include/rive/data_bind_flags.hpp new file mode 100644 index 0000000..2d8561f --- /dev/null +++ b/third_party/rive/include/rive/data_bind_flags.hpp @@ -0,0 +1,29 @@ +#ifndef _RIVE_DATA_BIND_FLAGS_HPP_ +#define _RIVE_DATA_BIND_FLAGS_HPP_ + +#include "rive/enum_bitset.hpp" + +namespace rive +{ +enum class DataBindFlags : unsigned short +{ + /// Whether the main binding direction is to source (0) or to target (1) + Direction = 1 << 0, + + /// Whether the binding direction is twoWay + TwoWay = 1 << 1, + + /// Whether the binding happens only once + Once = 1 << 2, + + /// Flag if set to target + ToTarget = 0, + + /// Flag if set to source + ToSource = 1 << 0, + +}; + +RIVE_MAKE_ENUM_BITSET(DataBindFlags) +} // namespace rive +#endif diff --git a/third_party/rive/include/rive/dependency_helper.hpp b/third_party/rive/include/rive/dependency_helper.hpp new file mode 100644 index 0000000..af1c9a0 --- /dev/null +++ b/third_party/rive/include/rive/dependency_helper.hpp @@ -0,0 +1,56 @@ +#ifndef _RIVE_DEPENDENCY_HELPER_HPP_ +#define _RIVE_DEPENDENCY_HELPER_HPP_ + +#include "rive/component_dirt.hpp" + +namespace rive +{ +class Component; +// class DependencyRoot +// { +// public: +// virtual void onComponentDirty(Component* component) {}; +// }; + +template class DependencyHelper +{ + std::vector m_Dependents; + T* m_dependecyRoot; + +public: + void dependecyRoot(T* value) { m_dependecyRoot = value; } + DependencyHelper(T* value) : m_dependecyRoot(value) {} + DependencyHelper() {} + void addDependent(U* component) + { + // Make it's not already a dependent. + if (std::find(m_Dependents.begin(), m_Dependents.end(), component) != + m_Dependents.end()) + { + return; + } + m_Dependents.push_back(component); + } + void removeDependent(U* component) + { + m_Dependents.erase( + std::remove(m_Dependents.begin(), m_Dependents.end(), component), + m_Dependents.end()); + } + void addDirt(ComponentDirt value) + { + for (auto d : m_Dependents) + { + d->addDirt(value, true); + } + } + + void onComponentDirty(U* component) + { + m_dependecyRoot->onComponentDirty(component); + } + + const std::vector& dependents() const { return m_Dependents; } +}; +} // namespace rive +#endif diff --git a/third_party/rive/include/rive/dependency_sorter.hpp b/third_party/rive/include/rive/dependency_sorter.hpp new file mode 100644 index 0000000..17ac825 --- /dev/null +++ b/third_party/rive/include/rive/dependency_sorter.hpp @@ -0,0 +1,23 @@ +#ifndef _RIVE_DEPENDENCYSORTER_HPP_ +#define _RIVE_DEPENDENCYSORTER_HPP_ + +#include +#include + +namespace rive +{ +class Component; +class DependencySorter +{ +private: + std::unordered_set m_Perm; + std::unordered_set m_Temp; + +public: + void sort(Component* root, std::vector& order); + void sort(std::vector roots, std::vector& order); + bool visit(Component* component, std::vector& order); +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/dirtyable.hpp b/third_party/rive/include/rive/dirtyable.hpp new file mode 100644 index 0000000..d603a13 --- /dev/null +++ b/third_party/rive/include/rive/dirtyable.hpp @@ -0,0 +1,16 @@ +#ifndef _RIVE_DIRTYABLE_HPP_ +#define _RIVE_DIRTYABLE_HPP_ + +#include "rive/component_dirt.hpp" + +namespace rive +{ + +class Dirtyable +{ + +public: + virtual void addDirt(ComponentDirt value, bool recurse) = 0; +}; +} // namespace rive +#endif diff --git a/third_party/rive/include/rive/draw_rules.hpp b/third_party/rive/include/rive/draw_rules.hpp new file mode 100644 index 0000000..7ff58e5 --- /dev/null +++ b/third_party/rive/include/rive/draw_rules.hpp @@ -0,0 +1,24 @@ +#ifndef _RIVE_DRAW_RULES_HPP_ +#define _RIVE_DRAW_RULES_HPP_ +#include "rive/generated/draw_rules_base.hpp" +#include +namespace rive +{ +class DrawTarget; +class DrawRules : public DrawRulesBase +{ +private: + DrawTarget* m_ActiveTarget = nullptr; + +public: + DrawTarget* activeTarget() const { return m_ActiveTarget; } + + StatusCode onAddedDirty(CoreContext* context) override; + StatusCode onAddedClean(CoreContext* context) override; + +protected: + void drawTargetIdChanged() override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/draw_target.hpp b/third_party/rive/include/rive/draw_target.hpp new file mode 100644 index 0000000..e7d6fed --- /dev/null +++ b/third_party/rive/include/rive/draw_target.hpp @@ -0,0 +1,38 @@ +#ifndef _RIVE_DRAW_TARGET_HPP_ +#define _RIVE_DRAW_TARGET_HPP_ + +#include "rive/draw_target_placement.hpp" +#include "rive/generated/draw_target_base.hpp" +#include + +namespace rive +{ +class Drawable; +class Artboard; +class DrawTarget : public DrawTargetBase +{ + friend class Artboard; + +private: + Drawable* m_Drawable = nullptr; + + // Controlled by the artboard. + Drawable* first = nullptr; + Drawable* last = nullptr; + +public: + Drawable* drawable() const { return m_Drawable; } + StatusCode onAddedDirty(CoreContext* context) override; + StatusCode onAddedClean(CoreContext* context) override; + + DrawTargetPlacement placement() const + { + return (DrawTargetPlacement)placementValue(); + } + +protected: + void placementValueChanged() override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/draw_target_placement.hpp b/third_party/rive/include/rive/draw_target_placement.hpp new file mode 100644 index 0000000..b2e45cd --- /dev/null +++ b/third_party/rive/include/rive/draw_target_placement.hpp @@ -0,0 +1,11 @@ +#ifndef _RIVE_DRAW_TARGET_PLACEMENT_HPP_ +#define _RIVE_DRAW_TARGET_PLACEMENT_HPP_ +namespace rive +{ +enum class DrawTargetPlacement : unsigned char +{ + before = 0, + after = 1 +}; +} +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/drawable.hpp b/third_party/rive/include/rive/drawable.hpp new file mode 100644 index 0000000..5c421ee --- /dev/null +++ b/third_party/rive/include/rive/drawable.hpp @@ -0,0 +1,97 @@ +#ifndef _RIVE_DRAWABLE_HPP_ +#define _RIVE_DRAWABLE_HPP_ +#include "rive/generated/drawable_base.hpp" +#include "rive/hit_info.hpp" +#include "rive/renderer.hpp" +#include "rive/clip_result.hpp" +#include "rive/drawable_flag.hpp" +#include + +namespace rive +{ +class ClippingShape; +class Artboard; +class DrawRules; +class LayoutComponent; + +class Drawable : public DrawableBase +{ + friend class Artboard; + friend class StateMachineInstance; + +private: + std::vector m_ClippingShapes; + + /// Used exclusively by the artboard; + DrawRules* flattenedDrawRules = nullptr; + Drawable* prev = nullptr; + Drawable* next = nullptr; + +public: + BlendMode blendMode() const { return (BlendMode)blendModeValue(); } + ClipResult applyClip(Renderer* renderer) const; + virtual void draw(Renderer* renderer) = 0; + virtual Core* hitTest(HitInfo*, const Mat2D&) = 0; + void addClippingShape(ClippingShape* shape); + inline const std::vector& clippingShapes() const + { + return m_ClippingShapes; + } + + virtual bool isHidden() const + { + return (static_cast(drawableFlags()) & + DrawableFlag::Hidden) == DrawableFlag::Hidden || + hasDirt(ComponentDirt::Collapsed); + } + + inline bool isTargetOpaque() const + { + return (static_cast(drawableFlags()) & + DrawableFlag::Opaque) == DrawableFlag::Opaque; + } + + virtual bool isProxy() { return false; } + + bool isChildOfLayout(LayoutComponent* layout); + + StatusCode onAddedDirty(CoreContext* context) override; + + virtual Drawable* hittableComponent() { return this; } +}; + +class ProxyDrawing +{ +public: + virtual void drawProxy(Renderer* renderer) = 0; + virtual bool isProxyHidden() = 0; +}; + +class DrawableProxy : public Drawable +{ +private: + ProxyDrawing* m_proxyDrawing; + +public: + DrawableProxy(ProxyDrawing* proxy) : m_proxyDrawing(proxy) {} + + void draw(Renderer* renderer) override + { + m_proxyDrawing->drawProxy(renderer); + } + + bool isHidden() const override { return m_proxyDrawing->isProxyHidden(); } + + Drawable* hittableComponent() override; + + bool isTargetOpaque(); + + Core* hitTest(HitInfo*, const Mat2D&) override { return nullptr; } + + bool isProxy() override { return true; } + + ProxyDrawing* proxyDrawing() const { return m_proxyDrawing; } +}; +} // namespace rive + +#endif diff --git a/third_party/rive/include/rive/drawable_flag.hpp b/third_party/rive/include/rive/drawable_flag.hpp new file mode 100644 index 0000000..fac31ad --- /dev/null +++ b/third_party/rive/include/rive/drawable_flag.hpp @@ -0,0 +1,31 @@ +#ifndef _RIVE_DRAWABLE_FLAGS_HPP_ +#define _RIVE_DRAWABLE_FLAGS_HPP_ + +#include "rive/enum_bitset.hpp" + +namespace rive +{ +enum class DrawableFlag : unsigned short +{ + None = 0, + + /// Whether the component should be drawn + Hidden = 1 << 0, + + /// Editor only + Locked = 1 << 1, + + /// Editor only + Disconnected = 1 << 2, + + /// Whether this Component lets hit events pass through to components behind + /// it + Opaque = 1 << 3, + + /// Whether the computed world bounds for a shape need to be recalculated + /// Using Clean instead of dirty so it doesn't need to be initialized to 1 + WorldBoundsClean = 1 << 4, +}; +RIVE_MAKE_ENUM_BITSET(DrawableFlag) +} // namespace rive +#endif diff --git a/third_party/rive/include/rive/enum_bitset.hpp b/third_party/rive/include/rive/enum_bitset.hpp new file mode 100644 index 0000000..0d78c38 --- /dev/null +++ b/third_party/rive/include/rive/enum_bitset.hpp @@ -0,0 +1,129 @@ +/* + * Copyright 2023 Rive + */ + +#ifndef _RIVE_ENUM_BITSET_HPP_ +#define _RIVE_ENUM_BITSET_HPP_ + +#include + +namespace rive +{ +// Wraps an enum containing a bitfield so that we can do implicit bool +// conversions. +template class EnumBitset +{ +public: + using UnderlyingType = typename std::underlying_type::type; + constexpr EnumBitset() = default; + constexpr EnumBitset(T value) : m_bits(static_cast(value)) + {} + constexpr UnderlyingType bits() const { return m_bits; } + constexpr T value() const { return static_cast(m_bits); } + constexpr operator T() const { return value(); } + constexpr operator bool() const { return m_bits != 0; } + +private: + UnderlyingType m_bits = 0; +}; +} // namespace rive + +#define RIVE_MAKE_ENUM_BITSET(ENUM) \ + constexpr inline ::rive::EnumBitset operator&( \ + ::rive::EnumBitset lhs, \ + ::rive::EnumBitset rhs) \ + { \ + return static_cast(lhs.bits() & rhs.bits()); \ + } \ + constexpr inline ::rive::EnumBitset operator&( \ + ENUM lhs, \ + ::rive::EnumBitset rhs) \ + { \ + return ::rive::EnumBitset(lhs) & rhs; \ + } \ + constexpr inline ::rive::EnumBitset operator&( \ + ::rive::EnumBitset lhs, \ + ENUM rhs) \ + { \ + return lhs & ::rive::EnumBitset(rhs); \ + } \ + constexpr inline ::rive::EnumBitset operator&(ENUM lhs, ENUM rhs) \ + { \ + return ::rive::EnumBitset(lhs) & ::rive::EnumBitset(rhs); \ + } \ + \ + constexpr inline ::rive::EnumBitset operator|( \ + ::rive::EnumBitset lhs, \ + ::rive::EnumBitset rhs) \ + { \ + return static_cast(lhs.bits() | rhs.bits()); \ + } \ + constexpr inline ::rive::EnumBitset operator|( \ + ENUM lhs, \ + ::rive::EnumBitset rhs) \ + { \ + return ::rive::EnumBitset(lhs) | rhs; \ + } \ + constexpr inline ::rive::EnumBitset operator|( \ + ::rive::EnumBitset lhs, \ + ENUM rhs) \ + { \ + return lhs | ::rive::EnumBitset(rhs); \ + } \ + constexpr inline ::rive::EnumBitset operator|(ENUM lhs, ENUM rhs) \ + { \ + return ::rive::EnumBitset(lhs) | ::rive::EnumBitset(rhs); \ + } \ + \ + constexpr inline ::rive::EnumBitset operator~( \ + ::rive::EnumBitset rhs) \ + { \ + return static_cast(~rhs.bits()); \ + } \ + constexpr inline ::rive::EnumBitset operator~(ENUM rhs) \ + { \ + return ~::rive::EnumBitset(rhs); \ + } \ + \ + inline ENUM& operator&=(ENUM& lhs, ::rive::EnumBitset rhs) \ + { \ + return lhs = lhs & rhs; \ + } \ + inline ENUM& operator&=(ENUM& lhs, ENUM rhs) { return lhs = lhs & rhs; } \ + \ + inline ENUM& operator|=(ENUM& lhs, ::rive::EnumBitset rhs) \ + { \ + return lhs = lhs | rhs; \ + } \ + inline ENUM& operator|=(ENUM& lhs, ENUM rhs) { return lhs = lhs | rhs; } + +#define RIVE_DECL_ENUM_BITSET_FRIENDS(ENUM) \ + friend constexpr ::rive::EnumBitset operator&( \ + ::rive::EnumBitset, \ + ::rive::EnumBitset); \ + friend constexpr ::rive::EnumBitset operator&( \ + ENUM, \ + ::rive::EnumBitset); \ + friend constexpr ::rive::EnumBitset operator&( \ + ::rive::EnumBitset, \ + ENUM); \ + friend constexpr ::rive::EnumBitset operator&(ENUM, ENUM); \ + friend constexpr ::rive::EnumBitset operator|( \ + ::rive::EnumBitset, \ + ::rive::EnumBitset); \ + friend constexpr ::rive::EnumBitset operator|( \ + ENUM, \ + ::rive::EnumBitset); \ + friend constexpr ::rive::EnumBitset operator|( \ + ::rive::EnumBitset, \ + ENUM); \ + friend constexpr ::rive::EnumBitset operator|(ENUM lhs, ENUM rhs); \ + friend constexpr ::rive::EnumBitset operator~( \ + ::rive::EnumBitset rhs); \ + friend constexpr ::rive::EnumBitset operator~(ENUM rhs); \ + friend ENUM& operator&=(ENUM& lhs, ::rive::EnumBitset rhs); \ + friend ENUM& operator&=(ENUM& lhs, ENUM rhs); \ + friend ENUM& operator|=(ENUM& lhs, ::rive::EnumBitset rhs); \ + friend ENUM& operator|=(ENUM& lhs, ENUM rhs); + +#endif diff --git a/third_party/rive/include/rive/event.hpp b/third_party/rive/include/rive/event.hpp new file mode 100644 index 0000000..743c6c5 --- /dev/null +++ b/third_party/rive/include/rive/event.hpp @@ -0,0 +1,14 @@ +#ifndef _RIVE_EVENT_HPP_ +#define _RIVE_EVENT_HPP_ +#include "rive/generated/event_base.hpp" + +namespace rive +{ +class Event : public EventBase +{ +public: + void trigger(const CallbackData& value) override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/event_report.hpp b/third_party/rive/include/rive/event_report.hpp new file mode 100644 index 0000000..51d07c4 --- /dev/null +++ b/third_party/rive/include/rive/event_report.hpp @@ -0,0 +1,23 @@ +#ifndef _RIVE_EVENT_REPORT_HPP_ +#define _RIVE_EVENT_REPORT_HPP_ + +namespace rive +{ +class Event; + +class EventReport +{ +public: + EventReport(Event* event, float secondsDelay) : + m_event(event), m_secondsDelay(secondsDelay) + {} + Event* event() const { return m_event; } + float secondsDelay() const { return m_secondsDelay; } + +private: + Event* m_event; + float m_secondsDelay; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/factory.hpp b/third_party/rive/include/rive/factory.hpp new file mode 100644 index 0000000..4fedd2e --- /dev/null +++ b/third_party/rive/include/rive/factory.hpp @@ -0,0 +1,73 @@ +/* + * Copyright 2022 Rive + */ + +#ifndef _RIVE_FACTORY_HPP_ +#define _RIVE_FACTORY_HPP_ + +#include "rive/renderer.hpp" +#include "rive/text_engine.hpp" +#include "rive/audio/audio_source.hpp" +#include "rive/refcnt.hpp" +#include "rive/span.hpp" +#include "rive/math/aabb.hpp" + +#include +#include + +namespace rive +{ + +class RawPath; + +class Factory +{ +public: + Factory() {} + virtual ~Factory() {} + + virtual rcp makeRenderBuffer(RenderBufferType, + RenderBufferFlags, + size_t sizeInBytes) = 0; + + virtual rcp makeLinearGradient( + float sx, + float sy, + float ex, + float ey, + const ColorInt colors[], // [count] + const float stops[], // [count] + size_t count) = 0; + + virtual rcp makeRadialGradient( + float cx, + float cy, + float radius, + const ColorInt colors[], // [count] + const float stops[], // [count] + size_t count) = 0; + + // Returns a full-formed RenderPath -- can be treated as immutable + // This call might swap out the arrays backing the points and verbs in the + // given RawPath, so the caller can expect it to be in an undefined state + // upon return. + virtual rcp makeRenderPath(RawPath&, FillRule) = 0; + + // Deprecated -- working to make RenderPath's immutable + virtual rcp makeEmptyRenderPath() = 0; + + virtual rcp makeRenderPaint() = 0; + + virtual rcp decodeImage(Span) = 0; + + rcp decodeFont(Span); + + rcp decodeAudio(Span); + + // Non-virtual helpers + + rcp makeRenderPath(const AABB&); +}; + +} // namespace rive +#endif diff --git a/third_party/rive/include/rive/file.hpp b/third_party/rive/include/rive/file.hpp new file mode 100644 index 0000000..a73f893 --- /dev/null +++ b/third_party/rive/include/rive/file.hpp @@ -0,0 +1,221 @@ +#ifndef _RIVE_FILE_HPP_ +#define _RIVE_FILE_HPP_ + +#include "rive/artboard.hpp" +#include "rive/backboard.hpp" +#include "rive/factory.hpp" +#include "rive/file_asset_loader.hpp" +#include "rive/viewmodel/data_enum.hpp" +#include "rive/viewmodel/viewmodel_component.hpp" +#include "rive/viewmodel/viewmodel_instance.hpp" +#include "rive/viewmodel/viewmodel_instance_value.hpp" +#include "rive/viewmodel/viewmodel_instance_viewmodel.hpp" +#include "rive/viewmodel/viewmodel_instance_list_item.hpp" +#include "rive/animation/keyframe_interpolator.hpp" +#include +#include +#include + +/// +/// Default namespace for Rive Cpp runtime code. +/// +namespace rive +{ +class BinaryReader; +class RuntimeHeader; +class Factory; +class ScrollPhysics; +class ViewModelRuntime; + +/// +/// Tracks the success/failure result when importing a Rive file. +/// +enum class ImportResult +{ + /// Indicates that a file's been successfully imported. + success, + /// Indicates that the Rive file is not supported by this runtime. + unsupportedVersion, + /// Indicates that the there is a formatting problem in the file itself. + malformed +}; + +/// +/// A Rive file. +/// +class File +{ +public: + /// Major version number supported by the runtime. + static const int majorVersion = 7; + /// Minor version number supported by the runtime. + static const int minorVersion = 0; + + File(Factory*, rcp); + +public: + ~File(); + + /// + /// Imports a Rive file from a binary buffer. + /// @param data the raw date of the file. + /// @param result is an optional status result. + /// @param assetLoader is an optional helper to load assets which + /// cannot be found in-band. + /// @returns a pointer to the file, or null on failure. + static std::unique_ptr import(Span data, + Factory* factory, + ImportResult* result = nullptr, + FileAssetLoader* assetLoader = nullptr) + { + return import(data, factory, result, ref_rcp(assetLoader)); + } + + static std::unique_ptr import(Span data, + Factory*, + ImportResult* result, + rcp assetLoader); + + /// @returns the file's backboard. All files have exactly one backboard. + Backboard* backboard() const { return m_backboard; } + + /// @returns the number of artboards in the file. + size_t artboardCount() const { return m_artboards.size(); } + std::string artboardNameAt(size_t index) const; + + const std::vector& assets() const; + + // Instances + std::unique_ptr artboardDefault() const; + std::unique_ptr artboardAt(size_t index) const; + std::unique_ptr artboardNamed(std::string name) const; + + Artboard* artboard() const; + + /// @returns the named artboard. If no artboard is found with that name, + /// the null pointer is returned. + Artboard* artboard(std::string name) const; + + /// @returns the artboard at the specified index, or the nullptr if the + /// index is out of range. + Artboard* artboard(size_t index) const; + + /// @returns a view model instance of the view model with the specified + /// name. + rcp createViewModelInstance(std::string name) const; + + /// @returns a view model instance attached to the artboard if it exists. + rcp createViewModelInstance(Artboard* artboard) const; + + /// @returns a view model instance of the viewModel. + rcp createViewModelInstance(ViewModel* viewModel) const; + + /// @returns the default view model instance of the viewModel, or returns an + /// empty one if there is no default. + rcp createDefaultViewModelInstance( + ViewModel* viewModel) const; + + /// @returns the default view model instance of the viewModel, or returns an + /// empty one if there is no default. + rcp createDefaultViewModelInstance( + Artboard* artboard) const; + + /// @returns a view model instance of the viewModel by name and instance + /// name. + rcp createViewModelInstance( + std::string name, + std::string instanceName) const; + + /// @returns a view model instance of the viewModel by their indexes. + rcp createViewModelInstance(size_t index, + size_t instanceIndex) const; + + size_t viewModelCount() const { return m_ViewModels.size(); } + ViewModel* viewModel(std::string name); + ViewModel* viewModel(size_t index); + ViewModelRuntime* defaultArtboardViewModel(Artboard* artboard) const; + ViewModelRuntime* viewModelByIndex(size_t index) const; + ViewModelRuntime* viewModelByName(std::string name) const; + ViewModelInstanceListItem* viewModelInstanceListItem( + rcp viewModelInstance); + ViewModelInstanceListItem* viewModelInstanceListItem( + rcp viewModelInstance, + Artboard* artboard); + void completeViewModelInstance( + rcp viewModelInstance, + std::unordered_map> + instancesMap) const; + void completeViewModelInstance( + rcp viewModelInstance) const; + const std::vector& enums() const; + FileAsset* asset(size_t index); + + std::vector artboards() { return m_artboards; }; + +#ifdef WITH_RIVE_TOOLS + /// Strips FileAssetContents for FileAssets of given typeKeys. + /// @param data the raw data of the file. + /// @param result is an optional status result. + /// @returns the data buffer of the file with the FileAssetContents objects + /// stripped out. + static const std::vector stripAssets( + Span data, + std::set typeKeys, + ImportResult* result = nullptr); +#endif + +#ifdef TESTING + FileAssetLoader* testing_getAssetLoader() const + { + return m_assetLoader.get(); + } +#endif + +private: + ImportResult read(BinaryReader&, const RuntimeHeader&); + + /// The file's backboard. All Rive files have a single backboard + /// where the artboards live. + Backboard* m_backboard; + + /// We just keep these alive for the life of this File + std::vector m_fileAssets; + + std::vector m_DataConverters; + + std::vector m_keyframeInterpolators; + std::vector m_scrollPhysics; + + /// List of artboards in the file. Each artboard encapsulates a set of + /// Rive components and animations. + std::vector m_artboards; + + /// List of view models in the file. They may outlive the file if viewmodel + /// instances are still needed after the file is destroyed + std::vector m_ViewModels; + + /// List of view models instances in the file. We keep this list to keep + /// them alive during the lifetime of this file. This list does not hold a + /// reference to instances created by users. + std::vector m_ViewModelInstances; + + mutable std::vector m_viewModelRuntimes; + std::vector m_Enums; + + Factory* m_factory; + + /// The helper used to load assets when they're not provided in-band + /// with the file. + rcp m_assetLoader; + + rcp copyViewModelInstance( + ViewModelInstance* viewModelInstance, + std::unordered_map> + instancesMap) const; + + ViewModelRuntime* createViewModelRuntime(ViewModel* viewModel) const; + + uint32_t findViewModelId(ViewModel* search) const; +}; +} // namespace rive +#endif diff --git a/third_party/rive/include/rive/file_asset_loader.hpp b/third_party/rive/include/rive/file_asset_loader.hpp new file mode 100644 index 0000000..4627991 --- /dev/null +++ b/third_party/rive/include/rive/file_asset_loader.hpp @@ -0,0 +1,30 @@ +#ifndef _RIVE_FILE_ASSET_RESOLVER_HPP_ +#define _RIVE_FILE_ASSET_RESOLVER_HPP_ + +#include +#include +#include "rive/span.hpp" +#include "rive/refcnt.hpp" + +namespace rive +{ +class Factory; +class FileAsset; +class FileAssetLoader : public RefCnt +{ +public: + virtual ~FileAssetLoader() {} + + /// Load the contents of the given asset + /// + /// @param asset describes the asset that Rive is looking for the + /// contents of. + /// @param inBandBytes is a pointer to the bytes in question + /// @returns bool indicating if we are loading or have loaded the contents + + virtual bool loadContents(FileAsset& asset, + Span inBandBytes, + Factory* factory) = 0; +}; +} // namespace rive +#endif diff --git a/third_party/rive/include/rive/foreground_layout_drawable.hpp b/third_party/rive/include/rive/foreground_layout_drawable.hpp new file mode 100644 index 0000000..e55550e --- /dev/null +++ b/third_party/rive/include/rive/foreground_layout_drawable.hpp @@ -0,0 +1,32 @@ +#ifndef _RIVE_FOREGROUND_LAYOUT_DRAWABLE_HPP_ +#define _RIVE_FOREGROUND_LAYOUT_DRAWABLE_HPP_ +#include "rive/generated/foreground_layout_drawable_base.hpp" +#include "rive/shapes/shape_paint_container.hpp" +#include +namespace rive +{ +class ForegroundLayoutDrawable : public ForegroundLayoutDrawableBase, + public ShapePaintContainer +{ +public: + void draw(Renderer* renderer) override; + void update(ComponentDirt value) override; + void buildDependencies() override; + Core* hitTest(HitInfo*, const Mat2D&) override; + + Artboard* getArtboard() override { return artboard(); } + + // Implemented for ShapePaintContainer. + const Mat2D& shapeWorldTransform() const override + { + return worldTransform(); + } + + Component* pathBuilder() override; + ShapePaintPath* worldPath() override; + ShapePaintPath* localPath() override; + ShapePaintPath* localClockwisePath() override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/function_type.hpp b/third_party/rive/include/rive/function_type.hpp new file mode 100644 index 0000000..2bbcc23 --- /dev/null +++ b/third_party/rive/include/rive/function_type.hpp @@ -0,0 +1,28 @@ +#ifndef _RIVE_FUNCTION_TYPE_HPP_ +#define _RIVE_FUNCTION_TYPE_HPP_ + +namespace rive +{ +enum class FunctionType : int +{ + min = 0, + max = 1, + round = 2, + ceil = 3, + floor = 4, + sqrt = 5, + pow = 6, + exp = 7, + log = 8, + cosine = 9, + sine = 10, + tangent = 11, + acosine = 12, + asine = 13, + atangent = 14, + atangent2 = 15, + random = 16, +}; +} // namespace rive + +#endif diff --git a/third_party/rive/include/rive/generated/animation/advanceable_state_base.hpp b/third_party/rive/include/rive/generated/animation/advanceable_state_base.hpp new file mode 100644 index 0000000..1229a45 --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/advanceable_state_base.hpp @@ -0,0 +1,71 @@ +#ifndef _RIVE_ADVANCEABLE_STATE_BASE_HPP_ +#define _RIVE_ADVANCEABLE_STATE_BASE_HPP_ +#include "rive/animation/layer_state.hpp" +#include "rive/core/field_types/core_double_type.hpp" +namespace rive +{ +class AdvanceableStateBase : public LayerState +{ +protected: + typedef LayerState Super; + +public: + static const uint16_t typeKey = 145; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case AdvanceableStateBase::typeKey: + case LayerStateBase::typeKey: + case StateMachineLayerComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t speedPropertyKey = 292; + +protected: + float m_Speed = 1.0f; + +public: + inline float speed() const { return m_Speed; } + void speed(float value) + { + if (m_Speed == value) + { + return; + } + m_Speed = value; + speedChanged(); + } + + void copy(const AdvanceableStateBase& object) + { + m_Speed = object.m_Speed; + LayerState::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case speedPropertyKey: + m_Speed = CoreDoubleType::deserialize(reader); + return true; + } + return LayerState::deserialize(propertyKey, reader); + } + +protected: + virtual void speedChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/animation_base.hpp b/third_party/rive/include/rive/generated/animation/animation_base.hpp new file mode 100644 index 0000000..82c96f3 --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/animation_base.hpp @@ -0,0 +1,67 @@ +#ifndef _RIVE_ANIMATION_BASE_HPP_ +#define _RIVE_ANIMATION_BASE_HPP_ +#include +#include "rive/core.hpp" +#include "rive/core/field_types/core_string_type.hpp" +namespace rive +{ +class AnimationBase : public Core +{ +protected: + typedef Core Super; + +public: + static const uint16_t typeKey = 27; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case AnimationBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t namePropertyKey = 55; + +protected: + std::string m_Name = ""; + +public: + inline const std::string& name() const { return m_Name; } + void name(std::string value) + { + if (m_Name == value) + { + return; + } + m_Name = value; + nameChanged(); + } + + Core* clone() const override; + void copy(const AnimationBase& object) { m_Name = object.m_Name; } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case namePropertyKey: + m_Name = CoreStringType::deserialize(reader); + return true; + } + return false; + } + +protected: + virtual void nameChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/animation_state_base.hpp b/third_party/rive/include/rive/generated/animation/animation_state_base.hpp new file mode 100644 index 0000000..001f37d --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/animation_state_base.hpp @@ -0,0 +1,73 @@ +#ifndef _RIVE_ANIMATION_STATE_BASE_HPP_ +#define _RIVE_ANIMATION_STATE_BASE_HPP_ +#include "rive/animation/advanceable_state.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +namespace rive +{ +class AnimationStateBase : public AdvanceableState +{ +protected: + typedef AdvanceableState Super; + +public: + static const uint16_t typeKey = 61; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case AnimationStateBase::typeKey: + case AdvanceableStateBase::typeKey: + case LayerStateBase::typeKey: + case StateMachineLayerComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t animationIdPropertyKey = 149; + +protected: + uint32_t m_AnimationId = -1; + +public: + inline uint32_t animationId() const { return m_AnimationId; } + void animationId(uint32_t value) + { + if (m_AnimationId == value) + { + return; + } + m_AnimationId = value; + animationIdChanged(); + } + + Core* clone() const override; + void copy(const AnimationStateBase& object) + { + m_AnimationId = object.m_AnimationId; + AdvanceableState::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case animationIdPropertyKey: + m_AnimationId = CoreUintType::deserialize(reader); + return true; + } + return AdvanceableState::deserialize(propertyKey, reader); + } + +protected: + virtual void animationIdChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/any_state_base.hpp b/third_party/rive/include/rive/generated/animation/any_state_base.hpp new file mode 100644 index 0000000..baba7de --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/any_state_base.hpp @@ -0,0 +1,37 @@ +#ifndef _RIVE_ANY_STATE_BASE_HPP_ +#define _RIVE_ANY_STATE_BASE_HPP_ +#include "rive/animation/layer_state.hpp" +namespace rive +{ +class AnyStateBase : public LayerState +{ +protected: + typedef LayerState Super; + +public: + static const uint16_t typeKey = 62; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case AnyStateBase::typeKey: + case LayerStateBase::typeKey: + case StateMachineLayerComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/blend_animation_1d_base.hpp b/third_party/rive/include/rive/generated/animation/blend_animation_1d_base.hpp new file mode 100644 index 0000000..d862921 --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/blend_animation_1d_base.hpp @@ -0,0 +1,71 @@ +#ifndef _RIVE_BLEND_ANIMATION1_DBASE_HPP_ +#define _RIVE_BLEND_ANIMATION1_DBASE_HPP_ +#include "rive/animation/blend_animation.hpp" +#include "rive/core/field_types/core_double_type.hpp" +namespace rive +{ +class BlendAnimation1DBase : public BlendAnimation +{ +protected: + typedef BlendAnimation Super; + +public: + static const uint16_t typeKey = 75; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case BlendAnimation1DBase::typeKey: + case BlendAnimationBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t valuePropertyKey = 166; + +protected: + float m_Value = 0.0f; + +public: + inline float value() const { return m_Value; } + void value(float value) + { + if (m_Value == value) + { + return; + } + m_Value = value; + valueChanged(); + } + + Core* clone() const override; + void copy(const BlendAnimation1DBase& object) + { + m_Value = object.m_Value; + BlendAnimation::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case valuePropertyKey: + m_Value = CoreDoubleType::deserialize(reader); + return true; + } + return BlendAnimation::deserialize(propertyKey, reader); + } + +protected: + virtual void valueChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/blend_animation_base.hpp b/third_party/rive/include/rive/generated/animation/blend_animation_base.hpp new file mode 100644 index 0000000..9d36b45 --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/blend_animation_base.hpp @@ -0,0 +1,68 @@ +#ifndef _RIVE_BLEND_ANIMATION_BASE_HPP_ +#define _RIVE_BLEND_ANIMATION_BASE_HPP_ +#include "rive/core.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +namespace rive +{ +class BlendAnimationBase : public Core +{ +protected: + typedef Core Super; + +public: + static const uint16_t typeKey = 74; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case BlendAnimationBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t animationIdPropertyKey = 165; + +protected: + uint32_t m_AnimationId = -1; + +public: + inline uint32_t animationId() const { return m_AnimationId; } + void animationId(uint32_t value) + { + if (m_AnimationId == value) + { + return; + } + m_AnimationId = value; + animationIdChanged(); + } + + void copy(const BlendAnimationBase& object) + { + m_AnimationId = object.m_AnimationId; + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case animationIdPropertyKey: + m_AnimationId = CoreUintType::deserialize(reader); + return true; + } + return false; + } + +protected: + virtual void animationIdChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/blend_animation_direct_base.hpp b/third_party/rive/include/rive/generated/animation/blend_animation_direct_base.hpp new file mode 100644 index 0000000..924d121 --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/blend_animation_direct_base.hpp @@ -0,0 +1,108 @@ +#ifndef _RIVE_BLEND_ANIMATION_DIRECT_BASE_HPP_ +#define _RIVE_BLEND_ANIMATION_DIRECT_BASE_HPP_ +#include "rive/animation/blend_animation.hpp" +#include "rive/core/field_types/core_double_type.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +namespace rive +{ +class BlendAnimationDirectBase : public BlendAnimation +{ +protected: + typedef BlendAnimation Super; + +public: + static const uint16_t typeKey = 77; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case BlendAnimationDirectBase::typeKey: + case BlendAnimationBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t inputIdPropertyKey = 168; + static const uint16_t mixValuePropertyKey = 297; + static const uint16_t blendSourcePropertyKey = 298; + +protected: + uint32_t m_InputId = -1; + float m_MixValue = 100.0f; + uint32_t m_BlendSource = 0; + +public: + inline uint32_t inputId() const { return m_InputId; } + void inputId(uint32_t value) + { + if (m_InputId == value) + { + return; + } + m_InputId = value; + inputIdChanged(); + } + + inline float mixValue() const { return m_MixValue; } + void mixValue(float value) + { + if (m_MixValue == value) + { + return; + } + m_MixValue = value; + mixValueChanged(); + } + + inline uint32_t blendSource() const { return m_BlendSource; } + void blendSource(uint32_t value) + { + if (m_BlendSource == value) + { + return; + } + m_BlendSource = value; + blendSourceChanged(); + } + + Core* clone() const override; + void copy(const BlendAnimationDirectBase& object) + { + m_InputId = object.m_InputId; + m_MixValue = object.m_MixValue; + m_BlendSource = object.m_BlendSource; + BlendAnimation::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case inputIdPropertyKey: + m_InputId = CoreUintType::deserialize(reader); + return true; + case mixValuePropertyKey: + m_MixValue = CoreDoubleType::deserialize(reader); + return true; + case blendSourcePropertyKey: + m_BlendSource = CoreUintType::deserialize(reader); + return true; + } + return BlendAnimation::deserialize(propertyKey, reader); + } + +protected: + virtual void inputIdChanged() {} + virtual void mixValueChanged() {} + virtual void blendSourceChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/blend_state_1d_base.hpp b/third_party/rive/include/rive/generated/animation/blend_state_1d_base.hpp new file mode 100644 index 0000000..1c7ad17 --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/blend_state_1d_base.hpp @@ -0,0 +1,36 @@ +#ifndef _RIVE_BLEND_STATE1_DBASE_HPP_ +#define _RIVE_BLEND_STATE1_DBASE_HPP_ +#include "rive/animation/blend_state.hpp" +namespace rive +{ +class BlendState1DBase : public BlendState +{ +protected: + typedef BlendState Super; + +public: + static const uint16_t typeKey = 527; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case BlendState1DBase::typeKey: + case BlendStateBase::typeKey: + case LayerStateBase::typeKey: + case StateMachineLayerComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/blend_state_1d_input_base.hpp b/third_party/rive/include/rive/generated/animation/blend_state_1d_input_base.hpp new file mode 100644 index 0000000..89f433d --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/blend_state_1d_input_base.hpp @@ -0,0 +1,74 @@ +#ifndef _RIVE_BLEND_STATE1_DINPUT_BASE_HPP_ +#define _RIVE_BLEND_STATE1_DINPUT_BASE_HPP_ +#include "rive/animation/blend_state_1d.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +namespace rive +{ +class BlendState1DInputBase : public BlendState1D +{ +protected: + typedef BlendState1D Super; + +public: + static const uint16_t typeKey = 76; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case BlendState1DInputBase::typeKey: + case BlendState1DBase::typeKey: + case BlendStateBase::typeKey: + case LayerStateBase::typeKey: + case StateMachineLayerComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t inputIdPropertyKey = 167; + +protected: + uint32_t m_InputId = -1; + +public: + inline uint32_t inputId() const { return m_InputId; } + void inputId(uint32_t value) + { + if (m_InputId == value) + { + return; + } + m_InputId = value; + inputIdChanged(); + } + + Core* clone() const override; + void copy(const BlendState1DInputBase& object) + { + m_InputId = object.m_InputId; + BlendState1D::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case inputIdPropertyKey: + m_InputId = CoreUintType::deserialize(reader); + return true; + } + return BlendState1D::deserialize(propertyKey, reader); + } + +protected: + virtual void inputIdChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/blend_state_1d_viewmodel_base.hpp b/third_party/rive/include/rive/generated/animation/blend_state_1d_viewmodel_base.hpp new file mode 100644 index 0000000..92bdf38 --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/blend_state_1d_viewmodel_base.hpp @@ -0,0 +1,39 @@ +#ifndef _RIVE_BLEND_STATE1_DVIEW_MODEL_BASE_HPP_ +#define _RIVE_BLEND_STATE1_DVIEW_MODEL_BASE_HPP_ +#include "rive/animation/blend_state_1d.hpp" +namespace rive +{ +class BlendState1DViewModelBase : public BlendState1D +{ +protected: + typedef BlendState1D Super; + +public: + static const uint16_t typeKey = 528; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case BlendState1DViewModelBase::typeKey: + case BlendState1DBase::typeKey: + case BlendStateBase::typeKey: + case LayerStateBase::typeKey: + case StateMachineLayerComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/blend_state_base.hpp b/third_party/rive/include/rive/generated/animation/blend_state_base.hpp new file mode 100644 index 0000000..af93d07 --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/blend_state_base.hpp @@ -0,0 +1,35 @@ +#ifndef _RIVE_BLEND_STATE_BASE_HPP_ +#define _RIVE_BLEND_STATE_BASE_HPP_ +#include "rive/animation/layer_state.hpp" +namespace rive +{ +class BlendStateBase : public LayerState +{ +protected: + typedef LayerState Super; + +public: + static const uint16_t typeKey = 72; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case BlendStateBase::typeKey: + case LayerStateBase::typeKey: + case StateMachineLayerComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/blend_state_direct_base.hpp b/third_party/rive/include/rive/generated/animation/blend_state_direct_base.hpp new file mode 100644 index 0000000..879f2a9 --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/blend_state_direct_base.hpp @@ -0,0 +1,38 @@ +#ifndef _RIVE_BLEND_STATE_DIRECT_BASE_HPP_ +#define _RIVE_BLEND_STATE_DIRECT_BASE_HPP_ +#include "rive/animation/blend_state.hpp" +namespace rive +{ +class BlendStateDirectBase : public BlendState +{ +protected: + typedef BlendState Super; + +public: + static const uint16_t typeKey = 73; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case BlendStateDirectBase::typeKey: + case BlendStateBase::typeKey: + case LayerStateBase::typeKey: + case StateMachineLayerComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/blend_state_transition_base.hpp b/third_party/rive/include/rive/generated/animation/blend_state_transition_base.hpp new file mode 100644 index 0000000..78928a0 --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/blend_state_transition_base.hpp @@ -0,0 +1,75 @@ +#ifndef _RIVE_BLEND_STATE_TRANSITION_BASE_HPP_ +#define _RIVE_BLEND_STATE_TRANSITION_BASE_HPP_ +#include "rive/animation/state_transition.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +namespace rive +{ +class BlendStateTransitionBase : public StateTransition +{ +protected: + typedef StateTransition Super; + +public: + static const uint16_t typeKey = 78; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case BlendStateTransitionBase::typeKey: + case StateTransitionBase::typeKey: + case StateMachineLayerComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t exitBlendAnimationIdPropertyKey = 171; + +protected: + uint32_t m_ExitBlendAnimationId = -1; + +public: + inline uint32_t exitBlendAnimationId() const + { + return m_ExitBlendAnimationId; + } + void exitBlendAnimationId(uint32_t value) + { + if (m_ExitBlendAnimationId == value) + { + return; + } + m_ExitBlendAnimationId = value; + exitBlendAnimationIdChanged(); + } + + Core* clone() const override; + void copy(const BlendStateTransitionBase& object) + { + m_ExitBlendAnimationId = object.m_ExitBlendAnimationId; + StateTransition::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case exitBlendAnimationIdPropertyKey: + m_ExitBlendAnimationId = CoreUintType::deserialize(reader); + return true; + } + return StateTransition::deserialize(propertyKey, reader); + } + +protected: + virtual void exitBlendAnimationIdChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/cubic_ease_interpolator_base.hpp b/third_party/rive/include/rive/generated/animation/cubic_ease_interpolator_base.hpp new file mode 100644 index 0000000..58d38f7 --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/cubic_ease_interpolator_base.hpp @@ -0,0 +1,37 @@ +#ifndef _RIVE_CUBIC_EASE_INTERPOLATOR_BASE_HPP_ +#define _RIVE_CUBIC_EASE_INTERPOLATOR_BASE_HPP_ +#include "rive/animation/cubic_interpolator.hpp" +namespace rive +{ +class CubicEaseInterpolatorBase : public CubicInterpolator +{ +protected: + typedef CubicInterpolator Super; + +public: + static const uint16_t typeKey = 28; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case CubicEaseInterpolatorBase::typeKey: + case CubicInterpolatorBase::typeKey: + case KeyFrameInterpolatorBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/cubic_interpolator_base.hpp b/third_party/rive/include/rive/generated/animation/cubic_interpolator_base.hpp new file mode 100644 index 0000000..905880f --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/cubic_interpolator_base.hpp @@ -0,0 +1,124 @@ +#ifndef _RIVE_CUBIC_INTERPOLATOR_BASE_HPP_ +#define _RIVE_CUBIC_INTERPOLATOR_BASE_HPP_ +#include "rive/animation/keyframe_interpolator.hpp" +#include "rive/core/field_types/core_double_type.hpp" +namespace rive +{ +class CubicInterpolatorBase : public KeyFrameInterpolator +{ +protected: + typedef KeyFrameInterpolator Super; + +public: + static const uint16_t typeKey = 139; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case CubicInterpolatorBase::typeKey: + case KeyFrameInterpolatorBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t x1PropertyKey = 63; + static const uint16_t y1PropertyKey = 64; + static const uint16_t x2PropertyKey = 65; + static const uint16_t y2PropertyKey = 66; + +protected: + float m_X1 = 0.42f; + float m_Y1 = 0.0f; + float m_X2 = 0.58f; + float m_Y2 = 1.0f; + +public: + inline float x1() const { return m_X1; } + void x1(float value) + { + if (m_X1 == value) + { + return; + } + m_X1 = value; + x1Changed(); + } + + inline float y1() const { return m_Y1; } + void y1(float value) + { + if (m_Y1 == value) + { + return; + } + m_Y1 = value; + y1Changed(); + } + + inline float x2() const { return m_X2; } + void x2(float value) + { + if (m_X2 == value) + { + return; + } + m_X2 = value; + x2Changed(); + } + + inline float y2() const { return m_Y2; } + void y2(float value) + { + if (m_Y2 == value) + { + return; + } + m_Y2 = value; + y2Changed(); + } + + void copy(const CubicInterpolatorBase& object) + { + m_X1 = object.m_X1; + m_Y1 = object.m_Y1; + m_X2 = object.m_X2; + m_Y2 = object.m_Y2; + KeyFrameInterpolator::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case x1PropertyKey: + m_X1 = CoreDoubleType::deserialize(reader); + return true; + case y1PropertyKey: + m_Y1 = CoreDoubleType::deserialize(reader); + return true; + case x2PropertyKey: + m_X2 = CoreDoubleType::deserialize(reader); + return true; + case y2PropertyKey: + m_Y2 = CoreDoubleType::deserialize(reader); + return true; + } + return KeyFrameInterpolator::deserialize(propertyKey, reader); + } + +protected: + virtual void x1Changed() {} + virtual void y1Changed() {} + virtual void x2Changed() {} + virtual void y2Changed() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/cubic_interpolator_component_base.hpp b/third_party/rive/include/rive/generated/animation/cubic_interpolator_component_base.hpp new file mode 100644 index 0000000..3e4060c --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/cubic_interpolator_component_base.hpp @@ -0,0 +1,125 @@ +#ifndef _RIVE_CUBIC_INTERPOLATOR_COMPONENT_BASE_HPP_ +#define _RIVE_CUBIC_INTERPOLATOR_COMPONENT_BASE_HPP_ +#include "rive/component.hpp" +#include "rive/core/field_types/core_double_type.hpp" +namespace rive +{ +class CubicInterpolatorComponentBase : public Component +{ +protected: + typedef Component Super; + +public: + static const uint16_t typeKey = 163; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case CubicInterpolatorComponentBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t x1PropertyKey = 337; + static const uint16_t y1PropertyKey = 338; + static const uint16_t x2PropertyKey = 339; + static const uint16_t y2PropertyKey = 340; + +protected: + float m_X1 = 0.42f; + float m_Y1 = 0.0f; + float m_X2 = 0.58f; + float m_Y2 = 1.0f; + +public: + inline float x1() const { return m_X1; } + void x1(float value) + { + if (m_X1 == value) + { + return; + } + m_X1 = value; + x1Changed(); + } + + inline float y1() const { return m_Y1; } + void y1(float value) + { + if (m_Y1 == value) + { + return; + } + m_Y1 = value; + y1Changed(); + } + + inline float x2() const { return m_X2; } + void x2(float value) + { + if (m_X2 == value) + { + return; + } + m_X2 = value; + x2Changed(); + } + + inline float y2() const { return m_Y2; } + void y2(float value) + { + if (m_Y2 == value) + { + return; + } + m_Y2 = value; + y2Changed(); + } + + Core* clone() const override; + void copy(const CubicInterpolatorComponentBase& object) + { + m_X1 = object.m_X1; + m_Y1 = object.m_Y1; + m_X2 = object.m_X2; + m_Y2 = object.m_Y2; + Component::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case x1PropertyKey: + m_X1 = CoreDoubleType::deserialize(reader); + return true; + case y1PropertyKey: + m_Y1 = CoreDoubleType::deserialize(reader); + return true; + case x2PropertyKey: + m_X2 = CoreDoubleType::deserialize(reader); + return true; + case y2PropertyKey: + m_Y2 = CoreDoubleType::deserialize(reader); + return true; + } + return Component::deserialize(propertyKey, reader); + } + +protected: + virtual void x1Changed() {} + virtual void y1Changed() {} + virtual void x2Changed() {} + virtual void y2Changed() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/cubic_value_interpolator_base.hpp b/third_party/rive/include/rive/generated/animation/cubic_value_interpolator_base.hpp new file mode 100644 index 0000000..cd3f3c1 --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/cubic_value_interpolator_base.hpp @@ -0,0 +1,37 @@ +#ifndef _RIVE_CUBIC_VALUE_INTERPOLATOR_BASE_HPP_ +#define _RIVE_CUBIC_VALUE_INTERPOLATOR_BASE_HPP_ +#include "rive/animation/cubic_interpolator.hpp" +namespace rive +{ +class CubicValueInterpolatorBase : public CubicInterpolator +{ +protected: + typedef CubicInterpolator Super; + +public: + static const uint16_t typeKey = 138; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case CubicValueInterpolatorBase::typeKey: + case CubicInterpolatorBase::typeKey: + case KeyFrameInterpolatorBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/elastic_interpolator_base.hpp b/third_party/rive/include/rive/generated/animation/elastic_interpolator_base.hpp new file mode 100644 index 0000000..84e8b3d --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/elastic_interpolator_base.hpp @@ -0,0 +1,108 @@ +#ifndef _RIVE_ELASTIC_INTERPOLATOR_BASE_HPP_ +#define _RIVE_ELASTIC_INTERPOLATOR_BASE_HPP_ +#include "rive/animation/keyframe_interpolator.hpp" +#include "rive/core/field_types/core_double_type.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +namespace rive +{ +class ElasticInterpolatorBase : public KeyFrameInterpolator +{ +protected: + typedef KeyFrameInterpolator Super; + +public: + static const uint16_t typeKey = 174; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case ElasticInterpolatorBase::typeKey: + case KeyFrameInterpolatorBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t easingValuePropertyKey = 405; + static const uint16_t amplitudePropertyKey = 406; + static const uint16_t periodPropertyKey = 407; + +protected: + uint32_t m_EasingValue = 1; + float m_Amplitude = 1.0f; + float m_Period = 1.0f; + +public: + inline uint32_t easingValue() const { return m_EasingValue; } + void easingValue(uint32_t value) + { + if (m_EasingValue == value) + { + return; + } + m_EasingValue = value; + easingValueChanged(); + } + + inline float amplitude() const { return m_Amplitude; } + void amplitude(float value) + { + if (m_Amplitude == value) + { + return; + } + m_Amplitude = value; + amplitudeChanged(); + } + + inline float period() const { return m_Period; } + void period(float value) + { + if (m_Period == value) + { + return; + } + m_Period = value; + periodChanged(); + } + + Core* clone() const override; + void copy(const ElasticInterpolatorBase& object) + { + m_EasingValue = object.m_EasingValue; + m_Amplitude = object.m_Amplitude; + m_Period = object.m_Period; + KeyFrameInterpolator::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case easingValuePropertyKey: + m_EasingValue = CoreUintType::deserialize(reader); + return true; + case amplitudePropertyKey: + m_Amplitude = CoreDoubleType::deserialize(reader); + return true; + case periodPropertyKey: + m_Period = CoreDoubleType::deserialize(reader); + return true; + } + return KeyFrameInterpolator::deserialize(propertyKey, reader); + } + +protected: + virtual void easingValueChanged() {} + virtual void amplitudeChanged() {} + virtual void periodChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/entry_state_base.hpp b/third_party/rive/include/rive/generated/animation/entry_state_base.hpp new file mode 100644 index 0000000..a107632 --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/entry_state_base.hpp @@ -0,0 +1,37 @@ +#ifndef _RIVE_ENTRY_STATE_BASE_HPP_ +#define _RIVE_ENTRY_STATE_BASE_HPP_ +#include "rive/animation/layer_state.hpp" +namespace rive +{ +class EntryStateBase : public LayerState +{ +protected: + typedef LayerState Super; + +public: + static const uint16_t typeKey = 63; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case EntryStateBase::typeKey: + case LayerStateBase::typeKey: + case StateMachineLayerComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/exit_state_base.hpp b/third_party/rive/include/rive/generated/animation/exit_state_base.hpp new file mode 100644 index 0000000..9b67e99 --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/exit_state_base.hpp @@ -0,0 +1,37 @@ +#ifndef _RIVE_EXIT_STATE_BASE_HPP_ +#define _RIVE_EXIT_STATE_BASE_HPP_ +#include "rive/animation/layer_state.hpp" +namespace rive +{ +class ExitStateBase : public LayerState +{ +protected: + typedef LayerState Super; + +public: + static const uint16_t typeKey = 64; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case ExitStateBase::typeKey: + case LayerStateBase::typeKey: + case StateMachineLayerComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/interpolating_keyframe_base.hpp b/third_party/rive/include/rive/generated/animation/interpolating_keyframe_base.hpp new file mode 100644 index 0000000..8b7efe4 --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/interpolating_keyframe_base.hpp @@ -0,0 +1,88 @@ +#ifndef _RIVE_INTERPOLATING_KEY_FRAME_BASE_HPP_ +#define _RIVE_INTERPOLATING_KEY_FRAME_BASE_HPP_ +#include "rive/animation/keyframe.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +namespace rive +{ +class InterpolatingKeyFrameBase : public KeyFrame +{ +protected: + typedef KeyFrame Super; + +public: + static const uint16_t typeKey = 170; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case InterpolatingKeyFrameBase::typeKey: + case KeyFrameBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t interpolationTypePropertyKey = 68; + static const uint16_t interpolatorIdPropertyKey = 69; + +protected: + uint32_t m_InterpolationType = 0; + uint32_t m_InterpolatorId = -1; + +public: + inline uint32_t interpolationType() const { return m_InterpolationType; } + void interpolationType(uint32_t value) + { + if (m_InterpolationType == value) + { + return; + } + m_InterpolationType = value; + interpolationTypeChanged(); + } + + inline uint32_t interpolatorId() const { return m_InterpolatorId; } + void interpolatorId(uint32_t value) + { + if (m_InterpolatorId == value) + { + return; + } + m_InterpolatorId = value; + interpolatorIdChanged(); + } + + void copy(const InterpolatingKeyFrameBase& object) + { + m_InterpolationType = object.m_InterpolationType; + m_InterpolatorId = object.m_InterpolatorId; + KeyFrame::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case interpolationTypePropertyKey: + m_InterpolationType = CoreUintType::deserialize(reader); + return true; + case interpolatorIdPropertyKey: + m_InterpolatorId = CoreUintType::deserialize(reader); + return true; + } + return KeyFrame::deserialize(propertyKey, reader); + } + +protected: + virtual void interpolationTypeChanged() {} + virtual void interpolatorIdChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/keyed_object_base.hpp b/third_party/rive/include/rive/generated/animation/keyed_object_base.hpp new file mode 100644 index 0000000..3a85690 --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/keyed_object_base.hpp @@ -0,0 +1,66 @@ +#ifndef _RIVE_KEYED_OBJECT_BASE_HPP_ +#define _RIVE_KEYED_OBJECT_BASE_HPP_ +#include "rive/core.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +namespace rive +{ +class KeyedObjectBase : public Core +{ +protected: + typedef Core Super; + +public: + static const uint16_t typeKey = 25; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case KeyedObjectBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t objectIdPropertyKey = 51; + +protected: + uint32_t m_ObjectId = 0; + +public: + inline uint32_t objectId() const { return m_ObjectId; } + void objectId(uint32_t value) + { + if (m_ObjectId == value) + { + return; + } + m_ObjectId = value; + objectIdChanged(); + } + + Core* clone() const override; + void copy(const KeyedObjectBase& object) { m_ObjectId = object.m_ObjectId; } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case objectIdPropertyKey: + m_ObjectId = CoreUintType::deserialize(reader); + return true; + } + return false; + } + +protected: + virtual void objectIdChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/keyed_property_base.hpp b/third_party/rive/include/rive/generated/animation/keyed_property_base.hpp new file mode 100644 index 0000000..713b06d --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/keyed_property_base.hpp @@ -0,0 +1,69 @@ +#ifndef _RIVE_KEYED_PROPERTY_BASE_HPP_ +#define _RIVE_KEYED_PROPERTY_BASE_HPP_ +#include "rive/core.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +namespace rive +{ +class KeyedPropertyBase : public Core +{ +protected: + typedef Core Super; + +public: + static const uint16_t typeKey = 26; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case KeyedPropertyBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t propertyKeyPropertyKey = 53; + +protected: + uint32_t m_PropertyKey = Core::invalidPropertyKey; + +public: + inline uint32_t propertyKey() const { return m_PropertyKey; } + void propertyKey(uint32_t value) + { + if (m_PropertyKey == value) + { + return; + } + m_PropertyKey = value; + propertyKeyChanged(); + } + + Core* clone() const override; + void copy(const KeyedPropertyBase& object) + { + m_PropertyKey = object.m_PropertyKey; + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case propertyKeyPropertyKey: + m_PropertyKey = CoreUintType::deserialize(reader); + return true; + } + return false; + } + +protected: + virtual void propertyKeyChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/keyframe_base.hpp b/third_party/rive/include/rive/generated/animation/keyframe_base.hpp new file mode 100644 index 0000000..64e74c0 --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/keyframe_base.hpp @@ -0,0 +1,65 @@ +#ifndef _RIVE_KEY_FRAME_BASE_HPP_ +#define _RIVE_KEY_FRAME_BASE_HPP_ +#include "rive/core.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +namespace rive +{ +class KeyFrameBase : public Core +{ +protected: + typedef Core Super; + +public: + static const uint16_t typeKey = 29; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case KeyFrameBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t framePropertyKey = 67; + +protected: + uint32_t m_Frame = 0; + +public: + inline uint32_t frame() const { return m_Frame; } + void frame(uint32_t value) + { + if (m_Frame == value) + { + return; + } + m_Frame = value; + frameChanged(); + } + + void copy(const KeyFrameBase& object) { m_Frame = object.m_Frame; } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case framePropertyKey: + m_Frame = CoreUintType::deserialize(reader); + return true; + } + return false; + } + +protected: + virtual void frameChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/keyframe_bool_base.hpp b/third_party/rive/include/rive/generated/animation/keyframe_bool_base.hpp new file mode 100644 index 0000000..9d8e282 --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/keyframe_bool_base.hpp @@ -0,0 +1,72 @@ +#ifndef _RIVE_KEY_FRAME_BOOL_BASE_HPP_ +#define _RIVE_KEY_FRAME_BOOL_BASE_HPP_ +#include "rive/animation/interpolating_keyframe.hpp" +#include "rive/core/field_types/core_bool_type.hpp" +namespace rive +{ +class KeyFrameBoolBase : public InterpolatingKeyFrame +{ +protected: + typedef InterpolatingKeyFrame Super; + +public: + static const uint16_t typeKey = 84; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case KeyFrameBoolBase::typeKey: + case InterpolatingKeyFrameBase::typeKey: + case KeyFrameBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t valuePropertyKey = 181; + +protected: + bool m_Value = false; + +public: + inline bool value() const { return m_Value; } + void value(bool value) + { + if (m_Value == value) + { + return; + } + m_Value = value; + valueChanged(); + } + + Core* clone() const override; + void copy(const KeyFrameBoolBase& object) + { + m_Value = object.m_Value; + InterpolatingKeyFrame::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case valuePropertyKey: + m_Value = CoreBoolType::deserialize(reader); + return true; + } + return InterpolatingKeyFrame::deserialize(propertyKey, reader); + } + +protected: + virtual void valueChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/keyframe_callback_base.hpp b/third_party/rive/include/rive/generated/animation/keyframe_callback_base.hpp new file mode 100644 index 0000000..b2accac --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/keyframe_callback_base.hpp @@ -0,0 +1,36 @@ +#ifndef _RIVE_KEY_FRAME_CALLBACK_BASE_HPP_ +#define _RIVE_KEY_FRAME_CALLBACK_BASE_HPP_ +#include "rive/animation/keyframe.hpp" +namespace rive +{ +class KeyFrameCallbackBase : public KeyFrame +{ +protected: + typedef KeyFrame Super; + +public: + static const uint16_t typeKey = 171; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case KeyFrameCallbackBase::typeKey: + case KeyFrameBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/keyframe_color_base.hpp b/third_party/rive/include/rive/generated/animation/keyframe_color_base.hpp new file mode 100644 index 0000000..0bbc957 --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/keyframe_color_base.hpp @@ -0,0 +1,72 @@ +#ifndef _RIVE_KEY_FRAME_COLOR_BASE_HPP_ +#define _RIVE_KEY_FRAME_COLOR_BASE_HPP_ +#include "rive/animation/interpolating_keyframe.hpp" +#include "rive/core/field_types/core_color_type.hpp" +namespace rive +{ +class KeyFrameColorBase : public InterpolatingKeyFrame +{ +protected: + typedef InterpolatingKeyFrame Super; + +public: + static const uint16_t typeKey = 37; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case KeyFrameColorBase::typeKey: + case InterpolatingKeyFrameBase::typeKey: + case KeyFrameBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t valuePropertyKey = 88; + +protected: + int m_Value = 0; + +public: + inline int value() const { return m_Value; } + void value(int value) + { + if (m_Value == value) + { + return; + } + m_Value = value; + valueChanged(); + } + + Core* clone() const override; + void copy(const KeyFrameColorBase& object) + { + m_Value = object.m_Value; + InterpolatingKeyFrame::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case valuePropertyKey: + m_Value = CoreColorType::deserialize(reader); + return true; + } + return InterpolatingKeyFrame::deserialize(propertyKey, reader); + } + +protected: + virtual void valueChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/keyframe_double_base.hpp b/third_party/rive/include/rive/generated/animation/keyframe_double_base.hpp new file mode 100644 index 0000000..4effe9c --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/keyframe_double_base.hpp @@ -0,0 +1,72 @@ +#ifndef _RIVE_KEY_FRAME_DOUBLE_BASE_HPP_ +#define _RIVE_KEY_FRAME_DOUBLE_BASE_HPP_ +#include "rive/animation/interpolating_keyframe.hpp" +#include "rive/core/field_types/core_double_type.hpp" +namespace rive +{ +class KeyFrameDoubleBase : public InterpolatingKeyFrame +{ +protected: + typedef InterpolatingKeyFrame Super; + +public: + static const uint16_t typeKey = 30; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case KeyFrameDoubleBase::typeKey: + case InterpolatingKeyFrameBase::typeKey: + case KeyFrameBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t valuePropertyKey = 70; + +protected: + float m_Value = 0.0f; + +public: + inline float value() const { return m_Value; } + void value(float value) + { + if (m_Value == value) + { + return; + } + m_Value = value; + valueChanged(); + } + + Core* clone() const override; + void copy(const KeyFrameDoubleBase& object) + { + m_Value = object.m_Value; + InterpolatingKeyFrame::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case valuePropertyKey: + m_Value = CoreDoubleType::deserialize(reader); + return true; + } + return InterpolatingKeyFrame::deserialize(propertyKey, reader); + } + +protected: + virtual void valueChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/keyframe_id_base.hpp b/third_party/rive/include/rive/generated/animation/keyframe_id_base.hpp new file mode 100644 index 0000000..bf05698 --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/keyframe_id_base.hpp @@ -0,0 +1,72 @@ +#ifndef _RIVE_KEY_FRAME_ID_BASE_HPP_ +#define _RIVE_KEY_FRAME_ID_BASE_HPP_ +#include "rive/animation/interpolating_keyframe.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +namespace rive +{ +class KeyFrameIdBase : public InterpolatingKeyFrame +{ +protected: + typedef InterpolatingKeyFrame Super; + +public: + static const uint16_t typeKey = 50; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case KeyFrameIdBase::typeKey: + case InterpolatingKeyFrameBase::typeKey: + case KeyFrameBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t valuePropertyKey = 122; + +protected: + uint32_t m_Value = -1; + +public: + inline uint32_t value() const { return m_Value; } + void value(uint32_t value) + { + if (m_Value == value) + { + return; + } + m_Value = value; + valueChanged(); + } + + Core* clone() const override; + void copy(const KeyFrameIdBase& object) + { + m_Value = object.m_Value; + InterpolatingKeyFrame::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case valuePropertyKey: + m_Value = CoreUintType::deserialize(reader); + return true; + } + return InterpolatingKeyFrame::deserialize(propertyKey, reader); + } + +protected: + virtual void valueChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/keyframe_interpolator_base.hpp b/third_party/rive/include/rive/generated/animation/keyframe_interpolator_base.hpp new file mode 100644 index 0000000..2d580b6 --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/keyframe_interpolator_base.hpp @@ -0,0 +1,40 @@ +#ifndef _RIVE_KEY_FRAME_INTERPOLATOR_BASE_HPP_ +#define _RIVE_KEY_FRAME_INTERPOLATOR_BASE_HPP_ +#include "rive/core.hpp" +namespace rive +{ +class KeyFrameInterpolatorBase : public Core +{ +protected: + typedef Core Super; + +public: + static const uint16_t typeKey = 175; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case KeyFrameInterpolatorBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + void copy(const KeyFrameInterpolatorBase& object) {} + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + return false; + } + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/keyframe_string_base.hpp b/third_party/rive/include/rive/generated/animation/keyframe_string_base.hpp new file mode 100644 index 0000000..af66a5e --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/keyframe_string_base.hpp @@ -0,0 +1,73 @@ +#ifndef _RIVE_KEY_FRAME_STRING_BASE_HPP_ +#define _RIVE_KEY_FRAME_STRING_BASE_HPP_ +#include +#include "rive/animation/interpolating_keyframe.hpp" +#include "rive/core/field_types/core_string_type.hpp" +namespace rive +{ +class KeyFrameStringBase : public InterpolatingKeyFrame +{ +protected: + typedef InterpolatingKeyFrame Super; + +public: + static const uint16_t typeKey = 142; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case KeyFrameStringBase::typeKey: + case InterpolatingKeyFrameBase::typeKey: + case KeyFrameBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t valuePropertyKey = 280; + +protected: + std::string m_Value = ""; + +public: + inline const std::string& value() const { return m_Value; } + void value(std::string value) + { + if (m_Value == value) + { + return; + } + m_Value = value; + valueChanged(); + } + + Core* clone() const override; + void copy(const KeyFrameStringBase& object) + { + m_Value = object.m_Value; + InterpolatingKeyFrame::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case valuePropertyKey: + m_Value = CoreStringType::deserialize(reader); + return true; + } + return InterpolatingKeyFrame::deserialize(propertyKey, reader); + } + +protected: + virtual void valueChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/keyframe_uint_base.hpp b/third_party/rive/include/rive/generated/animation/keyframe_uint_base.hpp new file mode 100644 index 0000000..2f244e9 --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/keyframe_uint_base.hpp @@ -0,0 +1,72 @@ +#ifndef _RIVE_KEY_FRAME_UINT_BASE_HPP_ +#define _RIVE_KEY_FRAME_UINT_BASE_HPP_ +#include "rive/animation/interpolating_keyframe.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +namespace rive +{ +class KeyFrameUintBase : public InterpolatingKeyFrame +{ +protected: + typedef InterpolatingKeyFrame Super; + +public: + static const uint16_t typeKey = 450; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case KeyFrameUintBase::typeKey: + case InterpolatingKeyFrameBase::typeKey: + case KeyFrameBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t valuePropertyKey = 631; + +protected: + uint32_t m_Value = 0; + +public: + inline uint32_t value() const { return m_Value; } + void value(uint32_t value) + { + if (m_Value == value) + { + return; + } + m_Value = value; + valueChanged(); + } + + Core* clone() const override; + void copy(const KeyFrameUintBase& object) + { + m_Value = object.m_Value; + InterpolatingKeyFrame::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case valuePropertyKey: + m_Value = CoreUintType::deserialize(reader); + return true; + } + return InterpolatingKeyFrame::deserialize(propertyKey, reader); + } + +protected: + virtual void valueChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/layer_state_base.hpp b/third_party/rive/include/rive/generated/animation/layer_state_base.hpp new file mode 100644 index 0000000..aabb9e7 --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/layer_state_base.hpp @@ -0,0 +1,70 @@ +#ifndef _RIVE_LAYER_STATE_BASE_HPP_ +#define _RIVE_LAYER_STATE_BASE_HPP_ +#include "rive/animation/state_machine_layer_component.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +namespace rive +{ +class LayerStateBase : public StateMachineLayerComponent +{ +protected: + typedef StateMachineLayerComponent Super; + +public: + static const uint16_t typeKey = 60; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case LayerStateBase::typeKey: + case StateMachineLayerComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t flagsPropertyKey = 536; + +protected: + uint32_t m_Flags = 0; + +public: + inline uint32_t flags() const { return m_Flags; } + void flags(uint32_t value) + { + if (m_Flags == value) + { + return; + } + m_Flags = value; + flagsChanged(); + } + + void copy(const LayerStateBase& object) + { + m_Flags = object.m_Flags; + StateMachineLayerComponent::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case flagsPropertyKey: + m_Flags = CoreUintType::deserialize(reader); + return true; + } + return StateMachineLayerComponent::deserialize(propertyKey, reader); + } + +protected: + virtual void flagsChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/linear_animation_base.hpp b/third_party/rive/include/rive/generated/animation/linear_animation_base.hpp new file mode 100644 index 0000000..29b0de0 --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/linear_animation_base.hpp @@ -0,0 +1,199 @@ +#ifndef _RIVE_LINEAR_ANIMATION_BASE_HPP_ +#define _RIVE_LINEAR_ANIMATION_BASE_HPP_ +#include "rive/animation/animation.hpp" +#include "rive/core/field_types/core_bool_type.hpp" +#include "rive/core/field_types/core_double_type.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +namespace rive +{ +class LinearAnimationBase : public Animation +{ +protected: + typedef Animation Super; + +public: + static const uint16_t typeKey = 31; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case LinearAnimationBase::typeKey: + case AnimationBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t fpsPropertyKey = 56; + static const uint16_t durationPropertyKey = 57; + static const uint16_t speedPropertyKey = 58; + static const uint16_t loopValuePropertyKey = 59; + static const uint16_t workStartPropertyKey = 60; + static const uint16_t workEndPropertyKey = 61; + static const uint16_t enableWorkAreaPropertyKey = 62; + static const uint16_t quantizePropertyKey = 376; + +protected: + uint32_t m_Fps = 60; + uint32_t m_Duration = 60; + float m_Speed = 1.0f; + uint32_t m_LoopValue = 0; + uint32_t m_WorkStart = -1; + uint32_t m_WorkEnd = -1; + bool m_EnableWorkArea = false; + bool m_Quantize = false; + +public: + inline uint32_t fps() const { return m_Fps; } + void fps(uint32_t value) + { + if (m_Fps == value) + { + return; + } + m_Fps = value; + fpsChanged(); + } + + inline uint32_t duration() const { return m_Duration; } + void duration(uint32_t value) + { + if (m_Duration == value) + { + return; + } + m_Duration = value; + durationChanged(); + } + + inline float speed() const { return m_Speed; } + void speed(float value) + { + if (m_Speed == value) + { + return; + } + m_Speed = value; + speedChanged(); + } + + inline uint32_t loopValue() const { return m_LoopValue; } + void loopValue(uint32_t value) + { + if (m_LoopValue == value) + { + return; + } + m_LoopValue = value; + loopValueChanged(); + } + + inline uint32_t workStart() const { return m_WorkStart; } + void workStart(uint32_t value) + { + if (m_WorkStart == value) + { + return; + } + m_WorkStart = value; + workStartChanged(); + } + + inline uint32_t workEnd() const { return m_WorkEnd; } + void workEnd(uint32_t value) + { + if (m_WorkEnd == value) + { + return; + } + m_WorkEnd = value; + workEndChanged(); + } + + inline bool enableWorkArea() const { return m_EnableWorkArea; } + void enableWorkArea(bool value) + { + if (m_EnableWorkArea == value) + { + return; + } + m_EnableWorkArea = value; + enableWorkAreaChanged(); + } + + inline bool quantize() const { return m_Quantize; } + void quantize(bool value) + { + if (m_Quantize == value) + { + return; + } + m_Quantize = value; + quantizeChanged(); + } + + Core* clone() const override; + void copy(const LinearAnimationBase& object) + { + m_Fps = object.m_Fps; + m_Duration = object.m_Duration; + m_Speed = object.m_Speed; + m_LoopValue = object.m_LoopValue; + m_WorkStart = object.m_WorkStart; + m_WorkEnd = object.m_WorkEnd; + m_EnableWorkArea = object.m_EnableWorkArea; + m_Quantize = object.m_Quantize; + Animation::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case fpsPropertyKey: + m_Fps = CoreUintType::deserialize(reader); + return true; + case durationPropertyKey: + m_Duration = CoreUintType::deserialize(reader); + return true; + case speedPropertyKey: + m_Speed = CoreDoubleType::deserialize(reader); + return true; + case loopValuePropertyKey: + m_LoopValue = CoreUintType::deserialize(reader); + return true; + case workStartPropertyKey: + m_WorkStart = CoreUintType::deserialize(reader); + return true; + case workEndPropertyKey: + m_WorkEnd = CoreUintType::deserialize(reader); + return true; + case enableWorkAreaPropertyKey: + m_EnableWorkArea = CoreBoolType::deserialize(reader); + return true; + case quantizePropertyKey: + m_Quantize = CoreBoolType::deserialize(reader); + return true; + } + return Animation::deserialize(propertyKey, reader); + } + +protected: + virtual void fpsChanged() {} + virtual void durationChanged() {} + virtual void speedChanged() {} + virtual void loopValueChanged() {} + virtual void workStartChanged() {} + virtual void workEndChanged() {} + virtual void enableWorkAreaChanged() {} + virtual void quantizeChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/listener_action_base.hpp b/third_party/rive/include/rive/generated/animation/listener_action_base.hpp new file mode 100644 index 0000000..9437fa8 --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/listener_action_base.hpp @@ -0,0 +1,40 @@ +#ifndef _RIVE_LISTENER_ACTION_BASE_HPP_ +#define _RIVE_LISTENER_ACTION_BASE_HPP_ +#include "rive/core.hpp" +namespace rive +{ +class ListenerActionBase : public Core +{ +protected: + typedef Core Super; + +public: + static const uint16_t typeKey = 125; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case ListenerActionBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + void copy(const ListenerActionBase& object) {} + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + return false; + } + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/listener_align_target_base.hpp b/third_party/rive/include/rive/generated/animation/listener_align_target_base.hpp new file mode 100644 index 0000000..6e90e43 --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/listener_align_target_base.hpp @@ -0,0 +1,90 @@ +#ifndef _RIVE_LISTENER_ALIGN_TARGET_BASE_HPP_ +#define _RIVE_LISTENER_ALIGN_TARGET_BASE_HPP_ +#include "rive/animation/listener_action.hpp" +#include "rive/core/field_types/core_bool_type.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +namespace rive +{ +class ListenerAlignTargetBase : public ListenerAction +{ +protected: + typedef ListenerAction Super; + +public: + static const uint16_t typeKey = 126; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case ListenerAlignTargetBase::typeKey: + case ListenerActionBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t targetIdPropertyKey = 240; + static const uint16_t preserveOffsetPropertyKey = 541; + +protected: + uint32_t m_TargetId = -1; + bool m_PreserveOffset = false; + +public: + inline uint32_t targetId() const { return m_TargetId; } + void targetId(uint32_t value) + { + if (m_TargetId == value) + { + return; + } + m_TargetId = value; + targetIdChanged(); + } + + inline bool preserveOffset() const { return m_PreserveOffset; } + void preserveOffset(bool value) + { + if (m_PreserveOffset == value) + { + return; + } + m_PreserveOffset = value; + preserveOffsetChanged(); + } + + Core* clone() const override; + void copy(const ListenerAlignTargetBase& object) + { + m_TargetId = object.m_TargetId; + m_PreserveOffset = object.m_PreserveOffset; + ListenerAction::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case targetIdPropertyKey: + m_TargetId = CoreUintType::deserialize(reader); + return true; + case preserveOffsetPropertyKey: + m_PreserveOffset = CoreBoolType::deserialize(reader); + return true; + } + return ListenerAction::deserialize(propertyKey, reader); + } + +protected: + virtual void targetIdChanged() {} + virtual void preserveOffsetChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/listener_bool_change_base.hpp b/third_party/rive/include/rive/generated/animation/listener_bool_change_base.hpp new file mode 100644 index 0000000..3e10b64 --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/listener_bool_change_base.hpp @@ -0,0 +1,72 @@ +#ifndef _RIVE_LISTENER_BOOL_CHANGE_BASE_HPP_ +#define _RIVE_LISTENER_BOOL_CHANGE_BASE_HPP_ +#include "rive/animation/listener_input_change.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +namespace rive +{ +class ListenerBoolChangeBase : public ListenerInputChange +{ +protected: + typedef ListenerInputChange Super; + +public: + static const uint16_t typeKey = 117; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case ListenerBoolChangeBase::typeKey: + case ListenerInputChangeBase::typeKey: + case ListenerActionBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t valuePropertyKey = 228; + +protected: + uint32_t m_Value = 1; + +public: + inline uint32_t value() const { return m_Value; } + void value(uint32_t value) + { + if (m_Value == value) + { + return; + } + m_Value = value; + valueChanged(); + } + + Core* clone() const override; + void copy(const ListenerBoolChangeBase& object) + { + m_Value = object.m_Value; + ListenerInputChange::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case valuePropertyKey: + m_Value = CoreUintType::deserialize(reader); + return true; + } + return ListenerInputChange::deserialize(propertyKey, reader); + } + +protected: + virtual void valueChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/listener_fire_event_base.hpp b/third_party/rive/include/rive/generated/animation/listener_fire_event_base.hpp new file mode 100644 index 0000000..ee5fbdc --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/listener_fire_event_base.hpp @@ -0,0 +1,71 @@ +#ifndef _RIVE_LISTENER_FIRE_EVENT_BASE_HPP_ +#define _RIVE_LISTENER_FIRE_EVENT_BASE_HPP_ +#include "rive/animation/listener_action.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +namespace rive +{ +class ListenerFireEventBase : public ListenerAction +{ +protected: + typedef ListenerAction Super; + +public: + static const uint16_t typeKey = 168; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case ListenerFireEventBase::typeKey: + case ListenerActionBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t eventIdPropertyKey = 389; + +protected: + uint32_t m_EventId = -1; + +public: + inline uint32_t eventId() const { return m_EventId; } + void eventId(uint32_t value) + { + if (m_EventId == value) + { + return; + } + m_EventId = value; + eventIdChanged(); + } + + Core* clone() const override; + void copy(const ListenerFireEventBase& object) + { + m_EventId = object.m_EventId; + ListenerAction::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case eventIdPropertyKey: + m_EventId = CoreUintType::deserialize(reader); + return true; + } + return ListenerAction::deserialize(propertyKey, reader); + } + +protected: + virtual void eventIdChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/listener_input_change_base.hpp b/third_party/rive/include/rive/generated/animation/listener_input_change_base.hpp new file mode 100644 index 0000000..e2f6e80 --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/listener_input_change_base.hpp @@ -0,0 +1,88 @@ +#ifndef _RIVE_LISTENER_INPUT_CHANGE_BASE_HPP_ +#define _RIVE_LISTENER_INPUT_CHANGE_BASE_HPP_ +#include "rive/animation/listener_action.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +namespace rive +{ +class ListenerInputChangeBase : public ListenerAction +{ +protected: + typedef ListenerAction Super; + +public: + static const uint16_t typeKey = 116; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case ListenerInputChangeBase::typeKey: + case ListenerActionBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t inputIdPropertyKey = 227; + static const uint16_t nestedInputIdPropertyKey = 400; + +protected: + uint32_t m_InputId = -1; + uint32_t m_NestedInputId = -1; + +public: + inline uint32_t inputId() const { return m_InputId; } + void inputId(uint32_t value) + { + if (m_InputId == value) + { + return; + } + m_InputId = value; + inputIdChanged(); + } + + inline uint32_t nestedInputId() const { return m_NestedInputId; } + void nestedInputId(uint32_t value) + { + if (m_NestedInputId == value) + { + return; + } + m_NestedInputId = value; + nestedInputIdChanged(); + } + + void copy(const ListenerInputChangeBase& object) + { + m_InputId = object.m_InputId; + m_NestedInputId = object.m_NestedInputId; + ListenerAction::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case inputIdPropertyKey: + m_InputId = CoreUintType::deserialize(reader); + return true; + case nestedInputIdPropertyKey: + m_NestedInputId = CoreUintType::deserialize(reader); + return true; + } + return ListenerAction::deserialize(propertyKey, reader); + } + +protected: + virtual void inputIdChanged() {} + virtual void nestedInputIdChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/listener_number_change_base.hpp b/third_party/rive/include/rive/generated/animation/listener_number_change_base.hpp new file mode 100644 index 0000000..61bcfa4 --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/listener_number_change_base.hpp @@ -0,0 +1,72 @@ +#ifndef _RIVE_LISTENER_NUMBER_CHANGE_BASE_HPP_ +#define _RIVE_LISTENER_NUMBER_CHANGE_BASE_HPP_ +#include "rive/animation/listener_input_change.hpp" +#include "rive/core/field_types/core_double_type.hpp" +namespace rive +{ +class ListenerNumberChangeBase : public ListenerInputChange +{ +protected: + typedef ListenerInputChange Super; + +public: + static const uint16_t typeKey = 118; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case ListenerNumberChangeBase::typeKey: + case ListenerInputChangeBase::typeKey: + case ListenerActionBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t valuePropertyKey = 229; + +protected: + float m_Value = 0.0f; + +public: + inline float value() const { return m_Value; } + void value(float value) + { + if (m_Value == value) + { + return; + } + m_Value = value; + valueChanged(); + } + + Core* clone() const override; + void copy(const ListenerNumberChangeBase& object) + { + m_Value = object.m_Value; + ListenerInputChange::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case valuePropertyKey: + m_Value = CoreDoubleType::deserialize(reader); + return true; + } + return ListenerInputChange::deserialize(propertyKey, reader); + } + +protected: + virtual void valueChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/listener_trigger_change_base.hpp b/third_party/rive/include/rive/generated/animation/listener_trigger_change_base.hpp new file mode 100644 index 0000000..054a31f --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/listener_trigger_change_base.hpp @@ -0,0 +1,37 @@ +#ifndef _RIVE_LISTENER_TRIGGER_CHANGE_BASE_HPP_ +#define _RIVE_LISTENER_TRIGGER_CHANGE_BASE_HPP_ +#include "rive/animation/listener_input_change.hpp" +namespace rive +{ +class ListenerTriggerChangeBase : public ListenerInputChange +{ +protected: + typedef ListenerInputChange Super; + +public: + static const uint16_t typeKey = 115; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case ListenerTriggerChangeBase::typeKey: + case ListenerInputChangeBase::typeKey: + case ListenerActionBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/listener_viewmodel_change_base.hpp b/third_party/rive/include/rive/generated/animation/listener_viewmodel_change_base.hpp new file mode 100644 index 0000000..3e30416 --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/listener_viewmodel_change_base.hpp @@ -0,0 +1,36 @@ +#ifndef _RIVE_LISTENER_VIEW_MODEL_CHANGE_BASE_HPP_ +#define _RIVE_LISTENER_VIEW_MODEL_CHANGE_BASE_HPP_ +#include "rive/animation/listener_action.hpp" +namespace rive +{ +class ListenerViewModelChangeBase : public ListenerAction +{ +protected: + typedef ListenerAction Super; + +public: + static const uint16_t typeKey = 487; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case ListenerViewModelChangeBase::typeKey: + case ListenerActionBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/nested_bool_base.hpp b/third_party/rive/include/rive/generated/animation/nested_bool_base.hpp new file mode 100644 index 0000000..44d5cc4 --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/nested_bool_base.hpp @@ -0,0 +1,64 @@ +#ifndef _RIVE_NESTED_BOOL_BASE_HPP_ +#define _RIVE_NESTED_BOOL_BASE_HPP_ +#include "rive/animation/nested_input.hpp" +#include "rive/core/field_types/core_bool_type.hpp" +namespace rive +{ +class NestedBoolBase : public NestedInput +{ +protected: + typedef NestedInput Super; + +public: + static const uint16_t typeKey = 123; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case NestedBoolBase::typeKey: + case NestedInputBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t nestedValuePropertyKey = 238; + +protected: + bool m_NestedValue = false; + +public: + virtual bool nestedValue() const { return m_NestedValue; } + virtual void nestedValue(bool value) = 0; + + Core* clone() const override; + void copy(const NestedBoolBase& object) + { + m_NestedValue = object.m_NestedValue; + NestedInput::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case nestedValuePropertyKey: + m_NestedValue = CoreBoolType::deserialize(reader); + return true; + } + return NestedInput::deserialize(propertyKey, reader); + } + +protected: + virtual void nestedValueChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/nested_input_base.hpp b/third_party/rive/include/rive/generated/animation/nested_input_base.hpp new file mode 100644 index 0000000..ad1840f --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/nested_input_base.hpp @@ -0,0 +1,70 @@ +#ifndef _RIVE_NESTED_INPUT_BASE_HPP_ +#define _RIVE_NESTED_INPUT_BASE_HPP_ +#include "rive/component.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +namespace rive +{ +class NestedInputBase : public Component +{ +protected: + typedef Component Super; + +public: + static const uint16_t typeKey = 121; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case NestedInputBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t inputIdPropertyKey = 237; + +protected: + uint32_t m_InputId = -1; + +public: + inline uint32_t inputId() const { return m_InputId; } + void inputId(uint32_t value) + { + if (m_InputId == value) + { + return; + } + m_InputId = value; + inputIdChanged(); + } + + void copy(const NestedInputBase& object) + { + m_InputId = object.m_InputId; + Component::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case inputIdPropertyKey: + m_InputId = CoreUintType::deserialize(reader); + return true; + } + return Component::deserialize(propertyKey, reader); + } + +protected: + virtual void inputIdChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/nested_linear_animation_base.hpp b/third_party/rive/include/rive/generated/animation/nested_linear_animation_base.hpp new file mode 100644 index 0000000..b9c70f9 --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/nested_linear_animation_base.hpp @@ -0,0 +1,72 @@ +#ifndef _RIVE_NESTED_LINEAR_ANIMATION_BASE_HPP_ +#define _RIVE_NESTED_LINEAR_ANIMATION_BASE_HPP_ +#include "rive/core/field_types/core_double_type.hpp" +#include "rive/nested_animation.hpp" +namespace rive +{ +class NestedLinearAnimationBase : public NestedAnimation +{ +protected: + typedef NestedAnimation Super; + +public: + static const uint16_t typeKey = 97; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case NestedLinearAnimationBase::typeKey: + case NestedAnimationBase::typeKey: + case ContainerComponentBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t mixPropertyKey = 200; + +protected: + float m_Mix = 1.0f; + +public: + inline float mix() const { return m_Mix; } + void mix(float value) + { + if (m_Mix == value) + { + return; + } + m_Mix = value; + mixChanged(); + } + + void copy(const NestedLinearAnimationBase& object) + { + m_Mix = object.m_Mix; + NestedAnimation::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case mixPropertyKey: + m_Mix = CoreDoubleType::deserialize(reader); + return true; + } + return NestedAnimation::deserialize(propertyKey, reader); + } + +protected: + virtual void mixChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/nested_number_base.hpp b/third_party/rive/include/rive/generated/animation/nested_number_base.hpp new file mode 100644 index 0000000..7ac3697 --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/nested_number_base.hpp @@ -0,0 +1,64 @@ +#ifndef _RIVE_NESTED_NUMBER_BASE_HPP_ +#define _RIVE_NESTED_NUMBER_BASE_HPP_ +#include "rive/animation/nested_input.hpp" +#include "rive/core/field_types/core_double_type.hpp" +namespace rive +{ +class NestedNumberBase : public NestedInput +{ +protected: + typedef NestedInput Super; + +public: + static const uint16_t typeKey = 124; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case NestedNumberBase::typeKey: + case NestedInputBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t nestedValuePropertyKey = 239; + +protected: + float m_NestedValue = 0.0f; + +public: + virtual float nestedValue() const { return m_NestedValue; } + virtual void nestedValue(float value) = 0; + + Core* clone() const override; + void copy(const NestedNumberBase& object) + { + m_NestedValue = object.m_NestedValue; + NestedInput::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case nestedValuePropertyKey: + m_NestedValue = CoreDoubleType::deserialize(reader); + return true; + } + return NestedInput::deserialize(propertyKey, reader); + } + +protected: + virtual void nestedValueChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/nested_remap_animation_base.hpp b/third_party/rive/include/rive/generated/animation/nested_remap_animation_base.hpp new file mode 100644 index 0000000..2d29761 --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/nested_remap_animation_base.hpp @@ -0,0 +1,74 @@ +#ifndef _RIVE_NESTED_REMAP_ANIMATION_BASE_HPP_ +#define _RIVE_NESTED_REMAP_ANIMATION_BASE_HPP_ +#include "rive/animation/nested_linear_animation.hpp" +#include "rive/core/field_types/core_double_type.hpp" +namespace rive +{ +class NestedRemapAnimationBase : public NestedLinearAnimation +{ +protected: + typedef NestedLinearAnimation Super; + +public: + static const uint16_t typeKey = 98; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case NestedRemapAnimationBase::typeKey: + case NestedLinearAnimationBase::typeKey: + case NestedAnimationBase::typeKey: + case ContainerComponentBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t timePropertyKey = 202; + +protected: + float m_Time = 0.0f; + +public: + inline float time() const { return m_Time; } + void time(float value) + { + if (m_Time == value) + { + return; + } + m_Time = value; + timeChanged(); + } + + Core* clone() const override; + void copy(const NestedRemapAnimationBase& object) + { + m_Time = object.m_Time; + NestedLinearAnimation::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case timePropertyKey: + m_Time = CoreDoubleType::deserialize(reader); + return true; + } + return NestedLinearAnimation::deserialize(propertyKey, reader); + } + +protected: + virtual void timeChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/nested_simple_animation_base.hpp b/third_party/rive/include/rive/generated/animation/nested_simple_animation_base.hpp new file mode 100644 index 0000000..b2b2fbd --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/nested_simple_animation_base.hpp @@ -0,0 +1,93 @@ +#ifndef _RIVE_NESTED_SIMPLE_ANIMATION_BASE_HPP_ +#define _RIVE_NESTED_SIMPLE_ANIMATION_BASE_HPP_ +#include "rive/animation/nested_linear_animation.hpp" +#include "rive/core/field_types/core_bool_type.hpp" +#include "rive/core/field_types/core_double_type.hpp" +namespace rive +{ +class NestedSimpleAnimationBase : public NestedLinearAnimation +{ +protected: + typedef NestedLinearAnimation Super; + +public: + static const uint16_t typeKey = 96; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case NestedSimpleAnimationBase::typeKey: + case NestedLinearAnimationBase::typeKey: + case NestedAnimationBase::typeKey: + case ContainerComponentBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t speedPropertyKey = 199; + static const uint16_t isPlayingPropertyKey = 201; + +protected: + float m_Speed = 1.0f; + bool m_IsPlaying = false; + +public: + inline float speed() const { return m_Speed; } + void speed(float value) + { + if (m_Speed == value) + { + return; + } + m_Speed = value; + speedChanged(); + } + + inline bool isPlaying() const { return m_IsPlaying; } + void isPlaying(bool value) + { + if (m_IsPlaying == value) + { + return; + } + m_IsPlaying = value; + isPlayingChanged(); + } + + Core* clone() const override; + void copy(const NestedSimpleAnimationBase& object) + { + m_Speed = object.m_Speed; + m_IsPlaying = object.m_IsPlaying; + NestedLinearAnimation::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case speedPropertyKey: + m_Speed = CoreDoubleType::deserialize(reader); + return true; + case isPlayingPropertyKey: + m_IsPlaying = CoreBoolType::deserialize(reader); + return true; + } + return NestedLinearAnimation::deserialize(propertyKey, reader); + } + +protected: + virtual void speedChanged() {} + virtual void isPlayingChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/nested_state_machine_base.hpp b/third_party/rive/include/rive/generated/animation/nested_state_machine_base.hpp new file mode 100644 index 0000000..19ea70f --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/nested_state_machine_base.hpp @@ -0,0 +1,38 @@ +#ifndef _RIVE_NESTED_STATE_MACHINE_BASE_HPP_ +#define _RIVE_NESTED_STATE_MACHINE_BASE_HPP_ +#include "rive/nested_animation.hpp" +namespace rive +{ +class NestedStateMachineBase : public NestedAnimation +{ +protected: + typedef NestedAnimation Super; + +public: + static const uint16_t typeKey = 95; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case NestedStateMachineBase::typeKey: + case NestedAnimationBase::typeKey: + case ContainerComponentBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/nested_trigger_base.hpp b/third_party/rive/include/rive/generated/animation/nested_trigger_base.hpp new file mode 100644 index 0000000..8dc3678 --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/nested_trigger_base.hpp @@ -0,0 +1,43 @@ +#ifndef _RIVE_NESTED_TRIGGER_BASE_HPP_ +#define _RIVE_NESTED_TRIGGER_BASE_HPP_ +#include "rive/animation/nested_input.hpp" +#include "rive/core/field_types/core_callback_type.hpp" +namespace rive +{ +class NestedTriggerBase : public NestedInput +{ +protected: + typedef NestedInput Super; + +public: + static const uint16_t typeKey = 122; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case NestedTriggerBase::typeKey: + case NestedInputBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t firePropertyKey = 401; + +public: + virtual void fire(const CallbackData& value) = 0; + + Core* clone() const override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/state_machine_base.hpp b/third_party/rive/include/rive/generated/animation/state_machine_base.hpp new file mode 100644 index 0000000..fca399e --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/state_machine_base.hpp @@ -0,0 +1,36 @@ +#ifndef _RIVE_STATE_MACHINE_BASE_HPP_ +#define _RIVE_STATE_MACHINE_BASE_HPP_ +#include "rive/animation/animation.hpp" +namespace rive +{ +class StateMachineBase : public Animation +{ +protected: + typedef Animation Super; + +public: + static const uint16_t typeKey = 53; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case StateMachineBase::typeKey: + case AnimationBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/state_machine_bool_base.hpp b/third_party/rive/include/rive/generated/animation/state_machine_bool_base.hpp new file mode 100644 index 0000000..62d8084 --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/state_machine_bool_base.hpp @@ -0,0 +1,72 @@ +#ifndef _RIVE_STATE_MACHINE_BOOL_BASE_HPP_ +#define _RIVE_STATE_MACHINE_BOOL_BASE_HPP_ +#include "rive/animation/state_machine_input.hpp" +#include "rive/core/field_types/core_bool_type.hpp" +namespace rive +{ +class StateMachineBoolBase : public StateMachineInput +{ +protected: + typedef StateMachineInput Super; + +public: + static const uint16_t typeKey = 59; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case StateMachineBoolBase::typeKey: + case StateMachineInputBase::typeKey: + case StateMachineComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t valuePropertyKey = 141; + +protected: + bool m_Value = false; + +public: + inline bool value() const { return m_Value; } + void value(bool value) + { + if (m_Value == value) + { + return; + } + m_Value = value; + valueChanged(); + } + + Core* clone() const override; + void copy(const StateMachineBoolBase& object) + { + m_Value = object.m_Value; + StateMachineInput::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case valuePropertyKey: + m_Value = CoreBoolType::deserialize(reader); + return true; + } + return StateMachineInput::deserialize(propertyKey, reader); + } + +protected: + virtual void valueChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/state_machine_component_base.hpp b/third_party/rive/include/rive/generated/animation/state_machine_component_base.hpp new file mode 100644 index 0000000..1f42ffe --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/state_machine_component_base.hpp @@ -0,0 +1,69 @@ +#ifndef _RIVE_STATE_MACHINE_COMPONENT_BASE_HPP_ +#define _RIVE_STATE_MACHINE_COMPONENT_BASE_HPP_ +#include +#include "rive/core.hpp" +#include "rive/core/field_types/core_string_type.hpp" +namespace rive +{ +class StateMachineComponentBase : public Core +{ +protected: + typedef Core Super; + +public: + static const uint16_t typeKey = 54; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case StateMachineComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t namePropertyKey = 138; + +protected: + std::string m_Name = ""; + +public: + inline const std::string& name() const { return m_Name; } + void name(std::string value) + { + if (m_Name == value) + { + return; + } + m_Name = value; + nameChanged(); + } + + void copy(const StateMachineComponentBase& object) + { + m_Name = object.m_Name; + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case namePropertyKey: + m_Name = CoreStringType::deserialize(reader); + return true; + } + return false; + } + +protected: + virtual void nameChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/state_machine_fire_event_base.hpp b/third_party/rive/include/rive/generated/animation/state_machine_fire_event_base.hpp new file mode 100644 index 0000000..34138da --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/state_machine_fire_event_base.hpp @@ -0,0 +1,87 @@ +#ifndef _RIVE_STATE_MACHINE_FIRE_EVENT_BASE_HPP_ +#define _RIVE_STATE_MACHINE_FIRE_EVENT_BASE_HPP_ +#include "rive/core.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +namespace rive +{ +class StateMachineFireEventBase : public Core +{ +protected: + typedef Core Super; + +public: + static const uint16_t typeKey = 169; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case StateMachineFireEventBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t eventIdPropertyKey = 392; + static const uint16_t occursValuePropertyKey = 393; + +protected: + uint32_t m_EventId = -1; + uint32_t m_OccursValue = 0; + +public: + inline uint32_t eventId() const { return m_EventId; } + void eventId(uint32_t value) + { + if (m_EventId == value) + { + return; + } + m_EventId = value; + eventIdChanged(); + } + + inline uint32_t occursValue() const { return m_OccursValue; } + void occursValue(uint32_t value) + { + if (m_OccursValue == value) + { + return; + } + m_OccursValue = value; + occursValueChanged(); + } + + Core* clone() const override; + void copy(const StateMachineFireEventBase& object) + { + m_EventId = object.m_EventId; + m_OccursValue = object.m_OccursValue; + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case eventIdPropertyKey: + m_EventId = CoreUintType::deserialize(reader); + return true; + case occursValuePropertyKey: + m_OccursValue = CoreUintType::deserialize(reader); + return true; + } + return false; + } + +protected: + virtual void eventIdChanged() {} + virtual void occursValueChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/state_machine_input_base.hpp b/third_party/rive/include/rive/generated/animation/state_machine_input_base.hpp new file mode 100644 index 0000000..f3e8531 --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/state_machine_input_base.hpp @@ -0,0 +1,34 @@ +#ifndef _RIVE_STATE_MACHINE_INPUT_BASE_HPP_ +#define _RIVE_STATE_MACHINE_INPUT_BASE_HPP_ +#include "rive/animation/state_machine_component.hpp" +namespace rive +{ +class StateMachineInputBase : public StateMachineComponent +{ +protected: + typedef StateMachineComponent Super; + +public: + static const uint16_t typeKey = 55; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case StateMachineInputBase::typeKey: + case StateMachineComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/state_machine_layer_base.hpp b/third_party/rive/include/rive/generated/animation/state_machine_layer_base.hpp new file mode 100644 index 0000000..8ede0ea --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/state_machine_layer_base.hpp @@ -0,0 +1,36 @@ +#ifndef _RIVE_STATE_MACHINE_LAYER_BASE_HPP_ +#define _RIVE_STATE_MACHINE_LAYER_BASE_HPP_ +#include "rive/animation/state_machine_component.hpp" +namespace rive +{ +class StateMachineLayerBase : public StateMachineComponent +{ +protected: + typedef StateMachineComponent Super; + +public: + static const uint16_t typeKey = 57; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case StateMachineLayerBase::typeKey: + case StateMachineComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/state_machine_layer_component_base.hpp b/third_party/rive/include/rive/generated/animation/state_machine_layer_component_base.hpp new file mode 100644 index 0000000..0167676 --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/state_machine_layer_component_base.hpp @@ -0,0 +1,40 @@ +#ifndef _RIVE_STATE_MACHINE_LAYER_COMPONENT_BASE_HPP_ +#define _RIVE_STATE_MACHINE_LAYER_COMPONENT_BASE_HPP_ +#include "rive/core.hpp" +namespace rive +{ +class StateMachineLayerComponentBase : public Core +{ +protected: + typedef Core Super; + +public: + static const uint16_t typeKey = 66; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case StateMachineLayerComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + void copy(const StateMachineLayerComponentBase& object) {} + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + return false; + } + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/state_machine_listener_base.hpp b/third_party/rive/include/rive/generated/animation/state_machine_listener_base.hpp new file mode 100644 index 0000000..f65a966 --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/state_machine_listener_base.hpp @@ -0,0 +1,107 @@ +#ifndef _RIVE_STATE_MACHINE_LISTENER_BASE_HPP_ +#define _RIVE_STATE_MACHINE_LISTENER_BASE_HPP_ +#include "rive/animation/state_machine_component.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +namespace rive +{ +class StateMachineListenerBase : public StateMachineComponent +{ +protected: + typedef StateMachineComponent Super; + +public: + static const uint16_t typeKey = 114; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case StateMachineListenerBase::typeKey: + case StateMachineComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t targetIdPropertyKey = 224; + static const uint16_t listenerTypeValuePropertyKey = 225; + static const uint16_t eventIdPropertyKey = 399; + +protected: + uint32_t m_TargetId = -1; + uint32_t m_ListenerTypeValue = 0; + uint32_t m_EventId = -1; + +public: + inline uint32_t targetId() const { return m_TargetId; } + void targetId(uint32_t value) + { + if (m_TargetId == value) + { + return; + } + m_TargetId = value; + targetIdChanged(); + } + + inline uint32_t listenerTypeValue() const { return m_ListenerTypeValue; } + void listenerTypeValue(uint32_t value) + { + if (m_ListenerTypeValue == value) + { + return; + } + m_ListenerTypeValue = value; + listenerTypeValueChanged(); + } + + inline uint32_t eventId() const { return m_EventId; } + void eventId(uint32_t value) + { + if (m_EventId == value) + { + return; + } + m_EventId = value; + eventIdChanged(); + } + + Core* clone() const override; + void copy(const StateMachineListenerBase& object) + { + m_TargetId = object.m_TargetId; + m_ListenerTypeValue = object.m_ListenerTypeValue; + m_EventId = object.m_EventId; + StateMachineComponent::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case targetIdPropertyKey: + m_TargetId = CoreUintType::deserialize(reader); + return true; + case listenerTypeValuePropertyKey: + m_ListenerTypeValue = CoreUintType::deserialize(reader); + return true; + case eventIdPropertyKey: + m_EventId = CoreUintType::deserialize(reader); + return true; + } + return StateMachineComponent::deserialize(propertyKey, reader); + } + +protected: + virtual void targetIdChanged() {} + virtual void listenerTypeValueChanged() {} + virtual void eventIdChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/state_machine_number_base.hpp b/third_party/rive/include/rive/generated/animation/state_machine_number_base.hpp new file mode 100644 index 0000000..654a1da --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/state_machine_number_base.hpp @@ -0,0 +1,72 @@ +#ifndef _RIVE_STATE_MACHINE_NUMBER_BASE_HPP_ +#define _RIVE_STATE_MACHINE_NUMBER_BASE_HPP_ +#include "rive/animation/state_machine_input.hpp" +#include "rive/core/field_types/core_double_type.hpp" +namespace rive +{ +class StateMachineNumberBase : public StateMachineInput +{ +protected: + typedef StateMachineInput Super; + +public: + static const uint16_t typeKey = 56; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case StateMachineNumberBase::typeKey: + case StateMachineInputBase::typeKey: + case StateMachineComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t valuePropertyKey = 140; + +protected: + float m_Value = 0.0f; + +public: + inline float value() const { return m_Value; } + void value(float value) + { + if (m_Value == value) + { + return; + } + m_Value = value; + valueChanged(); + } + + Core* clone() const override; + void copy(const StateMachineNumberBase& object) + { + m_Value = object.m_Value; + StateMachineInput::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case valuePropertyKey: + m_Value = CoreDoubleType::deserialize(reader); + return true; + } + return StateMachineInput::deserialize(propertyKey, reader); + } + +protected: + virtual void valueChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/state_machine_trigger_base.hpp b/third_party/rive/include/rive/generated/animation/state_machine_trigger_base.hpp new file mode 100644 index 0000000..30b310e --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/state_machine_trigger_base.hpp @@ -0,0 +1,37 @@ +#ifndef _RIVE_STATE_MACHINE_TRIGGER_BASE_HPP_ +#define _RIVE_STATE_MACHINE_TRIGGER_BASE_HPP_ +#include "rive/animation/state_machine_input.hpp" +namespace rive +{ +class StateMachineTriggerBase : public StateMachineInput +{ +protected: + typedef StateMachineInput Super; + +public: + static const uint16_t typeKey = 58; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case StateMachineTriggerBase::typeKey: + case StateMachineInputBase::typeKey: + case StateMachineComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/state_transition_base.hpp b/third_party/rive/include/rive/generated/animation/state_transition_base.hpp new file mode 100644 index 0000000..9de4399 --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/state_transition_base.hpp @@ -0,0 +1,179 @@ +#ifndef _RIVE_STATE_TRANSITION_BASE_HPP_ +#define _RIVE_STATE_TRANSITION_BASE_HPP_ +#include "rive/animation/state_machine_layer_component.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +namespace rive +{ +class StateTransitionBase : public StateMachineLayerComponent +{ +protected: + typedef StateMachineLayerComponent Super; + +public: + static const uint16_t typeKey = 65; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case StateTransitionBase::typeKey: + case StateMachineLayerComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t stateToIdPropertyKey = 151; + static const uint16_t flagsPropertyKey = 152; + static const uint16_t durationPropertyKey = 158; + static const uint16_t exitTimePropertyKey = 160; + static const uint16_t interpolationTypePropertyKey = 349; + static const uint16_t interpolatorIdPropertyKey = 350; + static const uint16_t randomWeightPropertyKey = 537; + +protected: + uint32_t m_StateToId = -1; + uint32_t m_Flags = 0; + uint32_t m_Duration = 0; + uint32_t m_ExitTime = 0; + uint32_t m_InterpolationType = 1; + uint32_t m_InterpolatorId = -1; + uint32_t m_RandomWeight = 1; + +public: + inline uint32_t stateToId() const { return m_StateToId; } + void stateToId(uint32_t value) + { + if (m_StateToId == value) + { + return; + } + m_StateToId = value; + stateToIdChanged(); + } + + inline uint32_t flags() const { return m_Flags; } + void flags(uint32_t value) + { + if (m_Flags == value) + { + return; + } + m_Flags = value; + flagsChanged(); + } + + inline uint32_t duration() const { return m_Duration; } + void duration(uint32_t value) + { + if (m_Duration == value) + { + return; + } + m_Duration = value; + durationChanged(); + } + + inline uint32_t exitTime() const { return m_ExitTime; } + void exitTime(uint32_t value) + { + if (m_ExitTime == value) + { + return; + } + m_ExitTime = value; + exitTimeChanged(); + } + + inline uint32_t interpolationType() const { return m_InterpolationType; } + void interpolationType(uint32_t value) + { + if (m_InterpolationType == value) + { + return; + } + m_InterpolationType = value; + interpolationTypeChanged(); + } + + inline uint32_t interpolatorId() const { return m_InterpolatorId; } + void interpolatorId(uint32_t value) + { + if (m_InterpolatorId == value) + { + return; + } + m_InterpolatorId = value; + interpolatorIdChanged(); + } + + inline uint32_t randomWeight() const { return m_RandomWeight; } + void randomWeight(uint32_t value) + { + if (m_RandomWeight == value) + { + return; + } + m_RandomWeight = value; + randomWeightChanged(); + } + + Core* clone() const override; + void copy(const StateTransitionBase& object) + { + m_StateToId = object.m_StateToId; + m_Flags = object.m_Flags; + m_Duration = object.m_Duration; + m_ExitTime = object.m_ExitTime; + m_InterpolationType = object.m_InterpolationType; + m_InterpolatorId = object.m_InterpolatorId; + m_RandomWeight = object.m_RandomWeight; + StateMachineLayerComponent::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case stateToIdPropertyKey: + m_StateToId = CoreUintType::deserialize(reader); + return true; + case flagsPropertyKey: + m_Flags = CoreUintType::deserialize(reader); + return true; + case durationPropertyKey: + m_Duration = CoreUintType::deserialize(reader); + return true; + case exitTimePropertyKey: + m_ExitTime = CoreUintType::deserialize(reader); + return true; + case interpolationTypePropertyKey: + m_InterpolationType = CoreUintType::deserialize(reader); + return true; + case interpolatorIdPropertyKey: + m_InterpolatorId = CoreUintType::deserialize(reader); + return true; + case randomWeightPropertyKey: + m_RandomWeight = CoreUintType::deserialize(reader); + return true; + } + return StateMachineLayerComponent::deserialize(propertyKey, reader); + } + +protected: + virtual void stateToIdChanged() {} + virtual void flagsChanged() {} + virtual void durationChanged() {} + virtual void exitTimeChanged() {} + virtual void interpolationTypeChanged() {} + virtual void interpolatorIdChanged() {} + virtual void randomWeightChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/transition_artboard_condition_base.hpp b/third_party/rive/include/rive/generated/animation/transition_artboard_condition_base.hpp new file mode 100644 index 0000000..ac569da --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/transition_artboard_condition_base.hpp @@ -0,0 +1,37 @@ +#ifndef _RIVE_TRANSITION_ARTBOARD_CONDITION_BASE_HPP_ +#define _RIVE_TRANSITION_ARTBOARD_CONDITION_BASE_HPP_ +#include "rive/animation/transition_viewmodel_condition.hpp" +namespace rive +{ +class TransitionArtboardConditionBase : public TransitionViewModelCondition +{ +protected: + typedef TransitionViewModelCondition Super; + +public: + static const uint16_t typeKey = 497; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case TransitionArtboardConditionBase::typeKey: + case TransitionViewModelConditionBase::typeKey: + case TransitionConditionBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/transition_bool_condition_base.hpp b/third_party/rive/include/rive/generated/animation/transition_bool_condition_base.hpp new file mode 100644 index 0000000..50e5a44 --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/transition_bool_condition_base.hpp @@ -0,0 +1,38 @@ +#ifndef _RIVE_TRANSITION_BOOL_CONDITION_BASE_HPP_ +#define _RIVE_TRANSITION_BOOL_CONDITION_BASE_HPP_ +#include "rive/animation/transition_value_condition.hpp" +namespace rive +{ +class TransitionBoolConditionBase : public TransitionValueCondition +{ +protected: + typedef TransitionValueCondition Super; + +public: + static const uint16_t typeKey = 71; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case TransitionBoolConditionBase::typeKey: + case TransitionValueConditionBase::typeKey: + case TransitionInputConditionBase::typeKey: + case TransitionConditionBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/transition_comparator_base.hpp b/third_party/rive/include/rive/generated/animation/transition_comparator_base.hpp new file mode 100644 index 0000000..6ae9d38 --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/transition_comparator_base.hpp @@ -0,0 +1,40 @@ +#ifndef _RIVE_TRANSITION_COMPARATOR_BASE_HPP_ +#define _RIVE_TRANSITION_COMPARATOR_BASE_HPP_ +#include "rive/core.hpp" +namespace rive +{ +class TransitionComparatorBase : public Core +{ +protected: + typedef Core Super; + +public: + static const uint16_t typeKey = 477; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case TransitionComparatorBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + void copy(const TransitionComparatorBase& object) {} + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + return false; + } + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/transition_condition_base.hpp b/third_party/rive/include/rive/generated/animation/transition_condition_base.hpp new file mode 100644 index 0000000..db76c9a --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/transition_condition_base.hpp @@ -0,0 +1,40 @@ +#ifndef _RIVE_TRANSITION_CONDITION_BASE_HPP_ +#define _RIVE_TRANSITION_CONDITION_BASE_HPP_ +#include "rive/core.hpp" +namespace rive +{ +class TransitionConditionBase : public Core +{ +protected: + typedef Core Super; + +public: + static const uint16_t typeKey = 476; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case TransitionConditionBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + void copy(const TransitionConditionBase& object) {} + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + return false; + } + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/transition_input_condition_base.hpp b/third_party/rive/include/rive/generated/animation/transition_input_condition_base.hpp new file mode 100644 index 0000000..e357674 --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/transition_input_condition_base.hpp @@ -0,0 +1,70 @@ +#ifndef _RIVE_TRANSITION_INPUT_CONDITION_BASE_HPP_ +#define _RIVE_TRANSITION_INPUT_CONDITION_BASE_HPP_ +#include "rive/animation/transition_condition.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +namespace rive +{ +class TransitionInputConditionBase : public TransitionCondition +{ +protected: + typedef TransitionCondition Super; + +public: + static const uint16_t typeKey = 67; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case TransitionInputConditionBase::typeKey: + case TransitionConditionBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t inputIdPropertyKey = 155; + +protected: + uint32_t m_InputId = -1; + +public: + inline uint32_t inputId() const { return m_InputId; } + void inputId(uint32_t value) + { + if (m_InputId == value) + { + return; + } + m_InputId = value; + inputIdChanged(); + } + + void copy(const TransitionInputConditionBase& object) + { + m_InputId = object.m_InputId; + TransitionCondition::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case inputIdPropertyKey: + m_InputId = CoreUintType::deserialize(reader); + return true; + } + return TransitionCondition::deserialize(propertyKey, reader); + } + +protected: + virtual void inputIdChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/transition_number_condition_base.hpp b/third_party/rive/include/rive/generated/animation/transition_number_condition_base.hpp new file mode 100644 index 0000000..227d941 --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/transition_number_condition_base.hpp @@ -0,0 +1,73 @@ +#ifndef _RIVE_TRANSITION_NUMBER_CONDITION_BASE_HPP_ +#define _RIVE_TRANSITION_NUMBER_CONDITION_BASE_HPP_ +#include "rive/animation/transition_value_condition.hpp" +#include "rive/core/field_types/core_double_type.hpp" +namespace rive +{ +class TransitionNumberConditionBase : public TransitionValueCondition +{ +protected: + typedef TransitionValueCondition Super; + +public: + static const uint16_t typeKey = 70; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case TransitionNumberConditionBase::typeKey: + case TransitionValueConditionBase::typeKey: + case TransitionInputConditionBase::typeKey: + case TransitionConditionBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t valuePropertyKey = 157; + +protected: + float m_Value = 0.0f; + +public: + inline float value() const { return m_Value; } + void value(float value) + { + if (m_Value == value) + { + return; + } + m_Value = value; + valueChanged(); + } + + Core* clone() const override; + void copy(const TransitionNumberConditionBase& object) + { + m_Value = object.m_Value; + TransitionValueCondition::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case valuePropertyKey: + m_Value = CoreDoubleType::deserialize(reader); + return true; + } + return TransitionValueCondition::deserialize(propertyKey, reader); + } + +protected: + virtual void valueChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/transition_property_artboard_comparator_base.hpp b/third_party/rive/include/rive/generated/animation/transition_property_artboard_comparator_base.hpp new file mode 100644 index 0000000..563fe30 --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/transition_property_artboard_comparator_base.hpp @@ -0,0 +1,73 @@ +#ifndef _RIVE_TRANSITION_PROPERTY_ARTBOARD_COMPARATOR_BASE_HPP_ +#define _RIVE_TRANSITION_PROPERTY_ARTBOARD_COMPARATOR_BASE_HPP_ +#include "rive/animation/transition_property_comparator.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +namespace rive +{ +class TransitionPropertyArtboardComparatorBase + : public TransitionPropertyComparator +{ +protected: + typedef TransitionPropertyComparator Super; + +public: + static const uint16_t typeKey = 496; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case TransitionPropertyArtboardComparatorBase::typeKey: + case TransitionPropertyComparatorBase::typeKey: + case TransitionComparatorBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t propertyTypePropertyKey = 677; + +protected: + uint32_t m_PropertyType = 0; + +public: + inline uint32_t propertyType() const { return m_PropertyType; } + void propertyType(uint32_t value) + { + if (m_PropertyType == value) + { + return; + } + m_PropertyType = value; + propertyTypeChanged(); + } + + Core* clone() const override; + void copy(const TransitionPropertyArtboardComparatorBase& object) + { + m_PropertyType = object.m_PropertyType; + TransitionPropertyComparator::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case propertyTypePropertyKey: + m_PropertyType = CoreUintType::deserialize(reader); + return true; + } + return TransitionPropertyComparator::deserialize(propertyKey, reader); + } + +protected: + virtual void propertyTypeChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/transition_property_comparator_base.hpp b/third_party/rive/include/rive/generated/animation/transition_property_comparator_base.hpp new file mode 100644 index 0000000..846c3a2 --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/transition_property_comparator_base.hpp @@ -0,0 +1,34 @@ +#ifndef _RIVE_TRANSITION_PROPERTY_COMPARATOR_BASE_HPP_ +#define _RIVE_TRANSITION_PROPERTY_COMPARATOR_BASE_HPP_ +#include "rive/animation/transition_comparator.hpp" +namespace rive +{ +class TransitionPropertyComparatorBase : public TransitionComparator +{ +protected: + typedef TransitionComparator Super; + +public: + static const uint16_t typeKey = 478; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case TransitionPropertyComparatorBase::typeKey: + case TransitionComparatorBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/transition_property_viewmodel_comparator_base.hpp b/third_party/rive/include/rive/generated/animation/transition_property_viewmodel_comparator_base.hpp new file mode 100644 index 0000000..9cce541 --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/transition_property_viewmodel_comparator_base.hpp @@ -0,0 +1,38 @@ +#ifndef _RIVE_TRANSITION_PROPERTY_VIEW_MODEL_COMPARATOR_BASE_HPP_ +#define _RIVE_TRANSITION_PROPERTY_VIEW_MODEL_COMPARATOR_BASE_HPP_ +#include "rive/animation/transition_property_comparator.hpp" +namespace rive +{ +class TransitionPropertyViewModelComparatorBase + : public TransitionPropertyComparator +{ +protected: + typedef TransitionPropertyComparator Super; + +public: + static const uint16_t typeKey = 479; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case TransitionPropertyViewModelComparatorBase::typeKey: + case TransitionPropertyComparatorBase::typeKey: + case TransitionComparatorBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/transition_trigger_condition_base.hpp b/third_party/rive/include/rive/generated/animation/transition_trigger_condition_base.hpp new file mode 100644 index 0000000..c29b7cd --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/transition_trigger_condition_base.hpp @@ -0,0 +1,37 @@ +#ifndef _RIVE_TRANSITION_TRIGGER_CONDITION_BASE_HPP_ +#define _RIVE_TRANSITION_TRIGGER_CONDITION_BASE_HPP_ +#include "rive/animation/transition_input_condition.hpp" +namespace rive +{ +class TransitionTriggerConditionBase : public TransitionInputCondition +{ +protected: + typedef TransitionInputCondition Super; + +public: + static const uint16_t typeKey = 68; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case TransitionTriggerConditionBase::typeKey: + case TransitionInputConditionBase::typeKey: + case TransitionConditionBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/transition_value_boolean_comparator_base.hpp b/third_party/rive/include/rive/generated/animation/transition_value_boolean_comparator_base.hpp new file mode 100644 index 0000000..34eeab2 --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/transition_value_boolean_comparator_base.hpp @@ -0,0 +1,72 @@ +#ifndef _RIVE_TRANSITION_VALUE_BOOLEAN_COMPARATOR_BASE_HPP_ +#define _RIVE_TRANSITION_VALUE_BOOLEAN_COMPARATOR_BASE_HPP_ +#include "rive/animation/transition_value_comparator.hpp" +#include "rive/core/field_types/core_bool_type.hpp" +namespace rive +{ +class TransitionValueBooleanComparatorBase : public TransitionValueComparator +{ +protected: + typedef TransitionValueComparator Super; + +public: + static const uint16_t typeKey = 481; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case TransitionValueBooleanComparatorBase::typeKey: + case TransitionValueComparatorBase::typeKey: + case TransitionComparatorBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t valuePropertyKey = 647; + +protected: + bool m_Value = false; + +public: + inline bool value() const { return m_Value; } + void value(bool value) + { + if (m_Value == value) + { + return; + } + m_Value = value; + valueChanged(); + } + + Core* clone() const override; + void copy(const TransitionValueBooleanComparatorBase& object) + { + m_Value = object.m_Value; + TransitionValueComparator::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case valuePropertyKey: + m_Value = CoreBoolType::deserialize(reader); + return true; + } + return TransitionValueComparator::deserialize(propertyKey, reader); + } + +protected: + virtual void valueChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/transition_value_color_comparator_base.hpp b/third_party/rive/include/rive/generated/animation/transition_value_color_comparator_base.hpp new file mode 100644 index 0000000..d55c426 --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/transition_value_color_comparator_base.hpp @@ -0,0 +1,72 @@ +#ifndef _RIVE_TRANSITION_VALUE_COLOR_COMPARATOR_BASE_HPP_ +#define _RIVE_TRANSITION_VALUE_COLOR_COMPARATOR_BASE_HPP_ +#include "rive/animation/transition_value_comparator.hpp" +#include "rive/core/field_types/core_color_type.hpp" +namespace rive +{ +class TransitionValueColorComparatorBase : public TransitionValueComparator +{ +protected: + typedef TransitionValueComparator Super; + +public: + static const uint16_t typeKey = 483; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case TransitionValueColorComparatorBase::typeKey: + case TransitionValueComparatorBase::typeKey: + case TransitionComparatorBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t valuePropertyKey = 651; + +protected: + int m_Value = 0xFF1D1D1D; + +public: + inline int value() const { return m_Value; } + void value(int value) + { + if (m_Value == value) + { + return; + } + m_Value = value; + valueChanged(); + } + + Core* clone() const override; + void copy(const TransitionValueColorComparatorBase& object) + { + m_Value = object.m_Value; + TransitionValueComparator::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case valuePropertyKey: + m_Value = CoreColorType::deserialize(reader); + return true; + } + return TransitionValueComparator::deserialize(propertyKey, reader); + } + +protected: + virtual void valueChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/transition_value_comparator_base.hpp b/third_party/rive/include/rive/generated/animation/transition_value_comparator_base.hpp new file mode 100644 index 0000000..08ed528 --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/transition_value_comparator_base.hpp @@ -0,0 +1,34 @@ +#ifndef _RIVE_TRANSITION_VALUE_COMPARATOR_BASE_HPP_ +#define _RIVE_TRANSITION_VALUE_COMPARATOR_BASE_HPP_ +#include "rive/animation/transition_comparator.hpp" +namespace rive +{ +class TransitionValueComparatorBase : public TransitionComparator +{ +protected: + typedef TransitionComparator Super; + +public: + static const uint16_t typeKey = 480; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case TransitionValueComparatorBase::typeKey: + case TransitionComparatorBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/transition_value_condition_base.hpp b/third_party/rive/include/rive/generated/animation/transition_value_condition_base.hpp new file mode 100644 index 0000000..9928dbc --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/transition_value_condition_base.hpp @@ -0,0 +1,71 @@ +#ifndef _RIVE_TRANSITION_VALUE_CONDITION_BASE_HPP_ +#define _RIVE_TRANSITION_VALUE_CONDITION_BASE_HPP_ +#include "rive/animation/transition_input_condition.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +namespace rive +{ +class TransitionValueConditionBase : public TransitionInputCondition +{ +protected: + typedef TransitionInputCondition Super; + +public: + static const uint16_t typeKey = 69; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case TransitionValueConditionBase::typeKey: + case TransitionInputConditionBase::typeKey: + case TransitionConditionBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t opValuePropertyKey = 156; + +protected: + uint32_t m_OpValue = 0; + +public: + inline uint32_t opValue() const { return m_OpValue; } + void opValue(uint32_t value) + { + if (m_OpValue == value) + { + return; + } + m_OpValue = value; + opValueChanged(); + } + + void copy(const TransitionValueConditionBase& object) + { + m_OpValue = object.m_OpValue; + TransitionInputCondition::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case opValuePropertyKey: + m_OpValue = CoreUintType::deserialize(reader); + return true; + } + return TransitionInputCondition::deserialize(propertyKey, reader); + } + +protected: + virtual void opValueChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/transition_value_enum_comparator_base.hpp b/third_party/rive/include/rive/generated/animation/transition_value_enum_comparator_base.hpp new file mode 100644 index 0000000..f2bbec6 --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/transition_value_enum_comparator_base.hpp @@ -0,0 +1,72 @@ +#ifndef _RIVE_TRANSITION_VALUE_ENUM_COMPARATOR_BASE_HPP_ +#define _RIVE_TRANSITION_VALUE_ENUM_COMPARATOR_BASE_HPP_ +#include "rive/animation/transition_value_comparator.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +namespace rive +{ +class TransitionValueEnumComparatorBase : public TransitionValueComparator +{ +protected: + typedef TransitionValueComparator Super; + +public: + static const uint16_t typeKey = 485; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case TransitionValueEnumComparatorBase::typeKey: + case TransitionValueComparatorBase::typeKey: + case TransitionComparatorBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t valuePropertyKey = 653; + +protected: + uint32_t m_Value = -1; + +public: + inline uint32_t value() const { return m_Value; } + void value(uint32_t value) + { + if (m_Value == value) + { + return; + } + m_Value = value; + valueChanged(); + } + + Core* clone() const override; + void copy(const TransitionValueEnumComparatorBase& object) + { + m_Value = object.m_Value; + TransitionValueComparator::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case valuePropertyKey: + m_Value = CoreUintType::deserialize(reader); + return true; + } + return TransitionValueComparator::deserialize(propertyKey, reader); + } + +protected: + virtual void valueChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/transition_value_number_comparator_base.hpp b/third_party/rive/include/rive/generated/animation/transition_value_number_comparator_base.hpp new file mode 100644 index 0000000..27c0c6e --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/transition_value_number_comparator_base.hpp @@ -0,0 +1,72 @@ +#ifndef _RIVE_TRANSITION_VALUE_NUMBER_COMPARATOR_BASE_HPP_ +#define _RIVE_TRANSITION_VALUE_NUMBER_COMPARATOR_BASE_HPP_ +#include "rive/animation/transition_value_comparator.hpp" +#include "rive/core/field_types/core_double_type.hpp" +namespace rive +{ +class TransitionValueNumberComparatorBase : public TransitionValueComparator +{ +protected: + typedef TransitionValueComparator Super; + +public: + static const uint16_t typeKey = 484; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case TransitionValueNumberComparatorBase::typeKey: + case TransitionValueComparatorBase::typeKey: + case TransitionComparatorBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t valuePropertyKey = 652; + +protected: + float m_Value = 0.0f; + +public: + inline float value() const { return m_Value; } + void value(float value) + { + if (m_Value == value) + { + return; + } + m_Value = value; + valueChanged(); + } + + Core* clone() const override; + void copy(const TransitionValueNumberComparatorBase& object) + { + m_Value = object.m_Value; + TransitionValueComparator::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case valuePropertyKey: + m_Value = CoreDoubleType::deserialize(reader); + return true; + } + return TransitionValueComparator::deserialize(propertyKey, reader); + } + +protected: + virtual void valueChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/transition_value_string_comparator_base.hpp b/third_party/rive/include/rive/generated/animation/transition_value_string_comparator_base.hpp new file mode 100644 index 0000000..0b7db2d --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/transition_value_string_comparator_base.hpp @@ -0,0 +1,73 @@ +#ifndef _RIVE_TRANSITION_VALUE_STRING_COMPARATOR_BASE_HPP_ +#define _RIVE_TRANSITION_VALUE_STRING_COMPARATOR_BASE_HPP_ +#include +#include "rive/animation/transition_value_comparator.hpp" +#include "rive/core/field_types/core_string_type.hpp" +namespace rive +{ +class TransitionValueStringComparatorBase : public TransitionValueComparator +{ +protected: + typedef TransitionValueComparator Super; + +public: + static const uint16_t typeKey = 486; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case TransitionValueStringComparatorBase::typeKey: + case TransitionValueComparatorBase::typeKey: + case TransitionComparatorBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t valuePropertyKey = 654; + +protected: + std::string m_Value = ""; + +public: + inline const std::string& value() const { return m_Value; } + void value(std::string value) + { + if (m_Value == value) + { + return; + } + m_Value = value; + valueChanged(); + } + + Core* clone() const override; + void copy(const TransitionValueStringComparatorBase& object) + { + m_Value = object.m_Value; + TransitionValueComparator::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case valuePropertyKey: + m_Value = CoreStringType::deserialize(reader); + return true; + } + return TransitionValueComparator::deserialize(propertyKey, reader); + } + +protected: + virtual void valueChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/transition_value_trigger_comparator_base.hpp b/third_party/rive/include/rive/generated/animation/transition_value_trigger_comparator_base.hpp new file mode 100644 index 0000000..5289e76 --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/transition_value_trigger_comparator_base.hpp @@ -0,0 +1,72 @@ +#ifndef _RIVE_TRANSITION_VALUE_TRIGGER_COMPARATOR_BASE_HPP_ +#define _RIVE_TRANSITION_VALUE_TRIGGER_COMPARATOR_BASE_HPP_ +#include "rive/animation/transition_value_comparator.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +namespace rive +{ +class TransitionValueTriggerComparatorBase : public TransitionValueComparator +{ +protected: + typedef TransitionValueComparator Super; + +public: + static const uint16_t typeKey = 505; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case TransitionValueTriggerComparatorBase::typeKey: + case TransitionValueComparatorBase::typeKey: + case TransitionComparatorBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t valuePropertyKey = 689; + +protected: + uint32_t m_Value = 0; + +public: + inline uint32_t value() const { return m_Value; } + void value(uint32_t value) + { + if (m_Value == value) + { + return; + } + m_Value = value; + valueChanged(); + } + + Core* clone() const override; + void copy(const TransitionValueTriggerComparatorBase& object) + { + m_Value = object.m_Value; + TransitionValueComparator::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case valuePropertyKey: + m_Value = CoreUintType::deserialize(reader); + return true; + } + return TransitionValueComparator::deserialize(propertyKey, reader); + } + +protected: + virtual void valueChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/animation/transition_viewmodel_condition_base.hpp b/third_party/rive/include/rive/generated/animation/transition_viewmodel_condition_base.hpp new file mode 100644 index 0000000..6a5cecc --- /dev/null +++ b/third_party/rive/include/rive/generated/animation/transition_viewmodel_condition_base.hpp @@ -0,0 +1,71 @@ +#ifndef _RIVE_TRANSITION_VIEW_MODEL_CONDITION_BASE_HPP_ +#define _RIVE_TRANSITION_VIEW_MODEL_CONDITION_BASE_HPP_ +#include "rive/animation/transition_condition.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +namespace rive +{ +class TransitionViewModelConditionBase : public TransitionCondition +{ +protected: + typedef TransitionCondition Super; + +public: + static const uint16_t typeKey = 482; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case TransitionViewModelConditionBase::typeKey: + case TransitionConditionBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t opValuePropertyKey = 650; + +protected: + uint32_t m_OpValue = 0; + +public: + inline uint32_t opValue() const { return m_OpValue; } + void opValue(uint32_t value) + { + if (m_OpValue == value) + { + return; + } + m_OpValue = value; + opValueChanged(); + } + + Core* clone() const override; + void copy(const TransitionViewModelConditionBase& object) + { + m_OpValue = object.m_OpValue; + TransitionCondition::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case opValuePropertyKey: + m_OpValue = CoreUintType::deserialize(reader); + return true; + } + return TransitionCondition::deserialize(propertyKey, reader); + } + +protected: + virtual void opValueChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/artboard_base.hpp b/third_party/rive/include/rive/generated/artboard_base.hpp new file mode 100644 index 0000000..70cbaee --- /dev/null +++ b/third_party/rive/include/rive/generated/artboard_base.hpp @@ -0,0 +1,135 @@ +#ifndef _RIVE_ARTBOARD_BASE_HPP_ +#define _RIVE_ARTBOARD_BASE_HPP_ +#include "rive/core/field_types/core_double_type.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +#include "rive/layout_component.hpp" +namespace rive +{ +class ArtboardBase : public LayoutComponent +{ +protected: + typedef LayoutComponent Super; + +public: + static const uint16_t typeKey = 1; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case ArtboardBase::typeKey: + case LayoutComponentBase::typeKey: + case DrawableBase::typeKey: + case NodeBase::typeKey: + case TransformComponentBase::typeKey: + case WorldTransformComponentBase::typeKey: + case ContainerComponentBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t originXPropertyKey = 11; + static const uint16_t originYPropertyKey = 12; + static const uint16_t defaultStateMachineIdPropertyKey = 236; + static const uint16_t viewModelIdPropertyKey = 583; + +protected: + float m_OriginX = 0.0f; + float m_OriginY = 0.0f; + uint32_t m_DefaultStateMachineId = -1; + uint32_t m_ViewModelId = -1; + +public: + inline float originX() const { return m_OriginX; } + void originX(float value) + { + if (m_OriginX == value) + { + return; + } + m_OriginX = value; + originXChanged(); + } + + inline float originY() const { return m_OriginY; } + void originY(float value) + { + if (m_OriginY == value) + { + return; + } + m_OriginY = value; + originYChanged(); + } + + inline uint32_t defaultStateMachineId() const + { + return m_DefaultStateMachineId; + } + void defaultStateMachineId(uint32_t value) + { + if (m_DefaultStateMachineId == value) + { + return; + } + m_DefaultStateMachineId = value; + defaultStateMachineIdChanged(); + } + + inline uint32_t viewModelId() const { return m_ViewModelId; } + void viewModelId(uint32_t value) + { + if (m_ViewModelId == value) + { + return; + } + m_ViewModelId = value; + viewModelIdChanged(); + } + + Core* clone() const override; + void copy(const ArtboardBase& object) + { + m_OriginX = object.m_OriginX; + m_OriginY = object.m_OriginY; + m_DefaultStateMachineId = object.m_DefaultStateMachineId; + m_ViewModelId = object.m_ViewModelId; + LayoutComponent::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case originXPropertyKey: + m_OriginX = CoreDoubleType::deserialize(reader); + return true; + case originYPropertyKey: + m_OriginY = CoreDoubleType::deserialize(reader); + return true; + case defaultStateMachineIdPropertyKey: + m_DefaultStateMachineId = CoreUintType::deserialize(reader); + return true; + case viewModelIdPropertyKey: + m_ViewModelId = CoreUintType::deserialize(reader); + return true; + } + return LayoutComponent::deserialize(propertyKey, reader); + } + +protected: + virtual void originXChanged() {} + virtual void originYChanged() {} + virtual void defaultStateMachineIdChanged() {} + virtual void viewModelIdChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/artboard_component_list_base.hpp b/third_party/rive/include/rive/generated/artboard_component_list_base.hpp new file mode 100644 index 0000000..aa716be --- /dev/null +++ b/third_party/rive/include/rive/generated/artboard_component_list_base.hpp @@ -0,0 +1,76 @@ +#ifndef _RIVE_ARTBOARD_COMPONENT_LIST_BASE_HPP_ +#define _RIVE_ARTBOARD_COMPONENT_LIST_BASE_HPP_ +#include "rive/core/field_types/core_uint_type.hpp" +#include "rive/drawable.hpp" +namespace rive +{ +class ArtboardComponentListBase : public Drawable +{ +protected: + typedef Drawable Super; + +public: + static const uint16_t typeKey = 559; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case ArtboardComponentListBase::typeKey: + case DrawableBase::typeKey: + case NodeBase::typeKey: + case TransformComponentBase::typeKey: + case WorldTransformComponentBase::typeKey: + case ContainerComponentBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t listSourcePropertyKey = 800; + +protected: + uint32_t m_ListSource = -1; + +public: + inline uint32_t listSource() const { return m_ListSource; } + void listSource(uint32_t value) + { + if (m_ListSource == value) + { + return; + } + m_ListSource = value; + listSourceChanged(); + } + + Core* clone() const override; + void copy(const ArtboardComponentListBase& object) + { + m_ListSource = object.m_ListSource; + Drawable::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case listSourcePropertyKey: + m_ListSource = CoreUintType::deserialize(reader); + return true; + } + return Drawable::deserialize(propertyKey, reader); + } + +protected: + virtual void listSourceChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/assets/asset_base.hpp b/third_party/rive/include/rive/generated/assets/asset_base.hpp new file mode 100644 index 0000000..8fae075 --- /dev/null +++ b/third_party/rive/include/rive/generated/assets/asset_base.hpp @@ -0,0 +1,66 @@ +#ifndef _RIVE_ASSET_BASE_HPP_ +#define _RIVE_ASSET_BASE_HPP_ +#include +#include "rive/core.hpp" +#include "rive/core/field_types/core_string_type.hpp" +namespace rive +{ +class AssetBase : public Core +{ +protected: + typedef Core Super; + +public: + static const uint16_t typeKey = 99; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case AssetBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t namePropertyKey = 203; + +protected: + std::string m_Name = ""; + +public: + inline const std::string& name() const { return m_Name; } + void name(std::string value) + { + if (m_Name == value) + { + return; + } + m_Name = value; + nameChanged(); + } + + void copy(const AssetBase& object) { m_Name = object.m_Name; } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case namePropertyKey: + m_Name = CoreStringType::deserialize(reader); + return true; + } + return false; + } + +protected: + virtual void nameChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/assets/audio_asset_base.hpp b/third_party/rive/include/rive/generated/assets/audio_asset_base.hpp new file mode 100644 index 0000000..ab24e6b --- /dev/null +++ b/third_party/rive/include/rive/generated/assets/audio_asset_base.hpp @@ -0,0 +1,38 @@ +#ifndef _RIVE_AUDIO_ASSET_BASE_HPP_ +#define _RIVE_AUDIO_ASSET_BASE_HPP_ +#include "rive/assets/export_audio.hpp" +namespace rive +{ +class AudioAssetBase : public ExportAudio +{ +protected: + typedef ExportAudio Super; + +public: + static const uint16_t typeKey = 406; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case AudioAssetBase::typeKey: + case ExportAudioBase::typeKey: + case FileAssetBase::typeKey: + case AssetBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/assets/drawable_asset_base.hpp b/third_party/rive/include/rive/generated/assets/drawable_asset_base.hpp new file mode 100644 index 0000000..8579560 --- /dev/null +++ b/third_party/rive/include/rive/generated/assets/drawable_asset_base.hpp @@ -0,0 +1,89 @@ +#ifndef _RIVE_DRAWABLE_ASSET_BASE_HPP_ +#define _RIVE_DRAWABLE_ASSET_BASE_HPP_ +#include "rive/assets/file_asset.hpp" +#include "rive/core/field_types/core_double_type.hpp" +namespace rive +{ +class DrawableAssetBase : public FileAsset +{ +protected: + typedef FileAsset Super; + +public: + static const uint16_t typeKey = 104; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case DrawableAssetBase::typeKey: + case FileAssetBase::typeKey: + case AssetBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t heightPropertyKey = 207; + static const uint16_t widthPropertyKey = 208; + +protected: + float m_Height = 0.0f; + float m_Width = 0.0f; + +public: + inline float height() const { return m_Height; } + void height(float value) + { + if (m_Height == value) + { + return; + } + m_Height = value; + heightChanged(); + } + + inline float width() const { return m_Width; } + void width(float value) + { + if (m_Width == value) + { + return; + } + m_Width = value; + widthChanged(); + } + + void copy(const DrawableAssetBase& object) + { + m_Height = object.m_Height; + m_Width = object.m_Width; + FileAsset::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case heightPropertyKey: + m_Height = CoreDoubleType::deserialize(reader); + return true; + case widthPropertyKey: + m_Width = CoreDoubleType::deserialize(reader); + return true; + } + return FileAsset::deserialize(propertyKey, reader); + } + +protected: + virtual void heightChanged() {} + virtual void widthChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/assets/export_audio_base.hpp b/third_party/rive/include/rive/generated/assets/export_audio_base.hpp new file mode 100644 index 0000000..2575a08 --- /dev/null +++ b/third_party/rive/include/rive/generated/assets/export_audio_base.hpp @@ -0,0 +1,71 @@ +#ifndef _RIVE_EXPORT_AUDIO_BASE_HPP_ +#define _RIVE_EXPORT_AUDIO_BASE_HPP_ +#include "rive/assets/file_asset.hpp" +#include "rive/core/field_types/core_double_type.hpp" +namespace rive +{ +class ExportAudioBase : public FileAsset +{ +protected: + typedef FileAsset Super; + +public: + static const uint16_t typeKey = 422; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case ExportAudioBase::typeKey: + case FileAssetBase::typeKey: + case AssetBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t volumePropertyKey = 530; + +protected: + float m_Volume = 1.0f; + +public: + inline float volume() const { return m_Volume; } + void volume(float value) + { + if (m_Volume == value) + { + return; + } + m_Volume = value; + volumeChanged(); + } + + void copy(const ExportAudioBase& object) + { + m_Volume = object.m_Volume; + FileAsset::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case volumePropertyKey: + m_Volume = CoreDoubleType::deserialize(reader); + return true; + } + return FileAsset::deserialize(propertyKey, reader); + } + +protected: + virtual void volumeChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/assets/file_asset_base.hpp b/third_party/rive/include/rive/generated/assets/file_asset_base.hpp new file mode 100644 index 0000000..2c273c9 --- /dev/null +++ b/third_party/rive/include/rive/generated/assets/file_asset_base.hpp @@ -0,0 +1,101 @@ +#ifndef _RIVE_FILE_ASSET_BASE_HPP_ +#define _RIVE_FILE_ASSET_BASE_HPP_ +#include +#include "rive/assets/asset.hpp" +#include "rive/core/field_types/core_bytes_type.hpp" +#include "rive/core/field_types/core_string_type.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +#include "rive/span.hpp" +namespace rive +{ +class FileAssetBase : public Asset +{ +protected: + typedef Asset Super; + +public: + static const uint16_t typeKey = 103; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case FileAssetBase::typeKey: + case AssetBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t assetIdPropertyKey = 204; + static const uint16_t cdnUuidPropertyKey = 359; + static const uint16_t cdnBaseUrlPropertyKey = 362; + +protected: + uint32_t m_AssetId = 0; + std::string m_CdnBaseUrl = "https://public.rive.app/cdn/uuid"; + +public: + inline uint32_t assetId() const { return m_AssetId; } + void assetId(uint32_t value) + { + if (m_AssetId == value) + { + return; + } + m_AssetId = value; + assetIdChanged(); + } + + virtual void decodeCdnUuid(Span value) = 0; + virtual void copyCdnUuid(const FileAssetBase& object) = 0; + + inline const std::string& cdnBaseUrl() const { return m_CdnBaseUrl; } + void cdnBaseUrl(std::string value) + { + if (m_CdnBaseUrl == value) + { + return; + } + m_CdnBaseUrl = value; + cdnBaseUrlChanged(); + } + + void copy(const FileAssetBase& object) + { + m_AssetId = object.m_AssetId; + copyCdnUuid(object); + m_CdnBaseUrl = object.m_CdnBaseUrl; + Asset::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case assetIdPropertyKey: + m_AssetId = CoreUintType::deserialize(reader); + return true; + case cdnUuidPropertyKey: + decodeCdnUuid(CoreBytesType::deserialize(reader)); + return true; + case cdnBaseUrlPropertyKey: + m_CdnBaseUrl = CoreStringType::deserialize(reader); + return true; + } + return Asset::deserialize(propertyKey, reader); + } + +protected: + virtual void assetIdChanged() {} + virtual void cdnUuidChanged() {} + virtual void cdnBaseUrlChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/assets/file_asset_contents_base.hpp b/third_party/rive/include/rive/generated/assets/file_asset_contents_base.hpp new file mode 100644 index 0000000..aff6735 --- /dev/null +++ b/third_party/rive/include/rive/generated/assets/file_asset_contents_base.hpp @@ -0,0 +1,56 @@ +#ifndef _RIVE_FILE_ASSET_CONTENTS_BASE_HPP_ +#define _RIVE_FILE_ASSET_CONTENTS_BASE_HPP_ +#include "rive/core.hpp" +#include "rive/core/field_types/core_bytes_type.hpp" +#include "rive/span.hpp" +namespace rive +{ +class FileAssetContentsBase : public Core +{ +protected: + typedef Core Super; + +public: + static const uint16_t typeKey = 106; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case FileAssetContentsBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t bytesPropertyKey = 212; + +public: + virtual void decodeBytes(Span value) = 0; + virtual void copyBytes(const FileAssetContentsBase& object) = 0; + + Core* clone() const override; + void copy(const FileAssetContentsBase& object) { copyBytes(object); } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case bytesPropertyKey: + decodeBytes(CoreBytesType::deserialize(reader)); + return true; + } + return false; + } + +protected: + virtual void bytesChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/assets/folder_base.hpp b/third_party/rive/include/rive/generated/assets/folder_base.hpp new file mode 100644 index 0000000..66ab4a2 --- /dev/null +++ b/third_party/rive/include/rive/generated/assets/folder_base.hpp @@ -0,0 +1,36 @@ +#ifndef _RIVE_FOLDER_BASE_HPP_ +#define _RIVE_FOLDER_BASE_HPP_ +#include "rive/assets/asset.hpp" +namespace rive +{ +class FolderBase : public Asset +{ +protected: + typedef Asset Super; + +public: + static const uint16_t typeKey = 102; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case FolderBase::typeKey: + case AssetBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/assets/font_asset_base.hpp b/third_party/rive/include/rive/generated/assets/font_asset_base.hpp new file mode 100644 index 0000000..c91e45e --- /dev/null +++ b/third_party/rive/include/rive/generated/assets/font_asset_base.hpp @@ -0,0 +1,37 @@ +#ifndef _RIVE_FONT_ASSET_BASE_HPP_ +#define _RIVE_FONT_ASSET_BASE_HPP_ +#include "rive/assets/file_asset.hpp" +namespace rive +{ +class FontAssetBase : public FileAsset +{ +protected: + typedef FileAsset Super; + +public: + static const uint16_t typeKey = 141; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case FontAssetBase::typeKey: + case FileAssetBase::typeKey: + case AssetBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/assets/image_asset_base.hpp b/third_party/rive/include/rive/generated/assets/image_asset_base.hpp new file mode 100644 index 0000000..43b5775 --- /dev/null +++ b/third_party/rive/include/rive/generated/assets/image_asset_base.hpp @@ -0,0 +1,38 @@ +#ifndef _RIVE_IMAGE_ASSET_BASE_HPP_ +#define _RIVE_IMAGE_ASSET_BASE_HPP_ +#include "rive/assets/drawable_asset.hpp" +namespace rive +{ +class ImageAssetBase : public DrawableAsset +{ +protected: + typedef DrawableAsset Super; + +public: + static const uint16_t typeKey = 105; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case ImageAssetBase::typeKey: + case DrawableAssetBase::typeKey: + case FileAssetBase::typeKey: + case AssetBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/audio_event_base.hpp b/third_party/rive/include/rive/generated/audio_event_base.hpp new file mode 100644 index 0000000..f251306 --- /dev/null +++ b/third_party/rive/include/rive/generated/audio_event_base.hpp @@ -0,0 +1,74 @@ +#ifndef _RIVE_AUDIO_EVENT_BASE_HPP_ +#define _RIVE_AUDIO_EVENT_BASE_HPP_ +#include "rive/core/field_types/core_uint_type.hpp" +#include "rive/event.hpp" +namespace rive +{ +class AudioEventBase : public Event +{ +protected: + typedef Event Super; + +public: + static const uint16_t typeKey = 407; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case AudioEventBase::typeKey: + case EventBase::typeKey: + case CustomPropertyGroupBase::typeKey: + case ContainerComponentBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t assetIdPropertyKey = 408; + +protected: + uint32_t m_AssetId = -1; + +public: + inline uint32_t assetId() const { return m_AssetId; } + void assetId(uint32_t value) + { + if (m_AssetId == value) + { + return; + } + m_AssetId = value; + assetIdChanged(); + } + + Core* clone() const override; + void copy(const AudioEventBase& object) + { + m_AssetId = object.m_AssetId; + Event::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case assetIdPropertyKey: + m_AssetId = CoreUintType::deserialize(reader); + return true; + } + return Event::deserialize(propertyKey, reader); + } + +protected: + virtual void assetIdChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/backboard_base.hpp b/third_party/rive/include/rive/generated/backboard_base.hpp new file mode 100644 index 0000000..26f15ce --- /dev/null +++ b/third_party/rive/include/rive/generated/backboard_base.hpp @@ -0,0 +1,41 @@ +#ifndef _RIVE_BACKBOARD_BASE_HPP_ +#define _RIVE_BACKBOARD_BASE_HPP_ +#include "rive/core.hpp" +namespace rive +{ +class BackboardBase : public Core +{ +protected: + typedef Core Super; + +public: + static const uint16_t typeKey = 23; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case BackboardBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + void copy(const BackboardBase& object) {} + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + return false; + } + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/bones/bone_base.hpp b/third_party/rive/include/rive/generated/bones/bone_base.hpp new file mode 100644 index 0000000..8427ef5 --- /dev/null +++ b/third_party/rive/include/rive/generated/bones/bone_base.hpp @@ -0,0 +1,75 @@ +#ifndef _RIVE_BONE_BASE_HPP_ +#define _RIVE_BONE_BASE_HPP_ +#include "rive/bones/skeletal_component.hpp" +#include "rive/core/field_types/core_double_type.hpp" +namespace rive +{ +class BoneBase : public SkeletalComponent +{ +protected: + typedef SkeletalComponent Super; + +public: + static const uint16_t typeKey = 40; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case BoneBase::typeKey: + case SkeletalComponentBase::typeKey: + case TransformComponentBase::typeKey: + case WorldTransformComponentBase::typeKey: + case ContainerComponentBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t lengthPropertyKey = 89; + +protected: + float m_Length = 0.0f; + +public: + inline float length() const { return m_Length; } + void length(float value) + { + if (m_Length == value) + { + return; + } + m_Length = value; + lengthChanged(); + } + + Core* clone() const override; + void copy(const BoneBase& object) + { + m_Length = object.m_Length; + SkeletalComponent::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case lengthPropertyKey: + m_Length = CoreDoubleType::deserialize(reader); + return true; + } + return SkeletalComponent::deserialize(propertyKey, reader); + } + +protected: + virtual void lengthChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/bones/cubic_weight_base.hpp b/third_party/rive/include/rive/generated/bones/cubic_weight_base.hpp new file mode 100644 index 0000000..ce0be6d --- /dev/null +++ b/third_party/rive/include/rive/generated/bones/cubic_weight_base.hpp @@ -0,0 +1,126 @@ +#ifndef _RIVE_CUBIC_WEIGHT_BASE_HPP_ +#define _RIVE_CUBIC_WEIGHT_BASE_HPP_ +#include "rive/bones/weight.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +namespace rive +{ +class CubicWeightBase : public Weight +{ +protected: + typedef Weight Super; + +public: + static const uint16_t typeKey = 46; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case CubicWeightBase::typeKey: + case WeightBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t inValuesPropertyKey = 110; + static const uint16_t inIndicesPropertyKey = 111; + static const uint16_t outValuesPropertyKey = 112; + static const uint16_t outIndicesPropertyKey = 113; + +protected: + uint32_t m_InValues = 255; + uint32_t m_InIndices = 1; + uint32_t m_OutValues = 255; + uint32_t m_OutIndices = 1; + +public: + inline uint32_t inValues() const { return m_InValues; } + void inValues(uint32_t value) + { + if (m_InValues == value) + { + return; + } + m_InValues = value; + inValuesChanged(); + } + + inline uint32_t inIndices() const { return m_InIndices; } + void inIndices(uint32_t value) + { + if (m_InIndices == value) + { + return; + } + m_InIndices = value; + inIndicesChanged(); + } + + inline uint32_t outValues() const { return m_OutValues; } + void outValues(uint32_t value) + { + if (m_OutValues == value) + { + return; + } + m_OutValues = value; + outValuesChanged(); + } + + inline uint32_t outIndices() const { return m_OutIndices; } + void outIndices(uint32_t value) + { + if (m_OutIndices == value) + { + return; + } + m_OutIndices = value; + outIndicesChanged(); + } + + Core* clone() const override; + void copy(const CubicWeightBase& object) + { + m_InValues = object.m_InValues; + m_InIndices = object.m_InIndices; + m_OutValues = object.m_OutValues; + m_OutIndices = object.m_OutIndices; + Weight::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case inValuesPropertyKey: + m_InValues = CoreUintType::deserialize(reader); + return true; + case inIndicesPropertyKey: + m_InIndices = CoreUintType::deserialize(reader); + return true; + case outValuesPropertyKey: + m_OutValues = CoreUintType::deserialize(reader); + return true; + case outIndicesPropertyKey: + m_OutIndices = CoreUintType::deserialize(reader); + return true; + } + return Weight::deserialize(propertyKey, reader); + } + +protected: + virtual void inValuesChanged() {} + virtual void inIndicesChanged() {} + virtual void outValuesChanged() {} + virtual void outIndicesChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/bones/root_bone_base.hpp b/third_party/rive/include/rive/generated/bones/root_bone_base.hpp new file mode 100644 index 0000000..8827711 --- /dev/null +++ b/third_party/rive/include/rive/generated/bones/root_bone_base.hpp @@ -0,0 +1,94 @@ +#ifndef _RIVE_ROOT_BONE_BASE_HPP_ +#define _RIVE_ROOT_BONE_BASE_HPP_ +#include "rive/bones/bone.hpp" +#include "rive/core/field_types/core_double_type.hpp" +namespace rive +{ +class RootBoneBase : public Bone +{ +protected: + typedef Bone Super; + +public: + static const uint16_t typeKey = 41; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case RootBoneBase::typeKey: + case BoneBase::typeKey: + case SkeletalComponentBase::typeKey: + case TransformComponentBase::typeKey: + case WorldTransformComponentBase::typeKey: + case ContainerComponentBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t xPropertyKey = 90; + static const uint16_t yPropertyKey = 91; + +protected: + float m_X = 0.0f; + float m_Y = 0.0f; + +public: + inline float x() const override { return m_X; } + void x(float value) + { + if (m_X == value) + { + return; + } + m_X = value; + xChanged(); + } + + inline float y() const override { return m_Y; } + void y(float value) + { + if (m_Y == value) + { + return; + } + m_Y = value; + yChanged(); + } + + Core* clone() const override; + void copy(const RootBoneBase& object) + { + m_X = object.m_X; + m_Y = object.m_Y; + Bone::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case xPropertyKey: + m_X = CoreDoubleType::deserialize(reader); + return true; + case yPropertyKey: + m_Y = CoreDoubleType::deserialize(reader); + return true; + } + return Bone::deserialize(propertyKey, reader); + } + +protected: + virtual void xChanged() {} + virtual void yChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/bones/skeletal_component_base.hpp b/third_party/rive/include/rive/generated/bones/skeletal_component_base.hpp new file mode 100644 index 0000000..86d60ca --- /dev/null +++ b/third_party/rive/include/rive/generated/bones/skeletal_component_base.hpp @@ -0,0 +1,37 @@ +#ifndef _RIVE_SKELETAL_COMPONENT_BASE_HPP_ +#define _RIVE_SKELETAL_COMPONENT_BASE_HPP_ +#include "rive/transform_component.hpp" +namespace rive +{ +class SkeletalComponentBase : public TransformComponent +{ +protected: + typedef TransformComponent Super; + +public: + static const uint16_t typeKey = 39; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case SkeletalComponentBase::typeKey: + case TransformComponentBase::typeKey: + case WorldTransformComponentBase::typeKey: + case ContainerComponentBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/bones/skin_base.hpp b/third_party/rive/include/rive/generated/bones/skin_base.hpp new file mode 100644 index 0000000..c5074ad --- /dev/null +++ b/third_party/rive/include/rive/generated/bones/skin_base.hpp @@ -0,0 +1,162 @@ +#ifndef _RIVE_SKIN_BASE_HPP_ +#define _RIVE_SKIN_BASE_HPP_ +#include "rive/container_component.hpp" +#include "rive/core/field_types/core_double_type.hpp" +namespace rive +{ +class SkinBase : public ContainerComponent +{ +protected: + typedef ContainerComponent Super; + +public: + static const uint16_t typeKey = 43; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case SkinBase::typeKey: + case ContainerComponentBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t xxPropertyKey = 104; + static const uint16_t yxPropertyKey = 105; + static const uint16_t xyPropertyKey = 106; + static const uint16_t yyPropertyKey = 107; + static const uint16_t txPropertyKey = 108; + static const uint16_t tyPropertyKey = 109; + +protected: + float m_Xx = 1.0f; + float m_Yx = 0.0f; + float m_Xy = 0.0f; + float m_Yy = 1.0f; + float m_Tx = 0.0f; + float m_Ty = 0.0f; + +public: + inline float xx() const { return m_Xx; } + void xx(float value) + { + if (m_Xx == value) + { + return; + } + m_Xx = value; + xxChanged(); + } + + inline float yx() const { return m_Yx; } + void yx(float value) + { + if (m_Yx == value) + { + return; + } + m_Yx = value; + yxChanged(); + } + + inline float xy() const { return m_Xy; } + void xy(float value) + { + if (m_Xy == value) + { + return; + } + m_Xy = value; + xyChanged(); + } + + inline float yy() const { return m_Yy; } + void yy(float value) + { + if (m_Yy == value) + { + return; + } + m_Yy = value; + yyChanged(); + } + + inline float tx() const { return m_Tx; } + void tx(float value) + { + if (m_Tx == value) + { + return; + } + m_Tx = value; + txChanged(); + } + + inline float ty() const { return m_Ty; } + void ty(float value) + { + if (m_Ty == value) + { + return; + } + m_Ty = value; + tyChanged(); + } + + Core* clone() const override; + void copy(const SkinBase& object) + { + m_Xx = object.m_Xx; + m_Yx = object.m_Yx; + m_Xy = object.m_Xy; + m_Yy = object.m_Yy; + m_Tx = object.m_Tx; + m_Ty = object.m_Ty; + ContainerComponent::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case xxPropertyKey: + m_Xx = CoreDoubleType::deserialize(reader); + return true; + case yxPropertyKey: + m_Yx = CoreDoubleType::deserialize(reader); + return true; + case xyPropertyKey: + m_Xy = CoreDoubleType::deserialize(reader); + return true; + case yyPropertyKey: + m_Yy = CoreDoubleType::deserialize(reader); + return true; + case txPropertyKey: + m_Tx = CoreDoubleType::deserialize(reader); + return true; + case tyPropertyKey: + m_Ty = CoreDoubleType::deserialize(reader); + return true; + } + return ContainerComponent::deserialize(propertyKey, reader); + } + +protected: + virtual void xxChanged() {} + virtual void yxChanged() {} + virtual void xyChanged() {} + virtual void yyChanged() {} + virtual void txChanged() {} + virtual void tyChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/bones/tendon_base.hpp b/third_party/rive/include/rive/generated/bones/tendon_base.hpp new file mode 100644 index 0000000..708b9f2 --- /dev/null +++ b/third_party/rive/include/rive/generated/bones/tendon_base.hpp @@ -0,0 +1,180 @@ +#ifndef _RIVE_TENDON_BASE_HPP_ +#define _RIVE_TENDON_BASE_HPP_ +#include "rive/component.hpp" +#include "rive/core/field_types/core_double_type.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +namespace rive +{ +class TendonBase : public Component +{ +protected: + typedef Component Super; + +public: + static const uint16_t typeKey = 44; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case TendonBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t boneIdPropertyKey = 95; + static const uint16_t xxPropertyKey = 96; + static const uint16_t yxPropertyKey = 97; + static const uint16_t xyPropertyKey = 98; + static const uint16_t yyPropertyKey = 99; + static const uint16_t txPropertyKey = 100; + static const uint16_t tyPropertyKey = 101; + +protected: + uint32_t m_BoneId = -1; + float m_Xx = 1.0f; + float m_Yx = 0.0f; + float m_Xy = 0.0f; + float m_Yy = 1.0f; + float m_Tx = 0.0f; + float m_Ty = 0.0f; + +public: + inline uint32_t boneId() const { return m_BoneId; } + void boneId(uint32_t value) + { + if (m_BoneId == value) + { + return; + } + m_BoneId = value; + boneIdChanged(); + } + + inline float xx() const { return m_Xx; } + void xx(float value) + { + if (m_Xx == value) + { + return; + } + m_Xx = value; + xxChanged(); + } + + inline float yx() const { return m_Yx; } + void yx(float value) + { + if (m_Yx == value) + { + return; + } + m_Yx = value; + yxChanged(); + } + + inline float xy() const { return m_Xy; } + void xy(float value) + { + if (m_Xy == value) + { + return; + } + m_Xy = value; + xyChanged(); + } + + inline float yy() const { return m_Yy; } + void yy(float value) + { + if (m_Yy == value) + { + return; + } + m_Yy = value; + yyChanged(); + } + + inline float tx() const { return m_Tx; } + void tx(float value) + { + if (m_Tx == value) + { + return; + } + m_Tx = value; + txChanged(); + } + + inline float ty() const { return m_Ty; } + void ty(float value) + { + if (m_Ty == value) + { + return; + } + m_Ty = value; + tyChanged(); + } + + Core* clone() const override; + void copy(const TendonBase& object) + { + m_BoneId = object.m_BoneId; + m_Xx = object.m_Xx; + m_Yx = object.m_Yx; + m_Xy = object.m_Xy; + m_Yy = object.m_Yy; + m_Tx = object.m_Tx; + m_Ty = object.m_Ty; + Component::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case boneIdPropertyKey: + m_BoneId = CoreUintType::deserialize(reader); + return true; + case xxPropertyKey: + m_Xx = CoreDoubleType::deserialize(reader); + return true; + case yxPropertyKey: + m_Yx = CoreDoubleType::deserialize(reader); + return true; + case xyPropertyKey: + m_Xy = CoreDoubleType::deserialize(reader); + return true; + case yyPropertyKey: + m_Yy = CoreDoubleType::deserialize(reader); + return true; + case txPropertyKey: + m_Tx = CoreDoubleType::deserialize(reader); + return true; + case tyPropertyKey: + m_Ty = CoreDoubleType::deserialize(reader); + return true; + } + return Component::deserialize(propertyKey, reader); + } + +protected: + virtual void boneIdChanged() {} + virtual void xxChanged() {} + virtual void yxChanged() {} + virtual void xyChanged() {} + virtual void yyChanged() {} + virtual void txChanged() {} + virtual void tyChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/bones/weight_base.hpp b/third_party/rive/include/rive/generated/bones/weight_base.hpp new file mode 100644 index 0000000..37df1c2 --- /dev/null +++ b/third_party/rive/include/rive/generated/bones/weight_base.hpp @@ -0,0 +1,89 @@ +#ifndef _RIVE_WEIGHT_BASE_HPP_ +#define _RIVE_WEIGHT_BASE_HPP_ +#include "rive/component.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +namespace rive +{ +class WeightBase : public Component +{ +protected: + typedef Component Super; + +public: + static const uint16_t typeKey = 45; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case WeightBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t valuesPropertyKey = 102; + static const uint16_t indicesPropertyKey = 103; + +protected: + uint32_t m_Values = 255; + uint32_t m_Indices = 1; + +public: + inline uint32_t values() const { return m_Values; } + void values(uint32_t value) + { + if (m_Values == value) + { + return; + } + m_Values = value; + valuesChanged(); + } + + inline uint32_t indices() const { return m_Indices; } + void indices(uint32_t value) + { + if (m_Indices == value) + { + return; + } + m_Indices = value; + indicesChanged(); + } + + Core* clone() const override; + void copy(const WeightBase& object) + { + m_Values = object.m_Values; + m_Indices = object.m_Indices; + Component::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case valuesPropertyKey: + m_Values = CoreUintType::deserialize(reader); + return true; + case indicesPropertyKey: + m_Indices = CoreUintType::deserialize(reader); + return true; + } + return Component::deserialize(propertyKey, reader); + } + +protected: + virtual void valuesChanged() {} + virtual void indicesChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/component_base.hpp b/third_party/rive/include/rive/generated/component_base.hpp new file mode 100644 index 0000000..6f8e366 --- /dev/null +++ b/third_party/rive/include/rive/generated/component_base.hpp @@ -0,0 +1,88 @@ +#ifndef _RIVE_COMPONENT_BASE_HPP_ +#define _RIVE_COMPONENT_BASE_HPP_ +#include +#include "rive/core.hpp" +#include "rive/core/field_types/core_string_type.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +namespace rive +{ +class ComponentBase : public Core +{ +protected: + typedef Core Super; + +public: + static const uint16_t typeKey = 10; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t namePropertyKey = 4; + static const uint16_t parentIdPropertyKey = 5; + +protected: + std::string m_Name = ""; + uint32_t m_ParentId = 0; + +public: + inline const std::string& name() const { return m_Name; } + void name(std::string value) + { + if (m_Name == value) + { + return; + } + m_Name = value; + nameChanged(); + } + + inline uint32_t parentId() const { return m_ParentId; } + void parentId(uint32_t value) + { + if (m_ParentId == value) + { + return; + } + m_ParentId = value; + parentIdChanged(); + } + + void copy(const ComponentBase& object) + { + m_Name = object.m_Name; + m_ParentId = object.m_ParentId; + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case namePropertyKey: + m_Name = CoreStringType::deserialize(reader); + return true; + case parentIdPropertyKey: + m_ParentId = CoreUintType::deserialize(reader); + return true; + } + return false; + } + +protected: + virtual void nameChanged() {} + virtual void parentIdChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/constraints/constraint_base.hpp b/third_party/rive/include/rive/generated/constraints/constraint_base.hpp new file mode 100644 index 0000000..bc6cacc --- /dev/null +++ b/third_party/rive/include/rive/generated/constraints/constraint_base.hpp @@ -0,0 +1,70 @@ +#ifndef _RIVE_CONSTRAINT_BASE_HPP_ +#define _RIVE_CONSTRAINT_BASE_HPP_ +#include "rive/component.hpp" +#include "rive/core/field_types/core_double_type.hpp" +namespace rive +{ +class ConstraintBase : public Component +{ +protected: + typedef Component Super; + +public: + static const uint16_t typeKey = 79; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case ConstraintBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t strengthPropertyKey = 172; + +protected: + float m_Strength = 1.0f; + +public: + inline float strength() const { return m_Strength; } + void strength(float value) + { + if (m_Strength == value) + { + return; + } + m_Strength = value; + strengthChanged(); + } + + void copy(const ConstraintBase& object) + { + m_Strength = object.m_Strength; + Component::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case strengthPropertyKey: + m_Strength = CoreDoubleType::deserialize(reader); + return true; + } + return Component::deserialize(propertyKey, reader); + } + +protected: + virtual void strengthChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/constraints/distance_constraint_base.hpp b/third_party/rive/include/rive/generated/constraints/distance_constraint_base.hpp new file mode 100644 index 0000000..a7f70ae --- /dev/null +++ b/third_party/rive/include/rive/generated/constraints/distance_constraint_base.hpp @@ -0,0 +1,92 @@ +#ifndef _RIVE_DISTANCE_CONSTRAINT_BASE_HPP_ +#define _RIVE_DISTANCE_CONSTRAINT_BASE_HPP_ +#include "rive/constraints/targeted_constraint.hpp" +#include "rive/core/field_types/core_double_type.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +namespace rive +{ +class DistanceConstraintBase : public TargetedConstraint +{ +protected: + typedef TargetedConstraint Super; + +public: + static const uint16_t typeKey = 82; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case DistanceConstraintBase::typeKey: + case TargetedConstraintBase::typeKey: + case ConstraintBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t distancePropertyKey = 177; + static const uint16_t modeValuePropertyKey = 178; + +protected: + float m_Distance = 100.0f; + uint32_t m_ModeValue = 0; + +public: + inline float distance() const { return m_Distance; } + void distance(float value) + { + if (m_Distance == value) + { + return; + } + m_Distance = value; + distanceChanged(); + } + + inline uint32_t modeValue() const { return m_ModeValue; } + void modeValue(uint32_t value) + { + if (m_ModeValue == value) + { + return; + } + m_ModeValue = value; + modeValueChanged(); + } + + Core* clone() const override; + void copy(const DistanceConstraintBase& object) + { + m_Distance = object.m_Distance; + m_ModeValue = object.m_ModeValue; + TargetedConstraint::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case distancePropertyKey: + m_Distance = CoreDoubleType::deserialize(reader); + return true; + case modeValuePropertyKey: + m_ModeValue = CoreUintType::deserialize(reader); + return true; + } + return TargetedConstraint::deserialize(propertyKey, reader); + } + +protected: + virtual void distanceChanged() {} + virtual void modeValueChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/constraints/draggable_constraint_base.hpp b/third_party/rive/include/rive/generated/constraints/draggable_constraint_base.hpp new file mode 100644 index 0000000..b4715dc --- /dev/null +++ b/third_party/rive/include/rive/generated/constraints/draggable_constraint_base.hpp @@ -0,0 +1,71 @@ +#ifndef _RIVE_DRAGGABLE_CONSTRAINT_BASE_HPP_ +#define _RIVE_DRAGGABLE_CONSTRAINT_BASE_HPP_ +#include "rive/constraints/constraint.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +namespace rive +{ +class DraggableConstraintBase : public Constraint +{ +protected: + typedef Constraint Super; + +public: + static const uint16_t typeKey = 520; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case DraggableConstraintBase::typeKey: + case ConstraintBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t directionValuePropertyKey = 722; + +protected: + uint32_t m_DirectionValue = 1; + +public: + inline uint32_t directionValue() const { return m_DirectionValue; } + void directionValue(uint32_t value) + { + if (m_DirectionValue == value) + { + return; + } + m_DirectionValue = value; + directionValueChanged(); + } + + void copy(const DraggableConstraintBase& object) + { + m_DirectionValue = object.m_DirectionValue; + Constraint::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case directionValuePropertyKey: + m_DirectionValue = CoreUintType::deserialize(reader); + return true; + } + return Constraint::deserialize(propertyKey, reader); + } + +protected: + virtual void directionValueChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/constraints/follow_path_constraint_base.hpp b/third_party/rive/include/rive/generated/constraints/follow_path_constraint_base.hpp new file mode 100644 index 0000000..26253f4 --- /dev/null +++ b/third_party/rive/include/rive/generated/constraints/follow_path_constraint_base.hpp @@ -0,0 +1,111 @@ +#ifndef _RIVE_FOLLOW_PATH_CONSTRAINT_BASE_HPP_ +#define _RIVE_FOLLOW_PATH_CONSTRAINT_BASE_HPP_ +#include "rive/constraints/transform_space_constraint.hpp" +#include "rive/core/field_types/core_bool_type.hpp" +#include "rive/core/field_types/core_double_type.hpp" +namespace rive +{ +class FollowPathConstraintBase : public TransformSpaceConstraint +{ +protected: + typedef TransformSpaceConstraint Super; + +public: + static const uint16_t typeKey = 165; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case FollowPathConstraintBase::typeKey: + case TransformSpaceConstraintBase::typeKey: + case TargetedConstraintBase::typeKey: + case ConstraintBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t distancePropertyKey = 363; + static const uint16_t orientPropertyKey = 364; + static const uint16_t offsetPropertyKey = 365; + +protected: + float m_Distance = 0.0f; + bool m_Orient = true; + bool m_Offset = false; + +public: + inline float distance() const { return m_Distance; } + void distance(float value) + { + if (m_Distance == value) + { + return; + } + m_Distance = value; + distanceChanged(); + } + + inline bool orient() const { return m_Orient; } + void orient(bool value) + { + if (m_Orient == value) + { + return; + } + m_Orient = value; + orientChanged(); + } + + inline bool offset() const { return m_Offset; } + void offset(bool value) + { + if (m_Offset == value) + { + return; + } + m_Offset = value; + offsetChanged(); + } + + Core* clone() const override; + void copy(const FollowPathConstraintBase& object) + { + m_Distance = object.m_Distance; + m_Orient = object.m_Orient; + m_Offset = object.m_Offset; + TransformSpaceConstraint::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case distancePropertyKey: + m_Distance = CoreDoubleType::deserialize(reader); + return true; + case orientPropertyKey: + m_Orient = CoreBoolType::deserialize(reader); + return true; + case offsetPropertyKey: + m_Offset = CoreBoolType::deserialize(reader); + return true; + } + return TransformSpaceConstraint::deserialize(propertyKey, reader); + } + +protected: + virtual void distanceChanged() {} + virtual void orientChanged() {} + virtual void offsetChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/constraints/ik_constraint_base.hpp b/third_party/rive/include/rive/generated/constraints/ik_constraint_base.hpp new file mode 100644 index 0000000..4e30830 --- /dev/null +++ b/third_party/rive/include/rive/generated/constraints/ik_constraint_base.hpp @@ -0,0 +1,92 @@ +#ifndef _RIVE_I_KCONSTRAINT_BASE_HPP_ +#define _RIVE_I_KCONSTRAINT_BASE_HPP_ +#include "rive/constraints/targeted_constraint.hpp" +#include "rive/core/field_types/core_bool_type.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +namespace rive +{ +class IKConstraintBase : public TargetedConstraint +{ +protected: + typedef TargetedConstraint Super; + +public: + static const uint16_t typeKey = 81; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case IKConstraintBase::typeKey: + case TargetedConstraintBase::typeKey: + case ConstraintBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t invertDirectionPropertyKey = 174; + static const uint16_t parentBoneCountPropertyKey = 175; + +protected: + bool m_InvertDirection = false; + uint32_t m_ParentBoneCount = 0; + +public: + inline bool invertDirection() const { return m_InvertDirection; } + void invertDirection(bool value) + { + if (m_InvertDirection == value) + { + return; + } + m_InvertDirection = value; + invertDirectionChanged(); + } + + inline uint32_t parentBoneCount() const { return m_ParentBoneCount; } + void parentBoneCount(uint32_t value) + { + if (m_ParentBoneCount == value) + { + return; + } + m_ParentBoneCount = value; + parentBoneCountChanged(); + } + + Core* clone() const override; + void copy(const IKConstraintBase& object) + { + m_InvertDirection = object.m_InvertDirection; + m_ParentBoneCount = object.m_ParentBoneCount; + TargetedConstraint::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case invertDirectionPropertyKey: + m_InvertDirection = CoreBoolType::deserialize(reader); + return true; + case parentBoneCountPropertyKey: + m_ParentBoneCount = CoreUintType::deserialize(reader); + return true; + } + return TargetedConstraint::deserialize(propertyKey, reader); + } + +protected: + virtual void invertDirectionChanged() {} + virtual void parentBoneCountChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/constraints/rotation_constraint_base.hpp b/third_party/rive/include/rive/generated/constraints/rotation_constraint_base.hpp new file mode 100644 index 0000000..e056582 --- /dev/null +++ b/third_party/rive/include/rive/generated/constraints/rotation_constraint_base.hpp @@ -0,0 +1,40 @@ +#ifndef _RIVE_ROTATION_CONSTRAINT_BASE_HPP_ +#define _RIVE_ROTATION_CONSTRAINT_BASE_HPP_ +#include "rive/constraints/transform_component_constraint.hpp" +namespace rive +{ +class RotationConstraintBase : public TransformComponentConstraint +{ +protected: + typedef TransformComponentConstraint Super; + +public: + static const uint16_t typeKey = 89; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case RotationConstraintBase::typeKey: + case TransformComponentConstraintBase::typeKey: + case TransformSpaceConstraintBase::typeKey: + case TargetedConstraintBase::typeKey: + case ConstraintBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/constraints/scale_constraint_base.hpp b/third_party/rive/include/rive/generated/constraints/scale_constraint_base.hpp new file mode 100644 index 0000000..207bb8d --- /dev/null +++ b/third_party/rive/include/rive/generated/constraints/scale_constraint_base.hpp @@ -0,0 +1,41 @@ +#ifndef _RIVE_SCALE_CONSTRAINT_BASE_HPP_ +#define _RIVE_SCALE_CONSTRAINT_BASE_HPP_ +#include "rive/constraints/transform_component_constraint_y.hpp" +namespace rive +{ +class ScaleConstraintBase : public TransformComponentConstraintY +{ +protected: + typedef TransformComponentConstraintY Super; + +public: + static const uint16_t typeKey = 88; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case ScaleConstraintBase::typeKey: + case TransformComponentConstraintYBase::typeKey: + case TransformComponentConstraintBase::typeKey: + case TransformSpaceConstraintBase::typeKey: + case TargetedConstraintBase::typeKey: + case ConstraintBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/constraints/scrolling/clamped_scroll_physics_base.hpp b/third_party/rive/include/rive/generated/constraints/scrolling/clamped_scroll_physics_base.hpp new file mode 100644 index 0000000..45e4064 --- /dev/null +++ b/third_party/rive/include/rive/generated/constraints/scrolling/clamped_scroll_physics_base.hpp @@ -0,0 +1,37 @@ +#ifndef _RIVE_CLAMPED_SCROLL_PHYSICS_BASE_HPP_ +#define _RIVE_CLAMPED_SCROLL_PHYSICS_BASE_HPP_ +#include "rive/constraints/scrolling/scroll_physics.hpp" +namespace rive +{ +class ClampedScrollPhysicsBase : public ScrollPhysics +{ +protected: + typedef ScrollPhysics Super; + +public: + static const uint16_t typeKey = 524; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case ClampedScrollPhysicsBase::typeKey: + case ScrollPhysicsBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/constraints/scrolling/elastic_scroll_physics_base.hpp b/third_party/rive/include/rive/generated/constraints/scrolling/elastic_scroll_physics_base.hpp new file mode 100644 index 0000000..142715a --- /dev/null +++ b/third_party/rive/include/rive/generated/constraints/scrolling/elastic_scroll_physics_base.hpp @@ -0,0 +1,108 @@ +#ifndef _RIVE_ELASTIC_SCROLL_PHYSICS_BASE_HPP_ +#define _RIVE_ELASTIC_SCROLL_PHYSICS_BASE_HPP_ +#include "rive/constraints/scrolling/scroll_physics.hpp" +#include "rive/core/field_types/core_double_type.hpp" +namespace rive +{ +class ElasticScrollPhysicsBase : public ScrollPhysics +{ +protected: + typedef ScrollPhysics Super; + +public: + static const uint16_t typeKey = 525; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case ElasticScrollPhysicsBase::typeKey: + case ScrollPhysicsBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t frictionPropertyKey = 728; + static const uint16_t speedMultiplierPropertyKey = 729; + static const uint16_t elasticFactorPropertyKey = 730; + +protected: + float m_Friction = 8.0f; + float m_SpeedMultiplier = 1.0f; + float m_ElasticFactor = 0.66f; + +public: + inline float friction() const { return m_Friction; } + void friction(float value) + { + if (m_Friction == value) + { + return; + } + m_Friction = value; + frictionChanged(); + } + + inline float speedMultiplier() const { return m_SpeedMultiplier; } + void speedMultiplier(float value) + { + if (m_SpeedMultiplier == value) + { + return; + } + m_SpeedMultiplier = value; + speedMultiplierChanged(); + } + + inline float elasticFactor() const { return m_ElasticFactor; } + void elasticFactor(float value) + { + if (m_ElasticFactor == value) + { + return; + } + m_ElasticFactor = value; + elasticFactorChanged(); + } + + Core* clone() const override; + void copy(const ElasticScrollPhysicsBase& object) + { + m_Friction = object.m_Friction; + m_SpeedMultiplier = object.m_SpeedMultiplier; + m_ElasticFactor = object.m_ElasticFactor; + ScrollPhysics::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case frictionPropertyKey: + m_Friction = CoreDoubleType::deserialize(reader); + return true; + case speedMultiplierPropertyKey: + m_SpeedMultiplier = CoreDoubleType::deserialize(reader); + return true; + case elasticFactorPropertyKey: + m_ElasticFactor = CoreDoubleType::deserialize(reader); + return true; + } + return ScrollPhysics::deserialize(propertyKey, reader); + } + +protected: + virtual void frictionChanged() {} + virtual void speedMultiplierChanged() {} + virtual void elasticFactorChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/constraints/scrolling/scroll_bar_constraint_base.hpp b/third_party/rive/include/rive/generated/constraints/scrolling/scroll_bar_constraint_base.hpp new file mode 100644 index 0000000..f8c4ab0 --- /dev/null +++ b/third_party/rive/include/rive/generated/constraints/scrolling/scroll_bar_constraint_base.hpp @@ -0,0 +1,92 @@ +#ifndef _RIVE_SCROLL_BAR_CONSTRAINT_BASE_HPP_ +#define _RIVE_SCROLL_BAR_CONSTRAINT_BASE_HPP_ +#include "rive/constraints/draggable_constraint.hpp" +#include "rive/core/field_types/core_bool_type.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +namespace rive +{ +class ScrollBarConstraintBase : public DraggableConstraint +{ +protected: + typedef DraggableConstraint Super; + +public: + static const uint16_t typeKey = 522; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case ScrollBarConstraintBase::typeKey: + case DraggableConstraintBase::typeKey: + case ConstraintBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t scrollConstraintIdPropertyKey = 725; + static const uint16_t autoSizePropertyKey = 734; + +protected: + uint32_t m_ScrollConstraintId = -1; + bool m_AutoSize = true; + +public: + inline uint32_t scrollConstraintId() const { return m_ScrollConstraintId; } + void scrollConstraintId(uint32_t value) + { + if (m_ScrollConstraintId == value) + { + return; + } + m_ScrollConstraintId = value; + scrollConstraintIdChanged(); + } + + inline bool autoSize() const { return m_AutoSize; } + void autoSize(bool value) + { + if (m_AutoSize == value) + { + return; + } + m_AutoSize = value; + autoSizeChanged(); + } + + Core* clone() const override; + void copy(const ScrollBarConstraintBase& object) + { + m_ScrollConstraintId = object.m_ScrollConstraintId; + m_AutoSize = object.m_AutoSize; + DraggableConstraint::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case scrollConstraintIdPropertyKey: + m_ScrollConstraintId = CoreUintType::deserialize(reader); + return true; + case autoSizePropertyKey: + m_AutoSize = CoreBoolType::deserialize(reader); + return true; + } + return DraggableConstraint::deserialize(propertyKey, reader); + } + +protected: + virtual void scrollConstraintIdChanged() {} + virtual void autoSizeChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/constraints/scrolling/scroll_constraint_base.hpp b/third_party/rive/include/rive/generated/constraints/scrolling/scroll_constraint_base.hpp new file mode 100644 index 0000000..fe59097 --- /dev/null +++ b/third_party/rive/include/rive/generated/constraints/scrolling/scroll_constraint_base.hpp @@ -0,0 +1,189 @@ +#ifndef _RIVE_SCROLL_CONSTRAINT_BASE_HPP_ +#define _RIVE_SCROLL_CONSTRAINT_BASE_HPP_ +#include "rive/constraints/draggable_constraint.hpp" +#include "rive/core/field_types/core_bool_type.hpp" +#include "rive/core/field_types/core_double_type.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +namespace rive +{ +class ScrollConstraintBase : public DraggableConstraint +{ +protected: + typedef DraggableConstraint Super; + +public: + static const uint16_t typeKey = 521; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case ScrollConstraintBase::typeKey: + case DraggableConstraintBase::typeKey: + case ConstraintBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t scrollOffsetXPropertyKey = 759; + static const uint16_t scrollOffsetYPropertyKey = 760; + static const uint16_t scrollPercentXPropertyKey = 761; + static const uint16_t scrollPercentYPropertyKey = 762; + static const uint16_t scrollIndexPropertyKey = 763; + static const uint16_t snapPropertyKey = 724; + static const uint16_t physicsTypeValuePropertyKey = 727; + static const uint16_t physicsIdPropertyKey = 726; + +protected: + float m_ScrollOffsetX = 0.0f; + float m_ScrollOffsetY = 0.0f; + bool m_Snap = false; + uint32_t m_PhysicsTypeValue = 0; + uint32_t m_PhysicsId = -1; + +public: + inline float scrollOffsetX() const { return m_ScrollOffsetX; } + void scrollOffsetX(float value) + { + if (m_ScrollOffsetX == value) + { + return; + } + m_ScrollOffsetX = value; + scrollOffsetXChanged(); + } + + inline float scrollOffsetY() const { return m_ScrollOffsetY; } + void scrollOffsetY(float value) + { + if (m_ScrollOffsetY == value) + { + return; + } + m_ScrollOffsetY = value; + scrollOffsetYChanged(); + } + + virtual void setScrollPercentX(float value) = 0; + virtual float scrollPercentX() = 0; + void scrollPercentX(float value) + { + if (scrollPercentX() == value) + { + return; + } + setScrollPercentX(value); + scrollPercentXChanged(); + } + + virtual void setScrollPercentY(float value) = 0; + virtual float scrollPercentY() = 0; + void scrollPercentY(float value) + { + if (scrollPercentY() == value) + { + return; + } + setScrollPercentY(value); + scrollPercentYChanged(); + } + + virtual void setScrollIndex(float value) = 0; + virtual float scrollIndex() = 0; + void scrollIndex(float value) + { + if (scrollIndex() == value) + { + return; + } + setScrollIndex(value); + scrollIndexChanged(); + } + + inline bool snap() const { return m_Snap; } + void snap(bool value) + { + if (m_Snap == value) + { + return; + } + m_Snap = value; + snapChanged(); + } + + inline uint32_t physicsTypeValue() const { return m_PhysicsTypeValue; } + void physicsTypeValue(uint32_t value) + { + if (m_PhysicsTypeValue == value) + { + return; + } + m_PhysicsTypeValue = value; + physicsTypeValueChanged(); + } + + inline uint32_t physicsId() const { return m_PhysicsId; } + void physicsId(uint32_t value) + { + if (m_PhysicsId == value) + { + return; + } + m_PhysicsId = value; + physicsIdChanged(); + } + + Core* clone() const override; + void copy(const ScrollConstraintBase& object) + { + m_ScrollOffsetX = object.m_ScrollOffsetX; + m_ScrollOffsetY = object.m_ScrollOffsetY; + m_Snap = object.m_Snap; + m_PhysicsTypeValue = object.m_PhysicsTypeValue; + m_PhysicsId = object.m_PhysicsId; + DraggableConstraint::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case scrollOffsetXPropertyKey: + m_ScrollOffsetX = CoreDoubleType::deserialize(reader); + return true; + case scrollOffsetYPropertyKey: + m_ScrollOffsetY = CoreDoubleType::deserialize(reader); + return true; + case snapPropertyKey: + m_Snap = CoreBoolType::deserialize(reader); + return true; + case physicsTypeValuePropertyKey: + m_PhysicsTypeValue = CoreUintType::deserialize(reader); + return true; + case physicsIdPropertyKey: + m_PhysicsId = CoreUintType::deserialize(reader); + return true; + } + return DraggableConstraint::deserialize(propertyKey, reader); + } + +protected: + virtual void scrollOffsetXChanged() {} + virtual void scrollOffsetYChanged() {} + virtual void scrollPercentXChanged() {} + virtual void scrollPercentYChanged() {} + virtual void scrollIndexChanged() {} + virtual void snapChanged() {} + virtual void physicsTypeValueChanged() {} + virtual void physicsIdChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/constraints/scrolling/scroll_physics_base.hpp b/third_party/rive/include/rive/generated/constraints/scrolling/scroll_physics_base.hpp new file mode 100644 index 0000000..03c4806 --- /dev/null +++ b/third_party/rive/include/rive/generated/constraints/scrolling/scroll_physics_base.hpp @@ -0,0 +1,70 @@ +#ifndef _RIVE_SCROLL_PHYSICS_BASE_HPP_ +#define _RIVE_SCROLL_PHYSICS_BASE_HPP_ +#include "rive/component.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +namespace rive +{ +class ScrollPhysicsBase : public Component +{ +protected: + typedef Component Super; + +public: + static const uint16_t typeKey = 523; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case ScrollPhysicsBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t constraintIdPropertyKey = 731; + +protected: + uint32_t m_ConstraintId = -1; + +public: + inline uint32_t constraintId() const { return m_ConstraintId; } + void constraintId(uint32_t value) + { + if (m_ConstraintId == value) + { + return; + } + m_ConstraintId = value; + constraintIdChanged(); + } + + void copy(const ScrollPhysicsBase& object) + { + m_ConstraintId = object.m_ConstraintId; + Component::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case constraintIdPropertyKey: + m_ConstraintId = CoreUintType::deserialize(reader); + return true; + } + return Component::deserialize(propertyKey, reader); + } + +protected: + virtual void constraintIdChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/constraints/targeted_constraint_base.hpp b/third_party/rive/include/rive/generated/constraints/targeted_constraint_base.hpp new file mode 100644 index 0000000..2c8da22 --- /dev/null +++ b/third_party/rive/include/rive/generated/constraints/targeted_constraint_base.hpp @@ -0,0 +1,71 @@ +#ifndef _RIVE_TARGETED_CONSTRAINT_BASE_HPP_ +#define _RIVE_TARGETED_CONSTRAINT_BASE_HPP_ +#include "rive/constraints/constraint.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +namespace rive +{ +class TargetedConstraintBase : public Constraint +{ +protected: + typedef Constraint Super; + +public: + static const uint16_t typeKey = 80; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case TargetedConstraintBase::typeKey: + case ConstraintBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t targetIdPropertyKey = 173; + +protected: + uint32_t m_TargetId = -1; + +public: + inline uint32_t targetId() const { return m_TargetId; } + void targetId(uint32_t value) + { + if (m_TargetId == value) + { + return; + } + m_TargetId = value; + targetIdChanged(); + } + + void copy(const TargetedConstraintBase& object) + { + m_TargetId = object.m_TargetId; + Constraint::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case targetIdPropertyKey: + m_TargetId = CoreUintType::deserialize(reader); + return true; + } + return Constraint::deserialize(propertyKey, reader); + } + +protected: + virtual void targetIdChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/constraints/transform_component_constraint_base.hpp b/third_party/rive/include/rive/generated/constraints/transform_component_constraint_base.hpp new file mode 100644 index 0000000..69898eb --- /dev/null +++ b/third_party/rive/include/rive/generated/constraints/transform_component_constraint_base.hpp @@ -0,0 +1,201 @@ +#ifndef _RIVE_TRANSFORM_COMPONENT_CONSTRAINT_BASE_HPP_ +#define _RIVE_TRANSFORM_COMPONENT_CONSTRAINT_BASE_HPP_ +#include "rive/constraints/transform_space_constraint.hpp" +#include "rive/core/field_types/core_bool_type.hpp" +#include "rive/core/field_types/core_double_type.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +namespace rive +{ +class TransformComponentConstraintBase : public TransformSpaceConstraint +{ +protected: + typedef TransformSpaceConstraint Super; + +public: + static const uint16_t typeKey = 85; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case TransformComponentConstraintBase::typeKey: + case TransformSpaceConstraintBase::typeKey: + case TargetedConstraintBase::typeKey: + case ConstraintBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t minMaxSpaceValuePropertyKey = 195; + static const uint16_t copyFactorPropertyKey = 182; + static const uint16_t minValuePropertyKey = 183; + static const uint16_t maxValuePropertyKey = 184; + static const uint16_t offsetPropertyKey = 188; + static const uint16_t doesCopyPropertyKey = 189; + static const uint16_t minPropertyKey = 190; + static const uint16_t maxPropertyKey = 191; + +protected: + uint32_t m_MinMaxSpaceValue = 0; + float m_CopyFactor = 1.0f; + float m_MinValue = 0.0f; + float m_MaxValue = 0.0f; + bool m_Offset = false; + bool m_DoesCopy = true; + bool m_Min = false; + bool m_Max = false; + +public: + inline uint32_t minMaxSpaceValue() const { return m_MinMaxSpaceValue; } + void minMaxSpaceValue(uint32_t value) + { + if (m_MinMaxSpaceValue == value) + { + return; + } + m_MinMaxSpaceValue = value; + minMaxSpaceValueChanged(); + } + + inline float copyFactor() const { return m_CopyFactor; } + void copyFactor(float value) + { + if (m_CopyFactor == value) + { + return; + } + m_CopyFactor = value; + copyFactorChanged(); + } + + inline float minValue() const { return m_MinValue; } + void minValue(float value) + { + if (m_MinValue == value) + { + return; + } + m_MinValue = value; + minValueChanged(); + } + + inline float maxValue() const { return m_MaxValue; } + void maxValue(float value) + { + if (m_MaxValue == value) + { + return; + } + m_MaxValue = value; + maxValueChanged(); + } + + inline bool offset() const { return m_Offset; } + void offset(bool value) + { + if (m_Offset == value) + { + return; + } + m_Offset = value; + offsetChanged(); + } + + inline bool doesCopy() const { return m_DoesCopy; } + void doesCopy(bool value) + { + if (m_DoesCopy == value) + { + return; + } + m_DoesCopy = value; + doesCopyChanged(); + } + + inline bool min() const { return m_Min; } + void min(bool value) + { + if (m_Min == value) + { + return; + } + m_Min = value; + minChanged(); + } + + inline bool max() const { return m_Max; } + void max(bool value) + { + if (m_Max == value) + { + return; + } + m_Max = value; + maxChanged(); + } + + void copy(const TransformComponentConstraintBase& object) + { + m_MinMaxSpaceValue = object.m_MinMaxSpaceValue; + m_CopyFactor = object.m_CopyFactor; + m_MinValue = object.m_MinValue; + m_MaxValue = object.m_MaxValue; + m_Offset = object.m_Offset; + m_DoesCopy = object.m_DoesCopy; + m_Min = object.m_Min; + m_Max = object.m_Max; + TransformSpaceConstraint::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case minMaxSpaceValuePropertyKey: + m_MinMaxSpaceValue = CoreUintType::deserialize(reader); + return true; + case copyFactorPropertyKey: + m_CopyFactor = CoreDoubleType::deserialize(reader); + return true; + case minValuePropertyKey: + m_MinValue = CoreDoubleType::deserialize(reader); + return true; + case maxValuePropertyKey: + m_MaxValue = CoreDoubleType::deserialize(reader); + return true; + case offsetPropertyKey: + m_Offset = CoreBoolType::deserialize(reader); + return true; + case doesCopyPropertyKey: + m_DoesCopy = CoreBoolType::deserialize(reader); + return true; + case minPropertyKey: + m_Min = CoreBoolType::deserialize(reader); + return true; + case maxPropertyKey: + m_Max = CoreBoolType::deserialize(reader); + return true; + } + return TransformSpaceConstraint::deserialize(propertyKey, reader); + } + +protected: + virtual void minMaxSpaceValueChanged() {} + virtual void copyFactorChanged() {} + virtual void minValueChanged() {} + virtual void maxValueChanged() {} + virtual void offsetChanged() {} + virtual void doesCopyChanged() {} + virtual void minChanged() {} + virtual void maxChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/constraints/transform_component_constraint_y_base.hpp b/third_party/rive/include/rive/generated/constraints/transform_component_constraint_y_base.hpp new file mode 100644 index 0000000..1b029a1 --- /dev/null +++ b/third_party/rive/include/rive/generated/constraints/transform_component_constraint_y_base.hpp @@ -0,0 +1,165 @@ +#ifndef _RIVE_TRANSFORM_COMPONENT_CONSTRAINT_YBASE_HPP_ +#define _RIVE_TRANSFORM_COMPONENT_CONSTRAINT_YBASE_HPP_ +#include "rive/constraints/transform_component_constraint.hpp" +#include "rive/core/field_types/core_bool_type.hpp" +#include "rive/core/field_types/core_double_type.hpp" +namespace rive +{ +class TransformComponentConstraintYBase : public TransformComponentConstraint +{ +protected: + typedef TransformComponentConstraint Super; + +public: + static const uint16_t typeKey = 86; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case TransformComponentConstraintYBase::typeKey: + case TransformComponentConstraintBase::typeKey: + case TransformSpaceConstraintBase::typeKey: + case TargetedConstraintBase::typeKey: + case ConstraintBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t copyFactorYPropertyKey = 185; + static const uint16_t minValueYPropertyKey = 186; + static const uint16_t maxValueYPropertyKey = 187; + static const uint16_t doesCopyYPropertyKey = 192; + static const uint16_t minYPropertyKey = 193; + static const uint16_t maxYPropertyKey = 194; + +protected: + float m_CopyFactorY = 1.0f; + float m_MinValueY = 0.0f; + float m_MaxValueY = 0.0f; + bool m_DoesCopyY = true; + bool m_MinY = false; + bool m_MaxY = false; + +public: + inline float copyFactorY() const { return m_CopyFactorY; } + void copyFactorY(float value) + { + if (m_CopyFactorY == value) + { + return; + } + m_CopyFactorY = value; + copyFactorYChanged(); + } + + inline float minValueY() const { return m_MinValueY; } + void minValueY(float value) + { + if (m_MinValueY == value) + { + return; + } + m_MinValueY = value; + minValueYChanged(); + } + + inline float maxValueY() const { return m_MaxValueY; } + void maxValueY(float value) + { + if (m_MaxValueY == value) + { + return; + } + m_MaxValueY = value; + maxValueYChanged(); + } + + inline bool doesCopyY() const { return m_DoesCopyY; } + void doesCopyY(bool value) + { + if (m_DoesCopyY == value) + { + return; + } + m_DoesCopyY = value; + doesCopyYChanged(); + } + + inline bool minY() const { return m_MinY; } + void minY(bool value) + { + if (m_MinY == value) + { + return; + } + m_MinY = value; + minYChanged(); + } + + inline bool maxY() const { return m_MaxY; } + void maxY(bool value) + { + if (m_MaxY == value) + { + return; + } + m_MaxY = value; + maxYChanged(); + } + + void copy(const TransformComponentConstraintYBase& object) + { + m_CopyFactorY = object.m_CopyFactorY; + m_MinValueY = object.m_MinValueY; + m_MaxValueY = object.m_MaxValueY; + m_DoesCopyY = object.m_DoesCopyY; + m_MinY = object.m_MinY; + m_MaxY = object.m_MaxY; + TransformComponentConstraint::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case copyFactorYPropertyKey: + m_CopyFactorY = CoreDoubleType::deserialize(reader); + return true; + case minValueYPropertyKey: + m_MinValueY = CoreDoubleType::deserialize(reader); + return true; + case maxValueYPropertyKey: + m_MaxValueY = CoreDoubleType::deserialize(reader); + return true; + case doesCopyYPropertyKey: + m_DoesCopyY = CoreBoolType::deserialize(reader); + return true; + case minYPropertyKey: + m_MinY = CoreBoolType::deserialize(reader); + return true; + case maxYPropertyKey: + m_MaxY = CoreBoolType::deserialize(reader); + return true; + } + return TransformComponentConstraint::deserialize(propertyKey, reader); + } + +protected: + virtual void copyFactorYChanged() {} + virtual void minValueYChanged() {} + virtual void maxValueYChanged() {} + virtual void doesCopyYChanged() {} + virtual void minYChanged() {} + virtual void maxYChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/constraints/transform_constraint_base.hpp b/third_party/rive/include/rive/generated/constraints/transform_constraint_base.hpp new file mode 100644 index 0000000..e0bf5c8 --- /dev/null +++ b/third_party/rive/include/rive/generated/constraints/transform_constraint_base.hpp @@ -0,0 +1,92 @@ +#ifndef _RIVE_TRANSFORM_CONSTRAINT_BASE_HPP_ +#define _RIVE_TRANSFORM_CONSTRAINT_BASE_HPP_ +#include "rive/constraints/transform_space_constraint.hpp" +#include "rive/core/field_types/core_double_type.hpp" +namespace rive +{ +class TransformConstraintBase : public TransformSpaceConstraint +{ +protected: + typedef TransformSpaceConstraint Super; + +public: + static const uint16_t typeKey = 83; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case TransformConstraintBase::typeKey: + case TransformSpaceConstraintBase::typeKey: + case TargetedConstraintBase::typeKey: + case ConstraintBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t originXPropertyKey = 372; + static const uint16_t originYPropertyKey = 373; + +protected: + float m_OriginX = 0.0f; + float m_OriginY = 0.0f; + +public: + inline float originX() const { return m_OriginX; } + void originX(float value) + { + if (m_OriginX == value) + { + return; + } + m_OriginX = value; + originXChanged(); + } + + inline float originY() const { return m_OriginY; } + void originY(float value) + { + if (m_OriginY == value) + { + return; + } + m_OriginY = value; + originYChanged(); + } + + Core* clone() const override; + void copy(const TransformConstraintBase& object) + { + m_OriginX = object.m_OriginX; + m_OriginY = object.m_OriginY; + TransformSpaceConstraint::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case originXPropertyKey: + m_OriginX = CoreDoubleType::deserialize(reader); + return true; + case originYPropertyKey: + m_OriginY = CoreDoubleType::deserialize(reader); + return true; + } + return TransformSpaceConstraint::deserialize(propertyKey, reader); + } + +protected: + virtual void originXChanged() {} + virtual void originYChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/constraints/transform_space_constraint_base.hpp b/third_party/rive/include/rive/generated/constraints/transform_space_constraint_base.hpp new file mode 100644 index 0000000..59aabf6 --- /dev/null +++ b/third_party/rive/include/rive/generated/constraints/transform_space_constraint_base.hpp @@ -0,0 +1,90 @@ +#ifndef _RIVE_TRANSFORM_SPACE_CONSTRAINT_BASE_HPP_ +#define _RIVE_TRANSFORM_SPACE_CONSTRAINT_BASE_HPP_ +#include "rive/constraints/targeted_constraint.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +namespace rive +{ +class TransformSpaceConstraintBase : public TargetedConstraint +{ +protected: + typedef TargetedConstraint Super; + +public: + static const uint16_t typeKey = 90; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case TransformSpaceConstraintBase::typeKey: + case TargetedConstraintBase::typeKey: + case ConstraintBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t sourceSpaceValuePropertyKey = 179; + static const uint16_t destSpaceValuePropertyKey = 180; + +protected: + uint32_t m_SourceSpaceValue = 0; + uint32_t m_DestSpaceValue = 0; + +public: + inline uint32_t sourceSpaceValue() const { return m_SourceSpaceValue; } + void sourceSpaceValue(uint32_t value) + { + if (m_SourceSpaceValue == value) + { + return; + } + m_SourceSpaceValue = value; + sourceSpaceValueChanged(); + } + + inline uint32_t destSpaceValue() const { return m_DestSpaceValue; } + void destSpaceValue(uint32_t value) + { + if (m_DestSpaceValue == value) + { + return; + } + m_DestSpaceValue = value; + destSpaceValueChanged(); + } + + void copy(const TransformSpaceConstraintBase& object) + { + m_SourceSpaceValue = object.m_SourceSpaceValue; + m_DestSpaceValue = object.m_DestSpaceValue; + TargetedConstraint::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case sourceSpaceValuePropertyKey: + m_SourceSpaceValue = CoreUintType::deserialize(reader); + return true; + case destSpaceValuePropertyKey: + m_DestSpaceValue = CoreUintType::deserialize(reader); + return true; + } + return TargetedConstraint::deserialize(propertyKey, reader); + } + +protected: + virtual void sourceSpaceValueChanged() {} + virtual void destSpaceValueChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/constraints/translation_constraint_base.hpp b/third_party/rive/include/rive/generated/constraints/translation_constraint_base.hpp new file mode 100644 index 0000000..6f64a3e --- /dev/null +++ b/third_party/rive/include/rive/generated/constraints/translation_constraint_base.hpp @@ -0,0 +1,41 @@ +#ifndef _RIVE_TRANSLATION_CONSTRAINT_BASE_HPP_ +#define _RIVE_TRANSLATION_CONSTRAINT_BASE_HPP_ +#include "rive/constraints/transform_component_constraint_y.hpp" +namespace rive +{ +class TranslationConstraintBase : public TransformComponentConstraintY +{ +protected: + typedef TransformComponentConstraintY Super; + +public: + static const uint16_t typeKey = 87; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case TranslationConstraintBase::typeKey: + case TransformComponentConstraintYBase::typeKey: + case TransformComponentConstraintBase::typeKey: + case TransformSpaceConstraintBase::typeKey: + case TargetedConstraintBase::typeKey: + case ConstraintBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/container_component_base.hpp b/third_party/rive/include/rive/generated/container_component_base.hpp new file mode 100644 index 0000000..9cf0005 --- /dev/null +++ b/third_party/rive/include/rive/generated/container_component_base.hpp @@ -0,0 +1,34 @@ +#ifndef _RIVE_CONTAINER_COMPONENT_BASE_HPP_ +#define _RIVE_CONTAINER_COMPONENT_BASE_HPP_ +#include "rive/component.hpp" +namespace rive +{ +class ContainerComponentBase : public Component +{ +protected: + typedef Component Super; + +public: + static const uint16_t typeKey = 11; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case ContainerComponentBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/core_registry.hpp b/third_party/rive/include/rive/generated/core_registry.hpp new file mode 100644 index 0000000..429b078 --- /dev/null +++ b/third_party/rive/include/rive/generated/core_registry.hpp @@ -0,0 +1,4760 @@ +#ifndef _RIVE_CORE_REGISTRY_HPP_ +#define _RIVE_CORE_REGISTRY_HPP_ +#include "rive/animation/advanceable_state.hpp" +#include "rive/animation/animation.hpp" +#include "rive/animation/animation_state.hpp" +#include "rive/animation/any_state.hpp" +#include "rive/animation/blend_animation.hpp" +#include "rive/animation/blend_animation_1d.hpp" +#include "rive/animation/blend_animation_direct.hpp" +#include "rive/animation/blend_state.hpp" +#include "rive/animation/blend_state_1d.hpp" +#include "rive/animation/blend_state_1d_input.hpp" +#include "rive/animation/blend_state_1d_viewmodel.hpp" +#include "rive/animation/blend_state_direct.hpp" +#include "rive/animation/blend_state_transition.hpp" +#include "rive/animation/cubic_ease_interpolator.hpp" +#include "rive/animation/cubic_interpolator.hpp" +#include "rive/animation/cubic_interpolator_component.hpp" +#include "rive/animation/cubic_value_interpolator.hpp" +#include "rive/animation/elastic_interpolator.hpp" +#include "rive/animation/entry_state.hpp" +#include "rive/animation/exit_state.hpp" +#include "rive/animation/interpolating_keyframe.hpp" +#include "rive/animation/keyed_object.hpp" +#include "rive/animation/keyed_property.hpp" +#include "rive/animation/keyframe.hpp" +#include "rive/animation/keyframe_bool.hpp" +#include "rive/animation/keyframe_callback.hpp" +#include "rive/animation/keyframe_color.hpp" +#include "rive/animation/keyframe_double.hpp" +#include "rive/animation/keyframe_id.hpp" +#include "rive/animation/keyframe_interpolator.hpp" +#include "rive/animation/keyframe_string.hpp" +#include "rive/animation/keyframe_uint.hpp" +#include "rive/animation/layer_state.hpp" +#include "rive/animation/linear_animation.hpp" +#include "rive/animation/listener_action.hpp" +#include "rive/animation/listener_align_target.hpp" +#include "rive/animation/listener_bool_change.hpp" +#include "rive/animation/listener_fire_event.hpp" +#include "rive/animation/listener_input_change.hpp" +#include "rive/animation/listener_number_change.hpp" +#include "rive/animation/listener_trigger_change.hpp" +#include "rive/animation/listener_viewmodel_change.hpp" +#include "rive/animation/nested_bool.hpp" +#include "rive/animation/nested_input.hpp" +#include "rive/animation/nested_linear_animation.hpp" +#include "rive/animation/nested_number.hpp" +#include "rive/animation/nested_remap_animation.hpp" +#include "rive/animation/nested_simple_animation.hpp" +#include "rive/animation/nested_state_machine.hpp" +#include "rive/animation/nested_trigger.hpp" +#include "rive/animation/state_machine.hpp" +#include "rive/animation/state_machine_bool.hpp" +#include "rive/animation/state_machine_component.hpp" +#include "rive/animation/state_machine_fire_event.hpp" +#include "rive/animation/state_machine_input.hpp" +#include "rive/animation/state_machine_layer.hpp" +#include "rive/animation/state_machine_layer_component.hpp" +#include "rive/animation/state_machine_listener.hpp" +#include "rive/animation/state_machine_number.hpp" +#include "rive/animation/state_machine_trigger.hpp" +#include "rive/animation/state_transition.hpp" +#include "rive/animation/transition_artboard_condition.hpp" +#include "rive/animation/transition_bool_condition.hpp" +#include "rive/animation/transition_comparator.hpp" +#include "rive/animation/transition_condition.hpp" +#include "rive/animation/transition_input_condition.hpp" +#include "rive/animation/transition_number_condition.hpp" +#include "rive/animation/transition_property_artboard_comparator.hpp" +#include "rive/animation/transition_property_comparator.hpp" +#include "rive/animation/transition_property_viewmodel_comparator.hpp" +#include "rive/animation/transition_trigger_condition.hpp" +#include "rive/animation/transition_value_boolean_comparator.hpp" +#include "rive/animation/transition_value_color_comparator.hpp" +#include "rive/animation/transition_value_comparator.hpp" +#include "rive/animation/transition_value_condition.hpp" +#include "rive/animation/transition_value_enum_comparator.hpp" +#include "rive/animation/transition_value_number_comparator.hpp" +#include "rive/animation/transition_value_string_comparator.hpp" +#include "rive/animation/transition_value_trigger_comparator.hpp" +#include "rive/animation/transition_viewmodel_condition.hpp" +#include "rive/artboard.hpp" +#include "rive/artboard_component_list.hpp" +#include "rive/assets/asset.hpp" +#include "rive/assets/audio_asset.hpp" +#include "rive/assets/drawable_asset.hpp" +#include "rive/assets/export_audio.hpp" +#include "rive/assets/file_asset.hpp" +#include "rive/assets/file_asset_contents.hpp" +#include "rive/assets/folder.hpp" +#include "rive/assets/font_asset.hpp" +#include "rive/assets/image_asset.hpp" +#include "rive/audio_event.hpp" +#include "rive/backboard.hpp" +#include "rive/bones/bone.hpp" +#include "rive/bones/cubic_weight.hpp" +#include "rive/bones/root_bone.hpp" +#include "rive/bones/skeletal_component.hpp" +#include "rive/bones/skin.hpp" +#include "rive/bones/tendon.hpp" +#include "rive/bones/weight.hpp" +#include "rive/component.hpp" +#include "rive/constraints/constraint.hpp" +#include "rive/constraints/distance_constraint.hpp" +#include "rive/constraints/draggable_constraint.hpp" +#include "rive/constraints/follow_path_constraint.hpp" +#include "rive/constraints/ik_constraint.hpp" +#include "rive/constraints/rotation_constraint.hpp" +#include "rive/constraints/scale_constraint.hpp" +#include "rive/constraints/scrolling/clamped_scroll_physics.hpp" +#include "rive/constraints/scrolling/elastic_scroll_physics.hpp" +#include "rive/constraints/scrolling/scroll_bar_constraint.hpp" +#include "rive/constraints/scrolling/scroll_constraint.hpp" +#include "rive/constraints/scrolling/scroll_physics.hpp" +#include "rive/constraints/targeted_constraint.hpp" +#include "rive/constraints/transform_component_constraint.hpp" +#include "rive/constraints/transform_component_constraint_y.hpp" +#include "rive/constraints/transform_constraint.hpp" +#include "rive/constraints/transform_space_constraint.hpp" +#include "rive/constraints/translation_constraint.hpp" +#include "rive/container_component.hpp" +#include "rive/custom_property.hpp" +#include "rive/custom_property_boolean.hpp" +#include "rive/custom_property_group.hpp" +#include "rive/custom_property_number.hpp" +#include "rive/custom_property_string.hpp" +#include "rive/data_bind/bindable_property.hpp" +#include "rive/data_bind/bindable_property_asset.hpp" +#include "rive/data_bind/bindable_property_boolean.hpp" +#include "rive/data_bind/bindable_property_color.hpp" +#include "rive/data_bind/bindable_property_enum.hpp" +#include "rive/data_bind/bindable_property_integer.hpp" +#include "rive/data_bind/bindable_property_number.hpp" +#include "rive/data_bind/bindable_property_string.hpp" +#include "rive/data_bind/bindable_property_trigger.hpp" +#include "rive/data_bind/converters/data_converter.hpp" +#include "rive/data_bind/converters/data_converter_boolean_negate.hpp" +#include "rive/data_bind/converters/data_converter_formula.hpp" +#include "rive/data_bind/converters/data_converter_group.hpp" +#include "rive/data_bind/converters/data_converter_group_item.hpp" +#include "rive/data_bind/converters/data_converter_interpolator.hpp" +#include "rive/data_bind/converters/data_converter_number_to_list.hpp" +#include "rive/data_bind/converters/data_converter_operation.hpp" +#include "rive/data_bind/converters/data_converter_operation_value.hpp" +#include "rive/data_bind/converters/data_converter_operation_viewmodel.hpp" +#include "rive/data_bind/converters/data_converter_range_mapper.hpp" +#include "rive/data_bind/converters/data_converter_rounder.hpp" +#include "rive/data_bind/converters/data_converter_string_pad.hpp" +#include "rive/data_bind/converters/data_converter_string_remove_zeros.hpp" +#include "rive/data_bind/converters/data_converter_string_trim.hpp" +#include "rive/data_bind/converters/data_converter_system_degs_to_rads.hpp" +#include "rive/data_bind/converters/data_converter_system_normalizer.hpp" +#include "rive/data_bind/converters/data_converter_to_string.hpp" +#include "rive/data_bind/converters/data_converter_trigger.hpp" +#include "rive/data_bind/converters/formula/formula_token.hpp" +#include "rive/data_bind/converters/formula/formula_token_argument_separator.hpp" +#include "rive/data_bind/converters/formula/formula_token_function.hpp" +#include "rive/data_bind/converters/formula/formula_token_input.hpp" +#include "rive/data_bind/converters/formula/formula_token_operation.hpp" +#include "rive/data_bind/converters/formula/formula_token_parenthesis.hpp" +#include "rive/data_bind/converters/formula/formula_token_parenthesis_close.hpp" +#include "rive/data_bind/converters/formula/formula_token_parenthesis_open.hpp" +#include "rive/data_bind/converters/formula/formula_token_value.hpp" +#include "rive/data_bind/data_bind.hpp" +#include "rive/data_bind/data_bind_context.hpp" +#include "rive/draw_rules.hpp" +#include "rive/draw_target.hpp" +#include "rive/drawable.hpp" +#include "rive/event.hpp" +#include "rive/foreground_layout_drawable.hpp" +#include "rive/joystick.hpp" +#include "rive/layout/axis.hpp" +#include "rive/layout/axis_x.hpp" +#include "rive/layout/axis_y.hpp" +#include "rive/layout/layout_component_style.hpp" +#include "rive/layout/n_sliced_node.hpp" +#include "rive/layout/n_slicer.hpp" +#include "rive/layout/n_slicer_tile_mode.hpp" +#include "rive/layout_component.hpp" +#include "rive/nested_animation.hpp" +#include "rive/nested_artboard.hpp" +#include "rive/nested_artboard_layout.hpp" +#include "rive/nested_artboard_leaf.hpp" +#include "rive/node.hpp" +#include "rive/open_url_event.hpp" +#include "rive/shapes/clipping_shape.hpp" +#include "rive/shapes/contour_mesh_vertex.hpp" +#include "rive/shapes/cubic_asymmetric_vertex.hpp" +#include "rive/shapes/cubic_detached_vertex.hpp" +#include "rive/shapes/cubic_mirrored_vertex.hpp" +#include "rive/shapes/cubic_vertex.hpp" +#include "rive/shapes/ellipse.hpp" +#include "rive/shapes/image.hpp" +#include "rive/shapes/mesh.hpp" +#include "rive/shapes/mesh_vertex.hpp" +#include "rive/shapes/paint/dash.hpp" +#include "rive/shapes/paint/dash_path.hpp" +#include "rive/shapes/paint/feather.hpp" +#include "rive/shapes/paint/fill.hpp" +#include "rive/shapes/paint/gradient_stop.hpp" +#include "rive/shapes/paint/linear_gradient.hpp" +#include "rive/shapes/paint/radial_gradient.hpp" +#include "rive/shapes/paint/shape_paint.hpp" +#include "rive/shapes/paint/solid_color.hpp" +#include "rive/shapes/paint/stroke.hpp" +#include "rive/shapes/paint/trim_path.hpp" +#include "rive/shapes/parametric_path.hpp" +#include "rive/shapes/path.hpp" +#include "rive/shapes/path_vertex.hpp" +#include "rive/shapes/points_path.hpp" +#include "rive/shapes/polygon.hpp" +#include "rive/shapes/rectangle.hpp" +#include "rive/shapes/shape.hpp" +#include "rive/shapes/star.hpp" +#include "rive/shapes/straight_vertex.hpp" +#include "rive/shapes/triangle.hpp" +#include "rive/shapes/vertex.hpp" +#include "rive/solo.hpp" +#include "rive/text/text.hpp" +#include "rive/text/text_follow_path_modifier.hpp" +#include "rive/text/text_input.hpp" +#include "rive/text/text_input_cursor.hpp" +#include "rive/text/text_input_drawable.hpp" +#include "rive/text/text_input_selected_text.hpp" +#include "rive/text/text_input_selection.hpp" +#include "rive/text/text_input_text.hpp" +#include "rive/text/text_modifier.hpp" +#include "rive/text/text_modifier_group.hpp" +#include "rive/text/text_modifier_range.hpp" +#include "rive/text/text_shape_modifier.hpp" +#include "rive/text/text_style.hpp" +#include "rive/text/text_style_axis.hpp" +#include "rive/text/text_style_feature.hpp" +#include "rive/text/text_style_paint.hpp" +#include "rive/text/text_target_modifier.hpp" +#include "rive/text/text_value_run.hpp" +#include "rive/text/text_variation_modifier.hpp" +#include "rive/transform_component.hpp" +#include "rive/viewmodel/data_enum.hpp" +#include "rive/viewmodel/data_enum_custom.hpp" +#include "rive/viewmodel/data_enum_system.hpp" +#include "rive/viewmodel/data_enum_value.hpp" +#include "rive/viewmodel/viewmodel.hpp" +#include "rive/viewmodel/viewmodel_component.hpp" +#include "rive/viewmodel/viewmodel_instance.hpp" +#include "rive/viewmodel/viewmodel_instance_asset.hpp" +#include "rive/viewmodel/viewmodel_instance_asset_image.hpp" +#include "rive/viewmodel/viewmodel_instance_boolean.hpp" +#include "rive/viewmodel/viewmodel_instance_color.hpp" +#include "rive/viewmodel/viewmodel_instance_enum.hpp" +#include "rive/viewmodel/viewmodel_instance_list.hpp" +#include "rive/viewmodel/viewmodel_instance_list_item.hpp" +#include "rive/viewmodel/viewmodel_instance_number.hpp" +#include "rive/viewmodel/viewmodel_instance_string.hpp" +#include "rive/viewmodel/viewmodel_instance_symbol.hpp" +#include "rive/viewmodel/viewmodel_instance_symbol_list_index.hpp" +#include "rive/viewmodel/viewmodel_instance_trigger.hpp" +#include "rive/viewmodel/viewmodel_instance_value.hpp" +#include "rive/viewmodel/viewmodel_instance_viewmodel.hpp" +#include "rive/viewmodel/viewmodel_property.hpp" +#include "rive/viewmodel/viewmodel_property_asset.hpp" +#include "rive/viewmodel/viewmodel_property_asset_image.hpp" +#include "rive/viewmodel/viewmodel_property_boolean.hpp" +#include "rive/viewmodel/viewmodel_property_color.hpp" +#include "rive/viewmodel/viewmodel_property_enum.hpp" +#include "rive/viewmodel/viewmodel_property_enum_custom.hpp" +#include "rive/viewmodel/viewmodel_property_enum_system.hpp" +#include "rive/viewmodel/viewmodel_property_list.hpp" +#include "rive/viewmodel/viewmodel_property_number.hpp" +#include "rive/viewmodel/viewmodel_property_string.hpp" +#include "rive/viewmodel/viewmodel_property_symbol.hpp" +#include "rive/viewmodel/viewmodel_property_symbol_list_index.hpp" +#include "rive/viewmodel/viewmodel_property_trigger.hpp" +#include "rive/viewmodel/viewmodel_property_viewmodel.hpp" +#include "rive/world_transform_component.hpp" +namespace rive +{ +class CoreRegistry +{ +public: + static Core* makeCoreInstance(int typeKey) + { + switch (typeKey) + { + case ViewModelInstanceListItemBase::typeKey: + return new ViewModelInstanceListItem(); + case ViewModelInstanceColorBase::typeKey: + return new ViewModelInstanceColor(); + case ViewModelComponentBase::typeKey: + return new ViewModelComponent(); + case ViewModelPropertyBase::typeKey: + return new ViewModelProperty(); + case ViewModelPropertyEnumBase::typeKey: + return new ViewModelPropertyEnum(); + case ViewModelPropertyEnumCustomBase::typeKey: + return new ViewModelPropertyEnumCustom(); + case DataEnumBase::typeKey: + return new DataEnum(); + case DataEnumCustomBase::typeKey: + return new DataEnumCustom(); + case ViewModelPropertyNumberBase::typeKey: + return new ViewModelPropertyNumber(); + case ViewModelInstanceEnumBase::typeKey: + return new ViewModelInstanceEnum(); + case ViewModelPropertySymbolListIndexBase::typeKey: + return new ViewModelPropertySymbolListIndex(); + case ViewModelInstanceStringBase::typeKey: + return new ViewModelInstanceString(); + case ViewModelPropertyListBase::typeKey: + return new ViewModelPropertyList(); + case ViewModelPropertyEnumSystemBase::typeKey: + return new ViewModelPropertyEnumSystem(); + case ViewModelBase::typeKey: + return new ViewModel(); + case ViewModelPropertyAssetBase::typeKey: + return new ViewModelPropertyAsset(); + case DataEnumSystemBase::typeKey: + return new DataEnumSystem(); + case ViewModelPropertyViewModelBase::typeKey: + return new ViewModelPropertyViewModel(); + case DataEnumValueBase::typeKey: + return new DataEnumValue(); + case ViewModelPropertyTriggerBase::typeKey: + return new ViewModelPropertyTrigger(); + case ViewModelPropertyStringBase::typeKey: + return new ViewModelPropertyString(); + case ViewModelPropertyColorBase::typeKey: + return new ViewModelPropertyColor(); + case ViewModelPropertyBooleanBase::typeKey: + return new ViewModelPropertyBoolean(); + case ViewModelInstanceBase::typeKey: + return new ViewModelInstance(); + case ViewModelPropertyAssetImageBase::typeKey: + return new ViewModelPropertyAssetImage(); + case ViewModelInstanceBooleanBase::typeKey: + return new ViewModelInstanceBoolean(); + case ViewModelInstanceListBase::typeKey: + return new ViewModelInstanceList(); + case ViewModelInstanceNumberBase::typeKey: + return new ViewModelInstanceNumber(); + case ViewModelInstanceTriggerBase::typeKey: + return new ViewModelInstanceTrigger(); + case ViewModelInstanceSymbolListIndexBase::typeKey: + return new ViewModelInstanceSymbolListIndex(); + case ViewModelInstanceViewModelBase::typeKey: + return new ViewModelInstanceViewModel(); + case ViewModelInstanceAssetBase::typeKey: + return new ViewModelInstanceAsset(); + case ViewModelInstanceAssetImageBase::typeKey: + return new ViewModelInstanceAssetImage(); + case DrawTargetBase::typeKey: + return new DrawTarget(); + case CustomPropertyNumberBase::typeKey: + return new CustomPropertyNumber(); + case DistanceConstraintBase::typeKey: + return new DistanceConstraint(); + case IKConstraintBase::typeKey: + return new IKConstraint(); + case FollowPathConstraintBase::typeKey: + return new FollowPathConstraint(); + case TranslationConstraintBase::typeKey: + return new TranslationConstraint(); + case ClampedScrollPhysicsBase::typeKey: + return new ClampedScrollPhysics(); + case ScrollConstraintBase::typeKey: + return new ScrollConstraint(); + case ElasticScrollPhysicsBase::typeKey: + return new ElasticScrollPhysics(); + case ScrollBarConstraintBase::typeKey: + return new ScrollBarConstraint(); + case TransformConstraintBase::typeKey: + return new TransformConstraint(); + case ScaleConstraintBase::typeKey: + return new ScaleConstraint(); + case RotationConstraintBase::typeKey: + return new RotationConstraint(); + case NodeBase::typeKey: + return new Node(); + case ForegroundLayoutDrawableBase::typeKey: + return new ForegroundLayoutDrawable(); + case NestedArtboardBase::typeKey: + return new NestedArtboard(); + case ArtboardComponentListBase::typeKey: + return new ArtboardComponentList(); + case SoloBase::typeKey: + return new Solo(); + case NestedArtboardLayoutBase::typeKey: + return new NestedArtboardLayout(); + case NSlicerTileModeBase::typeKey: + return new NSlicerTileMode(); + case AxisYBase::typeKey: + return new AxisY(); + case LayoutComponentStyleBase::typeKey: + return new LayoutComponentStyle(); + case AxisXBase::typeKey: + return new AxisX(); + case NSlicerBase::typeKey: + return new NSlicer(); + case NSlicedNodeBase::typeKey: + return new NSlicedNode(); + case ListenerFireEventBase::typeKey: + return new ListenerFireEvent(); + case TransitionValueTriggerComparatorBase::typeKey: + return new TransitionValueTriggerComparator(); + case KeyFrameUintBase::typeKey: + return new KeyFrameUint(); + case NestedSimpleAnimationBase::typeKey: + return new NestedSimpleAnimation(); + case AnimationStateBase::typeKey: + return new AnimationState(); + case NestedTriggerBase::typeKey: + return new NestedTrigger(); + case KeyedObjectBase::typeKey: + return new KeyedObject(); + case AnimationBase::typeKey: + return new Animation(); + case BlendAnimationDirectBase::typeKey: + return new BlendAnimationDirect(); + case StateMachineNumberBase::typeKey: + return new StateMachineNumber(); + case CubicValueInterpolatorBase::typeKey: + return new CubicValueInterpolator(); + case TransitionTriggerConditionBase::typeKey: + return new TransitionTriggerCondition(); + case KeyedPropertyBase::typeKey: + return new KeyedProperty(); + case StateMachineListenerBase::typeKey: + return new StateMachineListener(); + case TransitionPropertyArtboardComparatorBase::typeKey: + return new TransitionPropertyArtboardComparator(); + case TransitionPropertyViewModelComparatorBase::typeKey: + return new TransitionPropertyViewModelComparator(); + case KeyFrameIdBase::typeKey: + return new KeyFrameId(); + case KeyFrameBoolBase::typeKey: + return new KeyFrameBool(); + case ListenerBoolChangeBase::typeKey: + return new ListenerBoolChange(); + case ListenerAlignTargetBase::typeKey: + return new ListenerAlignTarget(); + case TransitionNumberConditionBase::typeKey: + return new TransitionNumberCondition(); + case TransitionValueBooleanComparatorBase::typeKey: + return new TransitionValueBooleanComparator(); + case TransitionViewModelConditionBase::typeKey: + return new TransitionViewModelCondition(); + case TransitionArtboardConditionBase::typeKey: + return new TransitionArtboardCondition(); + case AnyStateBase::typeKey: + return new AnyState(); + case BlendState1DInputBase::typeKey: + return new BlendState1DInput(); + case CubicInterpolatorComponentBase::typeKey: + return new CubicInterpolatorComponent(); + case StateMachineLayerBase::typeKey: + return new StateMachineLayer(); + case KeyFrameStringBase::typeKey: + return new KeyFrameString(); + case ListenerNumberChangeBase::typeKey: + return new ListenerNumberChange(); + case CubicEaseInterpolatorBase::typeKey: + return new CubicEaseInterpolator(); + case StateTransitionBase::typeKey: + return new StateTransition(); + case NestedBoolBase::typeKey: + return new NestedBool(); + case KeyFrameDoubleBase::typeKey: + return new KeyFrameDouble(); + case KeyFrameColorBase::typeKey: + return new KeyFrameColor(); + case StateMachineBase::typeKey: + return new StateMachine(); + case StateMachineFireEventBase::typeKey: + return new StateMachineFireEvent(); + case EntryStateBase::typeKey: + return new EntryState(); + case LinearAnimationBase::typeKey: + return new LinearAnimation(); + case StateMachineTriggerBase::typeKey: + return new StateMachineTrigger(); + case TransitionValueColorComparatorBase::typeKey: + return new TransitionValueColorComparator(); + case ListenerTriggerChangeBase::typeKey: + return new ListenerTriggerChange(); + case BlendStateDirectBase::typeKey: + return new BlendStateDirect(); + case ListenerViewModelChangeBase::typeKey: + return new ListenerViewModelChange(); + case TransitionValueNumberComparatorBase::typeKey: + return new TransitionValueNumberComparator(); + case NestedStateMachineBase::typeKey: + return new NestedStateMachine(); + case ElasticInterpolatorBase::typeKey: + return new ElasticInterpolator(); + case ExitStateBase::typeKey: + return new ExitState(); + case NestedNumberBase::typeKey: + return new NestedNumber(); + case TransitionValueEnumComparatorBase::typeKey: + return new TransitionValueEnumComparator(); + case KeyFrameCallbackBase::typeKey: + return new KeyFrameCallback(); + case TransitionValueStringComparatorBase::typeKey: + return new TransitionValueStringComparator(); + case NestedRemapAnimationBase::typeKey: + return new NestedRemapAnimation(); + case TransitionBoolConditionBase::typeKey: + return new TransitionBoolCondition(); + case BlendState1DViewModelBase::typeKey: + return new BlendState1DViewModel(); + case BlendStateTransitionBase::typeKey: + return new BlendStateTransition(); + case StateMachineBoolBase::typeKey: + return new StateMachineBool(); + case BlendAnimation1DBase::typeKey: + return new BlendAnimation1D(); + case DashPathBase::typeKey: + return new DashPath(); + case LinearGradientBase::typeKey: + return new LinearGradient(); + case RadialGradientBase::typeKey: + return new RadialGradient(); + case DashBase::typeKey: + return new Dash(); + case StrokeBase::typeKey: + return new Stroke(); + case SolidColorBase::typeKey: + return new SolidColor(); + case GradientStopBase::typeKey: + return new GradientStop(); + case FeatherBase::typeKey: + return new Feather(); + case TrimPathBase::typeKey: + return new TrimPath(); + case FillBase::typeKey: + return new Fill(); + case MeshVertexBase::typeKey: + return new MeshVertex(); + case ShapeBase::typeKey: + return new Shape(); + case StraightVertexBase::typeKey: + return new StraightVertex(); + case CubicAsymmetricVertexBase::typeKey: + return new CubicAsymmetricVertex(); + case MeshBase::typeKey: + return new Mesh(); + case PointsPathBase::typeKey: + return new PointsPath(); + case ContourMeshVertexBase::typeKey: + return new ContourMeshVertex(); + case RectangleBase::typeKey: + return new Rectangle(); + case CubicMirroredVertexBase::typeKey: + return new CubicMirroredVertex(); + case TriangleBase::typeKey: + return new Triangle(); + case EllipseBase::typeKey: + return new Ellipse(); + case ClippingShapeBase::typeKey: + return new ClippingShape(); + case PolygonBase::typeKey: + return new Polygon(); + case StarBase::typeKey: + return new Star(); + case ImageBase::typeKey: + return new Image(); + case CubicDetachedVertexBase::typeKey: + return new CubicDetachedVertex(); + case CustomPropertyGroupBase::typeKey: + return new CustomPropertyGroup(); + case EventBase::typeKey: + return new Event(); + case DrawRulesBase::typeKey: + return new DrawRules(); + case CustomPropertyBooleanBase::typeKey: + return new CustomPropertyBoolean(); + case LayoutComponentBase::typeKey: + return new LayoutComponent(); + case ArtboardBase::typeKey: + return new Artboard(); + case JoystickBase::typeKey: + return new Joystick(); + case BackboardBase::typeKey: + return new Backboard(); + case OpenUrlEventBase::typeKey: + return new OpenUrlEvent(); + case BindablePropertyIntegerBase::typeKey: + return new BindablePropertyInteger(); + case BindablePropertyTriggerBase::typeKey: + return new BindablePropertyTrigger(); + case BindablePropertyBooleanBase::typeKey: + return new BindablePropertyBoolean(); + case DataBindBase::typeKey: + return new DataBind(); + case BindablePropertyAssetBase::typeKey: + return new BindablePropertyAsset(); + case DataConverterNumberToListBase::typeKey: + return new DataConverterNumberToList(); + case DataConverterFormulaBase::typeKey: + return new DataConverterFormula(); + case DataConverterOperationBase::typeKey: + return new DataConverterOperation(); + case DataConverterOperationValueBase::typeKey: + return new DataConverterOperationValue(); + case DataConverterSystemDegsToRadsBase::typeKey: + return new DataConverterSystemDegsToRads(); + case DataConverterRangeMapperBase::typeKey: + return new DataConverterRangeMapper(); + case DataConverterInterpolatorBase::typeKey: + return new DataConverterInterpolator(); + case DataConverterSystemNormalizerBase::typeKey: + return new DataConverterSystemNormalizer(); + case DataConverterGroupItemBase::typeKey: + return new DataConverterGroupItem(); + case DataConverterGroupBase::typeKey: + return new DataConverterGroup(); + case DataConverterStringRemoveZerosBase::typeKey: + return new DataConverterStringRemoveZeros(); + case DataConverterRounderBase::typeKey: + return new DataConverterRounder(); + case DataConverterStringPadBase::typeKey: + return new DataConverterStringPad(); + case DataConverterTriggerBase::typeKey: + return new DataConverterTrigger(); + case DataConverterStringTrimBase::typeKey: + return new DataConverterStringTrim(); + case FormulaTokenBase::typeKey: + return new FormulaToken(); + case FormulaTokenArgumentSeparatorBase::typeKey: + return new FormulaTokenArgumentSeparator(); + case FormulaTokenParenthesisBase::typeKey: + return new FormulaTokenParenthesis(); + case FormulaTokenParenthesisCloseBase::typeKey: + return new FormulaTokenParenthesisClose(); + case FormulaTokenOperationBase::typeKey: + return new FormulaTokenOperation(); + case FormulaTokenFunctionBase::typeKey: + return new FormulaTokenFunction(); + case FormulaTokenValueBase::typeKey: + return new FormulaTokenValue(); + case FormulaTokenParenthesisOpenBase::typeKey: + return new FormulaTokenParenthesisOpen(); + case FormulaTokenInputBase::typeKey: + return new FormulaTokenInput(); + case DataConverterOperationViewModelBase::typeKey: + return new DataConverterOperationViewModel(); + case DataConverterBooleanNegateBase::typeKey: + return new DataConverterBooleanNegate(); + case DataConverterToStringBase::typeKey: + return new DataConverterToString(); + case DataBindContextBase::typeKey: + return new DataBindContext(); + case BindablePropertyStringBase::typeKey: + return new BindablePropertyString(); + case BindablePropertyNumberBase::typeKey: + return new BindablePropertyNumber(); + case BindablePropertyEnumBase::typeKey: + return new BindablePropertyEnum(); + case BindablePropertyColorBase::typeKey: + return new BindablePropertyColor(); + case NestedArtboardLeafBase::typeKey: + return new NestedArtboardLeaf(); + case WeightBase::typeKey: + return new Weight(); + case BoneBase::typeKey: + return new Bone(); + case RootBoneBase::typeKey: + return new RootBone(); + case SkinBase::typeKey: + return new Skin(); + case TendonBase::typeKey: + return new Tendon(); + case CubicWeightBase::typeKey: + return new CubicWeight(); + case TextModifierRangeBase::typeKey: + return new TextModifierRange(); + case TextFollowPathModifierBase::typeKey: + return new TextFollowPathModifier(); + case TextInputCursorBase::typeKey: + return new TextInputCursor(); + case TextInputTextBase::typeKey: + return new TextInputText(); + case TextStyleFeatureBase::typeKey: + return new TextStyleFeature(); + case TextVariationModifierBase::typeKey: + return new TextVariationModifier(); + case TextModifierGroupBase::typeKey: + return new TextModifierGroup(); + case TextStyleBase::typeKey: + return new TextStyle(); + case TextStylePaintBase::typeKey: + return new TextStylePaint(); + case TextInputSelectedTextBase::typeKey: + return new TextInputSelectedText(); + case TextInputBase::typeKey: + return new TextInput(); + case TextStyleAxisBase::typeKey: + return new TextStyleAxis(); + case TextInputSelectionBase::typeKey: + return new TextInputSelection(); + case TextBase::typeKey: + return new Text(); + case TextValueRunBase::typeKey: + return new TextValueRun(); + case CustomPropertyStringBase::typeKey: + return new CustomPropertyString(); + case FolderBase::typeKey: + return new Folder(); + case ImageAssetBase::typeKey: + return new ImageAsset(); + case FontAssetBase::typeKey: + return new FontAsset(); + case AudioAssetBase::typeKey: + return new AudioAsset(); + case FileAssetContentsBase::typeKey: + return new FileAssetContents(); + case AudioEventBase::typeKey: + return new AudioEvent(); + } + return nullptr; + } + static void setUint(Core* object, int propertyKey, uint32_t value) + { + switch (propertyKey) + { + case ViewModelInstanceListItemBase::viewModelIdPropertyKey: + object->as()->viewModelId(value); + break; + case ViewModelInstanceListItemBase::viewModelInstanceIdPropertyKey: + object->as() + ->viewModelInstanceId(value); + break; + case ViewModelInstanceValueBase::viewModelPropertyIdPropertyKey: + object->as()->viewModelPropertyId( + value); + break; + case ViewModelPropertyEnumCustomBase::enumIdPropertyKey: + object->as()->enumId(value); + break; + case ViewModelInstanceEnumBase::propertyValuePropertyKey: + object->as()->propertyValue(value); + break; + case ViewModelPropertyEnumSystemBase::enumTypePropertyKey: + object->as()->enumType(value); + break; + case DataEnumSystemBase::enumTypePropertyKey: + object->as()->enumType(value); + break; + case ViewModelPropertyViewModelBase:: + viewModelReferenceIdPropertyKey: + object->as() + ->viewModelReferenceId(value); + break; + case ComponentBase::parentIdPropertyKey: + object->as()->parentId(value); + break; + case ViewModelInstanceBase::viewModelIdPropertyKey: + object->as()->viewModelId(value); + break; + case ViewModelInstanceTriggerBase::propertyValuePropertyKey: + object->as()->propertyValue( + value); + break; + case ViewModelInstanceSymbolListIndexBase::propertyValuePropertyKey: + object->as() + ->propertyValue(value); + break; + case ViewModelInstanceViewModelBase::propertyValuePropertyKey: + object->as()->propertyValue( + value); + break; + case ViewModelInstanceAssetBase::propertyValuePropertyKey: + object->as()->propertyValue(value); + break; + case DrawTargetBase::drawableIdPropertyKey: + object->as()->drawableId(value); + break; + case DrawTargetBase::placementValuePropertyKey: + object->as()->placementValue(value); + break; + case TargetedConstraintBase::targetIdPropertyKey: + object->as()->targetId(value); + break; + case DistanceConstraintBase::modeValuePropertyKey: + object->as()->modeValue(value); + break; + case TransformSpaceConstraintBase::sourceSpaceValuePropertyKey: + object->as()->sourceSpaceValue( + value); + break; + case TransformSpaceConstraintBase::destSpaceValuePropertyKey: + object->as()->destSpaceValue( + value); + break; + case TransformComponentConstraintBase::minMaxSpaceValuePropertyKey: + object->as() + ->minMaxSpaceValue(value); + break; + case IKConstraintBase::parentBoneCountPropertyKey: + object->as()->parentBoneCount(value); + break; + case ScrollPhysicsBase::constraintIdPropertyKey: + object->as()->constraintId(value); + break; + case DraggableConstraintBase::directionValuePropertyKey: + object->as()->directionValue(value); + break; + case ScrollConstraintBase::physicsTypeValuePropertyKey: + object->as()->physicsTypeValue(value); + break; + case ScrollConstraintBase::physicsIdPropertyKey: + object->as()->physicsId(value); + break; + case ScrollBarConstraintBase::scrollConstraintIdPropertyKey: + object->as()->scrollConstraintId( + value); + break; + case DrawableBase::blendModeValuePropertyKey: + object->as()->blendModeValue(value); + break; + case DrawableBase::drawableFlagsPropertyKey: + object->as()->drawableFlags(value); + break; + case NestedArtboardBase::artboardIdPropertyKey: + object->as()->artboardId(value); + break; + case ArtboardComponentListBase::listSourcePropertyKey: + object->as()->listSource(value); + break; + case NestedAnimationBase::animationIdPropertyKey: + object->as()->animationId(value); + break; + case SoloBase::activeComponentIdPropertyKey: + object->as()->activeComponentId(value); + break; + case NestedArtboardLayoutBase::instanceWidthUnitsValuePropertyKey: + object->as()->instanceWidthUnitsValue( + value); + break; + case NestedArtboardLayoutBase::instanceHeightUnitsValuePropertyKey: + object->as() + ->instanceHeightUnitsValue(value); + break; + case NestedArtboardLayoutBase::instanceWidthScaleTypePropertyKey: + object->as()->instanceWidthScaleType( + value); + break; + case NestedArtboardLayoutBase::instanceHeightScaleTypePropertyKey: + object->as()->instanceHeightScaleType( + value); + break; + case NSlicerTileModeBase::patchIndexPropertyKey: + object->as()->patchIndex(value); + break; + case NSlicerTileModeBase::stylePropertyKey: + object->as()->style(value); + break; + case LayoutComponentStyleBase::flexBasisUnitsValuePropertyKey: + object->as()->flexBasisUnitsValue( + value); + break; + case LayoutComponentStyleBase::layoutWidthScaleTypePropertyKey: + object->as()->layoutWidthScaleType( + value); + break; + case LayoutComponentStyleBase::layoutHeightScaleTypePropertyKey: + object->as()->layoutHeightScaleType( + value); + break; + case LayoutComponentStyleBase::layoutAlignmentTypePropertyKey: + object->as()->layoutAlignmentType( + value); + break; + case LayoutComponentStyleBase::animationStyleTypePropertyKey: + object->as()->animationStyleType( + value); + break; + case LayoutComponentStyleBase::interpolationTypePropertyKey: + object->as()->interpolationType( + value); + break; + case LayoutComponentStyleBase::interpolatorIdPropertyKey: + object->as()->interpolatorId(value); + break; + case LayoutComponentStyleBase::displayValuePropertyKey: + object->as()->displayValue(value); + break; + case LayoutComponentStyleBase::positionTypeValuePropertyKey: + object->as()->positionTypeValue( + value); + break; + case LayoutComponentStyleBase::flexDirectionValuePropertyKey: + object->as()->flexDirectionValue( + value); + break; + case LayoutComponentStyleBase::directionValuePropertyKey: + object->as()->directionValue(value); + break; + case LayoutComponentStyleBase::alignContentValuePropertyKey: + object->as()->alignContentValue( + value); + break; + case LayoutComponentStyleBase::alignItemsValuePropertyKey: + object->as()->alignItemsValue(value); + break; + case LayoutComponentStyleBase::alignSelfValuePropertyKey: + object->as()->alignSelfValue(value); + break; + case LayoutComponentStyleBase::justifyContentValuePropertyKey: + object->as()->justifyContentValue( + value); + break; + case LayoutComponentStyleBase::flexWrapValuePropertyKey: + object->as()->flexWrapValue(value); + break; + case LayoutComponentStyleBase::overflowValuePropertyKey: + object->as()->overflowValue(value); + break; + case LayoutComponentStyleBase::widthUnitsValuePropertyKey: + object->as()->widthUnitsValue(value); + break; + case LayoutComponentStyleBase::heightUnitsValuePropertyKey: + object->as()->heightUnitsValue(value); + break; + case LayoutComponentStyleBase::borderLeftUnitsValuePropertyKey: + object->as()->borderLeftUnitsValue( + value); + break; + case LayoutComponentStyleBase::borderRightUnitsValuePropertyKey: + object->as()->borderRightUnitsValue( + value); + break; + case LayoutComponentStyleBase::borderTopUnitsValuePropertyKey: + object->as()->borderTopUnitsValue( + value); + break; + case LayoutComponentStyleBase::borderBottomUnitsValuePropertyKey: + object->as()->borderBottomUnitsValue( + value); + break; + case LayoutComponentStyleBase::marginLeftUnitsValuePropertyKey: + object->as()->marginLeftUnitsValue( + value); + break; + case LayoutComponentStyleBase::marginRightUnitsValuePropertyKey: + object->as()->marginRightUnitsValue( + value); + break; + case LayoutComponentStyleBase::marginTopUnitsValuePropertyKey: + object->as()->marginTopUnitsValue( + value); + break; + case LayoutComponentStyleBase::marginBottomUnitsValuePropertyKey: + object->as()->marginBottomUnitsValue( + value); + break; + case LayoutComponentStyleBase::paddingLeftUnitsValuePropertyKey: + object->as()->paddingLeftUnitsValue( + value); + break; + case LayoutComponentStyleBase::paddingRightUnitsValuePropertyKey: + object->as()->paddingRightUnitsValue( + value); + break; + case LayoutComponentStyleBase::paddingTopUnitsValuePropertyKey: + object->as()->paddingTopUnitsValue( + value); + break; + case LayoutComponentStyleBase::paddingBottomUnitsValuePropertyKey: + object->as()->paddingBottomUnitsValue( + value); + break; + case LayoutComponentStyleBase::positionLeftUnitsValuePropertyKey: + object->as()->positionLeftUnitsValue( + value); + break; + case LayoutComponentStyleBase::positionRightUnitsValuePropertyKey: + object->as()->positionRightUnitsValue( + value); + break; + case LayoutComponentStyleBase::positionTopUnitsValuePropertyKey: + object->as()->positionTopUnitsValue( + value); + break; + case LayoutComponentStyleBase::positionBottomUnitsValuePropertyKey: + object->as() + ->positionBottomUnitsValue(value); + break; + case LayoutComponentStyleBase::gapHorizontalUnitsValuePropertyKey: + object->as()->gapHorizontalUnitsValue( + value); + break; + case LayoutComponentStyleBase::gapVerticalUnitsValuePropertyKey: + object->as()->gapVerticalUnitsValue( + value); + break; + case LayoutComponentStyleBase::minWidthUnitsValuePropertyKey: + object->as()->minWidthUnitsValue( + value); + break; + case LayoutComponentStyleBase::minHeightUnitsValuePropertyKey: + object->as()->minHeightUnitsValue( + value); + break; + case LayoutComponentStyleBase::maxWidthUnitsValuePropertyKey: + object->as()->maxWidthUnitsValue( + value); + break; + case LayoutComponentStyleBase::maxHeightUnitsValuePropertyKey: + object->as()->maxHeightUnitsValue( + value); + break; + case ListenerFireEventBase::eventIdPropertyKey: + object->as()->eventId(value); + break; + case LayerStateBase::flagsPropertyKey: + object->as()->flags(value); + break; + case TransitionValueTriggerComparatorBase::valuePropertyKey: + object->as()->value( + value); + break; + case KeyFrameBase::framePropertyKey: + object->as()->frame(value); + break; + case InterpolatingKeyFrameBase::interpolationTypePropertyKey: + object->as()->interpolationType( + value); + break; + case InterpolatingKeyFrameBase::interpolatorIdPropertyKey: + object->as()->interpolatorId(value); + break; + case KeyFrameUintBase::valuePropertyKey: + object->as()->value(value); + break; + case ListenerInputChangeBase::inputIdPropertyKey: + object->as()->inputId(value); + break; + case ListenerInputChangeBase::nestedInputIdPropertyKey: + object->as()->nestedInputId(value); + break; + case AnimationStateBase::animationIdPropertyKey: + object->as()->animationId(value); + break; + case NestedInputBase::inputIdPropertyKey: + object->as()->inputId(value); + break; + case KeyedObjectBase::objectIdPropertyKey: + object->as()->objectId(value); + break; + case BlendAnimationBase::animationIdPropertyKey: + object->as()->animationId(value); + break; + case BlendAnimationDirectBase::inputIdPropertyKey: + object->as()->inputId(value); + break; + case BlendAnimationDirectBase::blendSourcePropertyKey: + object->as()->blendSource(value); + break; + case TransitionInputConditionBase::inputIdPropertyKey: + object->as()->inputId(value); + break; + case KeyedPropertyBase::propertyKeyPropertyKey: + object->as()->propertyKey(value); + break; + case StateMachineListenerBase::targetIdPropertyKey: + object->as()->targetId(value); + break; + case StateMachineListenerBase::listenerTypeValuePropertyKey: + object->as()->listenerTypeValue( + value); + break; + case StateMachineListenerBase::eventIdPropertyKey: + object->as()->eventId(value); + break; + case TransitionPropertyArtboardComparatorBase:: + propertyTypePropertyKey: + object->as() + ->propertyType(value); + break; + case KeyFrameIdBase::valuePropertyKey: + object->as()->value(value); + break; + case ListenerBoolChangeBase::valuePropertyKey: + object->as()->value(value); + break; + case ListenerAlignTargetBase::targetIdPropertyKey: + object->as()->targetId(value); + break; + case TransitionValueConditionBase::opValuePropertyKey: + object->as()->opValue(value); + break; + case TransitionViewModelConditionBase::opValuePropertyKey: + object->as()->opValue(value); + break; + case BlendState1DInputBase::inputIdPropertyKey: + object->as()->inputId(value); + break; + case StateTransitionBase::stateToIdPropertyKey: + object->as()->stateToId(value); + break; + case StateTransitionBase::flagsPropertyKey: + object->as()->flags(value); + break; + case StateTransitionBase::durationPropertyKey: + object->as()->duration(value); + break; + case StateTransitionBase::exitTimePropertyKey: + object->as()->exitTime(value); + break; + case StateTransitionBase::interpolationTypePropertyKey: + object->as()->interpolationType(value); + break; + case StateTransitionBase::interpolatorIdPropertyKey: + object->as()->interpolatorId(value); + break; + case StateTransitionBase::randomWeightPropertyKey: + object->as()->randomWeight(value); + break; + case StateMachineFireEventBase::eventIdPropertyKey: + object->as()->eventId(value); + break; + case StateMachineFireEventBase::occursValuePropertyKey: + object->as()->occursValue(value); + break; + case LinearAnimationBase::fpsPropertyKey: + object->as()->fps(value); + break; + case LinearAnimationBase::durationPropertyKey: + object->as()->duration(value); + break; + case LinearAnimationBase::loopValuePropertyKey: + object->as()->loopValue(value); + break; + case LinearAnimationBase::workStartPropertyKey: + object->as()->workStart(value); + break; + case LinearAnimationBase::workEndPropertyKey: + object->as()->workEnd(value); + break; + case ElasticInterpolatorBase::easingValuePropertyKey: + object->as()->easingValue(value); + break; + case TransitionValueEnumComparatorBase::valuePropertyKey: + object->as()->value(value); + break; + case BlendStateTransitionBase::exitBlendAnimationIdPropertyKey: + object->as()->exitBlendAnimationId( + value); + break; + case ShapePaintBase::blendModeValuePropertyKey: + object->as()->blendModeValue(value); + break; + case StrokeBase::capPropertyKey: + object->as()->cap(value); + break; + case StrokeBase::joinPropertyKey: + object->as()->join(value); + break; + case FeatherBase::spaceValuePropertyKey: + object->as()->spaceValue(value); + break; + case TrimPathBase::modeValuePropertyKey: + object->as()->modeValue(value); + break; + case FillBase::fillRulePropertyKey: + object->as()->fillRule(value); + break; + case PathBase::pathFlagsPropertyKey: + object->as()->pathFlags(value); + break; + case ClippingShapeBase::sourceIdPropertyKey: + object->as()->sourceId(value); + break; + case ClippingShapeBase::fillRulePropertyKey: + object->as()->fillRule(value); + break; + case PolygonBase::pointsPropertyKey: + object->as()->points(value); + break; + case ImageBase::assetIdPropertyKey: + object->as()->assetId(value); + break; + case DrawRulesBase::drawTargetIdPropertyKey: + object->as()->drawTargetId(value); + break; + case LayoutComponentBase::styleIdPropertyKey: + object->as()->styleId(value); + break; + case ArtboardBase::defaultStateMachineIdPropertyKey: + object->as()->defaultStateMachineId(value); + break; + case ArtboardBase::viewModelIdPropertyKey: + object->as()->viewModelId(value); + break; + case JoystickBase::xIdPropertyKey: + object->as()->xId(value); + break; + case JoystickBase::yIdPropertyKey: + object->as()->yId(value); + break; + case JoystickBase::joystickFlagsPropertyKey: + object->as()->joystickFlags(value); + break; + case JoystickBase::handleSourceIdPropertyKey: + object->as()->handleSourceId(value); + break; + case OpenUrlEventBase::targetValuePropertyKey: + object->as()->targetValue(value); + break; + case BindablePropertyIntegerBase::propertyValuePropertyKey: + object->as()->propertyValue(value); + break; + case DataBindBase::propertyKeyPropertyKey: + object->as()->propertyKey(value); + break; + case DataBindBase::flagsPropertyKey: + object->as()->flags(value); + break; + case DataBindBase::converterIdPropertyKey: + object->as()->converterId(value); + break; + case BindablePropertyAssetBase::propertyValuePropertyKey: + object->as()->propertyValue(value); + break; + case DataConverterNumberToListBase::viewModelIdPropertyKey: + object->as()->viewModelId(value); + break; + case DataConverterOperationBase::operationTypePropertyKey: + object->as()->operationType(value); + break; + case DataConverterRangeMapperBase::interpolationTypePropertyKey: + object->as()->interpolationType( + value); + break; + case DataConverterRangeMapperBase::interpolatorIdPropertyKey: + object->as()->interpolatorId( + value); + break; + case DataConverterRangeMapperBase::flagsPropertyKey: + object->as()->flags(value); + break; + case DataConverterInterpolatorBase::interpolationTypePropertyKey: + object->as()->interpolationType( + value); + break; + case DataConverterInterpolatorBase::interpolatorIdPropertyKey: + object->as()->interpolatorId( + value); + break; + case DataConverterGroupItemBase::converterIdPropertyKey: + object->as()->converterId(value); + break; + case DataConverterRounderBase::decimalsPropertyKey: + object->as()->decimals(value); + break; + case DataConverterStringPadBase::lengthPropertyKey: + object->as()->length(value); + break; + case DataConverterStringPadBase::padTypePropertyKey: + object->as()->padType(value); + break; + case DataConverterStringTrimBase::trimTypePropertyKey: + object->as()->trimType(value); + break; + case FormulaTokenOperationBase::operationTypePropertyKey: + object->as()->operationType(value); + break; + case FormulaTokenFunctionBase::functionTypePropertyKey: + object->as()->functionType(value); + break; + case DataConverterToStringBase::flagsPropertyKey: + object->as()->flags(value); + break; + case DataConverterToStringBase::decimalsPropertyKey: + object->as()->decimals(value); + break; + case BindablePropertyEnumBase::propertyValuePropertyKey: + object->as()->propertyValue(value); + break; + case NestedArtboardLeafBase::fitPropertyKey: + object->as()->fit(value); + break; + case WeightBase::valuesPropertyKey: + object->as()->values(value); + break; + case WeightBase::indicesPropertyKey: + object->as()->indices(value); + break; + case TendonBase::boneIdPropertyKey: + object->as()->boneId(value); + break; + case CubicWeightBase::inValuesPropertyKey: + object->as()->inValues(value); + break; + case CubicWeightBase::inIndicesPropertyKey: + object->as()->inIndices(value); + break; + case CubicWeightBase::outValuesPropertyKey: + object->as()->outValues(value); + break; + case CubicWeightBase::outIndicesPropertyKey: + object->as()->outIndices(value); + break; + case TextModifierRangeBase::unitsValuePropertyKey: + object->as()->unitsValue(value); + break; + case TextModifierRangeBase::typeValuePropertyKey: + object->as()->typeValue(value); + break; + case TextModifierRangeBase::modeValuePropertyKey: + object->as()->modeValue(value); + break; + case TextModifierRangeBase::runIdPropertyKey: + object->as()->runId(value); + break; + case TextTargetModifierBase::targetIdPropertyKey: + object->as()->targetId(value); + break; + case TextStyleFeatureBase::tagPropertyKey: + object->as()->tag(value); + break; + case TextStyleFeatureBase::featureValuePropertyKey: + object->as()->featureValue(value); + break; + case TextVariationModifierBase::axisTagPropertyKey: + object->as()->axisTag(value); + break; + case TextModifierGroupBase::modifierFlagsPropertyKey: + object->as()->modifierFlags(value); + break; + case TextStyleBase::fontAssetIdPropertyKey: + object->as()->fontAssetId(value); + break; + case TextStyleAxisBase::tagPropertyKey: + object->as()->tag(value); + break; + case TextBase::alignValuePropertyKey: + object->as()->alignValue(value); + break; + case TextBase::sizingValuePropertyKey: + object->as()->sizingValue(value); + break; + case TextBase::overflowValuePropertyKey: + object->as()->overflowValue(value); + break; + case TextBase::originValuePropertyKey: + object->as()->originValue(value); + break; + case TextBase::wrapValuePropertyKey: + object->as()->wrapValue(value); + break; + case TextBase::verticalAlignValuePropertyKey: + object->as()->verticalAlignValue(value); + break; + case TextValueRunBase::styleIdPropertyKey: + object->as()->styleId(value); + break; + case FileAssetBase::assetIdPropertyKey: + object->as()->assetId(value); + break; + case AudioEventBase::assetIdPropertyKey: + object->as()->assetId(value); + break; + } + } + static void setColor(Core* object, int propertyKey, int value) + { + switch (propertyKey) + { + case ViewModelInstanceColorBase::propertyValuePropertyKey: + object->as()->propertyValue(value); + break; + case KeyFrameColorBase::valuePropertyKey: + object->as()->value(value); + break; + case TransitionValueColorComparatorBase::valuePropertyKey: + object->as()->value(value); + break; + case SolidColorBase::colorValuePropertyKey: + object->as()->colorValue(value); + break; + case GradientStopBase::colorValuePropertyKey: + object->as()->colorValue(value); + break; + case BindablePropertyColorBase::propertyValuePropertyKey: + object->as()->propertyValue(value); + break; + } + } + static void setString(Core* object, int propertyKey, std::string value) + { + switch (propertyKey) + { + case ViewModelComponentBase::namePropertyKey: + object->as()->name(value); + break; + case DataEnumCustomBase::namePropertyKey: + object->as()->name(value); + break; + case ViewModelInstanceStringBase::propertyValuePropertyKey: + object->as()->propertyValue(value); + break; + case DataEnumValueBase::keyPropertyKey: + object->as()->key(value); + break; + case DataEnumValueBase::valuePropertyKey: + object->as()->value(value); + break; + case ComponentBase::namePropertyKey: + object->as()->name(value); + break; + case AnimationBase::namePropertyKey: + object->as()->name(value); + break; + case StateMachineComponentBase::namePropertyKey: + object->as()->name(value); + break; + case KeyFrameStringBase::valuePropertyKey: + object->as()->value(value); + break; + case TransitionValueStringComparatorBase::valuePropertyKey: + object->as()->value(value); + break; + case OpenUrlEventBase::urlPropertyKey: + object->as()->url(value); + break; + case DataConverterBase::namePropertyKey: + object->as()->name(value); + break; + case DataConverterStringPadBase::textPropertyKey: + object->as()->text(value); + break; + case DataConverterToStringBase::colorFormatPropertyKey: + object->as()->colorFormat(value); + break; + case BindablePropertyStringBase::propertyValuePropertyKey: + object->as()->propertyValue(value); + break; + case TextInputBase::textPropertyKey: + object->as()->text(value); + break; + case TextValueRunBase::textPropertyKey: + object->as()->text(value); + break; + case CustomPropertyStringBase::propertyValuePropertyKey: + object->as()->propertyValue(value); + break; + case AssetBase::namePropertyKey: + object->as()->name(value); + break; + case FileAssetBase::cdnBaseUrlPropertyKey: + object->as()->cdnBaseUrl(value); + break; + } + } + static void setBool(Core* object, int propertyKey, bool value) + { + switch (propertyKey) + { + case ViewModelInstanceBooleanBase::propertyValuePropertyKey: + object->as()->propertyValue( + value); + break; + case TransformComponentConstraintBase::offsetPropertyKey: + object->as()->offset(value); + break; + case TransformComponentConstraintBase::doesCopyPropertyKey: + object->as()->doesCopy(value); + break; + case TransformComponentConstraintBase::minPropertyKey: + object->as()->min(value); + break; + case TransformComponentConstraintBase::maxPropertyKey: + object->as()->max(value); + break; + case TransformComponentConstraintYBase::doesCopyYPropertyKey: + object->as()->doesCopyY( + value); + break; + case TransformComponentConstraintYBase::minYPropertyKey: + object->as()->minY(value); + break; + case TransformComponentConstraintYBase::maxYPropertyKey: + object->as()->maxY(value); + break; + case IKConstraintBase::invertDirectionPropertyKey: + object->as()->invertDirection(value); + break; + case FollowPathConstraintBase::orientPropertyKey: + object->as()->orient(value); + break; + case FollowPathConstraintBase::offsetPropertyKey: + object->as()->offset(value); + break; + case ScrollConstraintBase::snapPropertyKey: + object->as()->snap(value); + break; + case ScrollBarConstraintBase::autoSizePropertyKey: + object->as()->autoSize(value); + break; + case AxisBase::normalizedPropertyKey: + object->as()->normalized(value); + break; + case LayoutComponentStyleBase::intrinsicallySizedValuePropertyKey: + object->as()->intrinsicallySizedValue( + value); + break; + case LayoutComponentStyleBase::linkCornerRadiusPropertyKey: + object->as()->linkCornerRadius(value); + break; + case NestedSimpleAnimationBase::isPlayingPropertyKey: + object->as()->isPlaying(value); + break; + case KeyFrameBoolBase::valuePropertyKey: + object->as()->value(value); + break; + case ListenerAlignTargetBase::preserveOffsetPropertyKey: + object->as()->preserveOffset(value); + break; + case TransitionValueBooleanComparatorBase::valuePropertyKey: + object->as()->value( + value); + break; + case NestedBoolBase::nestedValuePropertyKey: + object->as()->nestedValue(value); + break; + case LinearAnimationBase::enableWorkAreaPropertyKey: + object->as()->enableWorkArea(value); + break; + case LinearAnimationBase::quantizePropertyKey: + object->as()->quantize(value); + break; + case StateMachineBoolBase::valuePropertyKey: + object->as()->value(value); + break; + case ShapePaintBase::isVisiblePropertyKey: + object->as()->isVisible(value); + break; + case DashPathBase::offsetIsPercentagePropertyKey: + object->as()->offsetIsPercentage(value); + break; + case DashBase::lengthIsPercentagePropertyKey: + object->as()->lengthIsPercentage(value); + break; + case StrokeBase::transformAffectsStrokePropertyKey: + object->as()->transformAffectsStroke(value); + break; + case FeatherBase::innerPropertyKey: + object->as()->inner(value); + break; + case PathBase::isHolePropertyKey: + object->as()->isHole(value); + break; + case PointsPathBase::isClosedPropertyKey: + object->as()->isClosed(value); + break; + case RectangleBase::linkCornerRadiusPropertyKey: + object->as()->linkCornerRadius(value); + break; + case ClippingShapeBase::isVisiblePropertyKey: + object->as()->isVisible(value); + break; + case CustomPropertyBooleanBase::propertyValuePropertyKey: + object->as()->propertyValue(value); + break; + case LayoutComponentBase::clipPropertyKey: + object->as()->clip(value); + break; + case BindablePropertyBooleanBase::propertyValuePropertyKey: + object->as()->propertyValue(value); + break; + case TextModifierRangeBase::clampPropertyKey: + object->as()->clamp(value); + break; + case TextFollowPathModifierBase::radialPropertyKey: + object->as()->radial(value); + break; + case TextFollowPathModifierBase::orientPropertyKey: + object->as()->orient(value); + break; + case TextBase::fitFromBaselinePropertyKey: + object->as()->fitFromBaseline(value); + break; + } + } + static void setDouble(Core* object, int propertyKey, float value) + { + switch (propertyKey) + { + case ViewModelInstanceNumberBase::propertyValuePropertyKey: + object->as()->propertyValue(value); + break; + case CustomPropertyNumberBase::propertyValuePropertyKey: + object->as()->propertyValue(value); + break; + case ConstraintBase::strengthPropertyKey: + object->as()->strength(value); + break; + case DistanceConstraintBase::distancePropertyKey: + object->as()->distance(value); + break; + case TransformComponentConstraintBase::copyFactorPropertyKey: + object->as()->copyFactor( + value); + break; + case TransformComponentConstraintBase::minValuePropertyKey: + object->as()->minValue(value); + break; + case TransformComponentConstraintBase::maxValuePropertyKey: + object->as()->maxValue(value); + break; + case TransformComponentConstraintYBase::copyFactorYPropertyKey: + object->as()->copyFactorY( + value); + break; + case TransformComponentConstraintYBase::minValueYPropertyKey: + object->as()->minValueY( + value); + break; + case TransformComponentConstraintYBase::maxValueYPropertyKey: + object->as()->maxValueY( + value); + break; + case FollowPathConstraintBase::distancePropertyKey: + object->as()->distance(value); + break; + case ScrollConstraintBase::scrollOffsetXPropertyKey: + object->as()->scrollOffsetX(value); + break; + case ScrollConstraintBase::scrollOffsetYPropertyKey: + object->as()->scrollOffsetY(value); + break; + case ScrollConstraintBase::scrollPercentXPropertyKey: + object->as()->scrollPercentX(value); + break; + case ScrollConstraintBase::scrollPercentYPropertyKey: + object->as()->scrollPercentY(value); + break; + case ScrollConstraintBase::scrollIndexPropertyKey: + object->as()->scrollIndex(value); + break; + case ElasticScrollPhysicsBase::frictionPropertyKey: + object->as()->friction(value); + break; + case ElasticScrollPhysicsBase::speedMultiplierPropertyKey: + object->as()->speedMultiplier(value); + break; + case ElasticScrollPhysicsBase::elasticFactorPropertyKey: + object->as()->elasticFactor(value); + break; + case TransformConstraintBase::originXPropertyKey: + object->as()->originX(value); + break; + case TransformConstraintBase::originYPropertyKey: + object->as()->originY(value); + break; + case WorldTransformComponentBase::opacityPropertyKey: + object->as()->opacity(value); + break; + case TransformComponentBase::rotationPropertyKey: + object->as()->rotation(value); + break; + case TransformComponentBase::scaleXPropertyKey: + object->as()->scaleX(value); + break; + case TransformComponentBase::scaleYPropertyKey: + object->as()->scaleY(value); + break; + case NodeBase::xPropertyKey: + case NodeBase::xArtboardPropertyKey: + object->as()->x(value); + break; + case NodeBase::yPropertyKey: + case NodeBase::yArtboardPropertyKey: + object->as()->y(value); + break; + case NodeBase::computedLocalXPropertyKey: + object->as()->computedLocalX(value); + break; + case NodeBase::computedLocalYPropertyKey: + object->as()->computedLocalY(value); + break; + case NodeBase::computedWorldXPropertyKey: + object->as()->computedWorldX(value); + break; + case NodeBase::computedWorldYPropertyKey: + object->as()->computedWorldY(value); + break; + case NodeBase::computedWidthPropertyKey: + object->as()->computedWidth(value); + break; + case NodeBase::computedHeightPropertyKey: + object->as()->computedHeight(value); + break; + case NestedArtboardLayoutBase::instanceWidthPropertyKey: + object->as()->instanceWidth(value); + break; + case NestedArtboardLayoutBase::instanceHeightPropertyKey: + object->as()->instanceHeight(value); + break; + case AxisBase::offsetPropertyKey: + object->as()->offset(value); + break; + case LayoutComponentStyleBase::gapHorizontalPropertyKey: + object->as()->gapHorizontal(value); + break; + case LayoutComponentStyleBase::gapVerticalPropertyKey: + object->as()->gapVertical(value); + break; + case LayoutComponentStyleBase::maxWidthPropertyKey: + object->as()->maxWidth(value); + break; + case LayoutComponentStyleBase::maxHeightPropertyKey: + object->as()->maxHeight(value); + break; + case LayoutComponentStyleBase::minWidthPropertyKey: + object->as()->minWidth(value); + break; + case LayoutComponentStyleBase::minHeightPropertyKey: + object->as()->minHeight(value); + break; + case LayoutComponentStyleBase::borderLeftPropertyKey: + object->as()->borderLeft(value); + break; + case LayoutComponentStyleBase::borderRightPropertyKey: + object->as()->borderRight(value); + break; + case LayoutComponentStyleBase::borderTopPropertyKey: + object->as()->borderTop(value); + break; + case LayoutComponentStyleBase::borderBottomPropertyKey: + object->as()->borderBottom(value); + break; + case LayoutComponentStyleBase::marginLeftPropertyKey: + object->as()->marginLeft(value); + break; + case LayoutComponentStyleBase::marginRightPropertyKey: + object->as()->marginRight(value); + break; + case LayoutComponentStyleBase::marginTopPropertyKey: + object->as()->marginTop(value); + break; + case LayoutComponentStyleBase::marginBottomPropertyKey: + object->as()->marginBottom(value); + break; + case LayoutComponentStyleBase::paddingLeftPropertyKey: + object->as()->paddingLeft(value); + break; + case LayoutComponentStyleBase::paddingRightPropertyKey: + object->as()->paddingRight(value); + break; + case LayoutComponentStyleBase::paddingTopPropertyKey: + object->as()->paddingTop(value); + break; + case LayoutComponentStyleBase::paddingBottomPropertyKey: + object->as()->paddingBottom(value); + break; + case LayoutComponentStyleBase::positionLeftPropertyKey: + object->as()->positionLeft(value); + break; + case LayoutComponentStyleBase::positionRightPropertyKey: + object->as()->positionRight(value); + break; + case LayoutComponentStyleBase::positionTopPropertyKey: + object->as()->positionTop(value); + break; + case LayoutComponentStyleBase::positionBottomPropertyKey: + object->as()->positionBottom(value); + break; + case LayoutComponentStyleBase::flexPropertyKey: + object->as()->flex(value); + break; + case LayoutComponentStyleBase::flexGrowPropertyKey: + object->as()->flexGrow(value); + break; + case LayoutComponentStyleBase::flexShrinkPropertyKey: + object->as()->flexShrink(value); + break; + case LayoutComponentStyleBase::flexBasisPropertyKey: + object->as()->flexBasis(value); + break; + case LayoutComponentStyleBase::aspectRatioPropertyKey: + object->as()->aspectRatio(value); + break; + case LayoutComponentStyleBase::interpolationTimePropertyKey: + object->as()->interpolationTime( + value); + break; + case LayoutComponentStyleBase::cornerRadiusTLPropertyKey: + object->as()->cornerRadiusTL(value); + break; + case LayoutComponentStyleBase::cornerRadiusTRPropertyKey: + object->as()->cornerRadiusTR(value); + break; + case LayoutComponentStyleBase::cornerRadiusBLPropertyKey: + object->as()->cornerRadiusBL(value); + break; + case LayoutComponentStyleBase::cornerRadiusBRPropertyKey: + object->as()->cornerRadiusBR(value); + break; + case NSlicedNodeBase::initialWidthPropertyKey: + object->as()->initialWidth(value); + break; + case NSlicedNodeBase::initialHeightPropertyKey: + object->as()->initialHeight(value); + break; + case NSlicedNodeBase::widthPropertyKey: + object->as()->width(value); + break; + case NSlicedNodeBase::heightPropertyKey: + object->as()->height(value); + break; + case NestedLinearAnimationBase::mixPropertyKey: + object->as()->mix(value); + break; + case NestedSimpleAnimationBase::speedPropertyKey: + object->as()->speed(value); + break; + case AdvanceableStateBase::speedPropertyKey: + object->as()->speed(value); + break; + case BlendAnimationDirectBase::mixValuePropertyKey: + object->as()->mixValue(value); + break; + case StateMachineNumberBase::valuePropertyKey: + object->as()->value(value); + break; + case CubicInterpolatorBase::x1PropertyKey: + object->as()->x1(value); + break; + case CubicInterpolatorBase::y1PropertyKey: + object->as()->y1(value); + break; + case CubicInterpolatorBase::x2PropertyKey: + object->as()->x2(value); + break; + case CubicInterpolatorBase::y2PropertyKey: + object->as()->y2(value); + break; + case TransitionNumberConditionBase::valuePropertyKey: + object->as()->value(value); + break; + case CubicInterpolatorComponentBase::x1PropertyKey: + object->as()->x1(value); + break; + case CubicInterpolatorComponentBase::y1PropertyKey: + object->as()->y1(value); + break; + case CubicInterpolatorComponentBase::x2PropertyKey: + object->as()->x2(value); + break; + case CubicInterpolatorComponentBase::y2PropertyKey: + object->as()->y2(value); + break; + case ListenerNumberChangeBase::valuePropertyKey: + object->as()->value(value); + break; + case KeyFrameDoubleBase::valuePropertyKey: + object->as()->value(value); + break; + case LinearAnimationBase::speedPropertyKey: + object->as()->speed(value); + break; + case TransitionValueNumberComparatorBase::valuePropertyKey: + object->as()->value(value); + break; + case ElasticInterpolatorBase::amplitudePropertyKey: + object->as()->amplitude(value); + break; + case ElasticInterpolatorBase::periodPropertyKey: + object->as()->period(value); + break; + case NestedNumberBase::nestedValuePropertyKey: + object->as()->nestedValue(value); + break; + case NestedRemapAnimationBase::timePropertyKey: + object->as()->time(value); + break; + case BlendAnimation1DBase::valuePropertyKey: + object->as()->value(value); + break; + case DashPathBase::offsetPropertyKey: + object->as()->offset(value); + break; + case LinearGradientBase::startXPropertyKey: + object->as()->startX(value); + break; + case LinearGradientBase::startYPropertyKey: + object->as()->startY(value); + break; + case LinearGradientBase::endXPropertyKey: + object->as()->endX(value); + break; + case LinearGradientBase::endYPropertyKey: + object->as()->endY(value); + break; + case LinearGradientBase::opacityPropertyKey: + object->as()->opacity(value); + break; + case DashBase::lengthPropertyKey: + object->as()->length(value); + break; + case StrokeBase::thicknessPropertyKey: + object->as()->thickness(value); + break; + case GradientStopBase::positionPropertyKey: + object->as()->position(value); + break; + case FeatherBase::strengthPropertyKey: + object->as()->strength(value); + break; + case FeatherBase::offsetXPropertyKey: + object->as()->offsetX(value); + break; + case FeatherBase::offsetYPropertyKey: + object->as()->offsetY(value); + break; + case TrimPathBase::startPropertyKey: + object->as()->start(value); + break; + case TrimPathBase::endPropertyKey: + object->as()->end(value); + break; + case TrimPathBase::offsetPropertyKey: + object->as()->offset(value); + break; + case VertexBase::xPropertyKey: + object->as()->x(value); + break; + case VertexBase::yPropertyKey: + object->as()->y(value); + break; + case MeshVertexBase::uPropertyKey: + object->as()->u(value); + break; + case MeshVertexBase::vPropertyKey: + object->as()->v(value); + break; + case ShapeBase::lengthPropertyKey: + object->as()->length(value); + break; + case StraightVertexBase::radiusPropertyKey: + object->as()->radius(value); + break; + case CubicAsymmetricVertexBase::rotationPropertyKey: + object->as()->rotation(value); + break; + case CubicAsymmetricVertexBase::inDistancePropertyKey: + object->as()->inDistance(value); + break; + case CubicAsymmetricVertexBase::outDistancePropertyKey: + object->as()->outDistance(value); + break; + case ParametricPathBase::widthPropertyKey: + object->as()->width(value); + break; + case ParametricPathBase::heightPropertyKey: + object->as()->height(value); + break; + case ParametricPathBase::originXPropertyKey: + object->as()->originX(value); + break; + case ParametricPathBase::originYPropertyKey: + object->as()->originY(value); + break; + case RectangleBase::cornerRadiusTLPropertyKey: + object->as()->cornerRadiusTL(value); + break; + case RectangleBase::cornerRadiusTRPropertyKey: + object->as()->cornerRadiusTR(value); + break; + case RectangleBase::cornerRadiusBLPropertyKey: + object->as()->cornerRadiusBL(value); + break; + case RectangleBase::cornerRadiusBRPropertyKey: + object->as()->cornerRadiusBR(value); + break; + case CubicMirroredVertexBase::rotationPropertyKey: + object->as()->rotation(value); + break; + case CubicMirroredVertexBase::distancePropertyKey: + object->as()->distance(value); + break; + case PolygonBase::cornerRadiusPropertyKey: + object->as()->cornerRadius(value); + break; + case StarBase::innerRadiusPropertyKey: + object->as()->innerRadius(value); + break; + case ImageBase::originXPropertyKey: + object->as()->originX(value); + break; + case ImageBase::originYPropertyKey: + object->as()->originY(value); + break; + case CubicDetachedVertexBase::inRotationPropertyKey: + object->as()->inRotation(value); + break; + case CubicDetachedVertexBase::inDistancePropertyKey: + object->as()->inDistance(value); + break; + case CubicDetachedVertexBase::outRotationPropertyKey: + object->as()->outRotation(value); + break; + case CubicDetachedVertexBase::outDistancePropertyKey: + object->as()->outDistance(value); + break; + case LayoutComponentBase::widthPropertyKey: + object->as()->width(value); + break; + case LayoutComponentBase::heightPropertyKey: + object->as()->height(value); + break; + case LayoutComponentBase::fractionalWidthPropertyKey: + object->as()->fractionalWidth(value); + break; + case LayoutComponentBase::fractionalHeightPropertyKey: + object->as()->fractionalHeight(value); + break; + case ArtboardBase::originXPropertyKey: + object->as()->originX(value); + break; + case ArtboardBase::originYPropertyKey: + object->as()->originY(value); + break; + case JoystickBase::xPropertyKey: + object->as()->x(value); + break; + case JoystickBase::yPropertyKey: + object->as()->y(value); + break; + case JoystickBase::posXPropertyKey: + object->as()->posX(value); + break; + case JoystickBase::posYPropertyKey: + object->as()->posY(value); + break; + case JoystickBase::originXPropertyKey: + object->as()->originX(value); + break; + case JoystickBase::originYPropertyKey: + object->as()->originY(value); + break; + case JoystickBase::widthPropertyKey: + object->as()->width(value); + break; + case JoystickBase::heightPropertyKey: + object->as()->height(value); + break; + case DataConverterOperationValueBase::operationValuePropertyKey: + object->as()->operationValue( + value); + break; + case DataConverterRangeMapperBase::minInputPropertyKey: + object->as()->minInput(value); + break; + case DataConverterRangeMapperBase::maxInputPropertyKey: + object->as()->maxInput(value); + break; + case DataConverterRangeMapperBase::minOutputPropertyKey: + object->as()->minOutput(value); + break; + case DataConverterRangeMapperBase::maxOutputPropertyKey: + object->as()->maxOutput(value); + break; + case DataConverterInterpolatorBase::durationPropertyKey: + object->as()->duration(value); + break; + case FormulaTokenValueBase::operationValuePropertyKey: + object->as()->operationValue(value); + break; + case BindablePropertyNumberBase::propertyValuePropertyKey: + object->as()->propertyValue(value); + break; + case NestedArtboardLeafBase::alignmentXPropertyKey: + object->as()->alignmentX(value); + break; + case NestedArtboardLeafBase::alignmentYPropertyKey: + object->as()->alignmentY(value); + break; + case BoneBase::lengthPropertyKey: + object->as()->length(value); + break; + case RootBoneBase::xPropertyKey: + object->as()->x(value); + break; + case RootBoneBase::yPropertyKey: + object->as()->y(value); + break; + case SkinBase::xxPropertyKey: + object->as()->xx(value); + break; + case SkinBase::yxPropertyKey: + object->as()->yx(value); + break; + case SkinBase::xyPropertyKey: + object->as()->xy(value); + break; + case SkinBase::yyPropertyKey: + object->as()->yy(value); + break; + case SkinBase::txPropertyKey: + object->as()->tx(value); + break; + case SkinBase::tyPropertyKey: + object->as()->ty(value); + break; + case TendonBase::xxPropertyKey: + object->as()->xx(value); + break; + case TendonBase::yxPropertyKey: + object->as()->yx(value); + break; + case TendonBase::xyPropertyKey: + object->as()->xy(value); + break; + case TendonBase::yyPropertyKey: + object->as()->yy(value); + break; + case TendonBase::txPropertyKey: + object->as()->tx(value); + break; + case TendonBase::tyPropertyKey: + object->as()->ty(value); + break; + case TextModifierRangeBase::modifyFromPropertyKey: + object->as()->modifyFrom(value); + break; + case TextModifierRangeBase::modifyToPropertyKey: + object->as()->modifyTo(value); + break; + case TextModifierRangeBase::strengthPropertyKey: + object->as()->strength(value); + break; + case TextModifierRangeBase::falloffFromPropertyKey: + object->as()->falloffFrom(value); + break; + case TextModifierRangeBase::falloffToPropertyKey: + object->as()->falloffTo(value); + break; + case TextModifierRangeBase::offsetPropertyKey: + object->as()->offset(value); + break; + case TextFollowPathModifierBase::startPropertyKey: + object->as()->start(value); + break; + case TextFollowPathModifierBase::endPropertyKey: + object->as()->end(value); + break; + case TextFollowPathModifierBase::strengthPropertyKey: + object->as()->strength(value); + break; + case TextFollowPathModifierBase::offsetPropertyKey: + object->as()->offset(value); + break; + case TextVariationModifierBase::axisValuePropertyKey: + object->as()->axisValue(value); + break; + case TextModifierGroupBase::originXPropertyKey: + object->as()->originX(value); + break; + case TextModifierGroupBase::originYPropertyKey: + object->as()->originY(value); + break; + case TextModifierGroupBase::opacityPropertyKey: + object->as()->opacity(value); + break; + case TextModifierGroupBase::xPropertyKey: + object->as()->x(value); + break; + case TextModifierGroupBase::yPropertyKey: + object->as()->y(value); + break; + case TextModifierGroupBase::rotationPropertyKey: + object->as()->rotation(value); + break; + case TextModifierGroupBase::scaleXPropertyKey: + object->as()->scaleX(value); + break; + case TextModifierGroupBase::scaleYPropertyKey: + object->as()->scaleY(value); + break; + case TextStyleBase::fontSizePropertyKey: + object->as()->fontSize(value); + break; + case TextStyleBase::lineHeightPropertyKey: + object->as()->lineHeight(value); + break; + case TextStyleBase::letterSpacingPropertyKey: + object->as()->letterSpacing(value); + break; + case TextInputBase::selectionRadiusPropertyKey: + object->as()->selectionRadius(value); + break; + case TextStyleAxisBase::axisValuePropertyKey: + object->as()->axisValue(value); + break; + case TextBase::widthPropertyKey: + object->as()->width(value); + break; + case TextBase::heightPropertyKey: + object->as()->height(value); + break; + case TextBase::originXPropertyKey: + object->as()->originX(value); + break; + case TextBase::originYPropertyKey: + object->as()->originY(value); + break; + case TextBase::paragraphSpacingPropertyKey: + object->as()->paragraphSpacing(value); + break; + case DrawableAssetBase::heightPropertyKey: + object->as()->height(value); + break; + case DrawableAssetBase::widthPropertyKey: + object->as()->width(value); + break; + case ExportAudioBase::volumePropertyKey: + object->as()->volume(value); + break; + } + } + static void setCallback(Core* object, int propertyKey, CallbackData value) + { + switch (propertyKey) + { + case NestedTriggerBase::firePropertyKey: + object->as()->fire(value); + break; + case EventBase::triggerPropertyKey: + object->as()->trigger(value); + break; + } + } + static uint32_t getUint(Core* object, int propertyKey) + { + switch (propertyKey) + { + case ViewModelInstanceListItemBase::viewModelIdPropertyKey: + return object->as() + ->viewModelId(); + case ViewModelInstanceListItemBase::viewModelInstanceIdPropertyKey: + return object->as() + ->viewModelInstanceId(); + case ViewModelInstanceValueBase::viewModelPropertyIdPropertyKey: + return object->as() + ->viewModelPropertyId(); + case ViewModelPropertyEnumCustomBase::enumIdPropertyKey: + return object->as()->enumId(); + case ViewModelInstanceEnumBase::propertyValuePropertyKey: + return object->as()->propertyValue(); + case ViewModelPropertyEnumSystemBase::enumTypePropertyKey: + return object->as() + ->enumType(); + case DataEnumSystemBase::enumTypePropertyKey: + return object->as()->enumType(); + case ViewModelPropertyViewModelBase:: + viewModelReferenceIdPropertyKey: + return object->as() + ->viewModelReferenceId(); + case ComponentBase::parentIdPropertyKey: + return object->as()->parentId(); + case ViewModelInstanceBase::viewModelIdPropertyKey: + return object->as()->viewModelId(); + case ViewModelInstanceTriggerBase::propertyValuePropertyKey: + return object->as() + ->propertyValue(); + case ViewModelInstanceSymbolListIndexBase::propertyValuePropertyKey: + return object->as() + ->propertyValue(); + case ViewModelInstanceViewModelBase::propertyValuePropertyKey: + return object->as() + ->propertyValue(); + case ViewModelInstanceAssetBase::propertyValuePropertyKey: + return object->as() + ->propertyValue(); + case DrawTargetBase::drawableIdPropertyKey: + return object->as()->drawableId(); + case DrawTargetBase::placementValuePropertyKey: + return object->as()->placementValue(); + case TargetedConstraintBase::targetIdPropertyKey: + return object->as()->targetId(); + case DistanceConstraintBase::modeValuePropertyKey: + return object->as()->modeValue(); + case TransformSpaceConstraintBase::sourceSpaceValuePropertyKey: + return object->as() + ->sourceSpaceValue(); + case TransformSpaceConstraintBase::destSpaceValuePropertyKey: + return object->as() + ->destSpaceValue(); + case TransformComponentConstraintBase::minMaxSpaceValuePropertyKey: + return object->as() + ->minMaxSpaceValue(); + case IKConstraintBase::parentBoneCountPropertyKey: + return object->as()->parentBoneCount(); + case ScrollPhysicsBase::constraintIdPropertyKey: + return object->as()->constraintId(); + case DraggableConstraintBase::directionValuePropertyKey: + return object->as()->directionValue(); + case ScrollConstraintBase::physicsTypeValuePropertyKey: + return object->as()->physicsTypeValue(); + case ScrollConstraintBase::physicsIdPropertyKey: + return object->as()->physicsId(); + case ScrollBarConstraintBase::scrollConstraintIdPropertyKey: + return object->as() + ->scrollConstraintId(); + case DrawableBase::blendModeValuePropertyKey: + return object->as()->blendModeValue(); + case DrawableBase::drawableFlagsPropertyKey: + return object->as()->drawableFlags(); + case NestedArtboardBase::artboardIdPropertyKey: + return object->as()->artboardId(); + case ArtboardComponentListBase::listSourcePropertyKey: + return object->as()->listSource(); + case NestedAnimationBase::animationIdPropertyKey: + return object->as()->animationId(); + case SoloBase::activeComponentIdPropertyKey: + return object->as()->activeComponentId(); + case NestedArtboardLayoutBase::instanceWidthUnitsValuePropertyKey: + return object->as() + ->instanceWidthUnitsValue(); + case NestedArtboardLayoutBase::instanceHeightUnitsValuePropertyKey: + return object->as() + ->instanceHeightUnitsValue(); + case NestedArtboardLayoutBase::instanceWidthScaleTypePropertyKey: + return object->as() + ->instanceWidthScaleType(); + case NestedArtboardLayoutBase::instanceHeightScaleTypePropertyKey: + return object->as() + ->instanceHeightScaleType(); + case NSlicerTileModeBase::patchIndexPropertyKey: + return object->as()->patchIndex(); + case NSlicerTileModeBase::stylePropertyKey: + return object->as()->style(); + case LayoutComponentStyleBase::flexBasisUnitsValuePropertyKey: + return object->as() + ->flexBasisUnitsValue(); + case LayoutComponentStyleBase::layoutWidthScaleTypePropertyKey: + return object->as() + ->layoutWidthScaleType(); + case LayoutComponentStyleBase::layoutHeightScaleTypePropertyKey: + return object->as() + ->layoutHeightScaleType(); + case LayoutComponentStyleBase::layoutAlignmentTypePropertyKey: + return object->as() + ->layoutAlignmentType(); + case LayoutComponentStyleBase::animationStyleTypePropertyKey: + return object->as() + ->animationStyleType(); + case LayoutComponentStyleBase::interpolationTypePropertyKey: + return object->as() + ->interpolationType(); + case LayoutComponentStyleBase::interpolatorIdPropertyKey: + return object->as()->interpolatorId(); + case LayoutComponentStyleBase::displayValuePropertyKey: + return object->as()->displayValue(); + case LayoutComponentStyleBase::positionTypeValuePropertyKey: + return object->as() + ->positionTypeValue(); + case LayoutComponentStyleBase::flexDirectionValuePropertyKey: + return object->as() + ->flexDirectionValue(); + case LayoutComponentStyleBase::directionValuePropertyKey: + return object->as()->directionValue(); + case LayoutComponentStyleBase::alignContentValuePropertyKey: + return object->as() + ->alignContentValue(); + case LayoutComponentStyleBase::alignItemsValuePropertyKey: + return object->as() + ->alignItemsValue(); + case LayoutComponentStyleBase::alignSelfValuePropertyKey: + return object->as()->alignSelfValue(); + case LayoutComponentStyleBase::justifyContentValuePropertyKey: + return object->as() + ->justifyContentValue(); + case LayoutComponentStyleBase::flexWrapValuePropertyKey: + return object->as()->flexWrapValue(); + case LayoutComponentStyleBase::overflowValuePropertyKey: + return object->as()->overflowValue(); + case LayoutComponentStyleBase::widthUnitsValuePropertyKey: + return object->as() + ->widthUnitsValue(); + case LayoutComponentStyleBase::heightUnitsValuePropertyKey: + return object->as() + ->heightUnitsValue(); + case LayoutComponentStyleBase::borderLeftUnitsValuePropertyKey: + return object->as() + ->borderLeftUnitsValue(); + case LayoutComponentStyleBase::borderRightUnitsValuePropertyKey: + return object->as() + ->borderRightUnitsValue(); + case LayoutComponentStyleBase::borderTopUnitsValuePropertyKey: + return object->as() + ->borderTopUnitsValue(); + case LayoutComponentStyleBase::borderBottomUnitsValuePropertyKey: + return object->as() + ->borderBottomUnitsValue(); + case LayoutComponentStyleBase::marginLeftUnitsValuePropertyKey: + return object->as() + ->marginLeftUnitsValue(); + case LayoutComponentStyleBase::marginRightUnitsValuePropertyKey: + return object->as() + ->marginRightUnitsValue(); + case LayoutComponentStyleBase::marginTopUnitsValuePropertyKey: + return object->as() + ->marginTopUnitsValue(); + case LayoutComponentStyleBase::marginBottomUnitsValuePropertyKey: + return object->as() + ->marginBottomUnitsValue(); + case LayoutComponentStyleBase::paddingLeftUnitsValuePropertyKey: + return object->as() + ->paddingLeftUnitsValue(); + case LayoutComponentStyleBase::paddingRightUnitsValuePropertyKey: + return object->as() + ->paddingRightUnitsValue(); + case LayoutComponentStyleBase::paddingTopUnitsValuePropertyKey: + return object->as() + ->paddingTopUnitsValue(); + case LayoutComponentStyleBase::paddingBottomUnitsValuePropertyKey: + return object->as() + ->paddingBottomUnitsValue(); + case LayoutComponentStyleBase::positionLeftUnitsValuePropertyKey: + return object->as() + ->positionLeftUnitsValue(); + case LayoutComponentStyleBase::positionRightUnitsValuePropertyKey: + return object->as() + ->positionRightUnitsValue(); + case LayoutComponentStyleBase::positionTopUnitsValuePropertyKey: + return object->as() + ->positionTopUnitsValue(); + case LayoutComponentStyleBase::positionBottomUnitsValuePropertyKey: + return object->as() + ->positionBottomUnitsValue(); + case LayoutComponentStyleBase::gapHorizontalUnitsValuePropertyKey: + return object->as() + ->gapHorizontalUnitsValue(); + case LayoutComponentStyleBase::gapVerticalUnitsValuePropertyKey: + return object->as() + ->gapVerticalUnitsValue(); + case LayoutComponentStyleBase::minWidthUnitsValuePropertyKey: + return object->as() + ->minWidthUnitsValue(); + case LayoutComponentStyleBase::minHeightUnitsValuePropertyKey: + return object->as() + ->minHeightUnitsValue(); + case LayoutComponentStyleBase::maxWidthUnitsValuePropertyKey: + return object->as() + ->maxWidthUnitsValue(); + case LayoutComponentStyleBase::maxHeightUnitsValuePropertyKey: + return object->as() + ->maxHeightUnitsValue(); + case ListenerFireEventBase::eventIdPropertyKey: + return object->as()->eventId(); + case LayerStateBase::flagsPropertyKey: + return object->as()->flags(); + case TransitionValueTriggerComparatorBase::valuePropertyKey: + return object->as() + ->value(); + case KeyFrameBase::framePropertyKey: + return object->as()->frame(); + case InterpolatingKeyFrameBase::interpolationTypePropertyKey: + return object->as() + ->interpolationType(); + case InterpolatingKeyFrameBase::interpolatorIdPropertyKey: + return object->as() + ->interpolatorId(); + case KeyFrameUintBase::valuePropertyKey: + return object->as()->value(); + case ListenerInputChangeBase::inputIdPropertyKey: + return object->as()->inputId(); + case ListenerInputChangeBase::nestedInputIdPropertyKey: + return object->as()->nestedInputId(); + case AnimationStateBase::animationIdPropertyKey: + return object->as()->animationId(); + case NestedInputBase::inputIdPropertyKey: + return object->as()->inputId(); + case KeyedObjectBase::objectIdPropertyKey: + return object->as()->objectId(); + case BlendAnimationBase::animationIdPropertyKey: + return object->as()->animationId(); + case BlendAnimationDirectBase::inputIdPropertyKey: + return object->as()->inputId(); + case BlendAnimationDirectBase::blendSourcePropertyKey: + return object->as()->blendSource(); + case TransitionInputConditionBase::inputIdPropertyKey: + return object->as()->inputId(); + case KeyedPropertyBase::propertyKeyPropertyKey: + return object->as()->propertyKey(); + case StateMachineListenerBase::targetIdPropertyKey: + return object->as()->targetId(); + case StateMachineListenerBase::listenerTypeValuePropertyKey: + return object->as() + ->listenerTypeValue(); + case StateMachineListenerBase::eventIdPropertyKey: + return object->as()->eventId(); + case TransitionPropertyArtboardComparatorBase:: + propertyTypePropertyKey: + return object->as() + ->propertyType(); + case KeyFrameIdBase::valuePropertyKey: + return object->as()->value(); + case ListenerBoolChangeBase::valuePropertyKey: + return object->as()->value(); + case ListenerAlignTargetBase::targetIdPropertyKey: + return object->as()->targetId(); + case TransitionValueConditionBase::opValuePropertyKey: + return object->as()->opValue(); + case TransitionViewModelConditionBase::opValuePropertyKey: + return object->as() + ->opValue(); + case BlendState1DInputBase::inputIdPropertyKey: + return object->as()->inputId(); + case StateTransitionBase::stateToIdPropertyKey: + return object->as()->stateToId(); + case StateTransitionBase::flagsPropertyKey: + return object->as()->flags(); + case StateTransitionBase::durationPropertyKey: + return object->as()->duration(); + case StateTransitionBase::exitTimePropertyKey: + return object->as()->exitTime(); + case StateTransitionBase::interpolationTypePropertyKey: + return object->as()->interpolationType(); + case StateTransitionBase::interpolatorIdPropertyKey: + return object->as()->interpolatorId(); + case StateTransitionBase::randomWeightPropertyKey: + return object->as()->randomWeight(); + case StateMachineFireEventBase::eventIdPropertyKey: + return object->as()->eventId(); + case StateMachineFireEventBase::occursValuePropertyKey: + return object->as()->occursValue(); + case LinearAnimationBase::fpsPropertyKey: + return object->as()->fps(); + case LinearAnimationBase::durationPropertyKey: + return object->as()->duration(); + case LinearAnimationBase::loopValuePropertyKey: + return object->as()->loopValue(); + case LinearAnimationBase::workStartPropertyKey: + return object->as()->workStart(); + case LinearAnimationBase::workEndPropertyKey: + return object->as()->workEnd(); + case ElasticInterpolatorBase::easingValuePropertyKey: + return object->as()->easingValue(); + case TransitionValueEnumComparatorBase::valuePropertyKey: + return object->as()->value(); + case BlendStateTransitionBase::exitBlendAnimationIdPropertyKey: + return object->as() + ->exitBlendAnimationId(); + case ShapePaintBase::blendModeValuePropertyKey: + return object->as()->blendModeValue(); + case StrokeBase::capPropertyKey: + return object->as()->cap(); + case StrokeBase::joinPropertyKey: + return object->as()->join(); + case FeatherBase::spaceValuePropertyKey: + return object->as()->spaceValue(); + case TrimPathBase::modeValuePropertyKey: + return object->as()->modeValue(); + case FillBase::fillRulePropertyKey: + return object->as()->fillRule(); + case PathBase::pathFlagsPropertyKey: + return object->as()->pathFlags(); + case ClippingShapeBase::sourceIdPropertyKey: + return object->as()->sourceId(); + case ClippingShapeBase::fillRulePropertyKey: + return object->as()->fillRule(); + case PolygonBase::pointsPropertyKey: + return object->as()->points(); + case ImageBase::assetIdPropertyKey: + return object->as()->assetId(); + case DrawRulesBase::drawTargetIdPropertyKey: + return object->as()->drawTargetId(); + case LayoutComponentBase::styleIdPropertyKey: + return object->as()->styleId(); + case ArtboardBase::defaultStateMachineIdPropertyKey: + return object->as()->defaultStateMachineId(); + case ArtboardBase::viewModelIdPropertyKey: + return object->as()->viewModelId(); + case JoystickBase::xIdPropertyKey: + return object->as()->xId(); + case JoystickBase::yIdPropertyKey: + return object->as()->yId(); + case JoystickBase::joystickFlagsPropertyKey: + return object->as()->joystickFlags(); + case JoystickBase::handleSourceIdPropertyKey: + return object->as()->handleSourceId(); + case OpenUrlEventBase::targetValuePropertyKey: + return object->as()->targetValue(); + case BindablePropertyIntegerBase::propertyValuePropertyKey: + return object->as() + ->propertyValue(); + case DataBindBase::propertyKeyPropertyKey: + return object->as()->propertyKey(); + case DataBindBase::flagsPropertyKey: + return object->as()->flags(); + case DataBindBase::converterIdPropertyKey: + return object->as()->converterId(); + case BindablePropertyAssetBase::propertyValuePropertyKey: + return object->as()->propertyValue(); + case DataConverterNumberToListBase::viewModelIdPropertyKey: + return object->as() + ->viewModelId(); + case DataConverterOperationBase::operationTypePropertyKey: + return object->as() + ->operationType(); + case DataConverterRangeMapperBase::interpolationTypePropertyKey: + return object->as() + ->interpolationType(); + case DataConverterRangeMapperBase::interpolatorIdPropertyKey: + return object->as() + ->interpolatorId(); + case DataConverterRangeMapperBase::flagsPropertyKey: + return object->as()->flags(); + case DataConverterInterpolatorBase::interpolationTypePropertyKey: + return object->as() + ->interpolationType(); + case DataConverterInterpolatorBase::interpolatorIdPropertyKey: + return object->as() + ->interpolatorId(); + case DataConverterGroupItemBase::converterIdPropertyKey: + return object->as()->converterId(); + case DataConverterRounderBase::decimalsPropertyKey: + return object->as()->decimals(); + case DataConverterStringPadBase::lengthPropertyKey: + return object->as()->length(); + case DataConverterStringPadBase::padTypePropertyKey: + return object->as()->padType(); + case DataConverterStringTrimBase::trimTypePropertyKey: + return object->as()->trimType(); + case FormulaTokenOperationBase::operationTypePropertyKey: + return object->as()->operationType(); + case FormulaTokenFunctionBase::functionTypePropertyKey: + return object->as()->functionType(); + case DataConverterToStringBase::flagsPropertyKey: + return object->as()->flags(); + case DataConverterToStringBase::decimalsPropertyKey: + return object->as()->decimals(); + case BindablePropertyEnumBase::propertyValuePropertyKey: + return object->as()->propertyValue(); + case NestedArtboardLeafBase::fitPropertyKey: + return object->as()->fit(); + case WeightBase::valuesPropertyKey: + return object->as()->values(); + case WeightBase::indicesPropertyKey: + return object->as()->indices(); + case TendonBase::boneIdPropertyKey: + return object->as()->boneId(); + case CubicWeightBase::inValuesPropertyKey: + return object->as()->inValues(); + case CubicWeightBase::inIndicesPropertyKey: + return object->as()->inIndices(); + case CubicWeightBase::outValuesPropertyKey: + return object->as()->outValues(); + case CubicWeightBase::outIndicesPropertyKey: + return object->as()->outIndices(); + case TextModifierRangeBase::unitsValuePropertyKey: + return object->as()->unitsValue(); + case TextModifierRangeBase::typeValuePropertyKey: + return object->as()->typeValue(); + case TextModifierRangeBase::modeValuePropertyKey: + return object->as()->modeValue(); + case TextModifierRangeBase::runIdPropertyKey: + return object->as()->runId(); + case TextTargetModifierBase::targetIdPropertyKey: + return object->as()->targetId(); + case TextStyleFeatureBase::tagPropertyKey: + return object->as()->tag(); + case TextStyleFeatureBase::featureValuePropertyKey: + return object->as()->featureValue(); + case TextVariationModifierBase::axisTagPropertyKey: + return object->as()->axisTag(); + case TextModifierGroupBase::modifierFlagsPropertyKey: + return object->as()->modifierFlags(); + case TextStyleBase::fontAssetIdPropertyKey: + return object->as()->fontAssetId(); + case TextStyleAxisBase::tagPropertyKey: + return object->as()->tag(); + case TextBase::alignValuePropertyKey: + return object->as()->alignValue(); + case TextBase::sizingValuePropertyKey: + return object->as()->sizingValue(); + case TextBase::overflowValuePropertyKey: + return object->as()->overflowValue(); + case TextBase::originValuePropertyKey: + return object->as()->originValue(); + case TextBase::wrapValuePropertyKey: + return object->as()->wrapValue(); + case TextBase::verticalAlignValuePropertyKey: + return object->as()->verticalAlignValue(); + case TextValueRunBase::styleIdPropertyKey: + return object->as()->styleId(); + case FileAssetBase::assetIdPropertyKey: + return object->as()->assetId(); + case AudioEventBase::assetIdPropertyKey: + return object->as()->assetId(); + } + return 0; + } + static int getColor(Core* object, int propertyKey) + { + switch (propertyKey) + { + case ViewModelInstanceColorBase::propertyValuePropertyKey: + return object->as() + ->propertyValue(); + case KeyFrameColorBase::valuePropertyKey: + return object->as()->value(); + case TransitionValueColorComparatorBase::valuePropertyKey: + return object->as() + ->value(); + case SolidColorBase::colorValuePropertyKey: + return object->as()->colorValue(); + case GradientStopBase::colorValuePropertyKey: + return object->as()->colorValue(); + case BindablePropertyColorBase::propertyValuePropertyKey: + return object->as()->propertyValue(); + } + return 0; + } + static std::string getString(Core* object, int propertyKey) + { + switch (propertyKey) + { + case ViewModelComponentBase::namePropertyKey: + return object->as()->name(); + case DataEnumCustomBase::namePropertyKey: + return object->as()->name(); + case ViewModelInstanceStringBase::propertyValuePropertyKey: + return object->as() + ->propertyValue(); + case DataEnumValueBase::keyPropertyKey: + return object->as()->key(); + case DataEnumValueBase::valuePropertyKey: + return object->as()->value(); + case ComponentBase::namePropertyKey: + return object->as()->name(); + case AnimationBase::namePropertyKey: + return object->as()->name(); + case StateMachineComponentBase::namePropertyKey: + return object->as()->name(); + case KeyFrameStringBase::valuePropertyKey: + return object->as()->value(); + case TransitionValueStringComparatorBase::valuePropertyKey: + return object->as() + ->value(); + case OpenUrlEventBase::urlPropertyKey: + return object->as()->url(); + case DataConverterBase::namePropertyKey: + return object->as()->name(); + case DataConverterStringPadBase::textPropertyKey: + return object->as()->text(); + case DataConverterToStringBase::colorFormatPropertyKey: + return object->as()->colorFormat(); + case BindablePropertyStringBase::propertyValuePropertyKey: + return object->as() + ->propertyValue(); + case TextInputBase::textPropertyKey: + return object->as()->text(); + case TextValueRunBase::textPropertyKey: + return object->as()->text(); + case CustomPropertyStringBase::propertyValuePropertyKey: + return object->as()->propertyValue(); + case AssetBase::namePropertyKey: + return object->as()->name(); + case FileAssetBase::cdnBaseUrlPropertyKey: + return object->as()->cdnBaseUrl(); + } + return ""; + } + static bool getBool(Core* object, int propertyKey) + { + switch (propertyKey) + { + case ViewModelInstanceBooleanBase::propertyValuePropertyKey: + return object->as() + ->propertyValue(); + case TransformComponentConstraintBase::offsetPropertyKey: + return object->as()->offset(); + case TransformComponentConstraintBase::doesCopyPropertyKey: + return object->as() + ->doesCopy(); + case TransformComponentConstraintBase::minPropertyKey: + return object->as()->min(); + case TransformComponentConstraintBase::maxPropertyKey: + return object->as()->max(); + case TransformComponentConstraintYBase::doesCopyYPropertyKey: + return object->as() + ->doesCopyY(); + case TransformComponentConstraintYBase::minYPropertyKey: + return object->as()->minY(); + case TransformComponentConstraintYBase::maxYPropertyKey: + return object->as()->maxY(); + case IKConstraintBase::invertDirectionPropertyKey: + return object->as()->invertDirection(); + case FollowPathConstraintBase::orientPropertyKey: + return object->as()->orient(); + case FollowPathConstraintBase::offsetPropertyKey: + return object->as()->offset(); + case ScrollConstraintBase::snapPropertyKey: + return object->as()->snap(); + case ScrollBarConstraintBase::autoSizePropertyKey: + return object->as()->autoSize(); + case AxisBase::normalizedPropertyKey: + return object->as()->normalized(); + case LayoutComponentStyleBase::intrinsicallySizedValuePropertyKey: + return object->as() + ->intrinsicallySizedValue(); + case LayoutComponentStyleBase::linkCornerRadiusPropertyKey: + return object->as() + ->linkCornerRadius(); + case NestedSimpleAnimationBase::isPlayingPropertyKey: + return object->as()->isPlaying(); + case KeyFrameBoolBase::valuePropertyKey: + return object->as()->value(); + case ListenerAlignTargetBase::preserveOffsetPropertyKey: + return object->as()->preserveOffset(); + case TransitionValueBooleanComparatorBase::valuePropertyKey: + return object->as() + ->value(); + case NestedBoolBase::nestedValuePropertyKey: + return object->as()->nestedValue(); + case LinearAnimationBase::enableWorkAreaPropertyKey: + return object->as()->enableWorkArea(); + case LinearAnimationBase::quantizePropertyKey: + return object->as()->quantize(); + case StateMachineBoolBase::valuePropertyKey: + return object->as()->value(); + case ShapePaintBase::isVisiblePropertyKey: + return object->as()->isVisible(); + case DashPathBase::offsetIsPercentagePropertyKey: + return object->as()->offsetIsPercentage(); + case DashBase::lengthIsPercentagePropertyKey: + return object->as()->lengthIsPercentage(); + case StrokeBase::transformAffectsStrokePropertyKey: + return object->as()->transformAffectsStroke(); + case FeatherBase::innerPropertyKey: + return object->as()->inner(); + case PathBase::isHolePropertyKey: + return object->as()->isHole(); + case PointsPathBase::isClosedPropertyKey: + return object->as()->isClosed(); + case RectangleBase::linkCornerRadiusPropertyKey: + return object->as()->linkCornerRadius(); + case ClippingShapeBase::isVisiblePropertyKey: + return object->as()->isVisible(); + case CustomPropertyBooleanBase::propertyValuePropertyKey: + return object->as()->propertyValue(); + case LayoutComponentBase::clipPropertyKey: + return object->as()->clip(); + case BindablePropertyBooleanBase::propertyValuePropertyKey: + return object->as() + ->propertyValue(); + case TextModifierRangeBase::clampPropertyKey: + return object->as()->clamp(); + case TextFollowPathModifierBase::radialPropertyKey: + return object->as()->radial(); + case TextFollowPathModifierBase::orientPropertyKey: + return object->as()->orient(); + case TextBase::fitFromBaselinePropertyKey: + return object->as()->fitFromBaseline(); + } + return false; + } + static float getDouble(Core* object, int propertyKey) + { + switch (propertyKey) + { + case ViewModelInstanceNumberBase::propertyValuePropertyKey: + return object->as() + ->propertyValue(); + case CustomPropertyNumberBase::propertyValuePropertyKey: + return object->as()->propertyValue(); + case ConstraintBase::strengthPropertyKey: + return object->as()->strength(); + case DistanceConstraintBase::distancePropertyKey: + return object->as()->distance(); + case TransformComponentConstraintBase::copyFactorPropertyKey: + return object->as() + ->copyFactor(); + case TransformComponentConstraintBase::minValuePropertyKey: + return object->as() + ->minValue(); + case TransformComponentConstraintBase::maxValuePropertyKey: + return object->as() + ->maxValue(); + case TransformComponentConstraintYBase::copyFactorYPropertyKey: + return object->as() + ->copyFactorY(); + case TransformComponentConstraintYBase::minValueYPropertyKey: + return object->as() + ->minValueY(); + case TransformComponentConstraintYBase::maxValueYPropertyKey: + return object->as() + ->maxValueY(); + case FollowPathConstraintBase::distancePropertyKey: + return object->as()->distance(); + case ScrollConstraintBase::scrollOffsetXPropertyKey: + return object->as()->scrollOffsetX(); + case ScrollConstraintBase::scrollOffsetYPropertyKey: + return object->as()->scrollOffsetY(); + case ScrollConstraintBase::scrollPercentXPropertyKey: + return object->as()->scrollPercentX(); + case ScrollConstraintBase::scrollPercentYPropertyKey: + return object->as()->scrollPercentY(); + case ScrollConstraintBase::scrollIndexPropertyKey: + return object->as()->scrollIndex(); + case ElasticScrollPhysicsBase::frictionPropertyKey: + return object->as()->friction(); + case ElasticScrollPhysicsBase::speedMultiplierPropertyKey: + return object->as() + ->speedMultiplier(); + case ElasticScrollPhysicsBase::elasticFactorPropertyKey: + return object->as()->elasticFactor(); + case TransformConstraintBase::originXPropertyKey: + return object->as()->originX(); + case TransformConstraintBase::originYPropertyKey: + return object->as()->originY(); + case WorldTransformComponentBase::opacityPropertyKey: + return object->as()->opacity(); + case TransformComponentBase::rotationPropertyKey: + return object->as()->rotation(); + case TransformComponentBase::scaleXPropertyKey: + return object->as()->scaleX(); + case TransformComponentBase::scaleYPropertyKey: + return object->as()->scaleY(); + case NodeBase::xPropertyKey: + case NodeBase::xArtboardPropertyKey: + return object->as()->x(); + case NodeBase::yPropertyKey: + case NodeBase::yArtboardPropertyKey: + return object->as()->y(); + case NodeBase::computedLocalXPropertyKey: + return object->as()->computedLocalX(); + case NodeBase::computedLocalYPropertyKey: + return object->as()->computedLocalY(); + case NodeBase::computedWorldXPropertyKey: + return object->as()->computedWorldX(); + case NodeBase::computedWorldYPropertyKey: + return object->as()->computedWorldY(); + case NodeBase::computedWidthPropertyKey: + return object->as()->computedWidth(); + case NodeBase::computedHeightPropertyKey: + return object->as()->computedHeight(); + case NestedArtboardLayoutBase::instanceWidthPropertyKey: + return object->as()->instanceWidth(); + case NestedArtboardLayoutBase::instanceHeightPropertyKey: + return object->as()->instanceHeight(); + case AxisBase::offsetPropertyKey: + return object->as()->offset(); + case LayoutComponentStyleBase::gapHorizontalPropertyKey: + return object->as()->gapHorizontal(); + case LayoutComponentStyleBase::gapVerticalPropertyKey: + return object->as()->gapVertical(); + case LayoutComponentStyleBase::maxWidthPropertyKey: + return object->as()->maxWidth(); + case LayoutComponentStyleBase::maxHeightPropertyKey: + return object->as()->maxHeight(); + case LayoutComponentStyleBase::minWidthPropertyKey: + return object->as()->minWidth(); + case LayoutComponentStyleBase::minHeightPropertyKey: + return object->as()->minHeight(); + case LayoutComponentStyleBase::borderLeftPropertyKey: + return object->as()->borderLeft(); + case LayoutComponentStyleBase::borderRightPropertyKey: + return object->as()->borderRight(); + case LayoutComponentStyleBase::borderTopPropertyKey: + return object->as()->borderTop(); + case LayoutComponentStyleBase::borderBottomPropertyKey: + return object->as()->borderBottom(); + case LayoutComponentStyleBase::marginLeftPropertyKey: + return object->as()->marginLeft(); + case LayoutComponentStyleBase::marginRightPropertyKey: + return object->as()->marginRight(); + case LayoutComponentStyleBase::marginTopPropertyKey: + return object->as()->marginTop(); + case LayoutComponentStyleBase::marginBottomPropertyKey: + return object->as()->marginBottom(); + case LayoutComponentStyleBase::paddingLeftPropertyKey: + return object->as()->paddingLeft(); + case LayoutComponentStyleBase::paddingRightPropertyKey: + return object->as()->paddingRight(); + case LayoutComponentStyleBase::paddingTopPropertyKey: + return object->as()->paddingTop(); + case LayoutComponentStyleBase::paddingBottomPropertyKey: + return object->as()->paddingBottom(); + case LayoutComponentStyleBase::positionLeftPropertyKey: + return object->as()->positionLeft(); + case LayoutComponentStyleBase::positionRightPropertyKey: + return object->as()->positionRight(); + case LayoutComponentStyleBase::positionTopPropertyKey: + return object->as()->positionTop(); + case LayoutComponentStyleBase::positionBottomPropertyKey: + return object->as()->positionBottom(); + case LayoutComponentStyleBase::flexPropertyKey: + return object->as()->flex(); + case LayoutComponentStyleBase::flexGrowPropertyKey: + return object->as()->flexGrow(); + case LayoutComponentStyleBase::flexShrinkPropertyKey: + return object->as()->flexShrink(); + case LayoutComponentStyleBase::flexBasisPropertyKey: + return object->as()->flexBasis(); + case LayoutComponentStyleBase::aspectRatioPropertyKey: + return object->as()->aspectRatio(); + case LayoutComponentStyleBase::interpolationTimePropertyKey: + return object->as() + ->interpolationTime(); + case LayoutComponentStyleBase::cornerRadiusTLPropertyKey: + return object->as()->cornerRadiusTL(); + case LayoutComponentStyleBase::cornerRadiusTRPropertyKey: + return object->as()->cornerRadiusTR(); + case LayoutComponentStyleBase::cornerRadiusBLPropertyKey: + return object->as()->cornerRadiusBL(); + case LayoutComponentStyleBase::cornerRadiusBRPropertyKey: + return object->as()->cornerRadiusBR(); + case NSlicedNodeBase::initialWidthPropertyKey: + return object->as()->initialWidth(); + case NSlicedNodeBase::initialHeightPropertyKey: + return object->as()->initialHeight(); + case NSlicedNodeBase::widthPropertyKey: + return object->as()->width(); + case NSlicedNodeBase::heightPropertyKey: + return object->as()->height(); + case NestedLinearAnimationBase::mixPropertyKey: + return object->as()->mix(); + case NestedSimpleAnimationBase::speedPropertyKey: + return object->as()->speed(); + case AdvanceableStateBase::speedPropertyKey: + return object->as()->speed(); + case BlendAnimationDirectBase::mixValuePropertyKey: + return object->as()->mixValue(); + case StateMachineNumberBase::valuePropertyKey: + return object->as()->value(); + case CubicInterpolatorBase::x1PropertyKey: + return object->as()->x1(); + case CubicInterpolatorBase::y1PropertyKey: + return object->as()->y1(); + case CubicInterpolatorBase::x2PropertyKey: + return object->as()->x2(); + case CubicInterpolatorBase::y2PropertyKey: + return object->as()->y2(); + case TransitionNumberConditionBase::valuePropertyKey: + return object->as()->value(); + case CubicInterpolatorComponentBase::x1PropertyKey: + return object->as()->x1(); + case CubicInterpolatorComponentBase::y1PropertyKey: + return object->as()->y1(); + case CubicInterpolatorComponentBase::x2PropertyKey: + return object->as()->x2(); + case CubicInterpolatorComponentBase::y2PropertyKey: + return object->as()->y2(); + case ListenerNumberChangeBase::valuePropertyKey: + return object->as()->value(); + case KeyFrameDoubleBase::valuePropertyKey: + return object->as()->value(); + case LinearAnimationBase::speedPropertyKey: + return object->as()->speed(); + case TransitionValueNumberComparatorBase::valuePropertyKey: + return object->as() + ->value(); + case ElasticInterpolatorBase::amplitudePropertyKey: + return object->as()->amplitude(); + case ElasticInterpolatorBase::periodPropertyKey: + return object->as()->period(); + case NestedNumberBase::nestedValuePropertyKey: + return object->as()->nestedValue(); + case NestedRemapAnimationBase::timePropertyKey: + return object->as()->time(); + case BlendAnimation1DBase::valuePropertyKey: + return object->as()->value(); + case DashPathBase::offsetPropertyKey: + return object->as()->offset(); + case LinearGradientBase::startXPropertyKey: + return object->as()->startX(); + case LinearGradientBase::startYPropertyKey: + return object->as()->startY(); + case LinearGradientBase::endXPropertyKey: + return object->as()->endX(); + case LinearGradientBase::endYPropertyKey: + return object->as()->endY(); + case LinearGradientBase::opacityPropertyKey: + return object->as()->opacity(); + case DashBase::lengthPropertyKey: + return object->as()->length(); + case StrokeBase::thicknessPropertyKey: + return object->as()->thickness(); + case GradientStopBase::positionPropertyKey: + return object->as()->position(); + case FeatherBase::strengthPropertyKey: + return object->as()->strength(); + case FeatherBase::offsetXPropertyKey: + return object->as()->offsetX(); + case FeatherBase::offsetYPropertyKey: + return object->as()->offsetY(); + case TrimPathBase::startPropertyKey: + return object->as()->start(); + case TrimPathBase::endPropertyKey: + return object->as()->end(); + case TrimPathBase::offsetPropertyKey: + return object->as()->offset(); + case VertexBase::xPropertyKey: + return object->as()->x(); + case VertexBase::yPropertyKey: + return object->as()->y(); + case MeshVertexBase::uPropertyKey: + return object->as()->u(); + case MeshVertexBase::vPropertyKey: + return object->as()->v(); + case ShapeBase::lengthPropertyKey: + return object->as()->length(); + case StraightVertexBase::radiusPropertyKey: + return object->as()->radius(); + case CubicAsymmetricVertexBase::rotationPropertyKey: + return object->as()->rotation(); + case CubicAsymmetricVertexBase::inDistancePropertyKey: + return object->as()->inDistance(); + case CubicAsymmetricVertexBase::outDistancePropertyKey: + return object->as()->outDistance(); + case ParametricPathBase::widthPropertyKey: + return object->as()->width(); + case ParametricPathBase::heightPropertyKey: + return object->as()->height(); + case ParametricPathBase::originXPropertyKey: + return object->as()->originX(); + case ParametricPathBase::originYPropertyKey: + return object->as()->originY(); + case RectangleBase::cornerRadiusTLPropertyKey: + return object->as()->cornerRadiusTL(); + case RectangleBase::cornerRadiusTRPropertyKey: + return object->as()->cornerRadiusTR(); + case RectangleBase::cornerRadiusBLPropertyKey: + return object->as()->cornerRadiusBL(); + case RectangleBase::cornerRadiusBRPropertyKey: + return object->as()->cornerRadiusBR(); + case CubicMirroredVertexBase::rotationPropertyKey: + return object->as()->rotation(); + case CubicMirroredVertexBase::distancePropertyKey: + return object->as()->distance(); + case PolygonBase::cornerRadiusPropertyKey: + return object->as()->cornerRadius(); + case StarBase::innerRadiusPropertyKey: + return object->as()->innerRadius(); + case ImageBase::originXPropertyKey: + return object->as()->originX(); + case ImageBase::originYPropertyKey: + return object->as()->originY(); + case CubicDetachedVertexBase::inRotationPropertyKey: + return object->as()->inRotation(); + case CubicDetachedVertexBase::inDistancePropertyKey: + return object->as()->inDistance(); + case CubicDetachedVertexBase::outRotationPropertyKey: + return object->as()->outRotation(); + case CubicDetachedVertexBase::outDistancePropertyKey: + return object->as()->outDistance(); + case LayoutComponentBase::widthPropertyKey: + return object->as()->width(); + case LayoutComponentBase::heightPropertyKey: + return object->as()->height(); + case LayoutComponentBase::fractionalWidthPropertyKey: + return object->as()->fractionalWidth(); + case LayoutComponentBase::fractionalHeightPropertyKey: + return object->as()->fractionalHeight(); + case ArtboardBase::originXPropertyKey: + return object->as()->originX(); + case ArtboardBase::originYPropertyKey: + return object->as()->originY(); + case JoystickBase::xPropertyKey: + return object->as()->x(); + case JoystickBase::yPropertyKey: + return object->as()->y(); + case JoystickBase::posXPropertyKey: + return object->as()->posX(); + case JoystickBase::posYPropertyKey: + return object->as()->posY(); + case JoystickBase::originXPropertyKey: + return object->as()->originX(); + case JoystickBase::originYPropertyKey: + return object->as()->originY(); + case JoystickBase::widthPropertyKey: + return object->as()->width(); + case JoystickBase::heightPropertyKey: + return object->as()->height(); + case DataConverterOperationValueBase::operationValuePropertyKey: + return object->as() + ->operationValue(); + case DataConverterRangeMapperBase::minInputPropertyKey: + return object->as()->minInput(); + case DataConverterRangeMapperBase::maxInputPropertyKey: + return object->as()->maxInput(); + case DataConverterRangeMapperBase::minOutputPropertyKey: + return object->as()->minOutput(); + case DataConverterRangeMapperBase::maxOutputPropertyKey: + return object->as()->maxOutput(); + case DataConverterInterpolatorBase::durationPropertyKey: + return object->as()->duration(); + case FormulaTokenValueBase::operationValuePropertyKey: + return object->as()->operationValue(); + case BindablePropertyNumberBase::propertyValuePropertyKey: + return object->as() + ->propertyValue(); + case NestedArtboardLeafBase::alignmentXPropertyKey: + return object->as()->alignmentX(); + case NestedArtboardLeafBase::alignmentYPropertyKey: + return object->as()->alignmentY(); + case BoneBase::lengthPropertyKey: + return object->as()->length(); + case RootBoneBase::xPropertyKey: + return object->as()->x(); + case RootBoneBase::yPropertyKey: + return object->as()->y(); + case SkinBase::xxPropertyKey: + return object->as()->xx(); + case SkinBase::yxPropertyKey: + return object->as()->yx(); + case SkinBase::xyPropertyKey: + return object->as()->xy(); + case SkinBase::yyPropertyKey: + return object->as()->yy(); + case SkinBase::txPropertyKey: + return object->as()->tx(); + case SkinBase::tyPropertyKey: + return object->as()->ty(); + case TendonBase::xxPropertyKey: + return object->as()->xx(); + case TendonBase::yxPropertyKey: + return object->as()->yx(); + case TendonBase::xyPropertyKey: + return object->as()->xy(); + case TendonBase::yyPropertyKey: + return object->as()->yy(); + case TendonBase::txPropertyKey: + return object->as()->tx(); + case TendonBase::tyPropertyKey: + return object->as()->ty(); + case TextModifierRangeBase::modifyFromPropertyKey: + return object->as()->modifyFrom(); + case TextModifierRangeBase::modifyToPropertyKey: + return object->as()->modifyTo(); + case TextModifierRangeBase::strengthPropertyKey: + return object->as()->strength(); + case TextModifierRangeBase::falloffFromPropertyKey: + return object->as()->falloffFrom(); + case TextModifierRangeBase::falloffToPropertyKey: + return object->as()->falloffTo(); + case TextModifierRangeBase::offsetPropertyKey: + return object->as()->offset(); + case TextFollowPathModifierBase::startPropertyKey: + return object->as()->start(); + case TextFollowPathModifierBase::endPropertyKey: + return object->as()->end(); + case TextFollowPathModifierBase::strengthPropertyKey: + return object->as()->strength(); + case TextFollowPathModifierBase::offsetPropertyKey: + return object->as()->offset(); + case TextVariationModifierBase::axisValuePropertyKey: + return object->as()->axisValue(); + case TextModifierGroupBase::originXPropertyKey: + return object->as()->originX(); + case TextModifierGroupBase::originYPropertyKey: + return object->as()->originY(); + case TextModifierGroupBase::opacityPropertyKey: + return object->as()->opacity(); + case TextModifierGroupBase::xPropertyKey: + return object->as()->x(); + case TextModifierGroupBase::yPropertyKey: + return object->as()->y(); + case TextModifierGroupBase::rotationPropertyKey: + return object->as()->rotation(); + case TextModifierGroupBase::scaleXPropertyKey: + return object->as()->scaleX(); + case TextModifierGroupBase::scaleYPropertyKey: + return object->as()->scaleY(); + case TextStyleBase::fontSizePropertyKey: + return object->as()->fontSize(); + case TextStyleBase::lineHeightPropertyKey: + return object->as()->lineHeight(); + case TextStyleBase::letterSpacingPropertyKey: + return object->as()->letterSpacing(); + case TextInputBase::selectionRadiusPropertyKey: + return object->as()->selectionRadius(); + case TextStyleAxisBase::axisValuePropertyKey: + return object->as()->axisValue(); + case TextBase::widthPropertyKey: + return object->as()->width(); + case TextBase::heightPropertyKey: + return object->as()->height(); + case TextBase::originXPropertyKey: + return object->as()->originX(); + case TextBase::originYPropertyKey: + return object->as()->originY(); + case TextBase::paragraphSpacingPropertyKey: + return object->as()->paragraphSpacing(); + case DrawableAssetBase::heightPropertyKey: + return object->as()->height(); + case DrawableAssetBase::widthPropertyKey: + return object->as()->width(); + case ExportAudioBase::volumePropertyKey: + return object->as()->volume(); + } + return 0.0f; + } + static int propertyFieldId(int propertyKey) + { + switch (propertyKey) + { + case ViewModelInstanceListItemBase::viewModelIdPropertyKey: + case ViewModelInstanceListItemBase::viewModelInstanceIdPropertyKey: + case ViewModelInstanceValueBase::viewModelPropertyIdPropertyKey: + case ViewModelPropertyEnumCustomBase::enumIdPropertyKey: + case ViewModelInstanceEnumBase::propertyValuePropertyKey: + case ViewModelPropertyEnumSystemBase::enumTypePropertyKey: + case DataEnumSystemBase::enumTypePropertyKey: + case ViewModelPropertyViewModelBase:: + viewModelReferenceIdPropertyKey: + case ComponentBase::parentIdPropertyKey: + case ViewModelInstanceBase::viewModelIdPropertyKey: + case ViewModelInstanceTriggerBase::propertyValuePropertyKey: + case ViewModelInstanceSymbolListIndexBase::propertyValuePropertyKey: + case ViewModelInstanceViewModelBase::propertyValuePropertyKey: + case ViewModelInstanceAssetBase::propertyValuePropertyKey: + case DrawTargetBase::drawableIdPropertyKey: + case DrawTargetBase::placementValuePropertyKey: + case TargetedConstraintBase::targetIdPropertyKey: + case DistanceConstraintBase::modeValuePropertyKey: + case TransformSpaceConstraintBase::sourceSpaceValuePropertyKey: + case TransformSpaceConstraintBase::destSpaceValuePropertyKey: + case TransformComponentConstraintBase::minMaxSpaceValuePropertyKey: + case IKConstraintBase::parentBoneCountPropertyKey: + case ScrollPhysicsBase::constraintIdPropertyKey: + case DraggableConstraintBase::directionValuePropertyKey: + case ScrollConstraintBase::physicsTypeValuePropertyKey: + case ScrollConstraintBase::physicsIdPropertyKey: + case ScrollBarConstraintBase::scrollConstraintIdPropertyKey: + case DrawableBase::blendModeValuePropertyKey: + case DrawableBase::drawableFlagsPropertyKey: + case NestedArtboardBase::artboardIdPropertyKey: + case ArtboardComponentListBase::listSourcePropertyKey: + case NestedAnimationBase::animationIdPropertyKey: + case SoloBase::activeComponentIdPropertyKey: + case NestedArtboardLayoutBase::instanceWidthUnitsValuePropertyKey: + case NestedArtboardLayoutBase::instanceHeightUnitsValuePropertyKey: + case NestedArtboardLayoutBase::instanceWidthScaleTypePropertyKey: + case NestedArtboardLayoutBase::instanceHeightScaleTypePropertyKey: + case NSlicerTileModeBase::patchIndexPropertyKey: + case NSlicerTileModeBase::stylePropertyKey: + case LayoutComponentStyleBase::flexBasisUnitsValuePropertyKey: + case LayoutComponentStyleBase::layoutWidthScaleTypePropertyKey: + case LayoutComponentStyleBase::layoutHeightScaleTypePropertyKey: + case LayoutComponentStyleBase::layoutAlignmentTypePropertyKey: + case LayoutComponentStyleBase::animationStyleTypePropertyKey: + case LayoutComponentStyleBase::interpolationTypePropertyKey: + case LayoutComponentStyleBase::interpolatorIdPropertyKey: + case LayoutComponentStyleBase::displayValuePropertyKey: + case LayoutComponentStyleBase::positionTypeValuePropertyKey: + case LayoutComponentStyleBase::flexDirectionValuePropertyKey: + case LayoutComponentStyleBase::directionValuePropertyKey: + case LayoutComponentStyleBase::alignContentValuePropertyKey: + case LayoutComponentStyleBase::alignItemsValuePropertyKey: + case LayoutComponentStyleBase::alignSelfValuePropertyKey: + case LayoutComponentStyleBase::justifyContentValuePropertyKey: + case LayoutComponentStyleBase::flexWrapValuePropertyKey: + case LayoutComponentStyleBase::overflowValuePropertyKey: + case LayoutComponentStyleBase::widthUnitsValuePropertyKey: + case LayoutComponentStyleBase::heightUnitsValuePropertyKey: + case LayoutComponentStyleBase::borderLeftUnitsValuePropertyKey: + case LayoutComponentStyleBase::borderRightUnitsValuePropertyKey: + case LayoutComponentStyleBase::borderTopUnitsValuePropertyKey: + case LayoutComponentStyleBase::borderBottomUnitsValuePropertyKey: + case LayoutComponentStyleBase::marginLeftUnitsValuePropertyKey: + case LayoutComponentStyleBase::marginRightUnitsValuePropertyKey: + case LayoutComponentStyleBase::marginTopUnitsValuePropertyKey: + case LayoutComponentStyleBase::marginBottomUnitsValuePropertyKey: + case LayoutComponentStyleBase::paddingLeftUnitsValuePropertyKey: + case LayoutComponentStyleBase::paddingRightUnitsValuePropertyKey: + case LayoutComponentStyleBase::paddingTopUnitsValuePropertyKey: + case LayoutComponentStyleBase::paddingBottomUnitsValuePropertyKey: + case LayoutComponentStyleBase::positionLeftUnitsValuePropertyKey: + case LayoutComponentStyleBase::positionRightUnitsValuePropertyKey: + case LayoutComponentStyleBase::positionTopUnitsValuePropertyKey: + case LayoutComponentStyleBase::positionBottomUnitsValuePropertyKey: + case LayoutComponentStyleBase::gapHorizontalUnitsValuePropertyKey: + case LayoutComponentStyleBase::gapVerticalUnitsValuePropertyKey: + case LayoutComponentStyleBase::minWidthUnitsValuePropertyKey: + case LayoutComponentStyleBase::minHeightUnitsValuePropertyKey: + case LayoutComponentStyleBase::maxWidthUnitsValuePropertyKey: + case LayoutComponentStyleBase::maxHeightUnitsValuePropertyKey: + case ListenerFireEventBase::eventIdPropertyKey: + case LayerStateBase::flagsPropertyKey: + case TransitionValueTriggerComparatorBase::valuePropertyKey: + case KeyFrameBase::framePropertyKey: + case InterpolatingKeyFrameBase::interpolationTypePropertyKey: + case InterpolatingKeyFrameBase::interpolatorIdPropertyKey: + case KeyFrameUintBase::valuePropertyKey: + case ListenerInputChangeBase::inputIdPropertyKey: + case ListenerInputChangeBase::nestedInputIdPropertyKey: + case AnimationStateBase::animationIdPropertyKey: + case NestedInputBase::inputIdPropertyKey: + case KeyedObjectBase::objectIdPropertyKey: + case BlendAnimationBase::animationIdPropertyKey: + case BlendAnimationDirectBase::inputIdPropertyKey: + case BlendAnimationDirectBase::blendSourcePropertyKey: + case TransitionInputConditionBase::inputIdPropertyKey: + case KeyedPropertyBase::propertyKeyPropertyKey: + case StateMachineListenerBase::targetIdPropertyKey: + case StateMachineListenerBase::listenerTypeValuePropertyKey: + case StateMachineListenerBase::eventIdPropertyKey: + case TransitionPropertyArtboardComparatorBase:: + propertyTypePropertyKey: + case KeyFrameIdBase::valuePropertyKey: + case ListenerBoolChangeBase::valuePropertyKey: + case ListenerAlignTargetBase::targetIdPropertyKey: + case TransitionValueConditionBase::opValuePropertyKey: + case TransitionViewModelConditionBase::opValuePropertyKey: + case BlendState1DInputBase::inputIdPropertyKey: + case StateTransitionBase::stateToIdPropertyKey: + case StateTransitionBase::flagsPropertyKey: + case StateTransitionBase::durationPropertyKey: + case StateTransitionBase::exitTimePropertyKey: + case StateTransitionBase::interpolationTypePropertyKey: + case StateTransitionBase::interpolatorIdPropertyKey: + case StateTransitionBase::randomWeightPropertyKey: + case StateMachineFireEventBase::eventIdPropertyKey: + case StateMachineFireEventBase::occursValuePropertyKey: + case LinearAnimationBase::fpsPropertyKey: + case LinearAnimationBase::durationPropertyKey: + case LinearAnimationBase::loopValuePropertyKey: + case LinearAnimationBase::workStartPropertyKey: + case LinearAnimationBase::workEndPropertyKey: + case ElasticInterpolatorBase::easingValuePropertyKey: + case TransitionValueEnumComparatorBase::valuePropertyKey: + case BlendStateTransitionBase::exitBlendAnimationIdPropertyKey: + case ShapePaintBase::blendModeValuePropertyKey: + case StrokeBase::capPropertyKey: + case StrokeBase::joinPropertyKey: + case FeatherBase::spaceValuePropertyKey: + case TrimPathBase::modeValuePropertyKey: + case FillBase::fillRulePropertyKey: + case PathBase::pathFlagsPropertyKey: + case ClippingShapeBase::sourceIdPropertyKey: + case ClippingShapeBase::fillRulePropertyKey: + case PolygonBase::pointsPropertyKey: + case ImageBase::assetIdPropertyKey: + case DrawRulesBase::drawTargetIdPropertyKey: + case LayoutComponentBase::styleIdPropertyKey: + case ArtboardBase::defaultStateMachineIdPropertyKey: + case ArtboardBase::viewModelIdPropertyKey: + case JoystickBase::xIdPropertyKey: + case JoystickBase::yIdPropertyKey: + case JoystickBase::joystickFlagsPropertyKey: + case JoystickBase::handleSourceIdPropertyKey: + case OpenUrlEventBase::targetValuePropertyKey: + case BindablePropertyIntegerBase::propertyValuePropertyKey: + case DataBindBase::propertyKeyPropertyKey: + case DataBindBase::flagsPropertyKey: + case DataBindBase::converterIdPropertyKey: + case BindablePropertyAssetBase::propertyValuePropertyKey: + case DataConverterNumberToListBase::viewModelIdPropertyKey: + case DataConverterOperationBase::operationTypePropertyKey: + case DataConverterRangeMapperBase::interpolationTypePropertyKey: + case DataConverterRangeMapperBase::interpolatorIdPropertyKey: + case DataConverterRangeMapperBase::flagsPropertyKey: + case DataConverterInterpolatorBase::interpolationTypePropertyKey: + case DataConverterInterpolatorBase::interpolatorIdPropertyKey: + case DataConverterGroupItemBase::converterIdPropertyKey: + case DataConverterRounderBase::decimalsPropertyKey: + case DataConverterStringPadBase::lengthPropertyKey: + case DataConverterStringPadBase::padTypePropertyKey: + case DataConverterStringTrimBase::trimTypePropertyKey: + case FormulaTokenOperationBase::operationTypePropertyKey: + case FormulaTokenFunctionBase::functionTypePropertyKey: + case DataConverterToStringBase::flagsPropertyKey: + case DataConverterToStringBase::decimalsPropertyKey: + case BindablePropertyEnumBase::propertyValuePropertyKey: + case NestedArtboardLeafBase::fitPropertyKey: + case WeightBase::valuesPropertyKey: + case WeightBase::indicesPropertyKey: + case TendonBase::boneIdPropertyKey: + case CubicWeightBase::inValuesPropertyKey: + case CubicWeightBase::inIndicesPropertyKey: + case CubicWeightBase::outValuesPropertyKey: + case CubicWeightBase::outIndicesPropertyKey: + case TextModifierRangeBase::unitsValuePropertyKey: + case TextModifierRangeBase::typeValuePropertyKey: + case TextModifierRangeBase::modeValuePropertyKey: + case TextModifierRangeBase::runIdPropertyKey: + case TextTargetModifierBase::targetIdPropertyKey: + case TextStyleFeatureBase::tagPropertyKey: + case TextStyleFeatureBase::featureValuePropertyKey: + case TextVariationModifierBase::axisTagPropertyKey: + case TextModifierGroupBase::modifierFlagsPropertyKey: + case TextStyleBase::fontAssetIdPropertyKey: + case TextStyleAxisBase::tagPropertyKey: + case TextBase::alignValuePropertyKey: + case TextBase::sizingValuePropertyKey: + case TextBase::overflowValuePropertyKey: + case TextBase::originValuePropertyKey: + case TextBase::wrapValuePropertyKey: + case TextBase::verticalAlignValuePropertyKey: + case TextValueRunBase::styleIdPropertyKey: + case FileAssetBase::assetIdPropertyKey: + case AudioEventBase::assetIdPropertyKey: + return CoreUintType::id; + case ViewModelInstanceColorBase::propertyValuePropertyKey: + case KeyFrameColorBase::valuePropertyKey: + case TransitionValueColorComparatorBase::valuePropertyKey: + case SolidColorBase::colorValuePropertyKey: + case GradientStopBase::colorValuePropertyKey: + case BindablePropertyColorBase::propertyValuePropertyKey: + return CoreColorType::id; + case ViewModelComponentBase::namePropertyKey: + case DataEnumCustomBase::namePropertyKey: + case ViewModelInstanceStringBase::propertyValuePropertyKey: + case DataEnumValueBase::keyPropertyKey: + case DataEnumValueBase::valuePropertyKey: + case ComponentBase::namePropertyKey: + case AnimationBase::namePropertyKey: + case StateMachineComponentBase::namePropertyKey: + case KeyFrameStringBase::valuePropertyKey: + case TransitionValueStringComparatorBase::valuePropertyKey: + case OpenUrlEventBase::urlPropertyKey: + case DataConverterBase::namePropertyKey: + case DataConverterStringPadBase::textPropertyKey: + case DataConverterToStringBase::colorFormatPropertyKey: + case BindablePropertyStringBase::propertyValuePropertyKey: + case TextInputBase::textPropertyKey: + case TextValueRunBase::textPropertyKey: + case CustomPropertyStringBase::propertyValuePropertyKey: + case AssetBase::namePropertyKey: + case FileAssetBase::cdnBaseUrlPropertyKey: + return CoreStringType::id; + case ViewModelInstanceBooleanBase::propertyValuePropertyKey: + case TransformComponentConstraintBase::offsetPropertyKey: + case TransformComponentConstraintBase::doesCopyPropertyKey: + case TransformComponentConstraintBase::minPropertyKey: + case TransformComponentConstraintBase::maxPropertyKey: + case TransformComponentConstraintYBase::doesCopyYPropertyKey: + case TransformComponentConstraintYBase::minYPropertyKey: + case TransformComponentConstraintYBase::maxYPropertyKey: + case IKConstraintBase::invertDirectionPropertyKey: + case FollowPathConstraintBase::orientPropertyKey: + case FollowPathConstraintBase::offsetPropertyKey: + case ScrollConstraintBase::snapPropertyKey: + case ScrollBarConstraintBase::autoSizePropertyKey: + case AxisBase::normalizedPropertyKey: + case LayoutComponentStyleBase::intrinsicallySizedValuePropertyKey: + case LayoutComponentStyleBase::linkCornerRadiusPropertyKey: + case NestedSimpleAnimationBase::isPlayingPropertyKey: + case KeyFrameBoolBase::valuePropertyKey: + case ListenerAlignTargetBase::preserveOffsetPropertyKey: + case TransitionValueBooleanComparatorBase::valuePropertyKey: + case NestedBoolBase::nestedValuePropertyKey: + case LinearAnimationBase::enableWorkAreaPropertyKey: + case LinearAnimationBase::quantizePropertyKey: + case StateMachineBoolBase::valuePropertyKey: + case ShapePaintBase::isVisiblePropertyKey: + case DashPathBase::offsetIsPercentagePropertyKey: + case DashBase::lengthIsPercentagePropertyKey: + case StrokeBase::transformAffectsStrokePropertyKey: + case FeatherBase::innerPropertyKey: + case PathBase::isHolePropertyKey: + case PointsPathBase::isClosedPropertyKey: + case RectangleBase::linkCornerRadiusPropertyKey: + case ClippingShapeBase::isVisiblePropertyKey: + case CustomPropertyBooleanBase::propertyValuePropertyKey: + case LayoutComponentBase::clipPropertyKey: + case BindablePropertyBooleanBase::propertyValuePropertyKey: + case TextModifierRangeBase::clampPropertyKey: + case TextFollowPathModifierBase::radialPropertyKey: + case TextFollowPathModifierBase::orientPropertyKey: + case TextBase::fitFromBaselinePropertyKey: + return CoreBoolType::id; + case ViewModelInstanceNumberBase::propertyValuePropertyKey: + case CustomPropertyNumberBase::propertyValuePropertyKey: + case ConstraintBase::strengthPropertyKey: + case DistanceConstraintBase::distancePropertyKey: + case TransformComponentConstraintBase::copyFactorPropertyKey: + case TransformComponentConstraintBase::minValuePropertyKey: + case TransformComponentConstraintBase::maxValuePropertyKey: + case TransformComponentConstraintYBase::copyFactorYPropertyKey: + case TransformComponentConstraintYBase::minValueYPropertyKey: + case TransformComponentConstraintYBase::maxValueYPropertyKey: + case FollowPathConstraintBase::distancePropertyKey: + case ScrollConstraintBase::scrollOffsetXPropertyKey: + case ScrollConstraintBase::scrollOffsetYPropertyKey: + case ScrollConstraintBase::scrollPercentXPropertyKey: + case ScrollConstraintBase::scrollPercentYPropertyKey: + case ScrollConstraintBase::scrollIndexPropertyKey: + case ElasticScrollPhysicsBase::frictionPropertyKey: + case ElasticScrollPhysicsBase::speedMultiplierPropertyKey: + case ElasticScrollPhysicsBase::elasticFactorPropertyKey: + case TransformConstraintBase::originXPropertyKey: + case TransformConstraintBase::originYPropertyKey: + case WorldTransformComponentBase::opacityPropertyKey: + case TransformComponentBase::rotationPropertyKey: + case TransformComponentBase::scaleXPropertyKey: + case TransformComponentBase::scaleYPropertyKey: + case NodeBase::xPropertyKey: + case NodeBase::xArtboardPropertyKey: + case NodeBase::yPropertyKey: + case NodeBase::yArtboardPropertyKey: + case NodeBase::computedLocalXPropertyKey: + case NodeBase::computedLocalYPropertyKey: + case NodeBase::computedWorldXPropertyKey: + case NodeBase::computedWorldYPropertyKey: + case NodeBase::computedWidthPropertyKey: + case NodeBase::computedHeightPropertyKey: + case NestedArtboardLayoutBase::instanceWidthPropertyKey: + case NestedArtboardLayoutBase::instanceHeightPropertyKey: + case AxisBase::offsetPropertyKey: + case LayoutComponentStyleBase::gapHorizontalPropertyKey: + case LayoutComponentStyleBase::gapVerticalPropertyKey: + case LayoutComponentStyleBase::maxWidthPropertyKey: + case LayoutComponentStyleBase::maxHeightPropertyKey: + case LayoutComponentStyleBase::minWidthPropertyKey: + case LayoutComponentStyleBase::minHeightPropertyKey: + case LayoutComponentStyleBase::borderLeftPropertyKey: + case LayoutComponentStyleBase::borderRightPropertyKey: + case LayoutComponentStyleBase::borderTopPropertyKey: + case LayoutComponentStyleBase::borderBottomPropertyKey: + case LayoutComponentStyleBase::marginLeftPropertyKey: + case LayoutComponentStyleBase::marginRightPropertyKey: + case LayoutComponentStyleBase::marginTopPropertyKey: + case LayoutComponentStyleBase::marginBottomPropertyKey: + case LayoutComponentStyleBase::paddingLeftPropertyKey: + case LayoutComponentStyleBase::paddingRightPropertyKey: + case LayoutComponentStyleBase::paddingTopPropertyKey: + case LayoutComponentStyleBase::paddingBottomPropertyKey: + case LayoutComponentStyleBase::positionLeftPropertyKey: + case LayoutComponentStyleBase::positionRightPropertyKey: + case LayoutComponentStyleBase::positionTopPropertyKey: + case LayoutComponentStyleBase::positionBottomPropertyKey: + case LayoutComponentStyleBase::flexPropertyKey: + case LayoutComponentStyleBase::flexGrowPropertyKey: + case LayoutComponentStyleBase::flexShrinkPropertyKey: + case LayoutComponentStyleBase::flexBasisPropertyKey: + case LayoutComponentStyleBase::aspectRatioPropertyKey: + case LayoutComponentStyleBase::interpolationTimePropertyKey: + case LayoutComponentStyleBase::cornerRadiusTLPropertyKey: + case LayoutComponentStyleBase::cornerRadiusTRPropertyKey: + case LayoutComponentStyleBase::cornerRadiusBLPropertyKey: + case LayoutComponentStyleBase::cornerRadiusBRPropertyKey: + case NSlicedNodeBase::initialWidthPropertyKey: + case NSlicedNodeBase::initialHeightPropertyKey: + case NSlicedNodeBase::widthPropertyKey: + case NSlicedNodeBase::heightPropertyKey: + case NestedLinearAnimationBase::mixPropertyKey: + case NestedSimpleAnimationBase::speedPropertyKey: + case AdvanceableStateBase::speedPropertyKey: + case BlendAnimationDirectBase::mixValuePropertyKey: + case StateMachineNumberBase::valuePropertyKey: + case CubicInterpolatorBase::x1PropertyKey: + case CubicInterpolatorBase::y1PropertyKey: + case CubicInterpolatorBase::x2PropertyKey: + case CubicInterpolatorBase::y2PropertyKey: + case TransitionNumberConditionBase::valuePropertyKey: + case CubicInterpolatorComponentBase::x1PropertyKey: + case CubicInterpolatorComponentBase::y1PropertyKey: + case CubicInterpolatorComponentBase::x2PropertyKey: + case CubicInterpolatorComponentBase::y2PropertyKey: + case ListenerNumberChangeBase::valuePropertyKey: + case KeyFrameDoubleBase::valuePropertyKey: + case LinearAnimationBase::speedPropertyKey: + case TransitionValueNumberComparatorBase::valuePropertyKey: + case ElasticInterpolatorBase::amplitudePropertyKey: + case ElasticInterpolatorBase::periodPropertyKey: + case NestedNumberBase::nestedValuePropertyKey: + case NestedRemapAnimationBase::timePropertyKey: + case BlendAnimation1DBase::valuePropertyKey: + case DashPathBase::offsetPropertyKey: + case LinearGradientBase::startXPropertyKey: + case LinearGradientBase::startYPropertyKey: + case LinearGradientBase::endXPropertyKey: + case LinearGradientBase::endYPropertyKey: + case LinearGradientBase::opacityPropertyKey: + case DashBase::lengthPropertyKey: + case StrokeBase::thicknessPropertyKey: + case GradientStopBase::positionPropertyKey: + case FeatherBase::strengthPropertyKey: + case FeatherBase::offsetXPropertyKey: + case FeatherBase::offsetYPropertyKey: + case TrimPathBase::startPropertyKey: + case TrimPathBase::endPropertyKey: + case TrimPathBase::offsetPropertyKey: + case VertexBase::xPropertyKey: + case VertexBase::yPropertyKey: + case MeshVertexBase::uPropertyKey: + case MeshVertexBase::vPropertyKey: + case ShapeBase::lengthPropertyKey: + case StraightVertexBase::radiusPropertyKey: + case CubicAsymmetricVertexBase::rotationPropertyKey: + case CubicAsymmetricVertexBase::inDistancePropertyKey: + case CubicAsymmetricVertexBase::outDistancePropertyKey: + case ParametricPathBase::widthPropertyKey: + case ParametricPathBase::heightPropertyKey: + case ParametricPathBase::originXPropertyKey: + case ParametricPathBase::originYPropertyKey: + case RectangleBase::cornerRadiusTLPropertyKey: + case RectangleBase::cornerRadiusTRPropertyKey: + case RectangleBase::cornerRadiusBLPropertyKey: + case RectangleBase::cornerRadiusBRPropertyKey: + case CubicMirroredVertexBase::rotationPropertyKey: + case CubicMirroredVertexBase::distancePropertyKey: + case PolygonBase::cornerRadiusPropertyKey: + case StarBase::innerRadiusPropertyKey: + case ImageBase::originXPropertyKey: + case ImageBase::originYPropertyKey: + case CubicDetachedVertexBase::inRotationPropertyKey: + case CubicDetachedVertexBase::inDistancePropertyKey: + case CubicDetachedVertexBase::outRotationPropertyKey: + case CubicDetachedVertexBase::outDistancePropertyKey: + case LayoutComponentBase::widthPropertyKey: + case LayoutComponentBase::heightPropertyKey: + case LayoutComponentBase::fractionalWidthPropertyKey: + case LayoutComponentBase::fractionalHeightPropertyKey: + case ArtboardBase::originXPropertyKey: + case ArtboardBase::originYPropertyKey: + case JoystickBase::xPropertyKey: + case JoystickBase::yPropertyKey: + case JoystickBase::posXPropertyKey: + case JoystickBase::posYPropertyKey: + case JoystickBase::originXPropertyKey: + case JoystickBase::originYPropertyKey: + case JoystickBase::widthPropertyKey: + case JoystickBase::heightPropertyKey: + case DataConverterOperationValueBase::operationValuePropertyKey: + case DataConverterRangeMapperBase::minInputPropertyKey: + case DataConverterRangeMapperBase::maxInputPropertyKey: + case DataConverterRangeMapperBase::minOutputPropertyKey: + case DataConverterRangeMapperBase::maxOutputPropertyKey: + case DataConverterInterpolatorBase::durationPropertyKey: + case FormulaTokenValueBase::operationValuePropertyKey: + case BindablePropertyNumberBase::propertyValuePropertyKey: + case NestedArtboardLeafBase::alignmentXPropertyKey: + case NestedArtboardLeafBase::alignmentYPropertyKey: + case BoneBase::lengthPropertyKey: + case RootBoneBase::xPropertyKey: + case RootBoneBase::yPropertyKey: + case SkinBase::xxPropertyKey: + case SkinBase::yxPropertyKey: + case SkinBase::xyPropertyKey: + case SkinBase::yyPropertyKey: + case SkinBase::txPropertyKey: + case SkinBase::tyPropertyKey: + case TendonBase::xxPropertyKey: + case TendonBase::yxPropertyKey: + case TendonBase::xyPropertyKey: + case TendonBase::yyPropertyKey: + case TendonBase::txPropertyKey: + case TendonBase::tyPropertyKey: + case TextModifierRangeBase::modifyFromPropertyKey: + case TextModifierRangeBase::modifyToPropertyKey: + case TextModifierRangeBase::strengthPropertyKey: + case TextModifierRangeBase::falloffFromPropertyKey: + case TextModifierRangeBase::falloffToPropertyKey: + case TextModifierRangeBase::offsetPropertyKey: + case TextFollowPathModifierBase::startPropertyKey: + case TextFollowPathModifierBase::endPropertyKey: + case TextFollowPathModifierBase::strengthPropertyKey: + case TextFollowPathModifierBase::offsetPropertyKey: + case TextVariationModifierBase::axisValuePropertyKey: + case TextModifierGroupBase::originXPropertyKey: + case TextModifierGroupBase::originYPropertyKey: + case TextModifierGroupBase::opacityPropertyKey: + case TextModifierGroupBase::xPropertyKey: + case TextModifierGroupBase::yPropertyKey: + case TextModifierGroupBase::rotationPropertyKey: + case TextModifierGroupBase::scaleXPropertyKey: + case TextModifierGroupBase::scaleYPropertyKey: + case TextStyleBase::fontSizePropertyKey: + case TextStyleBase::lineHeightPropertyKey: + case TextStyleBase::letterSpacingPropertyKey: + case TextInputBase::selectionRadiusPropertyKey: + case TextStyleAxisBase::axisValuePropertyKey: + case TextBase::widthPropertyKey: + case TextBase::heightPropertyKey: + case TextBase::originXPropertyKey: + case TextBase::originYPropertyKey: + case TextBase::paragraphSpacingPropertyKey: + case DrawableAssetBase::heightPropertyKey: + case DrawableAssetBase::widthPropertyKey: + case ExportAudioBase::volumePropertyKey: + return CoreDoubleType::id; + case NestedArtboardBase::dataBindPathIdsPropertyKey: + case MeshBase::triangleIndexBytesPropertyKey: + case DataConverterOperationViewModelBase::sourcePathIdsPropertyKey: + case DataBindContextBase::sourcePathIdsPropertyKey: + case FileAssetBase::cdnUuidPropertyKey: + case FileAssetContentsBase::bytesPropertyKey: + return CoreBytesType::id; + default: + return -1; + } + } + static bool isCallback(uint32_t propertyKey) + { + switch (propertyKey) + { + case NestedTriggerBase::firePropertyKey: + case EventBase::triggerPropertyKey: + return true; + default: + return false; + } + } + static bool objectSupportsProperty(Core* object, uint32_t propertyKey) + { + switch (propertyKey) + { + case ViewModelInstanceListItemBase::viewModelIdPropertyKey: + return object->is(); + case ViewModelInstanceListItemBase::viewModelInstanceIdPropertyKey: + return object->is(); + case ViewModelInstanceValueBase::viewModelPropertyIdPropertyKey: + return object->is(); + case ViewModelPropertyEnumCustomBase::enumIdPropertyKey: + return object->is(); + case ViewModelInstanceEnumBase::propertyValuePropertyKey: + return object->is(); + case ViewModelPropertyEnumSystemBase::enumTypePropertyKey: + return object->is(); + case DataEnumSystemBase::enumTypePropertyKey: + return object->is(); + case ViewModelPropertyViewModelBase:: + viewModelReferenceIdPropertyKey: + return object->is(); + case ComponentBase::parentIdPropertyKey: + return object->is(); + case ViewModelInstanceBase::viewModelIdPropertyKey: + return object->is(); + case ViewModelInstanceTriggerBase::propertyValuePropertyKey: + return object->is(); + case ViewModelInstanceSymbolListIndexBase::propertyValuePropertyKey: + return object->is(); + case ViewModelInstanceViewModelBase::propertyValuePropertyKey: + return object->is(); + case ViewModelInstanceAssetBase::propertyValuePropertyKey: + return object->is(); + case DrawTargetBase::drawableIdPropertyKey: + return object->is(); + case DrawTargetBase::placementValuePropertyKey: + return object->is(); + case TargetedConstraintBase::targetIdPropertyKey: + return object->is(); + case DistanceConstraintBase::modeValuePropertyKey: + return object->is(); + case TransformSpaceConstraintBase::sourceSpaceValuePropertyKey: + return object->is(); + case TransformSpaceConstraintBase::destSpaceValuePropertyKey: + return object->is(); + case TransformComponentConstraintBase::minMaxSpaceValuePropertyKey: + return object->is(); + case IKConstraintBase::parentBoneCountPropertyKey: + return object->is(); + case ScrollPhysicsBase::constraintIdPropertyKey: + return object->is(); + case DraggableConstraintBase::directionValuePropertyKey: + return object->is(); + case ScrollConstraintBase::physicsTypeValuePropertyKey: + return object->is(); + case ScrollConstraintBase::physicsIdPropertyKey: + return object->is(); + case ScrollBarConstraintBase::scrollConstraintIdPropertyKey: + return object->is(); + case DrawableBase::blendModeValuePropertyKey: + return object->is(); + case DrawableBase::drawableFlagsPropertyKey: + return object->is(); + case NestedArtboardBase::artboardIdPropertyKey: + return object->is(); + case ArtboardComponentListBase::listSourcePropertyKey: + return object->is(); + case NestedAnimationBase::animationIdPropertyKey: + return object->is(); + case SoloBase::activeComponentIdPropertyKey: + return object->is(); + case NestedArtboardLayoutBase::instanceWidthUnitsValuePropertyKey: + return object->is(); + case NestedArtboardLayoutBase::instanceHeightUnitsValuePropertyKey: + return object->is(); + case NestedArtboardLayoutBase::instanceWidthScaleTypePropertyKey: + return object->is(); + case NestedArtboardLayoutBase::instanceHeightScaleTypePropertyKey: + return object->is(); + case NSlicerTileModeBase::patchIndexPropertyKey: + return object->is(); + case NSlicerTileModeBase::stylePropertyKey: + return object->is(); + case LayoutComponentStyleBase::flexBasisUnitsValuePropertyKey: + return object->is(); + case LayoutComponentStyleBase::layoutWidthScaleTypePropertyKey: + return object->is(); + case LayoutComponentStyleBase::layoutHeightScaleTypePropertyKey: + return object->is(); + case LayoutComponentStyleBase::layoutAlignmentTypePropertyKey: + return object->is(); + case LayoutComponentStyleBase::animationStyleTypePropertyKey: + return object->is(); + case LayoutComponentStyleBase::interpolationTypePropertyKey: + return object->is(); + case LayoutComponentStyleBase::interpolatorIdPropertyKey: + return object->is(); + case LayoutComponentStyleBase::displayValuePropertyKey: + return object->is(); + case LayoutComponentStyleBase::positionTypeValuePropertyKey: + return object->is(); + case LayoutComponentStyleBase::flexDirectionValuePropertyKey: + return object->is(); + case LayoutComponentStyleBase::directionValuePropertyKey: + return object->is(); + case LayoutComponentStyleBase::alignContentValuePropertyKey: + return object->is(); + case LayoutComponentStyleBase::alignItemsValuePropertyKey: + return object->is(); + case LayoutComponentStyleBase::alignSelfValuePropertyKey: + return object->is(); + case LayoutComponentStyleBase::justifyContentValuePropertyKey: + return object->is(); + case LayoutComponentStyleBase::flexWrapValuePropertyKey: + return object->is(); + case LayoutComponentStyleBase::overflowValuePropertyKey: + return object->is(); + case LayoutComponentStyleBase::widthUnitsValuePropertyKey: + return object->is(); + case LayoutComponentStyleBase::heightUnitsValuePropertyKey: + return object->is(); + case LayoutComponentStyleBase::borderLeftUnitsValuePropertyKey: + return object->is(); + case LayoutComponentStyleBase::borderRightUnitsValuePropertyKey: + return object->is(); + case LayoutComponentStyleBase::borderTopUnitsValuePropertyKey: + return object->is(); + case LayoutComponentStyleBase::borderBottomUnitsValuePropertyKey: + return object->is(); + case LayoutComponentStyleBase::marginLeftUnitsValuePropertyKey: + return object->is(); + case LayoutComponentStyleBase::marginRightUnitsValuePropertyKey: + return object->is(); + case LayoutComponentStyleBase::marginTopUnitsValuePropertyKey: + return object->is(); + case LayoutComponentStyleBase::marginBottomUnitsValuePropertyKey: + return object->is(); + case LayoutComponentStyleBase::paddingLeftUnitsValuePropertyKey: + return object->is(); + case LayoutComponentStyleBase::paddingRightUnitsValuePropertyKey: + return object->is(); + case LayoutComponentStyleBase::paddingTopUnitsValuePropertyKey: + return object->is(); + case LayoutComponentStyleBase::paddingBottomUnitsValuePropertyKey: + return object->is(); + case LayoutComponentStyleBase::positionLeftUnitsValuePropertyKey: + return object->is(); + case LayoutComponentStyleBase::positionRightUnitsValuePropertyKey: + return object->is(); + case LayoutComponentStyleBase::positionTopUnitsValuePropertyKey: + return object->is(); + case LayoutComponentStyleBase::positionBottomUnitsValuePropertyKey: + return object->is(); + case LayoutComponentStyleBase::gapHorizontalUnitsValuePropertyKey: + return object->is(); + case LayoutComponentStyleBase::gapVerticalUnitsValuePropertyKey: + return object->is(); + case LayoutComponentStyleBase::minWidthUnitsValuePropertyKey: + return object->is(); + case LayoutComponentStyleBase::minHeightUnitsValuePropertyKey: + return object->is(); + case LayoutComponentStyleBase::maxWidthUnitsValuePropertyKey: + return object->is(); + case LayoutComponentStyleBase::maxHeightUnitsValuePropertyKey: + return object->is(); + case ListenerFireEventBase::eventIdPropertyKey: + return object->is(); + case LayerStateBase::flagsPropertyKey: + return object->is(); + case TransitionValueTriggerComparatorBase::valuePropertyKey: + return object->is(); + case KeyFrameBase::framePropertyKey: + return object->is(); + case InterpolatingKeyFrameBase::interpolationTypePropertyKey: + return object->is(); + case InterpolatingKeyFrameBase::interpolatorIdPropertyKey: + return object->is(); + case KeyFrameUintBase::valuePropertyKey: + return object->is(); + case ListenerInputChangeBase::inputIdPropertyKey: + return object->is(); + case ListenerInputChangeBase::nestedInputIdPropertyKey: + return object->is(); + case AnimationStateBase::animationIdPropertyKey: + return object->is(); + case NestedInputBase::inputIdPropertyKey: + return object->is(); + case KeyedObjectBase::objectIdPropertyKey: + return object->is(); + case BlendAnimationBase::animationIdPropertyKey: + return object->is(); + case BlendAnimationDirectBase::inputIdPropertyKey: + return object->is(); + case BlendAnimationDirectBase::blendSourcePropertyKey: + return object->is(); + case TransitionInputConditionBase::inputIdPropertyKey: + return object->is(); + case KeyedPropertyBase::propertyKeyPropertyKey: + return object->is(); + case StateMachineListenerBase::targetIdPropertyKey: + return object->is(); + case StateMachineListenerBase::listenerTypeValuePropertyKey: + return object->is(); + case StateMachineListenerBase::eventIdPropertyKey: + return object->is(); + case TransitionPropertyArtboardComparatorBase:: + propertyTypePropertyKey: + return object->is(); + case KeyFrameIdBase::valuePropertyKey: + return object->is(); + case ListenerBoolChangeBase::valuePropertyKey: + return object->is(); + case ListenerAlignTargetBase::targetIdPropertyKey: + return object->is(); + case TransitionValueConditionBase::opValuePropertyKey: + return object->is(); + case TransitionViewModelConditionBase::opValuePropertyKey: + return object->is(); + case BlendState1DInputBase::inputIdPropertyKey: + return object->is(); + case StateTransitionBase::stateToIdPropertyKey: + return object->is(); + case StateTransitionBase::flagsPropertyKey: + return object->is(); + case StateTransitionBase::durationPropertyKey: + return object->is(); + case StateTransitionBase::exitTimePropertyKey: + return object->is(); + case StateTransitionBase::interpolationTypePropertyKey: + return object->is(); + case StateTransitionBase::interpolatorIdPropertyKey: + return object->is(); + case StateTransitionBase::randomWeightPropertyKey: + return object->is(); + case StateMachineFireEventBase::eventIdPropertyKey: + return object->is(); + case StateMachineFireEventBase::occursValuePropertyKey: + return object->is(); + case LinearAnimationBase::fpsPropertyKey: + return object->is(); + case LinearAnimationBase::durationPropertyKey: + return object->is(); + case LinearAnimationBase::loopValuePropertyKey: + return object->is(); + case LinearAnimationBase::workStartPropertyKey: + return object->is(); + case LinearAnimationBase::workEndPropertyKey: + return object->is(); + case ElasticInterpolatorBase::easingValuePropertyKey: + return object->is(); + case TransitionValueEnumComparatorBase::valuePropertyKey: + return object->is(); + case BlendStateTransitionBase::exitBlendAnimationIdPropertyKey: + return object->is(); + case ShapePaintBase::blendModeValuePropertyKey: + return object->is(); + case StrokeBase::capPropertyKey: + return object->is(); + case StrokeBase::joinPropertyKey: + return object->is(); + case FeatherBase::spaceValuePropertyKey: + return object->is(); + case TrimPathBase::modeValuePropertyKey: + return object->is(); + case FillBase::fillRulePropertyKey: + return object->is(); + case PathBase::pathFlagsPropertyKey: + return object->is(); + case ClippingShapeBase::sourceIdPropertyKey: + return object->is(); + case ClippingShapeBase::fillRulePropertyKey: + return object->is(); + case PolygonBase::pointsPropertyKey: + return object->is(); + case ImageBase::assetIdPropertyKey: + return object->is(); + case DrawRulesBase::drawTargetIdPropertyKey: + return object->is(); + case LayoutComponentBase::styleIdPropertyKey: + return object->is(); + case ArtboardBase::defaultStateMachineIdPropertyKey: + return object->is(); + case ArtboardBase::viewModelIdPropertyKey: + return object->is(); + case JoystickBase::xIdPropertyKey: + return object->is(); + case JoystickBase::yIdPropertyKey: + return object->is(); + case JoystickBase::joystickFlagsPropertyKey: + return object->is(); + case JoystickBase::handleSourceIdPropertyKey: + return object->is(); + case OpenUrlEventBase::targetValuePropertyKey: + return object->is(); + case BindablePropertyIntegerBase::propertyValuePropertyKey: + return object->is(); + case DataBindBase::propertyKeyPropertyKey: + return object->is(); + case DataBindBase::flagsPropertyKey: + return object->is(); + case DataBindBase::converterIdPropertyKey: + return object->is(); + case BindablePropertyAssetBase::propertyValuePropertyKey: + return object->is(); + case DataConverterNumberToListBase::viewModelIdPropertyKey: + return object->is(); + case DataConverterOperationBase::operationTypePropertyKey: + return object->is(); + case DataConverterRangeMapperBase::interpolationTypePropertyKey: + return object->is(); + case DataConverterRangeMapperBase::interpolatorIdPropertyKey: + return object->is(); + case DataConverterRangeMapperBase::flagsPropertyKey: + return object->is(); + case DataConverterInterpolatorBase::interpolationTypePropertyKey: + return object->is(); + case DataConverterInterpolatorBase::interpolatorIdPropertyKey: + return object->is(); + case DataConverterGroupItemBase::converterIdPropertyKey: + return object->is(); + case DataConverterRounderBase::decimalsPropertyKey: + return object->is(); + case DataConverterStringPadBase::lengthPropertyKey: + return object->is(); + case DataConverterStringPadBase::padTypePropertyKey: + return object->is(); + case DataConverterStringTrimBase::trimTypePropertyKey: + return object->is(); + case FormulaTokenOperationBase::operationTypePropertyKey: + return object->is(); + case FormulaTokenFunctionBase::functionTypePropertyKey: + return object->is(); + case DataConverterToStringBase::flagsPropertyKey: + return object->is(); + case DataConverterToStringBase::decimalsPropertyKey: + return object->is(); + case BindablePropertyEnumBase::propertyValuePropertyKey: + return object->is(); + case NestedArtboardLeafBase::fitPropertyKey: + return object->is(); + case WeightBase::valuesPropertyKey: + return object->is(); + case WeightBase::indicesPropertyKey: + return object->is(); + case TendonBase::boneIdPropertyKey: + return object->is(); + case CubicWeightBase::inValuesPropertyKey: + return object->is(); + case CubicWeightBase::inIndicesPropertyKey: + return object->is(); + case CubicWeightBase::outValuesPropertyKey: + return object->is(); + case CubicWeightBase::outIndicesPropertyKey: + return object->is(); + case TextModifierRangeBase::unitsValuePropertyKey: + return object->is(); + case TextModifierRangeBase::typeValuePropertyKey: + return object->is(); + case TextModifierRangeBase::modeValuePropertyKey: + return object->is(); + case TextModifierRangeBase::runIdPropertyKey: + return object->is(); + case TextTargetModifierBase::targetIdPropertyKey: + return object->is(); + case TextStyleFeatureBase::tagPropertyKey: + return object->is(); + case TextStyleFeatureBase::featureValuePropertyKey: + return object->is(); + case TextVariationModifierBase::axisTagPropertyKey: + return object->is(); + case TextModifierGroupBase::modifierFlagsPropertyKey: + return object->is(); + case TextStyleBase::fontAssetIdPropertyKey: + return object->is(); + case TextStyleAxisBase::tagPropertyKey: + return object->is(); + case TextBase::alignValuePropertyKey: + return object->is(); + case TextBase::sizingValuePropertyKey: + return object->is(); + case TextBase::overflowValuePropertyKey: + return object->is(); + case TextBase::originValuePropertyKey: + return object->is(); + case TextBase::wrapValuePropertyKey: + return object->is(); + case TextBase::verticalAlignValuePropertyKey: + return object->is(); + case TextValueRunBase::styleIdPropertyKey: + return object->is(); + case FileAssetBase::assetIdPropertyKey: + return object->is(); + case AudioEventBase::assetIdPropertyKey: + return object->is(); + case ViewModelInstanceColorBase::propertyValuePropertyKey: + return object->is(); + case KeyFrameColorBase::valuePropertyKey: + return object->is(); + case TransitionValueColorComparatorBase::valuePropertyKey: + return object->is(); + case SolidColorBase::colorValuePropertyKey: + return object->is(); + case GradientStopBase::colorValuePropertyKey: + return object->is(); + case BindablePropertyColorBase::propertyValuePropertyKey: + return object->is(); + case ViewModelComponentBase::namePropertyKey: + return object->is(); + case DataEnumCustomBase::namePropertyKey: + return object->is(); + case ViewModelInstanceStringBase::propertyValuePropertyKey: + return object->is(); + case DataEnumValueBase::keyPropertyKey: + return object->is(); + case DataEnumValueBase::valuePropertyKey: + return object->is(); + case ComponentBase::namePropertyKey: + return object->is(); + case AnimationBase::namePropertyKey: + return object->is(); + case StateMachineComponentBase::namePropertyKey: + return object->is(); + case KeyFrameStringBase::valuePropertyKey: + return object->is(); + case TransitionValueStringComparatorBase::valuePropertyKey: + return object->is(); + case OpenUrlEventBase::urlPropertyKey: + return object->is(); + case DataConverterBase::namePropertyKey: + return object->is(); + case DataConverterStringPadBase::textPropertyKey: + return object->is(); + case DataConverterToStringBase::colorFormatPropertyKey: + return object->is(); + case BindablePropertyStringBase::propertyValuePropertyKey: + return object->is(); + case TextInputBase::textPropertyKey: + return object->is(); + case TextValueRunBase::textPropertyKey: + return object->is(); + case CustomPropertyStringBase::propertyValuePropertyKey: + return object->is(); + case AssetBase::namePropertyKey: + return object->is(); + case FileAssetBase::cdnBaseUrlPropertyKey: + return object->is(); + case ViewModelInstanceBooleanBase::propertyValuePropertyKey: + return object->is(); + case TransformComponentConstraintBase::offsetPropertyKey: + return object->is(); + case TransformComponentConstraintBase::doesCopyPropertyKey: + return object->is(); + case TransformComponentConstraintBase::minPropertyKey: + return object->is(); + case TransformComponentConstraintBase::maxPropertyKey: + return object->is(); + case TransformComponentConstraintYBase::doesCopyYPropertyKey: + return object->is(); + case TransformComponentConstraintYBase::minYPropertyKey: + return object->is(); + case TransformComponentConstraintYBase::maxYPropertyKey: + return object->is(); + case IKConstraintBase::invertDirectionPropertyKey: + return object->is(); + case FollowPathConstraintBase::orientPropertyKey: + return object->is(); + case FollowPathConstraintBase::offsetPropertyKey: + return object->is(); + case ScrollConstraintBase::snapPropertyKey: + return object->is(); + case ScrollBarConstraintBase::autoSizePropertyKey: + return object->is(); + case AxisBase::normalizedPropertyKey: + return object->is(); + case LayoutComponentStyleBase::intrinsicallySizedValuePropertyKey: + return object->is(); + case LayoutComponentStyleBase::linkCornerRadiusPropertyKey: + return object->is(); + case NestedSimpleAnimationBase::isPlayingPropertyKey: + return object->is(); + case KeyFrameBoolBase::valuePropertyKey: + return object->is(); + case ListenerAlignTargetBase::preserveOffsetPropertyKey: + return object->is(); + case TransitionValueBooleanComparatorBase::valuePropertyKey: + return object->is(); + case NestedBoolBase::nestedValuePropertyKey: + return object->is(); + case LinearAnimationBase::enableWorkAreaPropertyKey: + return object->is(); + case LinearAnimationBase::quantizePropertyKey: + return object->is(); + case StateMachineBoolBase::valuePropertyKey: + return object->is(); + case ShapePaintBase::isVisiblePropertyKey: + return object->is(); + case DashPathBase::offsetIsPercentagePropertyKey: + return object->is(); + case DashBase::lengthIsPercentagePropertyKey: + return object->is(); + case StrokeBase::transformAffectsStrokePropertyKey: + return object->is(); + case FeatherBase::innerPropertyKey: + return object->is(); + case PathBase::isHolePropertyKey: + return object->is(); + case PointsPathBase::isClosedPropertyKey: + return object->is(); + case RectangleBase::linkCornerRadiusPropertyKey: + return object->is(); + case ClippingShapeBase::isVisiblePropertyKey: + return object->is(); + case CustomPropertyBooleanBase::propertyValuePropertyKey: + return object->is(); + case LayoutComponentBase::clipPropertyKey: + return object->is(); + case BindablePropertyBooleanBase::propertyValuePropertyKey: + return object->is(); + case TextModifierRangeBase::clampPropertyKey: + return object->is(); + case TextFollowPathModifierBase::radialPropertyKey: + return object->is(); + case TextFollowPathModifierBase::orientPropertyKey: + return object->is(); + case TextBase::fitFromBaselinePropertyKey: + return object->is(); + case ViewModelInstanceNumberBase::propertyValuePropertyKey: + return object->is(); + case CustomPropertyNumberBase::propertyValuePropertyKey: + return object->is(); + case ConstraintBase::strengthPropertyKey: + return object->is(); + case DistanceConstraintBase::distancePropertyKey: + return object->is(); + case TransformComponentConstraintBase::copyFactorPropertyKey: + return object->is(); + case TransformComponentConstraintBase::minValuePropertyKey: + return object->is(); + case TransformComponentConstraintBase::maxValuePropertyKey: + return object->is(); + case TransformComponentConstraintYBase::copyFactorYPropertyKey: + return object->is(); + case TransformComponentConstraintYBase::minValueYPropertyKey: + return object->is(); + case TransformComponentConstraintYBase::maxValueYPropertyKey: + return object->is(); + case FollowPathConstraintBase::distancePropertyKey: + return object->is(); + case ScrollConstraintBase::scrollOffsetXPropertyKey: + return object->is(); + case ScrollConstraintBase::scrollOffsetYPropertyKey: + return object->is(); + case ScrollConstraintBase::scrollPercentXPropertyKey: + return object->is(); + case ScrollConstraintBase::scrollPercentYPropertyKey: + return object->is(); + case ScrollConstraintBase::scrollIndexPropertyKey: + return object->is(); + case ElasticScrollPhysicsBase::frictionPropertyKey: + return object->is(); + case ElasticScrollPhysicsBase::speedMultiplierPropertyKey: + return object->is(); + case ElasticScrollPhysicsBase::elasticFactorPropertyKey: + return object->is(); + case TransformConstraintBase::originXPropertyKey: + return object->is(); + case TransformConstraintBase::originYPropertyKey: + return object->is(); + case WorldTransformComponentBase::opacityPropertyKey: + return object->is(); + case TransformComponentBase::rotationPropertyKey: + return object->is(); + case TransformComponentBase::scaleXPropertyKey: + return object->is(); + case TransformComponentBase::scaleYPropertyKey: + return object->is(); + case NodeBase::xPropertyKey: + case NodeBase::xArtboardPropertyKey: + return object->is(); + case NodeBase::yPropertyKey: + case NodeBase::yArtboardPropertyKey: + return object->is(); + case NodeBase::computedLocalXPropertyKey: + return object->is(); + case NodeBase::computedLocalYPropertyKey: + return object->is(); + case NodeBase::computedWorldXPropertyKey: + return object->is(); + case NodeBase::computedWorldYPropertyKey: + return object->is(); + case NodeBase::computedWidthPropertyKey: + return object->is(); + case NodeBase::computedHeightPropertyKey: + return object->is(); + case NestedArtboardLayoutBase::instanceWidthPropertyKey: + return object->is(); + case NestedArtboardLayoutBase::instanceHeightPropertyKey: + return object->is(); + case AxisBase::offsetPropertyKey: + return object->is(); + case LayoutComponentStyleBase::gapHorizontalPropertyKey: + return object->is(); + case LayoutComponentStyleBase::gapVerticalPropertyKey: + return object->is(); + case LayoutComponentStyleBase::maxWidthPropertyKey: + return object->is(); + case LayoutComponentStyleBase::maxHeightPropertyKey: + return object->is(); + case LayoutComponentStyleBase::minWidthPropertyKey: + return object->is(); + case LayoutComponentStyleBase::minHeightPropertyKey: + return object->is(); + case LayoutComponentStyleBase::borderLeftPropertyKey: + return object->is(); + case LayoutComponentStyleBase::borderRightPropertyKey: + return object->is(); + case LayoutComponentStyleBase::borderTopPropertyKey: + return object->is(); + case LayoutComponentStyleBase::borderBottomPropertyKey: + return object->is(); + case LayoutComponentStyleBase::marginLeftPropertyKey: + return object->is(); + case LayoutComponentStyleBase::marginRightPropertyKey: + return object->is(); + case LayoutComponentStyleBase::marginTopPropertyKey: + return object->is(); + case LayoutComponentStyleBase::marginBottomPropertyKey: + return object->is(); + case LayoutComponentStyleBase::paddingLeftPropertyKey: + return object->is(); + case LayoutComponentStyleBase::paddingRightPropertyKey: + return object->is(); + case LayoutComponentStyleBase::paddingTopPropertyKey: + return object->is(); + case LayoutComponentStyleBase::paddingBottomPropertyKey: + return object->is(); + case LayoutComponentStyleBase::positionLeftPropertyKey: + return object->is(); + case LayoutComponentStyleBase::positionRightPropertyKey: + return object->is(); + case LayoutComponentStyleBase::positionTopPropertyKey: + return object->is(); + case LayoutComponentStyleBase::positionBottomPropertyKey: + return object->is(); + case LayoutComponentStyleBase::flexPropertyKey: + return object->is(); + case LayoutComponentStyleBase::flexGrowPropertyKey: + return object->is(); + case LayoutComponentStyleBase::flexShrinkPropertyKey: + return object->is(); + case LayoutComponentStyleBase::flexBasisPropertyKey: + return object->is(); + case LayoutComponentStyleBase::aspectRatioPropertyKey: + return object->is(); + case LayoutComponentStyleBase::interpolationTimePropertyKey: + return object->is(); + case LayoutComponentStyleBase::cornerRadiusTLPropertyKey: + return object->is(); + case LayoutComponentStyleBase::cornerRadiusTRPropertyKey: + return object->is(); + case LayoutComponentStyleBase::cornerRadiusBLPropertyKey: + return object->is(); + case LayoutComponentStyleBase::cornerRadiusBRPropertyKey: + return object->is(); + case NSlicedNodeBase::initialWidthPropertyKey: + return object->is(); + case NSlicedNodeBase::initialHeightPropertyKey: + return object->is(); + case NSlicedNodeBase::widthPropertyKey: + return object->is(); + case NSlicedNodeBase::heightPropertyKey: + return object->is(); + case NestedLinearAnimationBase::mixPropertyKey: + return object->is(); + case NestedSimpleAnimationBase::speedPropertyKey: + return object->is(); + case AdvanceableStateBase::speedPropertyKey: + return object->is(); + case BlendAnimationDirectBase::mixValuePropertyKey: + return object->is(); + case StateMachineNumberBase::valuePropertyKey: + return object->is(); + case CubicInterpolatorBase::x1PropertyKey: + return object->is(); + case CubicInterpolatorBase::y1PropertyKey: + return object->is(); + case CubicInterpolatorBase::x2PropertyKey: + return object->is(); + case CubicInterpolatorBase::y2PropertyKey: + return object->is(); + case TransitionNumberConditionBase::valuePropertyKey: + return object->is(); + case CubicInterpolatorComponentBase::x1PropertyKey: + return object->is(); + case CubicInterpolatorComponentBase::y1PropertyKey: + return object->is(); + case CubicInterpolatorComponentBase::x2PropertyKey: + return object->is(); + case CubicInterpolatorComponentBase::y2PropertyKey: + return object->is(); + case ListenerNumberChangeBase::valuePropertyKey: + return object->is(); + case KeyFrameDoubleBase::valuePropertyKey: + return object->is(); + case LinearAnimationBase::speedPropertyKey: + return object->is(); + case TransitionValueNumberComparatorBase::valuePropertyKey: + return object->is(); + case ElasticInterpolatorBase::amplitudePropertyKey: + return object->is(); + case ElasticInterpolatorBase::periodPropertyKey: + return object->is(); + case NestedNumberBase::nestedValuePropertyKey: + return object->is(); + case NestedRemapAnimationBase::timePropertyKey: + return object->is(); + case BlendAnimation1DBase::valuePropertyKey: + return object->is(); + case DashPathBase::offsetPropertyKey: + return object->is(); + case LinearGradientBase::startXPropertyKey: + return object->is(); + case LinearGradientBase::startYPropertyKey: + return object->is(); + case LinearGradientBase::endXPropertyKey: + return object->is(); + case LinearGradientBase::endYPropertyKey: + return object->is(); + case LinearGradientBase::opacityPropertyKey: + return object->is(); + case DashBase::lengthPropertyKey: + return object->is(); + case StrokeBase::thicknessPropertyKey: + return object->is(); + case GradientStopBase::positionPropertyKey: + return object->is(); + case FeatherBase::strengthPropertyKey: + return object->is(); + case FeatherBase::offsetXPropertyKey: + return object->is(); + case FeatherBase::offsetYPropertyKey: + return object->is(); + case TrimPathBase::startPropertyKey: + return object->is(); + case TrimPathBase::endPropertyKey: + return object->is(); + case TrimPathBase::offsetPropertyKey: + return object->is(); + case VertexBase::xPropertyKey: + return object->is(); + case VertexBase::yPropertyKey: + return object->is(); + case MeshVertexBase::uPropertyKey: + return object->is(); + case MeshVertexBase::vPropertyKey: + return object->is(); + case ShapeBase::lengthPropertyKey: + return object->is(); + case StraightVertexBase::radiusPropertyKey: + return object->is(); + case CubicAsymmetricVertexBase::rotationPropertyKey: + return object->is(); + case CubicAsymmetricVertexBase::inDistancePropertyKey: + return object->is(); + case CubicAsymmetricVertexBase::outDistancePropertyKey: + return object->is(); + case ParametricPathBase::widthPropertyKey: + return object->is(); + case ParametricPathBase::heightPropertyKey: + return object->is(); + case ParametricPathBase::originXPropertyKey: + return object->is(); + case ParametricPathBase::originYPropertyKey: + return object->is(); + case RectangleBase::cornerRadiusTLPropertyKey: + return object->is(); + case RectangleBase::cornerRadiusTRPropertyKey: + return object->is(); + case RectangleBase::cornerRadiusBLPropertyKey: + return object->is(); + case RectangleBase::cornerRadiusBRPropertyKey: + return object->is(); + case CubicMirroredVertexBase::rotationPropertyKey: + return object->is(); + case CubicMirroredVertexBase::distancePropertyKey: + return object->is(); + case PolygonBase::cornerRadiusPropertyKey: + return object->is(); + case StarBase::innerRadiusPropertyKey: + return object->is(); + case ImageBase::originXPropertyKey: + return object->is(); + case ImageBase::originYPropertyKey: + return object->is(); + case CubicDetachedVertexBase::inRotationPropertyKey: + return object->is(); + case CubicDetachedVertexBase::inDistancePropertyKey: + return object->is(); + case CubicDetachedVertexBase::outRotationPropertyKey: + return object->is(); + case CubicDetachedVertexBase::outDistancePropertyKey: + return object->is(); + case LayoutComponentBase::widthPropertyKey: + return object->is(); + case LayoutComponentBase::heightPropertyKey: + return object->is(); + case LayoutComponentBase::fractionalWidthPropertyKey: + return object->is(); + case LayoutComponentBase::fractionalHeightPropertyKey: + return object->is(); + case ArtboardBase::originXPropertyKey: + return object->is(); + case ArtboardBase::originYPropertyKey: + return object->is(); + case JoystickBase::xPropertyKey: + return object->is(); + case JoystickBase::yPropertyKey: + return object->is(); + case JoystickBase::posXPropertyKey: + return object->is(); + case JoystickBase::posYPropertyKey: + return object->is(); + case JoystickBase::originXPropertyKey: + return object->is(); + case JoystickBase::originYPropertyKey: + return object->is(); + case JoystickBase::widthPropertyKey: + return object->is(); + case JoystickBase::heightPropertyKey: + return object->is(); + case DataConverterOperationValueBase::operationValuePropertyKey: + return object->is(); + case DataConverterRangeMapperBase::minInputPropertyKey: + return object->is(); + case DataConverterRangeMapperBase::maxInputPropertyKey: + return object->is(); + case DataConverterRangeMapperBase::minOutputPropertyKey: + return object->is(); + case DataConverterRangeMapperBase::maxOutputPropertyKey: + return object->is(); + case DataConverterInterpolatorBase::durationPropertyKey: + return object->is(); + case FormulaTokenValueBase::operationValuePropertyKey: + return object->is(); + case BindablePropertyNumberBase::propertyValuePropertyKey: + return object->is(); + case NestedArtboardLeafBase::alignmentXPropertyKey: + return object->is(); + case NestedArtboardLeafBase::alignmentYPropertyKey: + return object->is(); + case BoneBase::lengthPropertyKey: + return object->is(); + case RootBoneBase::xPropertyKey: + return object->is(); + case RootBoneBase::yPropertyKey: + return object->is(); + case SkinBase::xxPropertyKey: + return object->is(); + case SkinBase::yxPropertyKey: + return object->is(); + case SkinBase::xyPropertyKey: + return object->is(); + case SkinBase::yyPropertyKey: + return object->is(); + case SkinBase::txPropertyKey: + return object->is(); + case SkinBase::tyPropertyKey: + return object->is(); + case TendonBase::xxPropertyKey: + return object->is(); + case TendonBase::yxPropertyKey: + return object->is(); + case TendonBase::xyPropertyKey: + return object->is(); + case TendonBase::yyPropertyKey: + return object->is(); + case TendonBase::txPropertyKey: + return object->is(); + case TendonBase::tyPropertyKey: + return object->is(); + case TextModifierRangeBase::modifyFromPropertyKey: + return object->is(); + case TextModifierRangeBase::modifyToPropertyKey: + return object->is(); + case TextModifierRangeBase::strengthPropertyKey: + return object->is(); + case TextModifierRangeBase::falloffFromPropertyKey: + return object->is(); + case TextModifierRangeBase::falloffToPropertyKey: + return object->is(); + case TextModifierRangeBase::offsetPropertyKey: + return object->is(); + case TextFollowPathModifierBase::startPropertyKey: + return object->is(); + case TextFollowPathModifierBase::endPropertyKey: + return object->is(); + case TextFollowPathModifierBase::strengthPropertyKey: + return object->is(); + case TextFollowPathModifierBase::offsetPropertyKey: + return object->is(); + case TextVariationModifierBase::axisValuePropertyKey: + return object->is(); + case TextModifierGroupBase::originXPropertyKey: + return object->is(); + case TextModifierGroupBase::originYPropertyKey: + return object->is(); + case TextModifierGroupBase::opacityPropertyKey: + return object->is(); + case TextModifierGroupBase::xPropertyKey: + return object->is(); + case TextModifierGroupBase::yPropertyKey: + return object->is(); + case TextModifierGroupBase::rotationPropertyKey: + return object->is(); + case TextModifierGroupBase::scaleXPropertyKey: + return object->is(); + case TextModifierGroupBase::scaleYPropertyKey: + return object->is(); + case TextStyleBase::fontSizePropertyKey: + return object->is(); + case TextStyleBase::lineHeightPropertyKey: + return object->is(); + case TextStyleBase::letterSpacingPropertyKey: + return object->is(); + case TextInputBase::selectionRadiusPropertyKey: + return object->is(); + case TextStyleAxisBase::axisValuePropertyKey: + return object->is(); + case TextBase::widthPropertyKey: + return object->is(); + case TextBase::heightPropertyKey: + return object->is(); + case TextBase::originXPropertyKey: + return object->is(); + case TextBase::originYPropertyKey: + return object->is(); + case TextBase::paragraphSpacingPropertyKey: + return object->is(); + case DrawableAssetBase::heightPropertyKey: + return object->is(); + case DrawableAssetBase::widthPropertyKey: + return object->is(); + case ExportAudioBase::volumePropertyKey: + return object->is(); + case NestedTriggerBase::firePropertyKey: + return object->is(); + case EventBase::triggerPropertyKey: + return object->is(); + } + return false; + } +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/custom_property_base.hpp b/third_party/rive/include/rive/generated/custom_property_base.hpp new file mode 100644 index 0000000..955cf5b --- /dev/null +++ b/third_party/rive/include/rive/generated/custom_property_base.hpp @@ -0,0 +1,34 @@ +#ifndef _RIVE_CUSTOM_PROPERTY_BASE_HPP_ +#define _RIVE_CUSTOM_PROPERTY_BASE_HPP_ +#include "rive/component.hpp" +namespace rive +{ +class CustomPropertyBase : public Component +{ +protected: + typedef Component Super; + +public: + static const uint16_t typeKey = 167; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case CustomPropertyBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/custom_property_boolean_base.hpp b/third_party/rive/include/rive/generated/custom_property_boolean_base.hpp new file mode 100644 index 0000000..f6f0134 --- /dev/null +++ b/third_party/rive/include/rive/generated/custom_property_boolean_base.hpp @@ -0,0 +1,72 @@ +#ifndef _RIVE_CUSTOM_PROPERTY_BOOLEAN_BASE_HPP_ +#define _RIVE_CUSTOM_PROPERTY_BOOLEAN_BASE_HPP_ +#include "rive/core/field_types/core_bool_type.hpp" +#include "rive/custom_property.hpp" +namespace rive +{ +class CustomPropertyBooleanBase : public CustomProperty +{ +protected: + typedef CustomProperty Super; + +public: + static const uint16_t typeKey = 129; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case CustomPropertyBooleanBase::typeKey: + case CustomPropertyBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t propertyValuePropertyKey = 245; + +protected: + bool m_PropertyValue = false; + +public: + inline bool propertyValue() const { return m_PropertyValue; } + void propertyValue(bool value) + { + if (m_PropertyValue == value) + { + return; + } + m_PropertyValue = value; + propertyValueChanged(); + } + + Core* clone() const override; + void copy(const CustomPropertyBooleanBase& object) + { + m_PropertyValue = object.m_PropertyValue; + CustomProperty::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case propertyValuePropertyKey: + m_PropertyValue = CoreBoolType::deserialize(reader); + return true; + } + return CustomProperty::deserialize(propertyKey, reader); + } + +protected: + virtual void propertyValueChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/custom_property_group_base.hpp b/third_party/rive/include/rive/generated/custom_property_group_base.hpp new file mode 100644 index 0000000..f1a8308 --- /dev/null +++ b/third_party/rive/include/rive/generated/custom_property_group_base.hpp @@ -0,0 +1,37 @@ +#ifndef _RIVE_CUSTOM_PROPERTY_GROUP_BASE_HPP_ +#define _RIVE_CUSTOM_PROPERTY_GROUP_BASE_HPP_ +#include "rive/container_component.hpp" +namespace rive +{ +class CustomPropertyGroupBase : public ContainerComponent +{ +protected: + typedef ContainerComponent Super; + +public: + static const uint16_t typeKey = 548; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case CustomPropertyGroupBase::typeKey: + case ContainerComponentBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/custom_property_number_base.hpp b/third_party/rive/include/rive/generated/custom_property_number_base.hpp new file mode 100644 index 0000000..e9288f5 --- /dev/null +++ b/third_party/rive/include/rive/generated/custom_property_number_base.hpp @@ -0,0 +1,72 @@ +#ifndef _RIVE_CUSTOM_PROPERTY_NUMBER_BASE_HPP_ +#define _RIVE_CUSTOM_PROPERTY_NUMBER_BASE_HPP_ +#include "rive/core/field_types/core_double_type.hpp" +#include "rive/custom_property.hpp" +namespace rive +{ +class CustomPropertyNumberBase : public CustomProperty +{ +protected: + typedef CustomProperty Super; + +public: + static const uint16_t typeKey = 127; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case CustomPropertyNumberBase::typeKey: + case CustomPropertyBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t propertyValuePropertyKey = 243; + +protected: + float m_PropertyValue = 0.0f; + +public: + inline float propertyValue() const { return m_PropertyValue; } + void propertyValue(float value) + { + if (m_PropertyValue == value) + { + return; + } + m_PropertyValue = value; + propertyValueChanged(); + } + + Core* clone() const override; + void copy(const CustomPropertyNumberBase& object) + { + m_PropertyValue = object.m_PropertyValue; + CustomProperty::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case propertyValuePropertyKey: + m_PropertyValue = CoreDoubleType::deserialize(reader); + return true; + } + return CustomProperty::deserialize(propertyKey, reader); + } + +protected: + virtual void propertyValueChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/custom_property_string_base.hpp b/third_party/rive/include/rive/generated/custom_property_string_base.hpp new file mode 100644 index 0000000..7575515 --- /dev/null +++ b/third_party/rive/include/rive/generated/custom_property_string_base.hpp @@ -0,0 +1,73 @@ +#ifndef _RIVE_CUSTOM_PROPERTY_STRING_BASE_HPP_ +#define _RIVE_CUSTOM_PROPERTY_STRING_BASE_HPP_ +#include +#include "rive/core/field_types/core_string_type.hpp" +#include "rive/custom_property.hpp" +namespace rive +{ +class CustomPropertyStringBase : public CustomProperty +{ +protected: + typedef CustomProperty Super; + +public: + static const uint16_t typeKey = 130; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case CustomPropertyStringBase::typeKey: + case CustomPropertyBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t propertyValuePropertyKey = 246; + +protected: + std::string m_PropertyValue = ""; + +public: + inline const std::string& propertyValue() const { return m_PropertyValue; } + void propertyValue(std::string value) + { + if (m_PropertyValue == value) + { + return; + } + m_PropertyValue = value; + propertyValueChanged(); + } + + Core* clone() const override; + void copy(const CustomPropertyStringBase& object) + { + m_PropertyValue = object.m_PropertyValue; + CustomProperty::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case propertyValuePropertyKey: + m_PropertyValue = CoreStringType::deserialize(reader); + return true; + } + return CustomProperty::deserialize(propertyKey, reader); + } + +protected: + virtual void propertyValueChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/data_bind/bindable_property_asset_base.hpp b/third_party/rive/include/rive/generated/data_bind/bindable_property_asset_base.hpp new file mode 100644 index 0000000..8608b46 --- /dev/null +++ b/third_party/rive/include/rive/generated/data_bind/bindable_property_asset_base.hpp @@ -0,0 +1,71 @@ +#ifndef _RIVE_BINDABLE_PROPERTY_ASSET_BASE_HPP_ +#define _RIVE_BINDABLE_PROPERTY_ASSET_BASE_HPP_ +#include "rive/core/field_types/core_uint_type.hpp" +#include "rive/data_bind/bindable_property.hpp" +namespace rive +{ +class BindablePropertyAssetBase : public BindableProperty +{ +protected: + typedef BindableProperty Super; + +public: + static const uint16_t typeKey = 588; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case BindablePropertyAssetBase::typeKey: + case BindablePropertyBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t propertyValuePropertyKey = 823; + +protected: + uint32_t m_PropertyValue = -1; + +public: + inline uint32_t propertyValue() const { return m_PropertyValue; } + void propertyValue(uint32_t value) + { + if (m_PropertyValue == value) + { + return; + } + m_PropertyValue = value; + propertyValueChanged(); + } + + Core* clone() const override; + void copy(const BindablePropertyAssetBase& object) + { + m_PropertyValue = object.m_PropertyValue; + BindableProperty::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case propertyValuePropertyKey: + m_PropertyValue = CoreUintType::deserialize(reader); + return true; + } + return BindableProperty::deserialize(propertyKey, reader); + } + +protected: + virtual void propertyValueChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/data_bind/bindable_property_base.hpp b/third_party/rive/include/rive/generated/data_bind/bindable_property_base.hpp new file mode 100644 index 0000000..2012574 --- /dev/null +++ b/third_party/rive/include/rive/generated/data_bind/bindable_property_base.hpp @@ -0,0 +1,40 @@ +#ifndef _RIVE_BINDABLE_PROPERTY_BASE_HPP_ +#define _RIVE_BINDABLE_PROPERTY_BASE_HPP_ +#include "rive/core.hpp" +namespace rive +{ +class BindablePropertyBase : public Core +{ +protected: + typedef Core Super; + +public: + static const uint16_t typeKey = 9; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case BindablePropertyBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + void copy(const BindablePropertyBase& object) {} + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + return false; + } + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/data_bind/bindable_property_boolean_base.hpp b/third_party/rive/include/rive/generated/data_bind/bindable_property_boolean_base.hpp new file mode 100644 index 0000000..f7c3ad7 --- /dev/null +++ b/third_party/rive/include/rive/generated/data_bind/bindable_property_boolean_base.hpp @@ -0,0 +1,71 @@ +#ifndef _RIVE_BINDABLE_PROPERTY_BOOLEAN_BASE_HPP_ +#define _RIVE_BINDABLE_PROPERTY_BOOLEAN_BASE_HPP_ +#include "rive/core/field_types/core_bool_type.hpp" +#include "rive/data_bind/bindable_property.hpp" +namespace rive +{ +class BindablePropertyBooleanBase : public BindableProperty +{ +protected: + typedef BindableProperty Super; + +public: + static const uint16_t typeKey = 472; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case BindablePropertyBooleanBase::typeKey: + case BindablePropertyBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t propertyValuePropertyKey = 634; + +protected: + bool m_PropertyValue = false; + +public: + inline bool propertyValue() const { return m_PropertyValue; } + void propertyValue(bool value) + { + if (m_PropertyValue == value) + { + return; + } + m_PropertyValue = value; + propertyValueChanged(); + } + + Core* clone() const override; + void copy(const BindablePropertyBooleanBase& object) + { + m_PropertyValue = object.m_PropertyValue; + BindableProperty::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case propertyValuePropertyKey: + m_PropertyValue = CoreBoolType::deserialize(reader); + return true; + } + return BindableProperty::deserialize(propertyKey, reader); + } + +protected: + virtual void propertyValueChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/data_bind/bindable_property_color_base.hpp b/third_party/rive/include/rive/generated/data_bind/bindable_property_color_base.hpp new file mode 100644 index 0000000..8ffe876 --- /dev/null +++ b/third_party/rive/include/rive/generated/data_bind/bindable_property_color_base.hpp @@ -0,0 +1,71 @@ +#ifndef _RIVE_BINDABLE_PROPERTY_COLOR_BASE_HPP_ +#define _RIVE_BINDABLE_PROPERTY_COLOR_BASE_HPP_ +#include "rive/core/field_types/core_color_type.hpp" +#include "rive/data_bind/bindable_property.hpp" +namespace rive +{ +class BindablePropertyColorBase : public BindableProperty +{ +protected: + typedef BindableProperty Super; + +public: + static const uint16_t typeKey = 475; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case BindablePropertyColorBase::typeKey: + case BindablePropertyBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t propertyValuePropertyKey = 638; + +protected: + int m_PropertyValue = 0xFF1D1D1D; + +public: + inline int propertyValue() const { return m_PropertyValue; } + void propertyValue(int value) + { + if (m_PropertyValue == value) + { + return; + } + m_PropertyValue = value; + propertyValueChanged(); + } + + Core* clone() const override; + void copy(const BindablePropertyColorBase& object) + { + m_PropertyValue = object.m_PropertyValue; + BindableProperty::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case propertyValuePropertyKey: + m_PropertyValue = CoreColorType::deserialize(reader); + return true; + } + return BindableProperty::deserialize(propertyKey, reader); + } + +protected: + virtual void propertyValueChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/data_bind/bindable_property_enum_base.hpp b/third_party/rive/include/rive/generated/data_bind/bindable_property_enum_base.hpp new file mode 100644 index 0000000..1b79d24 --- /dev/null +++ b/third_party/rive/include/rive/generated/data_bind/bindable_property_enum_base.hpp @@ -0,0 +1,71 @@ +#ifndef _RIVE_BINDABLE_PROPERTY_ENUM_BASE_HPP_ +#define _RIVE_BINDABLE_PROPERTY_ENUM_BASE_HPP_ +#include "rive/core/field_types/core_uint_type.hpp" +#include "rive/data_bind/bindable_property.hpp" +namespace rive +{ +class BindablePropertyEnumBase : public BindableProperty +{ +protected: + typedef BindableProperty Super; + +public: + static const uint16_t typeKey = 474; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case BindablePropertyEnumBase::typeKey: + case BindablePropertyBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t propertyValuePropertyKey = 637; + +protected: + uint32_t m_PropertyValue = -1; + +public: + inline uint32_t propertyValue() const { return m_PropertyValue; } + void propertyValue(uint32_t value) + { + if (m_PropertyValue == value) + { + return; + } + m_PropertyValue = value; + propertyValueChanged(); + } + + Core* clone() const override; + void copy(const BindablePropertyEnumBase& object) + { + m_PropertyValue = object.m_PropertyValue; + BindableProperty::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case propertyValuePropertyKey: + m_PropertyValue = CoreUintType::deserialize(reader); + return true; + } + return BindableProperty::deserialize(propertyKey, reader); + } + +protected: + virtual void propertyValueChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/data_bind/bindable_property_integer_base.hpp b/third_party/rive/include/rive/generated/data_bind/bindable_property_integer_base.hpp new file mode 100644 index 0000000..5355de0 --- /dev/null +++ b/third_party/rive/include/rive/generated/data_bind/bindable_property_integer_base.hpp @@ -0,0 +1,71 @@ +#ifndef _RIVE_BINDABLE_PROPERTY_INTEGER_BASE_HPP_ +#define _RIVE_BINDABLE_PROPERTY_INTEGER_BASE_HPP_ +#include "rive/core/field_types/core_uint_type.hpp" +#include "rive/data_bind/bindable_property.hpp" +namespace rive +{ +class BindablePropertyIntegerBase : public BindableProperty +{ +protected: + typedef BindableProperty Super; + +public: + static const uint16_t typeKey = 567; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case BindablePropertyIntegerBase::typeKey: + case BindablePropertyBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t propertyValuePropertyKey = 686; + +protected: + uint32_t m_PropertyValue = 0; + +public: + inline uint32_t propertyValue() const { return m_PropertyValue; } + void propertyValue(uint32_t value) + { + if (m_PropertyValue == value) + { + return; + } + m_PropertyValue = value; + propertyValueChanged(); + } + + Core* clone() const override; + void copy(const BindablePropertyIntegerBase& object) + { + m_PropertyValue = object.m_PropertyValue; + BindableProperty::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case propertyValuePropertyKey: + m_PropertyValue = CoreUintType::deserialize(reader); + return true; + } + return BindableProperty::deserialize(propertyKey, reader); + } + +protected: + virtual void propertyValueChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/data_bind/bindable_property_number_base.hpp b/third_party/rive/include/rive/generated/data_bind/bindable_property_number_base.hpp new file mode 100644 index 0000000..8049601 --- /dev/null +++ b/third_party/rive/include/rive/generated/data_bind/bindable_property_number_base.hpp @@ -0,0 +1,71 @@ +#ifndef _RIVE_BINDABLE_PROPERTY_NUMBER_BASE_HPP_ +#define _RIVE_BINDABLE_PROPERTY_NUMBER_BASE_HPP_ +#include "rive/core/field_types/core_double_type.hpp" +#include "rive/data_bind/bindable_property.hpp" +namespace rive +{ +class BindablePropertyNumberBase : public BindableProperty +{ +protected: + typedef BindableProperty Super; + +public: + static const uint16_t typeKey = 473; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case BindablePropertyNumberBase::typeKey: + case BindablePropertyBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t propertyValuePropertyKey = 636; + +protected: + float m_PropertyValue = 0.0f; + +public: + inline float propertyValue() const { return m_PropertyValue; } + void propertyValue(float value) + { + if (m_PropertyValue == value) + { + return; + } + m_PropertyValue = value; + propertyValueChanged(); + } + + Core* clone() const override; + void copy(const BindablePropertyNumberBase& object) + { + m_PropertyValue = object.m_PropertyValue; + BindableProperty::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case propertyValuePropertyKey: + m_PropertyValue = CoreDoubleType::deserialize(reader); + return true; + } + return BindableProperty::deserialize(propertyKey, reader); + } + +protected: + virtual void propertyValueChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/data_bind/bindable_property_string_base.hpp b/third_party/rive/include/rive/generated/data_bind/bindable_property_string_base.hpp new file mode 100644 index 0000000..7dee11d --- /dev/null +++ b/third_party/rive/include/rive/generated/data_bind/bindable_property_string_base.hpp @@ -0,0 +1,72 @@ +#ifndef _RIVE_BINDABLE_PROPERTY_STRING_BASE_HPP_ +#define _RIVE_BINDABLE_PROPERTY_STRING_BASE_HPP_ +#include +#include "rive/core/field_types/core_string_type.hpp" +#include "rive/data_bind/bindable_property.hpp" +namespace rive +{ +class BindablePropertyStringBase : public BindableProperty +{ +protected: + typedef BindableProperty Super; + +public: + static const uint16_t typeKey = 471; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case BindablePropertyStringBase::typeKey: + case BindablePropertyBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t propertyValuePropertyKey = 635; + +protected: + std::string m_PropertyValue = ""; + +public: + inline const std::string& propertyValue() const { return m_PropertyValue; } + void propertyValue(std::string value) + { + if (m_PropertyValue == value) + { + return; + } + m_PropertyValue = value; + propertyValueChanged(); + } + + Core* clone() const override; + void copy(const BindablePropertyStringBase& object) + { + m_PropertyValue = object.m_PropertyValue; + BindableProperty::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case propertyValuePropertyKey: + m_PropertyValue = CoreStringType::deserialize(reader); + return true; + } + return BindableProperty::deserialize(propertyKey, reader); + } + +protected: + virtual void propertyValueChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/data_bind/bindable_property_trigger_base.hpp b/third_party/rive/include/rive/generated/data_bind/bindable_property_trigger_base.hpp new file mode 100644 index 0000000..8ac8dac --- /dev/null +++ b/third_party/rive/include/rive/generated/data_bind/bindable_property_trigger_base.hpp @@ -0,0 +1,37 @@ +#ifndef _RIVE_BINDABLE_PROPERTY_TRIGGER_BASE_HPP_ +#define _RIVE_BINDABLE_PROPERTY_TRIGGER_BASE_HPP_ +#include "rive/data_bind/bindable_property_integer.hpp" +namespace rive +{ +class BindablePropertyTriggerBase : public BindablePropertyInteger +{ +protected: + typedef BindablePropertyInteger Super; + +public: + static const uint16_t typeKey = 503; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case BindablePropertyTriggerBase::typeKey: + case BindablePropertyIntegerBase::typeKey: + case BindablePropertyBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/data_bind/converters/data_converter_base.hpp b/third_party/rive/include/rive/generated/data_bind/converters/data_converter_base.hpp new file mode 100644 index 0000000..8ce85a7 --- /dev/null +++ b/third_party/rive/include/rive/generated/data_bind/converters/data_converter_base.hpp @@ -0,0 +1,66 @@ +#ifndef _RIVE_DATA_CONVERTER_BASE_HPP_ +#define _RIVE_DATA_CONVERTER_BASE_HPP_ +#include +#include "rive/core.hpp" +#include "rive/core/field_types/core_string_type.hpp" +namespace rive +{ +class DataConverterBase : public Core +{ +protected: + typedef Core Super; + +public: + static const uint16_t typeKey = 488; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case DataConverterBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t namePropertyKey = 662; + +protected: + std::string m_Name = ""; + +public: + inline const std::string& name() const { return m_Name; } + void name(std::string value) + { + if (m_Name == value) + { + return; + } + m_Name = value; + nameChanged(); + } + + void copy(const DataConverterBase& object) { m_Name = object.m_Name; } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case namePropertyKey: + m_Name = CoreStringType::deserialize(reader); + return true; + } + return false; + } + +protected: + virtual void nameChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/data_bind/converters/data_converter_boolean_negate_base.hpp b/third_party/rive/include/rive/generated/data_bind/converters/data_converter_boolean_negate_base.hpp new file mode 100644 index 0000000..7f697eb --- /dev/null +++ b/third_party/rive/include/rive/generated/data_bind/converters/data_converter_boolean_negate_base.hpp @@ -0,0 +1,36 @@ +#ifndef _RIVE_DATA_CONVERTER_BOOLEAN_NEGATE_BASE_HPP_ +#define _RIVE_DATA_CONVERTER_BOOLEAN_NEGATE_BASE_HPP_ +#include "rive/data_bind/converters/data_converter.hpp" +namespace rive +{ +class DataConverterBooleanNegateBase : public DataConverter +{ +protected: + typedef DataConverter Super; + +public: + static const uint16_t typeKey = 535; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case DataConverterBooleanNegateBase::typeKey: + case DataConverterBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/data_bind/converters/data_converter_formula_base.hpp b/third_party/rive/include/rive/generated/data_bind/converters/data_converter_formula_base.hpp new file mode 100644 index 0000000..b453420 --- /dev/null +++ b/third_party/rive/include/rive/generated/data_bind/converters/data_converter_formula_base.hpp @@ -0,0 +1,36 @@ +#ifndef _RIVE_DATA_CONVERTER_FORMULA_BASE_HPP_ +#define _RIVE_DATA_CONVERTER_FORMULA_BASE_HPP_ +#include "rive/data_bind/converters/data_converter.hpp" +namespace rive +{ +class DataConverterFormulaBase : public DataConverter +{ +protected: + typedef DataConverter Super; + +public: + static const uint16_t typeKey = 536; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case DataConverterFormulaBase::typeKey: + case DataConverterBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/data_bind/converters/data_converter_group_base.hpp b/third_party/rive/include/rive/generated/data_bind/converters/data_converter_group_base.hpp new file mode 100644 index 0000000..7f07759 --- /dev/null +++ b/third_party/rive/include/rive/generated/data_bind/converters/data_converter_group_base.hpp @@ -0,0 +1,36 @@ +#ifndef _RIVE_DATA_CONVERTER_GROUP_BASE_HPP_ +#define _RIVE_DATA_CONVERTER_GROUP_BASE_HPP_ +#include "rive/data_bind/converters/data_converter.hpp" +namespace rive +{ +class DataConverterGroupBase : public DataConverter +{ +protected: + typedef DataConverter Super; + +public: + static const uint16_t typeKey = 499; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case DataConverterGroupBase::typeKey: + case DataConverterBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/data_bind/converters/data_converter_group_item_base.hpp b/third_party/rive/include/rive/generated/data_bind/converters/data_converter_group_item_base.hpp new file mode 100644 index 0000000..80f66fa --- /dev/null +++ b/third_party/rive/include/rive/generated/data_bind/converters/data_converter_group_item_base.hpp @@ -0,0 +1,69 @@ +#ifndef _RIVE_DATA_CONVERTER_GROUP_ITEM_BASE_HPP_ +#define _RIVE_DATA_CONVERTER_GROUP_ITEM_BASE_HPP_ +#include "rive/core.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +namespace rive +{ +class DataConverterGroupItemBase : public Core +{ +protected: + typedef Core Super; + +public: + static const uint16_t typeKey = 498; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case DataConverterGroupItemBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t converterIdPropertyKey = 679; + +protected: + uint32_t m_ConverterId = -1; + +public: + inline uint32_t converterId() const { return m_ConverterId; } + void converterId(uint32_t value) + { + if (m_ConverterId == value) + { + return; + } + m_ConverterId = value; + converterIdChanged(); + } + + Core* clone() const override; + void copy(const DataConverterGroupItemBase& object) + { + m_ConverterId = object.m_ConverterId; + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case converterIdPropertyKey: + m_ConverterId = CoreUintType::deserialize(reader); + return true; + } + return false; + } + +protected: + virtual void converterIdChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/data_bind/converters/data_converter_interpolator_base.hpp b/third_party/rive/include/rive/generated/data_bind/converters/data_converter_interpolator_base.hpp new file mode 100644 index 0000000..ceaec48 --- /dev/null +++ b/third_party/rive/include/rive/generated/data_bind/converters/data_converter_interpolator_base.hpp @@ -0,0 +1,108 @@ +#ifndef _RIVE_DATA_CONVERTER_INTERPOLATOR_BASE_HPP_ +#define _RIVE_DATA_CONVERTER_INTERPOLATOR_BASE_HPP_ +#include "rive/core/field_types/core_double_type.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +#include "rive/data_bind/converters/data_converter.hpp" +namespace rive +{ +class DataConverterInterpolatorBase : public DataConverter +{ +protected: + typedef DataConverter Super; + +public: + static const uint16_t typeKey = 534; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case DataConverterInterpolatorBase::typeKey: + case DataConverterBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t interpolationTypePropertyKey = 757; + static const uint16_t interpolatorIdPropertyKey = 758; + static const uint16_t durationPropertyKey = 756; + +protected: + uint32_t m_InterpolationType = 1; + uint32_t m_InterpolatorId = -1; + float m_Duration = 1.0f; + +public: + inline uint32_t interpolationType() const { return m_InterpolationType; } + void interpolationType(uint32_t value) + { + if (m_InterpolationType == value) + { + return; + } + m_InterpolationType = value; + interpolationTypeChanged(); + } + + inline uint32_t interpolatorId() const { return m_InterpolatorId; } + void interpolatorId(uint32_t value) + { + if (m_InterpolatorId == value) + { + return; + } + m_InterpolatorId = value; + interpolatorIdChanged(); + } + + inline float duration() const { return m_Duration; } + void duration(float value) + { + if (m_Duration == value) + { + return; + } + m_Duration = value; + durationChanged(); + } + + Core* clone() const override; + void copy(const DataConverterInterpolatorBase& object) + { + m_InterpolationType = object.m_InterpolationType; + m_InterpolatorId = object.m_InterpolatorId; + m_Duration = object.m_Duration; + DataConverter::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case interpolationTypePropertyKey: + m_InterpolationType = CoreUintType::deserialize(reader); + return true; + case interpolatorIdPropertyKey: + m_InterpolatorId = CoreUintType::deserialize(reader); + return true; + case durationPropertyKey: + m_Duration = CoreDoubleType::deserialize(reader); + return true; + } + return DataConverter::deserialize(propertyKey, reader); + } + +protected: + virtual void interpolationTypeChanged() {} + virtual void interpolatorIdChanged() {} + virtual void durationChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/data_bind/converters/data_converter_number_to_list_base.hpp b/third_party/rive/include/rive/generated/data_bind/converters/data_converter_number_to_list_base.hpp new file mode 100644 index 0000000..e9f5924 --- /dev/null +++ b/third_party/rive/include/rive/generated/data_bind/converters/data_converter_number_to_list_base.hpp @@ -0,0 +1,71 @@ +#ifndef _RIVE_DATA_CONVERTER_NUMBER_TO_LIST_BASE_HPP_ +#define _RIVE_DATA_CONVERTER_NUMBER_TO_LIST_BASE_HPP_ +#include "rive/core/field_types/core_uint_type.hpp" +#include "rive/data_bind/converters/data_converter.hpp" +namespace rive +{ +class DataConverterNumberToListBase : public DataConverter +{ +protected: + typedef DataConverter Super; + +public: + static const uint16_t typeKey = 568; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case DataConverterNumberToListBase::typeKey: + case DataConverterBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t viewModelIdPropertyKey = 816; + +protected: + uint32_t m_ViewModelId = -1; + +public: + inline uint32_t viewModelId() const { return m_ViewModelId; } + void viewModelId(uint32_t value) + { + if (m_ViewModelId == value) + { + return; + } + m_ViewModelId = value; + viewModelIdChanged(); + } + + Core* clone() const override; + void copy(const DataConverterNumberToListBase& object) + { + m_ViewModelId = object.m_ViewModelId; + DataConverter::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case viewModelIdPropertyKey: + m_ViewModelId = CoreUintType::deserialize(reader); + return true; + } + return DataConverter::deserialize(propertyKey, reader); + } + +protected: + virtual void viewModelIdChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/data_bind/converters/data_converter_operation_base.hpp b/third_party/rive/include/rive/generated/data_bind/converters/data_converter_operation_base.hpp new file mode 100644 index 0000000..42afc49 --- /dev/null +++ b/third_party/rive/include/rive/generated/data_bind/converters/data_converter_operation_base.hpp @@ -0,0 +1,71 @@ +#ifndef _RIVE_DATA_CONVERTER_OPERATION_BASE_HPP_ +#define _RIVE_DATA_CONVERTER_OPERATION_BASE_HPP_ +#include "rive/core/field_types/core_uint_type.hpp" +#include "rive/data_bind/converters/data_converter.hpp" +namespace rive +{ +class DataConverterOperationBase : public DataConverter +{ +protected: + typedef DataConverter Super; + +public: + static const uint16_t typeKey = 516; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case DataConverterOperationBase::typeKey: + case DataConverterBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t operationTypePropertyKey = 682; + +protected: + uint32_t m_OperationType = 0; + +public: + inline uint32_t operationType() const { return m_OperationType; } + void operationType(uint32_t value) + { + if (m_OperationType == value) + { + return; + } + m_OperationType = value; + operationTypeChanged(); + } + + Core* clone() const override; + void copy(const DataConverterOperationBase& object) + { + m_OperationType = object.m_OperationType; + DataConverter::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case operationTypePropertyKey: + m_OperationType = CoreUintType::deserialize(reader); + return true; + } + return DataConverter::deserialize(propertyKey, reader); + } + +protected: + virtual void operationTypeChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/data_bind/converters/data_converter_operation_value_base.hpp b/third_party/rive/include/rive/generated/data_bind/converters/data_converter_operation_value_base.hpp new file mode 100644 index 0000000..edd73bb --- /dev/null +++ b/third_party/rive/include/rive/generated/data_bind/converters/data_converter_operation_value_base.hpp @@ -0,0 +1,72 @@ +#ifndef _RIVE_DATA_CONVERTER_OPERATION_VALUE_BASE_HPP_ +#define _RIVE_DATA_CONVERTER_OPERATION_VALUE_BASE_HPP_ +#include "rive/core/field_types/core_double_type.hpp" +#include "rive/data_bind/converters/data_converter_operation.hpp" +namespace rive +{ +class DataConverterOperationValueBase : public DataConverterOperation +{ +protected: + typedef DataConverterOperation Super; + +public: + static const uint16_t typeKey = 500; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case DataConverterOperationValueBase::typeKey: + case DataConverterOperationBase::typeKey: + case DataConverterBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t operationValuePropertyKey = 681; + +protected: + float m_OperationValue = 1.0f; + +public: + inline float operationValue() const { return m_OperationValue; } + void operationValue(float value) + { + if (m_OperationValue == value) + { + return; + } + m_OperationValue = value; + operationValueChanged(); + } + + Core* clone() const override; + void copy(const DataConverterOperationValueBase& object) + { + m_OperationValue = object.m_OperationValue; + DataConverterOperation::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case operationValuePropertyKey: + m_OperationValue = CoreDoubleType::deserialize(reader); + return true; + } + return DataConverterOperation::deserialize(propertyKey, reader); + } + +protected: + virtual void operationValueChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/data_bind/converters/data_converter_operation_viewmodel_base.hpp b/third_party/rive/include/rive/generated/data_bind/converters/data_converter_operation_viewmodel_base.hpp new file mode 100644 index 0000000..baec0e5 --- /dev/null +++ b/third_party/rive/include/rive/generated/data_bind/converters/data_converter_operation_viewmodel_base.hpp @@ -0,0 +1,63 @@ +#ifndef _RIVE_DATA_CONVERTER_OPERATION_VIEW_MODEL_BASE_HPP_ +#define _RIVE_DATA_CONVERTER_OPERATION_VIEW_MODEL_BASE_HPP_ +#include "rive/core/field_types/core_bytes_type.hpp" +#include "rive/data_bind/converters/data_converter_operation.hpp" +#include "rive/span.hpp" +namespace rive +{ +class DataConverterOperationViewModelBase : public DataConverterOperation +{ +protected: + typedef DataConverterOperation Super; + +public: + static const uint16_t typeKey = 517; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case DataConverterOperationViewModelBase::typeKey: + case DataConverterOperationBase::typeKey: + case DataConverterBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t sourcePathIdsPropertyKey = 711; + +public: + virtual void decodeSourcePathIds(Span value) = 0; + virtual void copySourcePathIds( + const DataConverterOperationViewModelBase& object) = 0; + + Core* clone() const override; + void copy(const DataConverterOperationViewModelBase& object) + { + copySourcePathIds(object); + DataConverterOperation::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case sourcePathIdsPropertyKey: + decodeSourcePathIds(CoreBytesType::deserialize(reader)); + return true; + } + return DataConverterOperation::deserialize(propertyKey, reader); + } + +protected: + virtual void sourcePathIdsChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/data_bind/converters/data_converter_range_mapper_base.hpp b/third_party/rive/include/rive/generated/data_bind/converters/data_converter_range_mapper_base.hpp new file mode 100644 index 0000000..f58d8d2 --- /dev/null +++ b/third_party/rive/include/rive/generated/data_bind/converters/data_converter_range_mapper_base.hpp @@ -0,0 +1,180 @@ +#ifndef _RIVE_DATA_CONVERTER_RANGE_MAPPER_BASE_HPP_ +#define _RIVE_DATA_CONVERTER_RANGE_MAPPER_BASE_HPP_ +#include "rive/core/field_types/core_double_type.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +#include "rive/data_bind/converters/data_converter.hpp" +namespace rive +{ +class DataConverterRangeMapperBase : public DataConverter +{ +protected: + typedef DataConverter Super; + +public: + static const uint16_t typeKey = 519; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case DataConverterRangeMapperBase::typeKey: + case DataConverterBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t interpolationTypePropertyKey = 713; + static const uint16_t interpolatorIdPropertyKey = 714; + static const uint16_t flagsPropertyKey = 715; + static const uint16_t minInputPropertyKey = 716; + static const uint16_t maxInputPropertyKey = 717; + static const uint16_t minOutputPropertyKey = 718; + static const uint16_t maxOutputPropertyKey = 719; + +protected: + uint32_t m_InterpolationType = 1; + uint32_t m_InterpolatorId = -1; + uint32_t m_Flags = 0; + float m_MinInput = 1.0f; + float m_MaxInput = 1.0f; + float m_MinOutput = 1.0f; + float m_MaxOutput = 1.0f; + +public: + inline uint32_t interpolationType() const { return m_InterpolationType; } + void interpolationType(uint32_t value) + { + if (m_InterpolationType == value) + { + return; + } + m_InterpolationType = value; + interpolationTypeChanged(); + } + + inline uint32_t interpolatorId() const { return m_InterpolatorId; } + void interpolatorId(uint32_t value) + { + if (m_InterpolatorId == value) + { + return; + } + m_InterpolatorId = value; + interpolatorIdChanged(); + } + + inline uint32_t flags() const { return m_Flags; } + void flags(uint32_t value) + { + if (m_Flags == value) + { + return; + } + m_Flags = value; + flagsChanged(); + } + + inline float minInput() const { return m_MinInput; } + void minInput(float value) + { + if (m_MinInput == value) + { + return; + } + m_MinInput = value; + minInputChanged(); + } + + inline float maxInput() const { return m_MaxInput; } + void maxInput(float value) + { + if (m_MaxInput == value) + { + return; + } + m_MaxInput = value; + maxInputChanged(); + } + + inline float minOutput() const { return m_MinOutput; } + void minOutput(float value) + { + if (m_MinOutput == value) + { + return; + } + m_MinOutput = value; + minOutputChanged(); + } + + inline float maxOutput() const { return m_MaxOutput; } + void maxOutput(float value) + { + if (m_MaxOutput == value) + { + return; + } + m_MaxOutput = value; + maxOutputChanged(); + } + + Core* clone() const override; + void copy(const DataConverterRangeMapperBase& object) + { + m_InterpolationType = object.m_InterpolationType; + m_InterpolatorId = object.m_InterpolatorId; + m_Flags = object.m_Flags; + m_MinInput = object.m_MinInput; + m_MaxInput = object.m_MaxInput; + m_MinOutput = object.m_MinOutput; + m_MaxOutput = object.m_MaxOutput; + DataConverter::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case interpolationTypePropertyKey: + m_InterpolationType = CoreUintType::deserialize(reader); + return true; + case interpolatorIdPropertyKey: + m_InterpolatorId = CoreUintType::deserialize(reader); + return true; + case flagsPropertyKey: + m_Flags = CoreUintType::deserialize(reader); + return true; + case minInputPropertyKey: + m_MinInput = CoreDoubleType::deserialize(reader); + return true; + case maxInputPropertyKey: + m_MaxInput = CoreDoubleType::deserialize(reader); + return true; + case minOutputPropertyKey: + m_MinOutput = CoreDoubleType::deserialize(reader); + return true; + case maxOutputPropertyKey: + m_MaxOutput = CoreDoubleType::deserialize(reader); + return true; + } + return DataConverter::deserialize(propertyKey, reader); + } + +protected: + virtual void interpolationTypeChanged() {} + virtual void interpolatorIdChanged() {} + virtual void flagsChanged() {} + virtual void minInputChanged() {} + virtual void maxInputChanged() {} + virtual void minOutputChanged() {} + virtual void maxOutputChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/data_bind/converters/data_converter_rounder_base.hpp b/third_party/rive/include/rive/generated/data_bind/converters/data_converter_rounder_base.hpp new file mode 100644 index 0000000..df45f38 --- /dev/null +++ b/third_party/rive/include/rive/generated/data_bind/converters/data_converter_rounder_base.hpp @@ -0,0 +1,71 @@ +#ifndef _RIVE_DATA_CONVERTER_ROUNDER_BASE_HPP_ +#define _RIVE_DATA_CONVERTER_ROUNDER_BASE_HPP_ +#include "rive/core/field_types/core_uint_type.hpp" +#include "rive/data_bind/converters/data_converter.hpp" +namespace rive +{ +class DataConverterRounderBase : public DataConverter +{ +protected: + typedef DataConverter Super; + +public: + static const uint16_t typeKey = 489; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case DataConverterRounderBase::typeKey: + case DataConverterBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t decimalsPropertyKey = 669; + +protected: + uint32_t m_Decimals = 0; + +public: + inline uint32_t decimals() const { return m_Decimals; } + void decimals(uint32_t value) + { + if (m_Decimals == value) + { + return; + } + m_Decimals = value; + decimalsChanged(); + } + + Core* clone() const override; + void copy(const DataConverterRounderBase& object) + { + m_Decimals = object.m_Decimals; + DataConverter::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case decimalsPropertyKey: + m_Decimals = CoreUintType::deserialize(reader); + return true; + } + return DataConverter::deserialize(propertyKey, reader); + } + +protected: + virtual void decimalsChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/data_bind/converters/data_converter_string_pad_base.hpp b/third_party/rive/include/rive/generated/data_bind/converters/data_converter_string_pad_base.hpp new file mode 100644 index 0000000..175987a --- /dev/null +++ b/third_party/rive/include/rive/generated/data_bind/converters/data_converter_string_pad_base.hpp @@ -0,0 +1,109 @@ +#ifndef _RIVE_DATA_CONVERTER_STRING_PAD_BASE_HPP_ +#define _RIVE_DATA_CONVERTER_STRING_PAD_BASE_HPP_ +#include +#include "rive/core/field_types/core_string_type.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +#include "rive/data_bind/converters/data_converter.hpp" +namespace rive +{ +class DataConverterStringPadBase : public DataConverter +{ +protected: + typedef DataConverter Super; + +public: + static const uint16_t typeKey = 530; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case DataConverterStringPadBase::typeKey: + case DataConverterBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t lengthPropertyKey = 743; + static const uint16_t textPropertyKey = 744; + static const uint16_t padTypePropertyKey = 745; + +protected: + uint32_t m_Length = 1; + std::string m_Text = ""; + uint32_t m_PadType = 0; + +public: + inline uint32_t length() const { return m_Length; } + void length(uint32_t value) + { + if (m_Length == value) + { + return; + } + m_Length = value; + lengthChanged(); + } + + inline const std::string& text() const { return m_Text; } + void text(std::string value) + { + if (m_Text == value) + { + return; + } + m_Text = value; + textChanged(); + } + + inline uint32_t padType() const { return m_PadType; } + void padType(uint32_t value) + { + if (m_PadType == value) + { + return; + } + m_PadType = value; + padTypeChanged(); + } + + Core* clone() const override; + void copy(const DataConverterStringPadBase& object) + { + m_Length = object.m_Length; + m_Text = object.m_Text; + m_PadType = object.m_PadType; + DataConverter::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case lengthPropertyKey: + m_Length = CoreUintType::deserialize(reader); + return true; + case textPropertyKey: + m_Text = CoreStringType::deserialize(reader); + return true; + case padTypePropertyKey: + m_PadType = CoreUintType::deserialize(reader); + return true; + } + return DataConverter::deserialize(propertyKey, reader); + } + +protected: + virtual void lengthChanged() {} + virtual void textChanged() {} + virtual void padTypeChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/data_bind/converters/data_converter_string_remove_zeros_base.hpp b/third_party/rive/include/rive/generated/data_bind/converters/data_converter_string_remove_zeros_base.hpp new file mode 100644 index 0000000..076002d --- /dev/null +++ b/third_party/rive/include/rive/generated/data_bind/converters/data_converter_string_remove_zeros_base.hpp @@ -0,0 +1,36 @@ +#ifndef _RIVE_DATA_CONVERTER_STRING_REMOVE_ZEROS_BASE_HPP_ +#define _RIVE_DATA_CONVERTER_STRING_REMOVE_ZEROS_BASE_HPP_ +#include "rive/data_bind/converters/data_converter.hpp" +namespace rive +{ +class DataConverterStringRemoveZerosBase : public DataConverter +{ +protected: + typedef DataConverter Super; + +public: + static const uint16_t typeKey = 531; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case DataConverterStringRemoveZerosBase::typeKey: + case DataConverterBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/data_bind/converters/data_converter_string_trim_base.hpp b/third_party/rive/include/rive/generated/data_bind/converters/data_converter_string_trim_base.hpp new file mode 100644 index 0000000..4441cda --- /dev/null +++ b/third_party/rive/include/rive/generated/data_bind/converters/data_converter_string_trim_base.hpp @@ -0,0 +1,71 @@ +#ifndef _RIVE_DATA_CONVERTER_STRING_TRIM_BASE_HPP_ +#define _RIVE_DATA_CONVERTER_STRING_TRIM_BASE_HPP_ +#include "rive/core/field_types/core_uint_type.hpp" +#include "rive/data_bind/converters/data_converter.hpp" +namespace rive +{ +class DataConverterStringTrimBase : public DataConverter +{ +protected: + typedef DataConverter Super; + +public: + static const uint16_t typeKey = 532; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case DataConverterStringTrimBase::typeKey: + case DataConverterBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t trimTypePropertyKey = 746; + +protected: + uint32_t m_TrimType = 1; + +public: + inline uint32_t trimType() const { return m_TrimType; } + void trimType(uint32_t value) + { + if (m_TrimType == value) + { + return; + } + m_TrimType = value; + trimTypeChanged(); + } + + Core* clone() const override; + void copy(const DataConverterStringTrimBase& object) + { + m_TrimType = object.m_TrimType; + DataConverter::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case trimTypePropertyKey: + m_TrimType = CoreUintType::deserialize(reader); + return true; + } + return DataConverter::deserialize(propertyKey, reader); + } + +protected: + virtual void trimTypeChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/data_bind/converters/data_converter_system_degs_to_rads_base.hpp b/third_party/rive/include/rive/generated/data_bind/converters/data_converter_system_degs_to_rads_base.hpp new file mode 100644 index 0000000..ca7f085 --- /dev/null +++ b/third_party/rive/include/rive/generated/data_bind/converters/data_converter_system_degs_to_rads_base.hpp @@ -0,0 +1,38 @@ +#ifndef _RIVE_DATA_CONVERTER_SYSTEM_DEGS_TO_RADS_BASE_HPP_ +#define _RIVE_DATA_CONVERTER_SYSTEM_DEGS_TO_RADS_BASE_HPP_ +#include "rive/data_bind/converters/data_converter_operation_value.hpp" +namespace rive +{ +class DataConverterSystemDegsToRadsBase : public DataConverterOperationValue +{ +protected: + typedef DataConverterOperationValue Super; + +public: + static const uint16_t typeKey = 514; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case DataConverterSystemDegsToRadsBase::typeKey: + case DataConverterOperationValueBase::typeKey: + case DataConverterOperationBase::typeKey: + case DataConverterBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/data_bind/converters/data_converter_system_normalizer_base.hpp b/third_party/rive/include/rive/generated/data_bind/converters/data_converter_system_normalizer_base.hpp new file mode 100644 index 0000000..0f34ad9 --- /dev/null +++ b/third_party/rive/include/rive/generated/data_bind/converters/data_converter_system_normalizer_base.hpp @@ -0,0 +1,38 @@ +#ifndef _RIVE_DATA_CONVERTER_SYSTEM_NORMALIZER_BASE_HPP_ +#define _RIVE_DATA_CONVERTER_SYSTEM_NORMALIZER_BASE_HPP_ +#include "rive/data_bind/converters/data_converter_operation_value.hpp" +namespace rive +{ +class DataConverterSystemNormalizerBase : public DataConverterOperationValue +{ +protected: + typedef DataConverterOperationValue Super; + +public: + static const uint16_t typeKey = 515; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case DataConverterSystemNormalizerBase::typeKey: + case DataConverterOperationValueBase::typeKey: + case DataConverterOperationBase::typeKey: + case DataConverterBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/data_bind/converters/data_converter_to_string_base.hpp b/third_party/rive/include/rive/generated/data_bind/converters/data_converter_to_string_base.hpp new file mode 100644 index 0000000..b1202fe --- /dev/null +++ b/third_party/rive/include/rive/generated/data_bind/converters/data_converter_to_string_base.hpp @@ -0,0 +1,109 @@ +#ifndef _RIVE_DATA_CONVERTER_TO_STRING_BASE_HPP_ +#define _RIVE_DATA_CONVERTER_TO_STRING_BASE_HPP_ +#include +#include "rive/core/field_types/core_string_type.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +#include "rive/data_bind/converters/data_converter.hpp" +namespace rive +{ +class DataConverterToStringBase : public DataConverter +{ +protected: + typedef DataConverter Super; + +public: + static const uint16_t typeKey = 490; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case DataConverterToStringBase::typeKey: + case DataConverterBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t flagsPropertyKey = 764; + static const uint16_t decimalsPropertyKey = 765; + static const uint16_t colorFormatPropertyKey = 766; + +protected: + uint32_t m_Flags = 0; + uint32_t m_Decimals = 0; + std::string m_ColorFormat = ""; + +public: + inline uint32_t flags() const { return m_Flags; } + void flags(uint32_t value) + { + if (m_Flags == value) + { + return; + } + m_Flags = value; + flagsChanged(); + } + + inline uint32_t decimals() const { return m_Decimals; } + void decimals(uint32_t value) + { + if (m_Decimals == value) + { + return; + } + m_Decimals = value; + decimalsChanged(); + } + + inline const std::string& colorFormat() const { return m_ColorFormat; } + void colorFormat(std::string value) + { + if (m_ColorFormat == value) + { + return; + } + m_ColorFormat = value; + colorFormatChanged(); + } + + Core* clone() const override; + void copy(const DataConverterToStringBase& object) + { + m_Flags = object.m_Flags; + m_Decimals = object.m_Decimals; + m_ColorFormat = object.m_ColorFormat; + DataConverter::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case flagsPropertyKey: + m_Flags = CoreUintType::deserialize(reader); + return true; + case decimalsPropertyKey: + m_Decimals = CoreUintType::deserialize(reader); + return true; + case colorFormatPropertyKey: + m_ColorFormat = CoreStringType::deserialize(reader); + return true; + } + return DataConverter::deserialize(propertyKey, reader); + } + +protected: + virtual void flagsChanged() {} + virtual void decimalsChanged() {} + virtual void colorFormatChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/data_bind/converters/data_converter_trigger_base.hpp b/third_party/rive/include/rive/generated/data_bind/converters/data_converter_trigger_base.hpp new file mode 100644 index 0000000..35e6587 --- /dev/null +++ b/third_party/rive/include/rive/generated/data_bind/converters/data_converter_trigger_base.hpp @@ -0,0 +1,36 @@ +#ifndef _RIVE_DATA_CONVERTER_TRIGGER_BASE_HPP_ +#define _RIVE_DATA_CONVERTER_TRIGGER_BASE_HPP_ +#include "rive/data_bind/converters/data_converter.hpp" +namespace rive +{ +class DataConverterTriggerBase : public DataConverter +{ +protected: + typedef DataConverter Super; + +public: + static const uint16_t typeKey = 504; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case DataConverterTriggerBase::typeKey: + case DataConverterBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/data_bind/converters/formula/formula_token_argument_separator_base.hpp b/third_party/rive/include/rive/generated/data_bind/converters/formula/formula_token_argument_separator_base.hpp new file mode 100644 index 0000000..49e8c7d --- /dev/null +++ b/third_party/rive/include/rive/generated/data_bind/converters/formula/formula_token_argument_separator_base.hpp @@ -0,0 +1,36 @@ +#ifndef _RIVE_FORMULA_TOKEN_ARGUMENT_SEPARATOR_BASE_HPP_ +#define _RIVE_FORMULA_TOKEN_ARGUMENT_SEPARATOR_BASE_HPP_ +#include "rive/data_bind/converters/formula/formula_token.hpp" +namespace rive +{ +class FormulaTokenArgumentSeparatorBase : public FormulaToken +{ +protected: + typedef FormulaToken Super; + +public: + static const uint16_t typeKey = 538; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case FormulaTokenArgumentSeparatorBase::typeKey: + case FormulaTokenBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/data_bind/converters/formula/formula_token_base.hpp b/third_party/rive/include/rive/generated/data_bind/converters/formula/formula_token_base.hpp new file mode 100644 index 0000000..c5813ea --- /dev/null +++ b/third_party/rive/include/rive/generated/data_bind/converters/formula/formula_token_base.hpp @@ -0,0 +1,41 @@ +#ifndef _RIVE_FORMULA_TOKEN_BASE_HPP_ +#define _RIVE_FORMULA_TOKEN_BASE_HPP_ +#include "rive/core.hpp" +namespace rive +{ +class FormulaTokenBase : public Core +{ +protected: + typedef Core Super; + +public: + static const uint16_t typeKey = 537; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case FormulaTokenBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + void copy(const FormulaTokenBase& object) {} + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + return false; + } + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/data_bind/converters/formula/formula_token_function_base.hpp b/third_party/rive/include/rive/generated/data_bind/converters/formula/formula_token_function_base.hpp new file mode 100644 index 0000000..9436c41 --- /dev/null +++ b/third_party/rive/include/rive/generated/data_bind/converters/formula/formula_token_function_base.hpp @@ -0,0 +1,72 @@ +#ifndef _RIVE_FORMULA_TOKEN_FUNCTION_BASE_HPP_ +#define _RIVE_FORMULA_TOKEN_FUNCTION_BASE_HPP_ +#include "rive/core/field_types/core_uint_type.hpp" +#include "rive/data_bind/converters/formula/formula_token_parenthesis.hpp" +namespace rive +{ +class FormulaTokenFunctionBase : public FormulaTokenParenthesis +{ +protected: + typedef FormulaTokenParenthesis Super; + +public: + static const uint16_t typeKey = 542; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case FormulaTokenFunctionBase::typeKey: + case FormulaTokenParenthesisBase::typeKey: + case FormulaTokenBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t functionTypePropertyKey = 776; + +protected: + uint32_t m_FunctionType = 0; + +public: + inline uint32_t functionType() const { return m_FunctionType; } + void functionType(uint32_t value) + { + if (m_FunctionType == value) + { + return; + } + m_FunctionType = value; + functionTypeChanged(); + } + + Core* clone() const override; + void copy(const FormulaTokenFunctionBase& object) + { + m_FunctionType = object.m_FunctionType; + FormulaTokenParenthesis::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case functionTypePropertyKey: + m_FunctionType = CoreUintType::deserialize(reader); + return true; + } + return FormulaTokenParenthesis::deserialize(propertyKey, reader); + } + +protected: + virtual void functionTypeChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/data_bind/converters/formula/formula_token_input_base.hpp b/third_party/rive/include/rive/generated/data_bind/converters/formula/formula_token_input_base.hpp new file mode 100644 index 0000000..fed3781 --- /dev/null +++ b/third_party/rive/include/rive/generated/data_bind/converters/formula/formula_token_input_base.hpp @@ -0,0 +1,36 @@ +#ifndef _RIVE_FORMULA_TOKEN_INPUT_BASE_HPP_ +#define _RIVE_FORMULA_TOKEN_INPUT_BASE_HPP_ +#include "rive/data_bind/converters/formula/formula_token.hpp" +namespace rive +{ +class FormulaTokenInputBase : public FormulaToken +{ +protected: + typedef FormulaToken Super; + +public: + static const uint16_t typeKey = 545; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case FormulaTokenInputBase::typeKey: + case FormulaTokenBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/data_bind/converters/formula/formula_token_operation_base.hpp b/third_party/rive/include/rive/generated/data_bind/converters/formula/formula_token_operation_base.hpp new file mode 100644 index 0000000..b0248c4 --- /dev/null +++ b/third_party/rive/include/rive/generated/data_bind/converters/formula/formula_token_operation_base.hpp @@ -0,0 +1,71 @@ +#ifndef _RIVE_FORMULA_TOKEN_OPERATION_BASE_HPP_ +#define _RIVE_FORMULA_TOKEN_OPERATION_BASE_HPP_ +#include "rive/core/field_types/core_uint_type.hpp" +#include "rive/data_bind/converters/formula/formula_token.hpp" +namespace rive +{ +class FormulaTokenOperationBase : public FormulaToken +{ +protected: + typedef FormulaToken Super; + +public: + static const uint16_t typeKey = 541; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case FormulaTokenOperationBase::typeKey: + case FormulaTokenBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t operationTypePropertyKey = 775; + +protected: + uint32_t m_OperationType = 0; + +public: + inline uint32_t operationType() const { return m_OperationType; } + void operationType(uint32_t value) + { + if (m_OperationType == value) + { + return; + } + m_OperationType = value; + operationTypeChanged(); + } + + Core* clone() const override; + void copy(const FormulaTokenOperationBase& object) + { + m_OperationType = object.m_OperationType; + FormulaToken::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case operationTypePropertyKey: + m_OperationType = CoreUintType::deserialize(reader); + return true; + } + return FormulaToken::deserialize(propertyKey, reader); + } + +protected: + virtual void operationTypeChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/data_bind/converters/formula/formula_token_parenthesis_base.hpp b/third_party/rive/include/rive/generated/data_bind/converters/formula/formula_token_parenthesis_base.hpp new file mode 100644 index 0000000..4dfec18 --- /dev/null +++ b/third_party/rive/include/rive/generated/data_bind/converters/formula/formula_token_parenthesis_base.hpp @@ -0,0 +1,36 @@ +#ifndef _RIVE_FORMULA_TOKEN_PARENTHESIS_BASE_HPP_ +#define _RIVE_FORMULA_TOKEN_PARENTHESIS_BASE_HPP_ +#include "rive/data_bind/converters/formula/formula_token.hpp" +namespace rive +{ +class FormulaTokenParenthesisBase : public FormulaToken +{ +protected: + typedef FormulaToken Super; + +public: + static const uint16_t typeKey = 539; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case FormulaTokenParenthesisBase::typeKey: + case FormulaTokenBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/data_bind/converters/formula/formula_token_parenthesis_close_base.hpp b/third_party/rive/include/rive/generated/data_bind/converters/formula/formula_token_parenthesis_close_base.hpp new file mode 100644 index 0000000..bfd7c79 --- /dev/null +++ b/third_party/rive/include/rive/generated/data_bind/converters/formula/formula_token_parenthesis_close_base.hpp @@ -0,0 +1,37 @@ +#ifndef _RIVE_FORMULA_TOKEN_PARENTHESIS_CLOSE_BASE_HPP_ +#define _RIVE_FORMULA_TOKEN_PARENTHESIS_CLOSE_BASE_HPP_ +#include "rive/data_bind/converters/formula/formula_token_parenthesis.hpp" +namespace rive +{ +class FormulaTokenParenthesisCloseBase : public FormulaTokenParenthesis +{ +protected: + typedef FormulaTokenParenthesis Super; + +public: + static const uint16_t typeKey = 540; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case FormulaTokenParenthesisCloseBase::typeKey: + case FormulaTokenParenthesisBase::typeKey: + case FormulaTokenBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/data_bind/converters/formula/formula_token_parenthesis_open_base.hpp b/third_party/rive/include/rive/generated/data_bind/converters/formula/formula_token_parenthesis_open_base.hpp new file mode 100644 index 0000000..ce1afdc --- /dev/null +++ b/third_party/rive/include/rive/generated/data_bind/converters/formula/formula_token_parenthesis_open_base.hpp @@ -0,0 +1,37 @@ +#ifndef _RIVE_FORMULA_TOKEN_PARENTHESIS_OPEN_BASE_HPP_ +#define _RIVE_FORMULA_TOKEN_PARENTHESIS_OPEN_BASE_HPP_ +#include "rive/data_bind/converters/formula/formula_token_parenthesis.hpp" +namespace rive +{ +class FormulaTokenParenthesisOpenBase : public FormulaTokenParenthesis +{ +protected: + typedef FormulaTokenParenthesis Super; + +public: + static const uint16_t typeKey = 544; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case FormulaTokenParenthesisOpenBase::typeKey: + case FormulaTokenParenthesisBase::typeKey: + case FormulaTokenBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/data_bind/converters/formula/formula_token_value_base.hpp b/third_party/rive/include/rive/generated/data_bind/converters/formula/formula_token_value_base.hpp new file mode 100644 index 0000000..2ccb163 --- /dev/null +++ b/third_party/rive/include/rive/generated/data_bind/converters/formula/formula_token_value_base.hpp @@ -0,0 +1,71 @@ +#ifndef _RIVE_FORMULA_TOKEN_VALUE_BASE_HPP_ +#define _RIVE_FORMULA_TOKEN_VALUE_BASE_HPP_ +#include "rive/core/field_types/core_double_type.hpp" +#include "rive/data_bind/converters/formula/formula_token.hpp" +namespace rive +{ +class FormulaTokenValueBase : public FormulaToken +{ +protected: + typedef FormulaToken Super; + +public: + static const uint16_t typeKey = 543; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case FormulaTokenValueBase::typeKey: + case FormulaTokenBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t operationValuePropertyKey = 777; + +protected: + float m_OperationValue = 1.0f; + +public: + inline float operationValue() const { return m_OperationValue; } + void operationValue(float value) + { + if (m_OperationValue == value) + { + return; + } + m_OperationValue = value; + operationValueChanged(); + } + + Core* clone() const override; + void copy(const FormulaTokenValueBase& object) + { + m_OperationValue = object.m_OperationValue; + FormulaToken::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case operationValuePropertyKey: + m_OperationValue = CoreDoubleType::deserialize(reader); + return true; + } + return FormulaToken::deserialize(propertyKey, reader); + } + +protected: + virtual void operationValueChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/data_bind/data_bind_base.hpp b/third_party/rive/include/rive/generated/data_bind/data_bind_base.hpp new file mode 100644 index 0000000..482a9ef --- /dev/null +++ b/third_party/rive/include/rive/generated/data_bind/data_bind_base.hpp @@ -0,0 +1,105 @@ +#ifndef _RIVE_DATA_BIND_BASE_HPP_ +#define _RIVE_DATA_BIND_BASE_HPP_ +#include "rive/core.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +namespace rive +{ +class DataBindBase : public Core +{ +protected: + typedef Core Super; + +public: + static const uint16_t typeKey = 446; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case DataBindBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t propertyKeyPropertyKey = 586; + static const uint16_t flagsPropertyKey = 587; + static const uint16_t converterIdPropertyKey = 660; + +protected: + uint32_t m_PropertyKey = Core::invalidPropertyKey; + uint32_t m_Flags = 0; + uint32_t m_ConverterId = -1; + +public: + inline uint32_t propertyKey() const { return m_PropertyKey; } + void propertyKey(uint32_t value) + { + if (m_PropertyKey == value) + { + return; + } + m_PropertyKey = value; + propertyKeyChanged(); + } + + inline uint32_t flags() const { return m_Flags; } + void flags(uint32_t value) + { + if (m_Flags == value) + { + return; + } + m_Flags = value; + flagsChanged(); + } + + inline uint32_t converterId() const { return m_ConverterId; } + void converterId(uint32_t value) + { + if (m_ConverterId == value) + { + return; + } + m_ConverterId = value; + converterIdChanged(); + } + + Core* clone() const override; + void copy(const DataBindBase& object) + { + m_PropertyKey = object.m_PropertyKey; + m_Flags = object.m_Flags; + m_ConverterId = object.m_ConverterId; + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case propertyKeyPropertyKey: + m_PropertyKey = CoreUintType::deserialize(reader); + return true; + case flagsPropertyKey: + m_Flags = CoreUintType::deserialize(reader); + return true; + case converterIdPropertyKey: + m_ConverterId = CoreUintType::deserialize(reader); + return true; + } + return false; + } + +protected: + virtual void propertyKeyChanged() {} + virtual void flagsChanged() {} + virtual void converterIdChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/data_bind/data_bind_context_base.hpp b/third_party/rive/include/rive/generated/data_bind/data_bind_context_base.hpp new file mode 100644 index 0000000..d63d283 --- /dev/null +++ b/third_party/rive/include/rive/generated/data_bind/data_bind_context_base.hpp @@ -0,0 +1,61 @@ +#ifndef _RIVE_DATA_BIND_CONTEXT_BASE_HPP_ +#define _RIVE_DATA_BIND_CONTEXT_BASE_HPP_ +#include "rive/core/field_types/core_bytes_type.hpp" +#include "rive/data_bind/data_bind.hpp" +#include "rive/span.hpp" +namespace rive +{ +class DataBindContextBase : public DataBind +{ +protected: + typedef DataBind Super; + +public: + static const uint16_t typeKey = 447; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case DataBindContextBase::typeKey: + case DataBindBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t sourcePathIdsPropertyKey = 588; + +public: + virtual void decodeSourcePathIds(Span value) = 0; + virtual void copySourcePathIds(const DataBindContextBase& object) = 0; + + Core* clone() const override; + void copy(const DataBindContextBase& object) + { + copySourcePathIds(object); + DataBind::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case sourcePathIdsPropertyKey: + decodeSourcePathIds(CoreBytesType::deserialize(reader)); + return true; + } + return DataBind::deserialize(propertyKey, reader); + } + +protected: + virtual void sourcePathIdsChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/draw_rules_base.hpp b/third_party/rive/include/rive/generated/draw_rules_base.hpp new file mode 100644 index 0000000..c3396a6 --- /dev/null +++ b/third_party/rive/include/rive/generated/draw_rules_base.hpp @@ -0,0 +1,72 @@ +#ifndef _RIVE_DRAW_RULES_BASE_HPP_ +#define _RIVE_DRAW_RULES_BASE_HPP_ +#include "rive/container_component.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +namespace rive +{ +class DrawRulesBase : public ContainerComponent +{ +protected: + typedef ContainerComponent Super; + +public: + static const uint16_t typeKey = 49; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case DrawRulesBase::typeKey: + case ContainerComponentBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t drawTargetIdPropertyKey = 121; + +protected: + uint32_t m_DrawTargetId = -1; + +public: + inline uint32_t drawTargetId() const { return m_DrawTargetId; } + void drawTargetId(uint32_t value) + { + if (m_DrawTargetId == value) + { + return; + } + m_DrawTargetId = value; + drawTargetIdChanged(); + } + + Core* clone() const override; + void copy(const DrawRulesBase& object) + { + m_DrawTargetId = object.m_DrawTargetId; + ContainerComponent::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case drawTargetIdPropertyKey: + m_DrawTargetId = CoreUintType::deserialize(reader); + return true; + } + return ContainerComponent::deserialize(propertyKey, reader); + } + +protected: + virtual void drawTargetIdChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/draw_target_base.hpp b/third_party/rive/include/rive/generated/draw_target_base.hpp new file mode 100644 index 0000000..2b2363a --- /dev/null +++ b/third_party/rive/include/rive/generated/draw_target_base.hpp @@ -0,0 +1,89 @@ +#ifndef _RIVE_DRAW_TARGET_BASE_HPP_ +#define _RIVE_DRAW_TARGET_BASE_HPP_ +#include "rive/component.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +namespace rive +{ +class DrawTargetBase : public Component +{ +protected: + typedef Component Super; + +public: + static const uint16_t typeKey = 48; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case DrawTargetBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t drawableIdPropertyKey = 119; + static const uint16_t placementValuePropertyKey = 120; + +protected: + uint32_t m_DrawableId = -1; + uint32_t m_PlacementValue = 0; + +public: + inline uint32_t drawableId() const { return m_DrawableId; } + void drawableId(uint32_t value) + { + if (m_DrawableId == value) + { + return; + } + m_DrawableId = value; + drawableIdChanged(); + } + + inline uint32_t placementValue() const { return m_PlacementValue; } + void placementValue(uint32_t value) + { + if (m_PlacementValue == value) + { + return; + } + m_PlacementValue = value; + placementValueChanged(); + } + + Core* clone() const override; + void copy(const DrawTargetBase& object) + { + m_DrawableId = object.m_DrawableId; + m_PlacementValue = object.m_PlacementValue; + Component::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case drawableIdPropertyKey: + m_DrawableId = CoreUintType::deserialize(reader); + return true; + case placementValuePropertyKey: + m_PlacementValue = CoreUintType::deserialize(reader); + return true; + } + return Component::deserialize(propertyKey, reader); + } + +protected: + virtual void drawableIdChanged() {} + virtual void placementValueChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/drawable_base.hpp b/third_party/rive/include/rive/generated/drawable_base.hpp new file mode 100644 index 0000000..869ac81 --- /dev/null +++ b/third_party/rive/include/rive/generated/drawable_base.hpp @@ -0,0 +1,92 @@ +#ifndef _RIVE_DRAWABLE_BASE_HPP_ +#define _RIVE_DRAWABLE_BASE_HPP_ +#include "rive/core/field_types/core_uint_type.hpp" +#include "rive/node.hpp" +namespace rive +{ +class DrawableBase : public Node +{ +protected: + typedef Node Super; + +public: + static const uint16_t typeKey = 13; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case DrawableBase::typeKey: + case NodeBase::typeKey: + case TransformComponentBase::typeKey: + case WorldTransformComponentBase::typeKey: + case ContainerComponentBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t blendModeValuePropertyKey = 23; + static const uint16_t drawableFlagsPropertyKey = 129; + +protected: + uint32_t m_BlendModeValue = 3; + uint32_t m_DrawableFlags = 0; + +public: + inline uint32_t blendModeValue() const { return m_BlendModeValue; } + void blendModeValue(uint32_t value) + { + if (m_BlendModeValue == value) + { + return; + } + m_BlendModeValue = value; + blendModeValueChanged(); + } + + inline uint32_t drawableFlags() const { return m_DrawableFlags; } + void drawableFlags(uint32_t value) + { + if (m_DrawableFlags == value) + { + return; + } + m_DrawableFlags = value; + drawableFlagsChanged(); + } + + void copy(const DrawableBase& object) + { + m_BlendModeValue = object.m_BlendModeValue; + m_DrawableFlags = object.m_DrawableFlags; + Node::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case blendModeValuePropertyKey: + m_BlendModeValue = CoreUintType::deserialize(reader); + return true; + case drawableFlagsPropertyKey: + m_DrawableFlags = CoreUintType::deserialize(reader); + return true; + } + return Node::deserialize(propertyKey, reader); + } + +protected: + virtual void blendModeValueChanged() {} + virtual void drawableFlagsChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/event_base.hpp b/third_party/rive/include/rive/generated/event_base.hpp new file mode 100644 index 0000000..0b6c46a --- /dev/null +++ b/third_party/rive/include/rive/generated/event_base.hpp @@ -0,0 +1,44 @@ +#ifndef _RIVE_EVENT_BASE_HPP_ +#define _RIVE_EVENT_BASE_HPP_ +#include "rive/core/field_types/core_callback_type.hpp" +#include "rive/custom_property_group.hpp" +namespace rive +{ +class EventBase : public CustomPropertyGroup +{ +protected: + typedef CustomPropertyGroup Super; + +public: + static const uint16_t typeKey = 128; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case EventBase::typeKey: + case CustomPropertyGroupBase::typeKey: + case ContainerComponentBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t triggerPropertyKey = 395; + +public: + virtual void trigger(const CallbackData& value) = 0; + + Core* clone() const override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/foreground_layout_drawable_base.hpp b/third_party/rive/include/rive/generated/foreground_layout_drawable_base.hpp new file mode 100644 index 0000000..7d0aee4 --- /dev/null +++ b/third_party/rive/include/rive/generated/foreground_layout_drawable_base.hpp @@ -0,0 +1,41 @@ +#ifndef _RIVE_FOREGROUND_LAYOUT_DRAWABLE_BASE_HPP_ +#define _RIVE_FOREGROUND_LAYOUT_DRAWABLE_BASE_HPP_ +#include "rive/drawable.hpp" +namespace rive +{ +class ForegroundLayoutDrawableBase : public Drawable +{ +protected: + typedef Drawable Super; + +public: + static const uint16_t typeKey = 513; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case ForegroundLayoutDrawableBase::typeKey: + case DrawableBase::typeKey: + case NodeBase::typeKey: + case TransformComponentBase::typeKey: + case WorldTransformComponentBase::typeKey: + case ContainerComponentBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/joystick_base.hpp b/third_party/rive/include/rive/generated/joystick_base.hpp new file mode 100644 index 0000000..7aa9cde --- /dev/null +++ b/third_party/rive/include/rive/generated/joystick_base.hpp @@ -0,0 +1,270 @@ +#ifndef _RIVE_JOYSTICK_BASE_HPP_ +#define _RIVE_JOYSTICK_BASE_HPP_ +#include "rive/component.hpp" +#include "rive/core/field_types/core_double_type.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +namespace rive +{ +class JoystickBase : public Component +{ +protected: + typedef Component Super; + +public: + static const uint16_t typeKey = 148; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case JoystickBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t xPropertyKey = 299; + static const uint16_t yPropertyKey = 300; + static const uint16_t posXPropertyKey = 303; + static const uint16_t posYPropertyKey = 304; + static const uint16_t originXPropertyKey = 307; + static const uint16_t originYPropertyKey = 308; + static const uint16_t widthPropertyKey = 305; + static const uint16_t heightPropertyKey = 306; + static const uint16_t xIdPropertyKey = 301; + static const uint16_t yIdPropertyKey = 302; + static const uint16_t joystickFlagsPropertyKey = 312; + static const uint16_t handleSourceIdPropertyKey = 313; + +protected: + float m_X = 0.0f; + float m_Y = 0.0f; + float m_PosX = 0.0f; + float m_PosY = 0.0f; + float m_OriginX = 0.5f; + float m_OriginY = 0.5f; + float m_Width = 100.0f; + float m_Height = 100.0f; + uint32_t m_XId = -1; + uint32_t m_YId = -1; + uint32_t m_JoystickFlags = 0; + uint32_t m_HandleSourceId = -1; + +public: + inline float x() const { return m_X; } + void x(float value) + { + if (m_X == value) + { + return; + } + m_X = value; + xChanged(); + } + + inline float y() const { return m_Y; } + void y(float value) + { + if (m_Y == value) + { + return; + } + m_Y = value; + yChanged(); + } + + inline float posX() const { return m_PosX; } + void posX(float value) + { + if (m_PosX == value) + { + return; + } + m_PosX = value; + posXChanged(); + } + + inline float posY() const { return m_PosY; } + void posY(float value) + { + if (m_PosY == value) + { + return; + } + m_PosY = value; + posYChanged(); + } + + inline float originX() const { return m_OriginX; } + void originX(float value) + { + if (m_OriginX == value) + { + return; + } + m_OriginX = value; + originXChanged(); + } + + inline float originY() const { return m_OriginY; } + void originY(float value) + { + if (m_OriginY == value) + { + return; + } + m_OriginY = value; + originYChanged(); + } + + inline float width() const { return m_Width; } + void width(float value) + { + if (m_Width == value) + { + return; + } + m_Width = value; + widthChanged(); + } + + inline float height() const { return m_Height; } + void height(float value) + { + if (m_Height == value) + { + return; + } + m_Height = value; + heightChanged(); + } + + inline uint32_t xId() const { return m_XId; } + void xId(uint32_t value) + { + if (m_XId == value) + { + return; + } + m_XId = value; + xIdChanged(); + } + + inline uint32_t yId() const { return m_YId; } + void yId(uint32_t value) + { + if (m_YId == value) + { + return; + } + m_YId = value; + yIdChanged(); + } + + inline uint32_t joystickFlags() const { return m_JoystickFlags; } + void joystickFlags(uint32_t value) + { + if (m_JoystickFlags == value) + { + return; + } + m_JoystickFlags = value; + joystickFlagsChanged(); + } + + inline uint32_t handleSourceId() const { return m_HandleSourceId; } + void handleSourceId(uint32_t value) + { + if (m_HandleSourceId == value) + { + return; + } + m_HandleSourceId = value; + handleSourceIdChanged(); + } + + Core* clone() const override; + void copy(const JoystickBase& object) + { + m_X = object.m_X; + m_Y = object.m_Y; + m_PosX = object.m_PosX; + m_PosY = object.m_PosY; + m_OriginX = object.m_OriginX; + m_OriginY = object.m_OriginY; + m_Width = object.m_Width; + m_Height = object.m_Height; + m_XId = object.m_XId; + m_YId = object.m_YId; + m_JoystickFlags = object.m_JoystickFlags; + m_HandleSourceId = object.m_HandleSourceId; + Component::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case xPropertyKey: + m_X = CoreDoubleType::deserialize(reader); + return true; + case yPropertyKey: + m_Y = CoreDoubleType::deserialize(reader); + return true; + case posXPropertyKey: + m_PosX = CoreDoubleType::deserialize(reader); + return true; + case posYPropertyKey: + m_PosY = CoreDoubleType::deserialize(reader); + return true; + case originXPropertyKey: + m_OriginX = CoreDoubleType::deserialize(reader); + return true; + case originYPropertyKey: + m_OriginY = CoreDoubleType::deserialize(reader); + return true; + case widthPropertyKey: + m_Width = CoreDoubleType::deserialize(reader); + return true; + case heightPropertyKey: + m_Height = CoreDoubleType::deserialize(reader); + return true; + case xIdPropertyKey: + m_XId = CoreUintType::deserialize(reader); + return true; + case yIdPropertyKey: + m_YId = CoreUintType::deserialize(reader); + return true; + case joystickFlagsPropertyKey: + m_JoystickFlags = CoreUintType::deserialize(reader); + return true; + case handleSourceIdPropertyKey: + m_HandleSourceId = CoreUintType::deserialize(reader); + return true; + } + return Component::deserialize(propertyKey, reader); + } + +protected: + virtual void xChanged() {} + virtual void yChanged() {} + virtual void posXChanged() {} + virtual void posYChanged() {} + virtual void originXChanged() {} + virtual void originYChanged() {} + virtual void widthChanged() {} + virtual void heightChanged() {} + virtual void xIdChanged() {} + virtual void yIdChanged() {} + virtual void joystickFlagsChanged() {} + virtual void handleSourceIdChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/layout/axis_base.hpp b/third_party/rive/include/rive/generated/layout/axis_base.hpp new file mode 100644 index 0000000..7baeaa7 --- /dev/null +++ b/third_party/rive/include/rive/generated/layout/axis_base.hpp @@ -0,0 +1,89 @@ +#ifndef _RIVE_AXIS_BASE_HPP_ +#define _RIVE_AXIS_BASE_HPP_ +#include "rive/component.hpp" +#include "rive/core/field_types/core_bool_type.hpp" +#include "rive/core/field_types/core_double_type.hpp" +namespace rive +{ +class AxisBase : public Component +{ +protected: + typedef Component Super; + +public: + static const uint16_t typeKey = 492; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case AxisBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t offsetPropertyKey = 675; + static const uint16_t normalizedPropertyKey = 676; + +protected: + float m_Offset = 0.0f; + bool m_Normalized = false; + +public: + inline float offset() const { return m_Offset; } + void offset(float value) + { + if (m_Offset == value) + { + return; + } + m_Offset = value; + offsetChanged(); + } + + inline bool normalized() const { return m_Normalized; } + void normalized(bool value) + { + if (m_Normalized == value) + { + return; + } + m_Normalized = value; + normalizedChanged(); + } + + void copy(const AxisBase& object) + { + m_Offset = object.m_Offset; + m_Normalized = object.m_Normalized; + Component::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case offsetPropertyKey: + m_Offset = CoreDoubleType::deserialize(reader); + return true; + case normalizedPropertyKey: + m_Normalized = CoreBoolType::deserialize(reader); + return true; + } + return Component::deserialize(propertyKey, reader); + } + +protected: + virtual void offsetChanged() {} + virtual void normalizedChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/layout/axis_x_base.hpp b/third_party/rive/include/rive/generated/layout/axis_x_base.hpp new file mode 100644 index 0000000..089fcef --- /dev/null +++ b/third_party/rive/include/rive/generated/layout/axis_x_base.hpp @@ -0,0 +1,37 @@ +#ifndef _RIVE_AXIS_XBASE_HPP_ +#define _RIVE_AXIS_XBASE_HPP_ +#include "rive/layout/axis.hpp" +namespace rive +{ +class AxisXBase : public Axis +{ +protected: + typedef Axis Super; + +public: + static const uint16_t typeKey = 495; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case AxisXBase::typeKey: + case AxisBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/layout/axis_y_base.hpp b/third_party/rive/include/rive/generated/layout/axis_y_base.hpp new file mode 100644 index 0000000..a8420ab --- /dev/null +++ b/third_party/rive/include/rive/generated/layout/axis_y_base.hpp @@ -0,0 +1,37 @@ +#ifndef _RIVE_AXIS_YBASE_HPP_ +#define _RIVE_AXIS_YBASE_HPP_ +#include "rive/layout/axis.hpp" +namespace rive +{ +class AxisYBase : public Axis +{ +protected: + typedef Axis Super; + +public: + static const uint16_t typeKey = 494; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case AxisYBase::typeKey: + case AxisBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/layout/layout_component_style_base.hpp b/third_party/rive/include/rive/generated/layout/layout_component_style_base.hpp new file mode 100644 index 0000000..2cde257 --- /dev/null +++ b/third_party/rive/include/rive/generated/layout/layout_component_style_base.hpp @@ -0,0 +1,1483 @@ +#ifndef _RIVE_LAYOUT_COMPONENT_STYLE_BASE_HPP_ +#define _RIVE_LAYOUT_COMPONENT_STYLE_BASE_HPP_ +#include "rive/component.hpp" +#include "rive/core/field_types/core_bool_type.hpp" +#include "rive/core/field_types/core_double_type.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +namespace rive +{ +class LayoutComponentStyleBase : public Component +{ +protected: + typedef Component Super; + +public: + static const uint16_t typeKey = 420; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case LayoutComponentStyleBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t gapHorizontalPropertyKey = 498; + static const uint16_t gapVerticalPropertyKey = 499; + static const uint16_t maxWidthPropertyKey = 500; + static const uint16_t maxHeightPropertyKey = 501; + static const uint16_t minWidthPropertyKey = 502; + static const uint16_t minHeightPropertyKey = 503; + static const uint16_t borderLeftPropertyKey = 504; + static const uint16_t borderRightPropertyKey = 505; + static const uint16_t borderTopPropertyKey = 506; + static const uint16_t borderBottomPropertyKey = 507; + static const uint16_t marginLeftPropertyKey = 508; + static const uint16_t marginRightPropertyKey = 509; + static const uint16_t marginTopPropertyKey = 510; + static const uint16_t marginBottomPropertyKey = 511; + static const uint16_t paddingLeftPropertyKey = 512; + static const uint16_t paddingRightPropertyKey = 513; + static const uint16_t paddingTopPropertyKey = 514; + static const uint16_t paddingBottomPropertyKey = 515; + static const uint16_t positionLeftPropertyKey = 516; + static const uint16_t positionRightPropertyKey = 517; + static const uint16_t positionTopPropertyKey = 518; + static const uint16_t positionBottomPropertyKey = 519; + static const uint16_t flexPropertyKey = 520; + static const uint16_t flexGrowPropertyKey = 521; + static const uint16_t flexShrinkPropertyKey = 522; + static const uint16_t flexBasisPropertyKey = 523; + static const uint16_t flexBasisUnitsValuePropertyKey = 705; + static const uint16_t aspectRatioPropertyKey = 524; + static const uint16_t layoutWidthScaleTypePropertyKey = 655; + static const uint16_t layoutHeightScaleTypePropertyKey = 656; + static const uint16_t layoutAlignmentTypePropertyKey = 632; + static const uint16_t animationStyleTypePropertyKey = 589; + static const uint16_t interpolationTypePropertyKey = 590; + static const uint16_t interpolatorIdPropertyKey = 591; + static const uint16_t interpolationTimePropertyKey = 592; + static const uint16_t displayValuePropertyKey = 596; + static const uint16_t positionTypeValuePropertyKey = 597; + static const uint16_t flexDirectionValuePropertyKey = 598; + static const uint16_t directionValuePropertyKey = 599; + static const uint16_t alignContentValuePropertyKey = 600; + static const uint16_t alignItemsValuePropertyKey = 601; + static const uint16_t alignSelfValuePropertyKey = 602; + static const uint16_t justifyContentValuePropertyKey = 603; + static const uint16_t flexWrapValuePropertyKey = 604; + static const uint16_t overflowValuePropertyKey = 605; + static const uint16_t intrinsicallySizedValuePropertyKey = 606; + static const uint16_t widthUnitsValuePropertyKey = 607; + static const uint16_t heightUnitsValuePropertyKey = 608; + static const uint16_t borderLeftUnitsValuePropertyKey = 609; + static const uint16_t borderRightUnitsValuePropertyKey = 610; + static const uint16_t borderTopUnitsValuePropertyKey = 611; + static const uint16_t borderBottomUnitsValuePropertyKey = 612; + static const uint16_t marginLeftUnitsValuePropertyKey = 613; + static const uint16_t marginRightUnitsValuePropertyKey = 614; + static const uint16_t marginTopUnitsValuePropertyKey = 615; + static const uint16_t marginBottomUnitsValuePropertyKey = 616; + static const uint16_t paddingLeftUnitsValuePropertyKey = 617; + static const uint16_t paddingRightUnitsValuePropertyKey = 618; + static const uint16_t paddingTopUnitsValuePropertyKey = 619; + static const uint16_t paddingBottomUnitsValuePropertyKey = 620; + static const uint16_t positionLeftUnitsValuePropertyKey = 621; + static const uint16_t positionRightUnitsValuePropertyKey = 622; + static const uint16_t positionTopUnitsValuePropertyKey = 623; + static const uint16_t positionBottomUnitsValuePropertyKey = 624; + static const uint16_t gapHorizontalUnitsValuePropertyKey = 625; + static const uint16_t gapVerticalUnitsValuePropertyKey = 626; + static const uint16_t minWidthUnitsValuePropertyKey = 627; + static const uint16_t minHeightUnitsValuePropertyKey = 628; + static const uint16_t maxWidthUnitsValuePropertyKey = 629; + static const uint16_t maxHeightUnitsValuePropertyKey = 630; + static const uint16_t linkCornerRadiusPropertyKey = 639; + static const uint16_t cornerRadiusTLPropertyKey = 640; + static const uint16_t cornerRadiusTRPropertyKey = 641; + static const uint16_t cornerRadiusBLPropertyKey = 642; + static const uint16_t cornerRadiusBRPropertyKey = 643; + +protected: + float m_GapHorizontal = 0.0f; + float m_GapVertical = 0.0f; + float m_MaxWidth = 0.0f; + float m_MaxHeight = 0.0f; + float m_MinWidth = 0.0f; + float m_MinHeight = 0.0f; + float m_BorderLeft = 0.0f; + float m_BorderRight = 0.0f; + float m_BorderTop = 0.0f; + float m_BorderBottom = 0.0f; + float m_MarginLeft = 0.0f; + float m_MarginRight = 0.0f; + float m_MarginTop = 0.0f; + float m_MarginBottom = 0.0f; + float m_PaddingLeft = 0.0f; + float m_PaddingRight = 0.0f; + float m_PaddingTop = 0.0f; + float m_PaddingBottom = 0.0f; + float m_PositionLeft = 0.0f; + float m_PositionRight = 0.0f; + float m_PositionTop = 0.0f; + float m_PositionBottom = 0.0f; + float m_Flex = 0.0f; + float m_FlexGrow = 0.0f; + float m_FlexShrink = 1.0f; + float m_FlexBasis = 0.0f; + uint32_t m_FlexBasisUnitsValue = 3; + float m_AspectRatio = 0.0f; + uint32_t m_LayoutWidthScaleType = 0; + uint32_t m_LayoutHeightScaleType = 0; + uint32_t m_LayoutAlignmentType = 0; + uint32_t m_AnimationStyleType = 0; + uint32_t m_InterpolationType = 0; + uint32_t m_InterpolatorId = -1; + float m_InterpolationTime = 0.0f; + uint32_t m_DisplayValue = 0; + uint32_t m_PositionTypeValue = 1; + uint32_t m_FlexDirectionValue = 2; + uint32_t m_DirectionValue = 0; + uint32_t m_AlignContentValue = 0; + uint32_t m_AlignItemsValue = 1; + uint32_t m_AlignSelfValue = 0; + uint32_t m_JustifyContentValue = 0; + uint32_t m_FlexWrapValue = 0; + uint32_t m_OverflowValue = 0; + bool m_IntrinsicallySizedValue = false; + uint32_t m_WidthUnitsValue = 1; + uint32_t m_HeightUnitsValue = 1; + uint32_t m_BorderLeftUnitsValue = 0; + uint32_t m_BorderRightUnitsValue = 0; + uint32_t m_BorderTopUnitsValue = 0; + uint32_t m_BorderBottomUnitsValue = 0; + uint32_t m_MarginLeftUnitsValue = 0; + uint32_t m_MarginRightUnitsValue = 0; + uint32_t m_MarginTopUnitsValue = 0; + uint32_t m_MarginBottomUnitsValue = 0; + uint32_t m_PaddingLeftUnitsValue = 0; + uint32_t m_PaddingRightUnitsValue = 0; + uint32_t m_PaddingTopUnitsValue = 0; + uint32_t m_PaddingBottomUnitsValue = 0; + uint32_t m_PositionLeftUnitsValue = 0; + uint32_t m_PositionRightUnitsValue = 0; + uint32_t m_PositionTopUnitsValue = 0; + uint32_t m_PositionBottomUnitsValue = 0; + uint32_t m_GapHorizontalUnitsValue = 0; + uint32_t m_GapVerticalUnitsValue = 0; + uint32_t m_MinWidthUnitsValue = 0; + uint32_t m_MinHeightUnitsValue = 0; + uint32_t m_MaxWidthUnitsValue = 0; + uint32_t m_MaxHeightUnitsValue = 0; + bool m_LinkCornerRadius = true; + float m_CornerRadiusTL = 0.0f; + float m_CornerRadiusTR = 0.0f; + float m_CornerRadiusBL = 0.0f; + float m_CornerRadiusBR = 0.0f; + +public: + inline float gapHorizontal() const { return m_GapHorizontal; } + void gapHorizontal(float value) + { + if (m_GapHorizontal == value) + { + return; + } + m_GapHorizontal = value; + gapHorizontalChanged(); + } + + inline float gapVertical() const { return m_GapVertical; } + void gapVertical(float value) + { + if (m_GapVertical == value) + { + return; + } + m_GapVertical = value; + gapVerticalChanged(); + } + + inline float maxWidth() const { return m_MaxWidth; } + void maxWidth(float value) + { + if (m_MaxWidth == value) + { + return; + } + m_MaxWidth = value; + maxWidthChanged(); + } + + inline float maxHeight() const { return m_MaxHeight; } + void maxHeight(float value) + { + if (m_MaxHeight == value) + { + return; + } + m_MaxHeight = value; + maxHeightChanged(); + } + + inline float minWidth() const { return m_MinWidth; } + void minWidth(float value) + { + if (m_MinWidth == value) + { + return; + } + m_MinWidth = value; + minWidthChanged(); + } + + inline float minHeight() const { return m_MinHeight; } + void minHeight(float value) + { + if (m_MinHeight == value) + { + return; + } + m_MinHeight = value; + minHeightChanged(); + } + + inline float borderLeft() const { return m_BorderLeft; } + void borderLeft(float value) + { + if (m_BorderLeft == value) + { + return; + } + m_BorderLeft = value; + borderLeftChanged(); + } + + inline float borderRight() const { return m_BorderRight; } + void borderRight(float value) + { + if (m_BorderRight == value) + { + return; + } + m_BorderRight = value; + borderRightChanged(); + } + + inline float borderTop() const { return m_BorderTop; } + void borderTop(float value) + { + if (m_BorderTop == value) + { + return; + } + m_BorderTop = value; + borderTopChanged(); + } + + inline float borderBottom() const { return m_BorderBottom; } + void borderBottom(float value) + { + if (m_BorderBottom == value) + { + return; + } + m_BorderBottom = value; + borderBottomChanged(); + } + + inline float marginLeft() const { return m_MarginLeft; } + void marginLeft(float value) + { + if (m_MarginLeft == value) + { + return; + } + m_MarginLeft = value; + marginLeftChanged(); + } + + inline float marginRight() const { return m_MarginRight; } + void marginRight(float value) + { + if (m_MarginRight == value) + { + return; + } + m_MarginRight = value; + marginRightChanged(); + } + + inline float marginTop() const { return m_MarginTop; } + void marginTop(float value) + { + if (m_MarginTop == value) + { + return; + } + m_MarginTop = value; + marginTopChanged(); + } + + inline float marginBottom() const { return m_MarginBottom; } + void marginBottom(float value) + { + if (m_MarginBottom == value) + { + return; + } + m_MarginBottom = value; + marginBottomChanged(); + } + + inline float paddingLeft() const { return m_PaddingLeft; } + void paddingLeft(float value) + { + if (m_PaddingLeft == value) + { + return; + } + m_PaddingLeft = value; + paddingLeftChanged(); + } + + inline float paddingRight() const { return m_PaddingRight; } + void paddingRight(float value) + { + if (m_PaddingRight == value) + { + return; + } + m_PaddingRight = value; + paddingRightChanged(); + } + + inline float paddingTop() const { return m_PaddingTop; } + void paddingTop(float value) + { + if (m_PaddingTop == value) + { + return; + } + m_PaddingTop = value; + paddingTopChanged(); + } + + inline float paddingBottom() const { return m_PaddingBottom; } + void paddingBottom(float value) + { + if (m_PaddingBottom == value) + { + return; + } + m_PaddingBottom = value; + paddingBottomChanged(); + } + + inline float positionLeft() const { return m_PositionLeft; } + void positionLeft(float value) + { + if (m_PositionLeft == value) + { + return; + } + m_PositionLeft = value; + positionLeftChanged(); + } + + inline float positionRight() const { return m_PositionRight; } + void positionRight(float value) + { + if (m_PositionRight == value) + { + return; + } + m_PositionRight = value; + positionRightChanged(); + } + + inline float positionTop() const { return m_PositionTop; } + void positionTop(float value) + { + if (m_PositionTop == value) + { + return; + } + m_PositionTop = value; + positionTopChanged(); + } + + inline float positionBottom() const { return m_PositionBottom; } + void positionBottom(float value) + { + if (m_PositionBottom == value) + { + return; + } + m_PositionBottom = value; + positionBottomChanged(); + } + + inline float flex() const { return m_Flex; } + void flex(float value) + { + if (m_Flex == value) + { + return; + } + m_Flex = value; + flexChanged(); + } + + inline float flexGrow() const { return m_FlexGrow; } + void flexGrow(float value) + { + if (m_FlexGrow == value) + { + return; + } + m_FlexGrow = value; + flexGrowChanged(); + } + + inline float flexShrink() const { return m_FlexShrink; } + void flexShrink(float value) + { + if (m_FlexShrink == value) + { + return; + } + m_FlexShrink = value; + flexShrinkChanged(); + } + + inline float flexBasis() const { return m_FlexBasis; } + void flexBasis(float value) + { + if (m_FlexBasis == value) + { + return; + } + m_FlexBasis = value; + flexBasisChanged(); + } + + inline uint32_t flexBasisUnitsValue() const + { + return m_FlexBasisUnitsValue; + } + void flexBasisUnitsValue(uint32_t value) + { + if (m_FlexBasisUnitsValue == value) + { + return; + } + m_FlexBasisUnitsValue = value; + flexBasisUnitsValueChanged(); + } + + inline float aspectRatio() const { return m_AspectRatio; } + void aspectRatio(float value) + { + if (m_AspectRatio == value) + { + return; + } + m_AspectRatio = value; + aspectRatioChanged(); + } + + inline uint32_t layoutWidthScaleType() const + { + return m_LayoutWidthScaleType; + } + void layoutWidthScaleType(uint32_t value) + { + if (m_LayoutWidthScaleType == value) + { + return; + } + m_LayoutWidthScaleType = value; + layoutWidthScaleTypeChanged(); + } + + inline uint32_t layoutHeightScaleType() const + { + return m_LayoutHeightScaleType; + } + void layoutHeightScaleType(uint32_t value) + { + if (m_LayoutHeightScaleType == value) + { + return; + } + m_LayoutHeightScaleType = value; + layoutHeightScaleTypeChanged(); + } + + inline uint32_t layoutAlignmentType() const + { + return m_LayoutAlignmentType; + } + void layoutAlignmentType(uint32_t value) + { + if (m_LayoutAlignmentType == value) + { + return; + } + m_LayoutAlignmentType = value; + layoutAlignmentTypeChanged(); + } + + inline uint32_t animationStyleType() const { return m_AnimationStyleType; } + void animationStyleType(uint32_t value) + { + if (m_AnimationStyleType == value) + { + return; + } + m_AnimationStyleType = value; + animationStyleTypeChanged(); + } + + inline uint32_t interpolationType() const { return m_InterpolationType; } + void interpolationType(uint32_t value) + { + if (m_InterpolationType == value) + { + return; + } + m_InterpolationType = value; + interpolationTypeChanged(); + } + + inline uint32_t interpolatorId() const { return m_InterpolatorId; } + void interpolatorId(uint32_t value) + { + if (m_InterpolatorId == value) + { + return; + } + m_InterpolatorId = value; + interpolatorIdChanged(); + } + + inline float interpolationTime() const { return m_InterpolationTime; } + void interpolationTime(float value) + { + if (m_InterpolationTime == value) + { + return; + } + m_InterpolationTime = value; + interpolationTimeChanged(); + } + + inline uint32_t displayValue() const { return m_DisplayValue; } + void displayValue(uint32_t value) + { + if (m_DisplayValue == value) + { + return; + } + m_DisplayValue = value; + displayValueChanged(); + } + + inline uint32_t positionTypeValue() const { return m_PositionTypeValue; } + void positionTypeValue(uint32_t value) + { + if (m_PositionTypeValue == value) + { + return; + } + m_PositionTypeValue = value; + positionTypeValueChanged(); + } + + inline uint32_t flexDirectionValue() const { return m_FlexDirectionValue; } + void flexDirectionValue(uint32_t value) + { + if (m_FlexDirectionValue == value) + { + return; + } + m_FlexDirectionValue = value; + flexDirectionValueChanged(); + } + + inline uint32_t directionValue() const { return m_DirectionValue; } + void directionValue(uint32_t value) + { + if (m_DirectionValue == value) + { + return; + } + m_DirectionValue = value; + directionValueChanged(); + } + + inline uint32_t alignContentValue() const { return m_AlignContentValue; } + void alignContentValue(uint32_t value) + { + if (m_AlignContentValue == value) + { + return; + } + m_AlignContentValue = value; + alignContentValueChanged(); + } + + inline uint32_t alignItemsValue() const { return m_AlignItemsValue; } + void alignItemsValue(uint32_t value) + { + if (m_AlignItemsValue == value) + { + return; + } + m_AlignItemsValue = value; + alignItemsValueChanged(); + } + + inline uint32_t alignSelfValue() const { return m_AlignSelfValue; } + void alignSelfValue(uint32_t value) + { + if (m_AlignSelfValue == value) + { + return; + } + m_AlignSelfValue = value; + alignSelfValueChanged(); + } + + inline uint32_t justifyContentValue() const + { + return m_JustifyContentValue; + } + void justifyContentValue(uint32_t value) + { + if (m_JustifyContentValue == value) + { + return; + } + m_JustifyContentValue = value; + justifyContentValueChanged(); + } + + inline uint32_t flexWrapValue() const { return m_FlexWrapValue; } + void flexWrapValue(uint32_t value) + { + if (m_FlexWrapValue == value) + { + return; + } + m_FlexWrapValue = value; + flexWrapValueChanged(); + } + + inline uint32_t overflowValue() const { return m_OverflowValue; } + void overflowValue(uint32_t value) + { + if (m_OverflowValue == value) + { + return; + } + m_OverflowValue = value; + overflowValueChanged(); + } + + inline bool intrinsicallySizedValue() const + { + return m_IntrinsicallySizedValue; + } + void intrinsicallySizedValue(bool value) + { + if (m_IntrinsicallySizedValue == value) + { + return; + } + m_IntrinsicallySizedValue = value; + intrinsicallySizedValueChanged(); + } + + inline uint32_t widthUnitsValue() const { return m_WidthUnitsValue; } + void widthUnitsValue(uint32_t value) + { + if (m_WidthUnitsValue == value) + { + return; + } + m_WidthUnitsValue = value; + widthUnitsValueChanged(); + } + + inline uint32_t heightUnitsValue() const { return m_HeightUnitsValue; } + void heightUnitsValue(uint32_t value) + { + if (m_HeightUnitsValue == value) + { + return; + } + m_HeightUnitsValue = value; + heightUnitsValueChanged(); + } + + inline uint32_t borderLeftUnitsValue() const + { + return m_BorderLeftUnitsValue; + } + void borderLeftUnitsValue(uint32_t value) + { + if (m_BorderLeftUnitsValue == value) + { + return; + } + m_BorderLeftUnitsValue = value; + borderLeftUnitsValueChanged(); + } + + inline uint32_t borderRightUnitsValue() const + { + return m_BorderRightUnitsValue; + } + void borderRightUnitsValue(uint32_t value) + { + if (m_BorderRightUnitsValue == value) + { + return; + } + m_BorderRightUnitsValue = value; + borderRightUnitsValueChanged(); + } + + inline uint32_t borderTopUnitsValue() const + { + return m_BorderTopUnitsValue; + } + void borderTopUnitsValue(uint32_t value) + { + if (m_BorderTopUnitsValue == value) + { + return; + } + m_BorderTopUnitsValue = value; + borderTopUnitsValueChanged(); + } + + inline uint32_t borderBottomUnitsValue() const + { + return m_BorderBottomUnitsValue; + } + void borderBottomUnitsValue(uint32_t value) + { + if (m_BorderBottomUnitsValue == value) + { + return; + } + m_BorderBottomUnitsValue = value; + borderBottomUnitsValueChanged(); + } + + inline uint32_t marginLeftUnitsValue() const + { + return m_MarginLeftUnitsValue; + } + void marginLeftUnitsValue(uint32_t value) + { + if (m_MarginLeftUnitsValue == value) + { + return; + } + m_MarginLeftUnitsValue = value; + marginLeftUnitsValueChanged(); + } + + inline uint32_t marginRightUnitsValue() const + { + return m_MarginRightUnitsValue; + } + void marginRightUnitsValue(uint32_t value) + { + if (m_MarginRightUnitsValue == value) + { + return; + } + m_MarginRightUnitsValue = value; + marginRightUnitsValueChanged(); + } + + inline uint32_t marginTopUnitsValue() const + { + return m_MarginTopUnitsValue; + } + void marginTopUnitsValue(uint32_t value) + { + if (m_MarginTopUnitsValue == value) + { + return; + } + m_MarginTopUnitsValue = value; + marginTopUnitsValueChanged(); + } + + inline uint32_t marginBottomUnitsValue() const + { + return m_MarginBottomUnitsValue; + } + void marginBottomUnitsValue(uint32_t value) + { + if (m_MarginBottomUnitsValue == value) + { + return; + } + m_MarginBottomUnitsValue = value; + marginBottomUnitsValueChanged(); + } + + inline uint32_t paddingLeftUnitsValue() const + { + return m_PaddingLeftUnitsValue; + } + void paddingLeftUnitsValue(uint32_t value) + { + if (m_PaddingLeftUnitsValue == value) + { + return; + } + m_PaddingLeftUnitsValue = value; + paddingLeftUnitsValueChanged(); + } + + inline uint32_t paddingRightUnitsValue() const + { + return m_PaddingRightUnitsValue; + } + void paddingRightUnitsValue(uint32_t value) + { + if (m_PaddingRightUnitsValue == value) + { + return; + } + m_PaddingRightUnitsValue = value; + paddingRightUnitsValueChanged(); + } + + inline uint32_t paddingTopUnitsValue() const + { + return m_PaddingTopUnitsValue; + } + void paddingTopUnitsValue(uint32_t value) + { + if (m_PaddingTopUnitsValue == value) + { + return; + } + m_PaddingTopUnitsValue = value; + paddingTopUnitsValueChanged(); + } + + inline uint32_t paddingBottomUnitsValue() const + { + return m_PaddingBottomUnitsValue; + } + void paddingBottomUnitsValue(uint32_t value) + { + if (m_PaddingBottomUnitsValue == value) + { + return; + } + m_PaddingBottomUnitsValue = value; + paddingBottomUnitsValueChanged(); + } + + inline uint32_t positionLeftUnitsValue() const + { + return m_PositionLeftUnitsValue; + } + void positionLeftUnitsValue(uint32_t value) + { + if (m_PositionLeftUnitsValue == value) + { + return; + } + m_PositionLeftUnitsValue = value; + positionLeftUnitsValueChanged(); + } + + inline uint32_t positionRightUnitsValue() const + { + return m_PositionRightUnitsValue; + } + void positionRightUnitsValue(uint32_t value) + { + if (m_PositionRightUnitsValue == value) + { + return; + } + m_PositionRightUnitsValue = value; + positionRightUnitsValueChanged(); + } + + inline uint32_t positionTopUnitsValue() const + { + return m_PositionTopUnitsValue; + } + void positionTopUnitsValue(uint32_t value) + { + if (m_PositionTopUnitsValue == value) + { + return; + } + m_PositionTopUnitsValue = value; + positionTopUnitsValueChanged(); + } + + inline uint32_t positionBottomUnitsValue() const + { + return m_PositionBottomUnitsValue; + } + void positionBottomUnitsValue(uint32_t value) + { + if (m_PositionBottomUnitsValue == value) + { + return; + } + m_PositionBottomUnitsValue = value; + positionBottomUnitsValueChanged(); + } + + inline uint32_t gapHorizontalUnitsValue() const + { + return m_GapHorizontalUnitsValue; + } + void gapHorizontalUnitsValue(uint32_t value) + { + if (m_GapHorizontalUnitsValue == value) + { + return; + } + m_GapHorizontalUnitsValue = value; + gapHorizontalUnitsValueChanged(); + } + + inline uint32_t gapVerticalUnitsValue() const + { + return m_GapVerticalUnitsValue; + } + void gapVerticalUnitsValue(uint32_t value) + { + if (m_GapVerticalUnitsValue == value) + { + return; + } + m_GapVerticalUnitsValue = value; + gapVerticalUnitsValueChanged(); + } + + inline uint32_t minWidthUnitsValue() const { return m_MinWidthUnitsValue; } + void minWidthUnitsValue(uint32_t value) + { + if (m_MinWidthUnitsValue == value) + { + return; + } + m_MinWidthUnitsValue = value; + minWidthUnitsValueChanged(); + } + + inline uint32_t minHeightUnitsValue() const + { + return m_MinHeightUnitsValue; + } + void minHeightUnitsValue(uint32_t value) + { + if (m_MinHeightUnitsValue == value) + { + return; + } + m_MinHeightUnitsValue = value; + minHeightUnitsValueChanged(); + } + + inline uint32_t maxWidthUnitsValue() const { return m_MaxWidthUnitsValue; } + void maxWidthUnitsValue(uint32_t value) + { + if (m_MaxWidthUnitsValue == value) + { + return; + } + m_MaxWidthUnitsValue = value; + maxWidthUnitsValueChanged(); + } + + inline uint32_t maxHeightUnitsValue() const + { + return m_MaxHeightUnitsValue; + } + void maxHeightUnitsValue(uint32_t value) + { + if (m_MaxHeightUnitsValue == value) + { + return; + } + m_MaxHeightUnitsValue = value; + maxHeightUnitsValueChanged(); + } + + inline bool linkCornerRadius() const { return m_LinkCornerRadius; } + void linkCornerRadius(bool value) + { + if (m_LinkCornerRadius == value) + { + return; + } + m_LinkCornerRadius = value; + linkCornerRadiusChanged(); + } + + inline float cornerRadiusTL() const { return m_CornerRadiusTL; } + void cornerRadiusTL(float value) + { + if (m_CornerRadiusTL == value) + { + return; + } + m_CornerRadiusTL = value; + cornerRadiusTLChanged(); + } + + inline float cornerRadiusTR() const { return m_CornerRadiusTR; } + void cornerRadiusTR(float value) + { + if (m_CornerRadiusTR == value) + { + return; + } + m_CornerRadiusTR = value; + cornerRadiusTRChanged(); + } + + inline float cornerRadiusBL() const { return m_CornerRadiusBL; } + void cornerRadiusBL(float value) + { + if (m_CornerRadiusBL == value) + { + return; + } + m_CornerRadiusBL = value; + cornerRadiusBLChanged(); + } + + inline float cornerRadiusBR() const { return m_CornerRadiusBR; } + void cornerRadiusBR(float value) + { + if (m_CornerRadiusBR == value) + { + return; + } + m_CornerRadiusBR = value; + cornerRadiusBRChanged(); + } + + Core* clone() const override; + void copy(const LayoutComponentStyleBase& object) + { + m_GapHorizontal = object.m_GapHorizontal; + m_GapVertical = object.m_GapVertical; + m_MaxWidth = object.m_MaxWidth; + m_MaxHeight = object.m_MaxHeight; + m_MinWidth = object.m_MinWidth; + m_MinHeight = object.m_MinHeight; + m_BorderLeft = object.m_BorderLeft; + m_BorderRight = object.m_BorderRight; + m_BorderTop = object.m_BorderTop; + m_BorderBottom = object.m_BorderBottom; + m_MarginLeft = object.m_MarginLeft; + m_MarginRight = object.m_MarginRight; + m_MarginTop = object.m_MarginTop; + m_MarginBottom = object.m_MarginBottom; + m_PaddingLeft = object.m_PaddingLeft; + m_PaddingRight = object.m_PaddingRight; + m_PaddingTop = object.m_PaddingTop; + m_PaddingBottom = object.m_PaddingBottom; + m_PositionLeft = object.m_PositionLeft; + m_PositionRight = object.m_PositionRight; + m_PositionTop = object.m_PositionTop; + m_PositionBottom = object.m_PositionBottom; + m_Flex = object.m_Flex; + m_FlexGrow = object.m_FlexGrow; + m_FlexShrink = object.m_FlexShrink; + m_FlexBasis = object.m_FlexBasis; + m_FlexBasisUnitsValue = object.m_FlexBasisUnitsValue; + m_AspectRatio = object.m_AspectRatio; + m_LayoutWidthScaleType = object.m_LayoutWidthScaleType; + m_LayoutHeightScaleType = object.m_LayoutHeightScaleType; + m_LayoutAlignmentType = object.m_LayoutAlignmentType; + m_AnimationStyleType = object.m_AnimationStyleType; + m_InterpolationType = object.m_InterpolationType; + m_InterpolatorId = object.m_InterpolatorId; + m_InterpolationTime = object.m_InterpolationTime; + m_DisplayValue = object.m_DisplayValue; + m_PositionTypeValue = object.m_PositionTypeValue; + m_FlexDirectionValue = object.m_FlexDirectionValue; + m_DirectionValue = object.m_DirectionValue; + m_AlignContentValue = object.m_AlignContentValue; + m_AlignItemsValue = object.m_AlignItemsValue; + m_AlignSelfValue = object.m_AlignSelfValue; + m_JustifyContentValue = object.m_JustifyContentValue; + m_FlexWrapValue = object.m_FlexWrapValue; + m_OverflowValue = object.m_OverflowValue; + m_IntrinsicallySizedValue = object.m_IntrinsicallySizedValue; + m_WidthUnitsValue = object.m_WidthUnitsValue; + m_HeightUnitsValue = object.m_HeightUnitsValue; + m_BorderLeftUnitsValue = object.m_BorderLeftUnitsValue; + m_BorderRightUnitsValue = object.m_BorderRightUnitsValue; + m_BorderTopUnitsValue = object.m_BorderTopUnitsValue; + m_BorderBottomUnitsValue = object.m_BorderBottomUnitsValue; + m_MarginLeftUnitsValue = object.m_MarginLeftUnitsValue; + m_MarginRightUnitsValue = object.m_MarginRightUnitsValue; + m_MarginTopUnitsValue = object.m_MarginTopUnitsValue; + m_MarginBottomUnitsValue = object.m_MarginBottomUnitsValue; + m_PaddingLeftUnitsValue = object.m_PaddingLeftUnitsValue; + m_PaddingRightUnitsValue = object.m_PaddingRightUnitsValue; + m_PaddingTopUnitsValue = object.m_PaddingTopUnitsValue; + m_PaddingBottomUnitsValue = object.m_PaddingBottomUnitsValue; + m_PositionLeftUnitsValue = object.m_PositionLeftUnitsValue; + m_PositionRightUnitsValue = object.m_PositionRightUnitsValue; + m_PositionTopUnitsValue = object.m_PositionTopUnitsValue; + m_PositionBottomUnitsValue = object.m_PositionBottomUnitsValue; + m_GapHorizontalUnitsValue = object.m_GapHorizontalUnitsValue; + m_GapVerticalUnitsValue = object.m_GapVerticalUnitsValue; + m_MinWidthUnitsValue = object.m_MinWidthUnitsValue; + m_MinHeightUnitsValue = object.m_MinHeightUnitsValue; + m_MaxWidthUnitsValue = object.m_MaxWidthUnitsValue; + m_MaxHeightUnitsValue = object.m_MaxHeightUnitsValue; + m_LinkCornerRadius = object.m_LinkCornerRadius; + m_CornerRadiusTL = object.m_CornerRadiusTL; + m_CornerRadiusTR = object.m_CornerRadiusTR; + m_CornerRadiusBL = object.m_CornerRadiusBL; + m_CornerRadiusBR = object.m_CornerRadiusBR; + Component::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case gapHorizontalPropertyKey: + m_GapHorizontal = CoreDoubleType::deserialize(reader); + return true; + case gapVerticalPropertyKey: + m_GapVertical = CoreDoubleType::deserialize(reader); + return true; + case maxWidthPropertyKey: + m_MaxWidth = CoreDoubleType::deserialize(reader); + return true; + case maxHeightPropertyKey: + m_MaxHeight = CoreDoubleType::deserialize(reader); + return true; + case minWidthPropertyKey: + m_MinWidth = CoreDoubleType::deserialize(reader); + return true; + case minHeightPropertyKey: + m_MinHeight = CoreDoubleType::deserialize(reader); + return true; + case borderLeftPropertyKey: + m_BorderLeft = CoreDoubleType::deserialize(reader); + return true; + case borderRightPropertyKey: + m_BorderRight = CoreDoubleType::deserialize(reader); + return true; + case borderTopPropertyKey: + m_BorderTop = CoreDoubleType::deserialize(reader); + return true; + case borderBottomPropertyKey: + m_BorderBottom = CoreDoubleType::deserialize(reader); + return true; + case marginLeftPropertyKey: + m_MarginLeft = CoreDoubleType::deserialize(reader); + return true; + case marginRightPropertyKey: + m_MarginRight = CoreDoubleType::deserialize(reader); + return true; + case marginTopPropertyKey: + m_MarginTop = CoreDoubleType::deserialize(reader); + return true; + case marginBottomPropertyKey: + m_MarginBottom = CoreDoubleType::deserialize(reader); + return true; + case paddingLeftPropertyKey: + m_PaddingLeft = CoreDoubleType::deserialize(reader); + return true; + case paddingRightPropertyKey: + m_PaddingRight = CoreDoubleType::deserialize(reader); + return true; + case paddingTopPropertyKey: + m_PaddingTop = CoreDoubleType::deserialize(reader); + return true; + case paddingBottomPropertyKey: + m_PaddingBottom = CoreDoubleType::deserialize(reader); + return true; + case positionLeftPropertyKey: + m_PositionLeft = CoreDoubleType::deserialize(reader); + return true; + case positionRightPropertyKey: + m_PositionRight = CoreDoubleType::deserialize(reader); + return true; + case positionTopPropertyKey: + m_PositionTop = CoreDoubleType::deserialize(reader); + return true; + case positionBottomPropertyKey: + m_PositionBottom = CoreDoubleType::deserialize(reader); + return true; + case flexPropertyKey: + m_Flex = CoreDoubleType::deserialize(reader); + return true; + case flexGrowPropertyKey: + m_FlexGrow = CoreDoubleType::deserialize(reader); + return true; + case flexShrinkPropertyKey: + m_FlexShrink = CoreDoubleType::deserialize(reader); + return true; + case flexBasisPropertyKey: + m_FlexBasis = CoreDoubleType::deserialize(reader); + return true; + case flexBasisUnitsValuePropertyKey: + m_FlexBasisUnitsValue = CoreUintType::deserialize(reader); + return true; + case aspectRatioPropertyKey: + m_AspectRatio = CoreDoubleType::deserialize(reader); + return true; + case layoutWidthScaleTypePropertyKey: + m_LayoutWidthScaleType = CoreUintType::deserialize(reader); + return true; + case layoutHeightScaleTypePropertyKey: + m_LayoutHeightScaleType = CoreUintType::deserialize(reader); + return true; + case layoutAlignmentTypePropertyKey: + m_LayoutAlignmentType = CoreUintType::deserialize(reader); + return true; + case animationStyleTypePropertyKey: + m_AnimationStyleType = CoreUintType::deserialize(reader); + return true; + case interpolationTypePropertyKey: + m_InterpolationType = CoreUintType::deserialize(reader); + return true; + case interpolatorIdPropertyKey: + m_InterpolatorId = CoreUintType::deserialize(reader); + return true; + case interpolationTimePropertyKey: + m_InterpolationTime = CoreDoubleType::deserialize(reader); + return true; + case displayValuePropertyKey: + m_DisplayValue = CoreUintType::deserialize(reader); + return true; + case positionTypeValuePropertyKey: + m_PositionTypeValue = CoreUintType::deserialize(reader); + return true; + case flexDirectionValuePropertyKey: + m_FlexDirectionValue = CoreUintType::deserialize(reader); + return true; + case directionValuePropertyKey: + m_DirectionValue = CoreUintType::deserialize(reader); + return true; + case alignContentValuePropertyKey: + m_AlignContentValue = CoreUintType::deserialize(reader); + return true; + case alignItemsValuePropertyKey: + m_AlignItemsValue = CoreUintType::deserialize(reader); + return true; + case alignSelfValuePropertyKey: + m_AlignSelfValue = CoreUintType::deserialize(reader); + return true; + case justifyContentValuePropertyKey: + m_JustifyContentValue = CoreUintType::deserialize(reader); + return true; + case flexWrapValuePropertyKey: + m_FlexWrapValue = CoreUintType::deserialize(reader); + return true; + case overflowValuePropertyKey: + m_OverflowValue = CoreUintType::deserialize(reader); + return true; + case intrinsicallySizedValuePropertyKey: + m_IntrinsicallySizedValue = CoreBoolType::deserialize(reader); + return true; + case widthUnitsValuePropertyKey: + m_WidthUnitsValue = CoreUintType::deserialize(reader); + return true; + case heightUnitsValuePropertyKey: + m_HeightUnitsValue = CoreUintType::deserialize(reader); + return true; + case borderLeftUnitsValuePropertyKey: + m_BorderLeftUnitsValue = CoreUintType::deserialize(reader); + return true; + case borderRightUnitsValuePropertyKey: + m_BorderRightUnitsValue = CoreUintType::deserialize(reader); + return true; + case borderTopUnitsValuePropertyKey: + m_BorderTopUnitsValue = CoreUintType::deserialize(reader); + return true; + case borderBottomUnitsValuePropertyKey: + m_BorderBottomUnitsValue = CoreUintType::deserialize(reader); + return true; + case marginLeftUnitsValuePropertyKey: + m_MarginLeftUnitsValue = CoreUintType::deserialize(reader); + return true; + case marginRightUnitsValuePropertyKey: + m_MarginRightUnitsValue = CoreUintType::deserialize(reader); + return true; + case marginTopUnitsValuePropertyKey: + m_MarginTopUnitsValue = CoreUintType::deserialize(reader); + return true; + case marginBottomUnitsValuePropertyKey: + m_MarginBottomUnitsValue = CoreUintType::deserialize(reader); + return true; + case paddingLeftUnitsValuePropertyKey: + m_PaddingLeftUnitsValue = CoreUintType::deserialize(reader); + return true; + case paddingRightUnitsValuePropertyKey: + m_PaddingRightUnitsValue = CoreUintType::deserialize(reader); + return true; + case paddingTopUnitsValuePropertyKey: + m_PaddingTopUnitsValue = CoreUintType::deserialize(reader); + return true; + case paddingBottomUnitsValuePropertyKey: + m_PaddingBottomUnitsValue = CoreUintType::deserialize(reader); + return true; + case positionLeftUnitsValuePropertyKey: + m_PositionLeftUnitsValue = CoreUintType::deserialize(reader); + return true; + case positionRightUnitsValuePropertyKey: + m_PositionRightUnitsValue = CoreUintType::deserialize(reader); + return true; + case positionTopUnitsValuePropertyKey: + m_PositionTopUnitsValue = CoreUintType::deserialize(reader); + return true; + case positionBottomUnitsValuePropertyKey: + m_PositionBottomUnitsValue = CoreUintType::deserialize(reader); + return true; + case gapHorizontalUnitsValuePropertyKey: + m_GapHorizontalUnitsValue = CoreUintType::deserialize(reader); + return true; + case gapVerticalUnitsValuePropertyKey: + m_GapVerticalUnitsValue = CoreUintType::deserialize(reader); + return true; + case minWidthUnitsValuePropertyKey: + m_MinWidthUnitsValue = CoreUintType::deserialize(reader); + return true; + case minHeightUnitsValuePropertyKey: + m_MinHeightUnitsValue = CoreUintType::deserialize(reader); + return true; + case maxWidthUnitsValuePropertyKey: + m_MaxWidthUnitsValue = CoreUintType::deserialize(reader); + return true; + case maxHeightUnitsValuePropertyKey: + m_MaxHeightUnitsValue = CoreUintType::deserialize(reader); + return true; + case linkCornerRadiusPropertyKey: + m_LinkCornerRadius = CoreBoolType::deserialize(reader); + return true; + case cornerRadiusTLPropertyKey: + m_CornerRadiusTL = CoreDoubleType::deserialize(reader); + return true; + case cornerRadiusTRPropertyKey: + m_CornerRadiusTR = CoreDoubleType::deserialize(reader); + return true; + case cornerRadiusBLPropertyKey: + m_CornerRadiusBL = CoreDoubleType::deserialize(reader); + return true; + case cornerRadiusBRPropertyKey: + m_CornerRadiusBR = CoreDoubleType::deserialize(reader); + return true; + } + return Component::deserialize(propertyKey, reader); + } + +protected: + virtual void gapHorizontalChanged() {} + virtual void gapVerticalChanged() {} + virtual void maxWidthChanged() {} + virtual void maxHeightChanged() {} + virtual void minWidthChanged() {} + virtual void minHeightChanged() {} + virtual void borderLeftChanged() {} + virtual void borderRightChanged() {} + virtual void borderTopChanged() {} + virtual void borderBottomChanged() {} + virtual void marginLeftChanged() {} + virtual void marginRightChanged() {} + virtual void marginTopChanged() {} + virtual void marginBottomChanged() {} + virtual void paddingLeftChanged() {} + virtual void paddingRightChanged() {} + virtual void paddingTopChanged() {} + virtual void paddingBottomChanged() {} + virtual void positionLeftChanged() {} + virtual void positionRightChanged() {} + virtual void positionTopChanged() {} + virtual void positionBottomChanged() {} + virtual void flexChanged() {} + virtual void flexGrowChanged() {} + virtual void flexShrinkChanged() {} + virtual void flexBasisChanged() {} + virtual void flexBasisUnitsValueChanged() {} + virtual void aspectRatioChanged() {} + virtual void layoutWidthScaleTypeChanged() {} + virtual void layoutHeightScaleTypeChanged() {} + virtual void layoutAlignmentTypeChanged() {} + virtual void animationStyleTypeChanged() {} + virtual void interpolationTypeChanged() {} + virtual void interpolatorIdChanged() {} + virtual void interpolationTimeChanged() {} + virtual void displayValueChanged() {} + virtual void positionTypeValueChanged() {} + virtual void flexDirectionValueChanged() {} + virtual void directionValueChanged() {} + virtual void alignContentValueChanged() {} + virtual void alignItemsValueChanged() {} + virtual void alignSelfValueChanged() {} + virtual void justifyContentValueChanged() {} + virtual void flexWrapValueChanged() {} + virtual void overflowValueChanged() {} + virtual void intrinsicallySizedValueChanged() {} + virtual void widthUnitsValueChanged() {} + virtual void heightUnitsValueChanged() {} + virtual void borderLeftUnitsValueChanged() {} + virtual void borderRightUnitsValueChanged() {} + virtual void borderTopUnitsValueChanged() {} + virtual void borderBottomUnitsValueChanged() {} + virtual void marginLeftUnitsValueChanged() {} + virtual void marginRightUnitsValueChanged() {} + virtual void marginTopUnitsValueChanged() {} + virtual void marginBottomUnitsValueChanged() {} + virtual void paddingLeftUnitsValueChanged() {} + virtual void paddingRightUnitsValueChanged() {} + virtual void paddingTopUnitsValueChanged() {} + virtual void paddingBottomUnitsValueChanged() {} + virtual void positionLeftUnitsValueChanged() {} + virtual void positionRightUnitsValueChanged() {} + virtual void positionTopUnitsValueChanged() {} + virtual void positionBottomUnitsValueChanged() {} + virtual void gapHorizontalUnitsValueChanged() {} + virtual void gapVerticalUnitsValueChanged() {} + virtual void minWidthUnitsValueChanged() {} + virtual void minHeightUnitsValueChanged() {} + virtual void maxWidthUnitsValueChanged() {} + virtual void maxHeightUnitsValueChanged() {} + virtual void linkCornerRadiusChanged() {} + virtual void cornerRadiusTLChanged() {} + virtual void cornerRadiusTRChanged() {} + virtual void cornerRadiusBLChanged() {} + virtual void cornerRadiusBRChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/layout/n_sliced_node_base.hpp b/third_party/rive/include/rive/generated/layout/n_sliced_node_base.hpp new file mode 100644 index 0000000..655c484 --- /dev/null +++ b/third_party/rive/include/rive/generated/layout/n_sliced_node_base.hpp @@ -0,0 +1,129 @@ +#ifndef _RIVE_N_SLICED_NODE_BASE_HPP_ +#define _RIVE_N_SLICED_NODE_BASE_HPP_ +#include "rive/core/field_types/core_double_type.hpp" +#include "rive/node.hpp" +namespace rive +{ +class NSlicedNodeBase : public Node +{ +protected: + typedef Node Super; + +public: + static const uint16_t typeKey = 508; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case NSlicedNodeBase::typeKey: + case NodeBase::typeKey: + case TransformComponentBase::typeKey: + case WorldTransformComponentBase::typeKey: + case ContainerComponentBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t initialWidthPropertyKey = 697; + static const uint16_t initialHeightPropertyKey = 698; + static const uint16_t widthPropertyKey = 699; + static const uint16_t heightPropertyKey = 700; + +protected: + float m_InitialWidth = 0.0f; + float m_InitialHeight = 0.0f; + float m_Width = 0.0f; + float m_Height = 0.0f; + +public: + inline float initialWidth() const { return m_InitialWidth; } + void initialWidth(float value) + { + if (m_InitialWidth == value) + { + return; + } + m_InitialWidth = value; + initialWidthChanged(); + } + + inline float initialHeight() const { return m_InitialHeight; } + void initialHeight(float value) + { + if (m_InitialHeight == value) + { + return; + } + m_InitialHeight = value; + initialHeightChanged(); + } + + inline float width() const { return m_Width; } + void width(float value) + { + if (m_Width == value) + { + return; + } + m_Width = value; + widthChanged(); + } + + inline float height() const { return m_Height; } + void height(float value) + { + if (m_Height == value) + { + return; + } + m_Height = value; + heightChanged(); + } + + Core* clone() const override; + void copy(const NSlicedNodeBase& object) + { + m_InitialWidth = object.m_InitialWidth; + m_InitialHeight = object.m_InitialHeight; + m_Width = object.m_Width; + m_Height = object.m_Height; + Node::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case initialWidthPropertyKey: + m_InitialWidth = CoreDoubleType::deserialize(reader); + return true; + case initialHeightPropertyKey: + m_InitialHeight = CoreDoubleType::deserialize(reader); + return true; + case widthPropertyKey: + m_Width = CoreDoubleType::deserialize(reader); + return true; + case heightPropertyKey: + m_Height = CoreDoubleType::deserialize(reader); + return true; + } + return Node::deserialize(propertyKey, reader); + } + +protected: + virtual void initialWidthChanged() {} + virtual void initialHeightChanged() {} + virtual void widthChanged() {} + virtual void heightChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/layout/n_slicer_base.hpp b/third_party/rive/include/rive/generated/layout/n_slicer_base.hpp new file mode 100644 index 0000000..4a24c60 --- /dev/null +++ b/third_party/rive/include/rive/generated/layout/n_slicer_base.hpp @@ -0,0 +1,37 @@ +#ifndef _RIVE_N_SLICER_BASE_HPP_ +#define _RIVE_N_SLICER_BASE_HPP_ +#include "rive/container_component.hpp" +namespace rive +{ +class NSlicerBase : public ContainerComponent +{ +protected: + typedef ContainerComponent Super; + +public: + static const uint16_t typeKey = 493; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case NSlicerBase::typeKey: + case ContainerComponentBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/layout/n_slicer_tile_mode_base.hpp b/third_party/rive/include/rive/generated/layout/n_slicer_tile_mode_base.hpp new file mode 100644 index 0000000..f4d40a1 --- /dev/null +++ b/third_party/rive/include/rive/generated/layout/n_slicer_tile_mode_base.hpp @@ -0,0 +1,89 @@ +#ifndef _RIVE_N_SLICER_TILE_MODE_BASE_HPP_ +#define _RIVE_N_SLICER_TILE_MODE_BASE_HPP_ +#include "rive/component.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +namespace rive +{ +class NSlicerTileModeBase : public Component +{ +protected: + typedef Component Super; + +public: + static const uint16_t typeKey = 491; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case NSlicerTileModeBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t patchIndexPropertyKey = 672; + static const uint16_t stylePropertyKey = 673; + +protected: + uint32_t m_PatchIndex = 0; + uint32_t m_Style = 0; + +public: + inline uint32_t patchIndex() const { return m_PatchIndex; } + void patchIndex(uint32_t value) + { + if (m_PatchIndex == value) + { + return; + } + m_PatchIndex = value; + patchIndexChanged(); + } + + inline uint32_t style() const { return m_Style; } + void style(uint32_t value) + { + if (m_Style == value) + { + return; + } + m_Style = value; + styleChanged(); + } + + Core* clone() const override; + void copy(const NSlicerTileModeBase& object) + { + m_PatchIndex = object.m_PatchIndex; + m_Style = object.m_Style; + Component::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case patchIndexPropertyKey: + m_PatchIndex = CoreUintType::deserialize(reader); + return true; + case stylePropertyKey: + m_Style = CoreUintType::deserialize(reader); + return true; + } + return Component::deserialize(propertyKey, reader); + } + +protected: + virtual void patchIndexChanged() {} + virtual void styleChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/layout_component_base.hpp b/third_party/rive/include/rive/generated/layout_component_base.hpp new file mode 100644 index 0000000..84d6d88 --- /dev/null +++ b/third_party/rive/include/rive/generated/layout_component_base.hpp @@ -0,0 +1,168 @@ +#ifndef _RIVE_LAYOUT_COMPONENT_BASE_HPP_ +#define _RIVE_LAYOUT_COMPONENT_BASE_HPP_ +#include "rive/core/field_types/core_bool_type.hpp" +#include "rive/core/field_types/core_double_type.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +#include "rive/drawable.hpp" +namespace rive +{ +class LayoutComponentBase : public Drawable +{ +protected: + typedef Drawable Super; + +public: + static const uint16_t typeKey = 409; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case LayoutComponentBase::typeKey: + case DrawableBase::typeKey: + case NodeBase::typeKey: + case TransformComponentBase::typeKey: + case WorldTransformComponentBase::typeKey: + case ContainerComponentBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t clipPropertyKey = 196; + static const uint16_t widthPropertyKey = 7; + static const uint16_t heightPropertyKey = 8; + static const uint16_t styleIdPropertyKey = 494; + static const uint16_t fractionalWidthPropertyKey = 706; + static const uint16_t fractionalHeightPropertyKey = 707; + +protected: + bool m_Clip = false; + float m_Width = 0.0f; + float m_Height = 0.0f; + uint32_t m_StyleId = -1; + float m_FractionalWidth = 1.0f; + float m_FractionalHeight = 1.0f; + +public: + inline bool clip() const { return m_Clip; } + void clip(bool value) + { + if (m_Clip == value) + { + return; + } + m_Clip = value; + clipChanged(); + } + + inline float width() const { return m_Width; } + void width(float value) + { + if (m_Width == value) + { + return; + } + m_Width = value; + widthChanged(); + } + + inline float height() const { return m_Height; } + void height(float value) + { + if (m_Height == value) + { + return; + } + m_Height = value; + heightChanged(); + } + + inline uint32_t styleId() const { return m_StyleId; } + void styleId(uint32_t value) + { + if (m_StyleId == value) + { + return; + } + m_StyleId = value; + styleIdChanged(); + } + + inline float fractionalWidth() const { return m_FractionalWidth; } + void fractionalWidth(float value) + { + if (m_FractionalWidth == value) + { + return; + } + m_FractionalWidth = value; + fractionalWidthChanged(); + } + + inline float fractionalHeight() const { return m_FractionalHeight; } + void fractionalHeight(float value) + { + if (m_FractionalHeight == value) + { + return; + } + m_FractionalHeight = value; + fractionalHeightChanged(); + } + + Core* clone() const override; + void copy(const LayoutComponentBase& object) + { + m_Clip = object.m_Clip; + m_Width = object.m_Width; + m_Height = object.m_Height; + m_StyleId = object.m_StyleId; + m_FractionalWidth = object.m_FractionalWidth; + m_FractionalHeight = object.m_FractionalHeight; + Drawable::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case clipPropertyKey: + m_Clip = CoreBoolType::deserialize(reader); + return true; + case widthPropertyKey: + m_Width = CoreDoubleType::deserialize(reader); + return true; + case heightPropertyKey: + m_Height = CoreDoubleType::deserialize(reader); + return true; + case styleIdPropertyKey: + m_StyleId = CoreUintType::deserialize(reader); + return true; + case fractionalWidthPropertyKey: + m_FractionalWidth = CoreDoubleType::deserialize(reader); + return true; + case fractionalHeightPropertyKey: + m_FractionalHeight = CoreDoubleType::deserialize(reader); + return true; + } + return Drawable::deserialize(propertyKey, reader); + } + +protected: + virtual void clipChanged() {} + virtual void widthChanged() {} + virtual void heightChanged() {} + virtual void styleIdChanged() {} + virtual void fractionalWidthChanged() {} + virtual void fractionalHeightChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/nested_animation_base.hpp b/third_party/rive/include/rive/generated/nested_animation_base.hpp new file mode 100644 index 0000000..40ece24 --- /dev/null +++ b/third_party/rive/include/rive/generated/nested_animation_base.hpp @@ -0,0 +1,71 @@ +#ifndef _RIVE_NESTED_ANIMATION_BASE_HPP_ +#define _RIVE_NESTED_ANIMATION_BASE_HPP_ +#include "rive/container_component.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +namespace rive +{ +class NestedAnimationBase : public ContainerComponent +{ +protected: + typedef ContainerComponent Super; + +public: + static const uint16_t typeKey = 93; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case NestedAnimationBase::typeKey: + case ContainerComponentBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t animationIdPropertyKey = 198; + +protected: + uint32_t m_AnimationId = -1; + +public: + inline uint32_t animationId() const { return m_AnimationId; } + void animationId(uint32_t value) + { + if (m_AnimationId == value) + { + return; + } + m_AnimationId = value; + animationIdChanged(); + } + + void copy(const NestedAnimationBase& object) + { + m_AnimationId = object.m_AnimationId; + ContainerComponent::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case animationIdPropertyKey: + m_AnimationId = CoreUintType::deserialize(reader); + return true; + } + return ContainerComponent::deserialize(propertyKey, reader); + } + +protected: + virtual void animationIdChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/nested_artboard_base.hpp b/third_party/rive/include/rive/generated/nested_artboard_base.hpp new file mode 100644 index 0000000..4b37dd8 --- /dev/null +++ b/third_party/rive/include/rive/generated/nested_artboard_base.hpp @@ -0,0 +1,87 @@ +#ifndef _RIVE_NESTED_ARTBOARD_BASE_HPP_ +#define _RIVE_NESTED_ARTBOARD_BASE_HPP_ +#include "rive/core/field_types/core_bytes_type.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +#include "rive/drawable.hpp" +#include "rive/span.hpp" +namespace rive +{ +class NestedArtboardBase : public Drawable +{ +protected: + typedef Drawable Super; + +public: + static const uint16_t typeKey = 92; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case NestedArtboardBase::typeKey: + case DrawableBase::typeKey: + case NodeBase::typeKey: + case TransformComponentBase::typeKey: + case WorldTransformComponentBase::typeKey: + case ContainerComponentBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t artboardIdPropertyKey = 197; + static const uint16_t dataBindPathIdsPropertyKey = 582; + +protected: + uint32_t m_ArtboardId = -1; + +public: + inline uint32_t artboardId() const { return m_ArtboardId; } + void artboardId(uint32_t value) + { + if (m_ArtboardId == value) + { + return; + } + m_ArtboardId = value; + artboardIdChanged(); + } + + virtual void decodeDataBindPathIds(Span value) = 0; + virtual void copyDataBindPathIds(const NestedArtboardBase& object) = 0; + + Core* clone() const override; + void copy(const NestedArtboardBase& object) + { + m_ArtboardId = object.m_ArtboardId; + copyDataBindPathIds(object); + Drawable::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case artboardIdPropertyKey: + m_ArtboardId = CoreUintType::deserialize(reader); + return true; + case dataBindPathIdsPropertyKey: + decodeDataBindPathIds(CoreBytesType::deserialize(reader)); + return true; + } + return Drawable::deserialize(propertyKey, reader); + } + +protected: + virtual void artboardIdChanged() {} + virtual void dataBindPathIdsChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/nested_artboard_layout_base.hpp b/third_party/rive/include/rive/generated/nested_artboard_layout_base.hpp new file mode 100644 index 0000000..a33eb6f --- /dev/null +++ b/third_party/rive/include/rive/generated/nested_artboard_layout_base.hpp @@ -0,0 +1,180 @@ +#ifndef _RIVE_NESTED_ARTBOARD_LAYOUT_BASE_HPP_ +#define _RIVE_NESTED_ARTBOARD_LAYOUT_BASE_HPP_ +#include "rive/core/field_types/core_double_type.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +#include "rive/nested_artboard.hpp" +namespace rive +{ +class NestedArtboardLayoutBase : public NestedArtboard +{ +protected: + typedef NestedArtboard Super; + +public: + static const uint16_t typeKey = 452; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case NestedArtboardLayoutBase::typeKey: + case NestedArtboardBase::typeKey: + case DrawableBase::typeKey: + case NodeBase::typeKey: + case TransformComponentBase::typeKey: + case WorldTransformComponentBase::typeKey: + case ContainerComponentBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t instanceWidthPropertyKey = 663; + static const uint16_t instanceHeightPropertyKey = 664; + static const uint16_t instanceWidthUnitsValuePropertyKey = 665; + static const uint16_t instanceHeightUnitsValuePropertyKey = 666; + static const uint16_t instanceWidthScaleTypePropertyKey = 667; + static const uint16_t instanceHeightScaleTypePropertyKey = 668; + +protected: + float m_InstanceWidth = -1.0f; + float m_InstanceHeight = -1.0f; + uint32_t m_InstanceWidthUnitsValue = 1; + uint32_t m_InstanceHeightUnitsValue = 1; + uint32_t m_InstanceWidthScaleType = 0; + uint32_t m_InstanceHeightScaleType = 0; + +public: + inline float instanceWidth() const { return m_InstanceWidth; } + void instanceWidth(float value) + { + if (m_InstanceWidth == value) + { + return; + } + m_InstanceWidth = value; + instanceWidthChanged(); + } + + inline float instanceHeight() const { return m_InstanceHeight; } + void instanceHeight(float value) + { + if (m_InstanceHeight == value) + { + return; + } + m_InstanceHeight = value; + instanceHeightChanged(); + } + + inline uint32_t instanceWidthUnitsValue() const + { + return m_InstanceWidthUnitsValue; + } + void instanceWidthUnitsValue(uint32_t value) + { + if (m_InstanceWidthUnitsValue == value) + { + return; + } + m_InstanceWidthUnitsValue = value; + instanceWidthUnitsValueChanged(); + } + + inline uint32_t instanceHeightUnitsValue() const + { + return m_InstanceHeightUnitsValue; + } + void instanceHeightUnitsValue(uint32_t value) + { + if (m_InstanceHeightUnitsValue == value) + { + return; + } + m_InstanceHeightUnitsValue = value; + instanceHeightUnitsValueChanged(); + } + + inline uint32_t instanceWidthScaleType() const + { + return m_InstanceWidthScaleType; + } + void instanceWidthScaleType(uint32_t value) + { + if (m_InstanceWidthScaleType == value) + { + return; + } + m_InstanceWidthScaleType = value; + instanceWidthScaleTypeChanged(); + } + + inline uint32_t instanceHeightScaleType() const + { + return m_InstanceHeightScaleType; + } + void instanceHeightScaleType(uint32_t value) + { + if (m_InstanceHeightScaleType == value) + { + return; + } + m_InstanceHeightScaleType = value; + instanceHeightScaleTypeChanged(); + } + + Core* clone() const override; + void copy(const NestedArtboardLayoutBase& object) + { + m_InstanceWidth = object.m_InstanceWidth; + m_InstanceHeight = object.m_InstanceHeight; + m_InstanceWidthUnitsValue = object.m_InstanceWidthUnitsValue; + m_InstanceHeightUnitsValue = object.m_InstanceHeightUnitsValue; + m_InstanceWidthScaleType = object.m_InstanceWidthScaleType; + m_InstanceHeightScaleType = object.m_InstanceHeightScaleType; + NestedArtboard::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case instanceWidthPropertyKey: + m_InstanceWidth = CoreDoubleType::deserialize(reader); + return true; + case instanceHeightPropertyKey: + m_InstanceHeight = CoreDoubleType::deserialize(reader); + return true; + case instanceWidthUnitsValuePropertyKey: + m_InstanceWidthUnitsValue = CoreUintType::deserialize(reader); + return true; + case instanceHeightUnitsValuePropertyKey: + m_InstanceHeightUnitsValue = CoreUintType::deserialize(reader); + return true; + case instanceWidthScaleTypePropertyKey: + m_InstanceWidthScaleType = CoreUintType::deserialize(reader); + return true; + case instanceHeightScaleTypePropertyKey: + m_InstanceHeightScaleType = CoreUintType::deserialize(reader); + return true; + } + return NestedArtboard::deserialize(propertyKey, reader); + } + +protected: + virtual void instanceWidthChanged() {} + virtual void instanceHeightChanged() {} + virtual void instanceWidthUnitsValueChanged() {} + virtual void instanceHeightUnitsValueChanged() {} + virtual void instanceWidthScaleTypeChanged() {} + virtual void instanceHeightScaleTypeChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/nested_artboard_leaf_base.hpp b/third_party/rive/include/rive/generated/nested_artboard_leaf_base.hpp new file mode 100644 index 0000000..a7be843 --- /dev/null +++ b/third_party/rive/include/rive/generated/nested_artboard_leaf_base.hpp @@ -0,0 +1,114 @@ +#ifndef _RIVE_NESTED_ARTBOARD_LEAF_BASE_HPP_ +#define _RIVE_NESTED_ARTBOARD_LEAF_BASE_HPP_ +#include "rive/core/field_types/core_double_type.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +#include "rive/nested_artboard.hpp" +namespace rive +{ +class NestedArtboardLeafBase : public NestedArtboard +{ +protected: + typedef NestedArtboard Super; + +public: + static const uint16_t typeKey = 451; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case NestedArtboardLeafBase::typeKey: + case NestedArtboardBase::typeKey: + case DrawableBase::typeKey: + case NodeBase::typeKey: + case TransformComponentBase::typeKey: + case WorldTransformComponentBase::typeKey: + case ContainerComponentBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t fitPropertyKey = 538; + static const uint16_t alignmentXPropertyKey = 644; + static const uint16_t alignmentYPropertyKey = 645; + +protected: + uint32_t m_Fit = 0; + float m_AlignmentX = 0.0f; + float m_AlignmentY = 0.0f; + +public: + inline uint32_t fit() const { return m_Fit; } + void fit(uint32_t value) + { + if (m_Fit == value) + { + return; + } + m_Fit = value; + fitChanged(); + } + + inline float alignmentX() const { return m_AlignmentX; } + void alignmentX(float value) + { + if (m_AlignmentX == value) + { + return; + } + m_AlignmentX = value; + alignmentXChanged(); + } + + inline float alignmentY() const { return m_AlignmentY; } + void alignmentY(float value) + { + if (m_AlignmentY == value) + { + return; + } + m_AlignmentY = value; + alignmentYChanged(); + } + + Core* clone() const override; + void copy(const NestedArtboardLeafBase& object) + { + m_Fit = object.m_Fit; + m_AlignmentX = object.m_AlignmentX; + m_AlignmentY = object.m_AlignmentY; + NestedArtboard::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case fitPropertyKey: + m_Fit = CoreUintType::deserialize(reader); + return true; + case alignmentXPropertyKey: + m_AlignmentX = CoreDoubleType::deserialize(reader); + return true; + case alignmentYPropertyKey: + m_AlignmentY = CoreDoubleType::deserialize(reader); + return true; + } + return NestedArtboard::deserialize(propertyKey, reader); + } + +protected: + virtual void fitChanged() {} + virtual void alignmentXChanged() {} + virtual void alignmentYChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/node_base.hpp b/third_party/rive/include/rive/generated/node_base.hpp new file mode 100644 index 0000000..64db1ce --- /dev/null +++ b/third_party/rive/include/rive/generated/node_base.hpp @@ -0,0 +1,178 @@ +#ifndef _RIVE_NODE_BASE_HPP_ +#define _RIVE_NODE_BASE_HPP_ +#include "rive/core/field_types/core_double_type.hpp" +#include "rive/transform_component.hpp" +namespace rive +{ +class NodeBase : public TransformComponent +{ +protected: + typedef TransformComponent Super; + +public: + static const uint16_t typeKey = 2; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case NodeBase::typeKey: + case TransformComponentBase::typeKey: + case WorldTransformComponentBase::typeKey: + case ContainerComponentBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t xPropertyKey = 13; + static const uint16_t xArtboardPropertyKey = 9; + static const uint16_t yPropertyKey = 14; + static const uint16_t yArtboardPropertyKey = 10; + static const uint16_t computedLocalXPropertyKey = 806; + static const uint16_t computedLocalYPropertyKey = 807; + static const uint16_t computedWorldXPropertyKey = 808; + static const uint16_t computedWorldYPropertyKey = 809; + static const uint16_t computedWidthPropertyKey = 810; + static const uint16_t computedHeightPropertyKey = 811; + +protected: + float m_X = 0.0f; + float m_Y = 0.0f; + +public: + inline float x() const override { return m_X; } + void x(float value) + { + if (m_X == value) + { + return; + } + m_X = value; + xChanged(); + } + + inline float y() const override { return m_Y; } + void y(float value) + { + if (m_Y == value) + { + return; + } + m_Y = value; + yChanged(); + } + + virtual void setComputedLocalX(float value) = 0; + virtual float computedLocalX() = 0; + void computedLocalX(float value) + { + if (computedLocalX() == value) + { + return; + } + setComputedLocalX(value); + computedLocalXChanged(); + } + + virtual void setComputedLocalY(float value) = 0; + virtual float computedLocalY() = 0; + void computedLocalY(float value) + { + if (computedLocalY() == value) + { + return; + } + setComputedLocalY(value); + computedLocalYChanged(); + } + + virtual void setComputedWorldX(float value) = 0; + virtual float computedWorldX() = 0; + void computedWorldX(float value) + { + if (computedWorldX() == value) + { + return; + } + setComputedWorldX(value); + computedWorldXChanged(); + } + + virtual void setComputedWorldY(float value) = 0; + virtual float computedWorldY() = 0; + void computedWorldY(float value) + { + if (computedWorldY() == value) + { + return; + } + setComputedWorldY(value); + computedWorldYChanged(); + } + + virtual void setComputedWidth(float value) = 0; + virtual float computedWidth() = 0; + void computedWidth(float value) + { + if (computedWidth() == value) + { + return; + } + setComputedWidth(value); + computedWidthChanged(); + } + + virtual void setComputedHeight(float value) = 0; + virtual float computedHeight() = 0; + void computedHeight(float value) + { + if (computedHeight() == value) + { + return; + } + setComputedHeight(value); + computedHeightChanged(); + } + + Core* clone() const override; + void copy(const NodeBase& object) + { + m_X = object.m_X; + m_Y = object.m_Y; + TransformComponent::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case xPropertyKey: + m_X = CoreDoubleType::deserialize(reader); + return true; + case yPropertyKey: + m_Y = CoreDoubleType::deserialize(reader); + return true; + } + return TransformComponent::deserialize(propertyKey, reader); + } + +protected: + virtual void xChanged() {} + virtual void yChanged() {} + virtual void computedLocalXChanged() {} + virtual void computedLocalYChanged() {} + virtual void computedWorldXChanged() {} + virtual void computedWorldYChanged() {} + virtual void computedWidthChanged() {} + virtual void computedHeightChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/open_url_event_base.hpp b/third_party/rive/include/rive/generated/open_url_event_base.hpp new file mode 100644 index 0000000..11eac04 --- /dev/null +++ b/third_party/rive/include/rive/generated/open_url_event_base.hpp @@ -0,0 +1,94 @@ +#ifndef _RIVE_OPEN_URL_EVENT_BASE_HPP_ +#define _RIVE_OPEN_URL_EVENT_BASE_HPP_ +#include +#include "rive/core/field_types/core_string_type.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +#include "rive/event.hpp" +namespace rive +{ +class OpenUrlEventBase : public Event +{ +protected: + typedef Event Super; + +public: + static const uint16_t typeKey = 131; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case OpenUrlEventBase::typeKey: + case EventBase::typeKey: + case CustomPropertyGroupBase::typeKey: + case ContainerComponentBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t urlPropertyKey = 248; + static const uint16_t targetValuePropertyKey = 249; + +protected: + std::string m_Url = ""; + uint32_t m_TargetValue = 0; + +public: + inline const std::string& url() const { return m_Url; } + void url(std::string value) + { + if (m_Url == value) + { + return; + } + m_Url = value; + urlChanged(); + } + + inline uint32_t targetValue() const { return m_TargetValue; } + void targetValue(uint32_t value) + { + if (m_TargetValue == value) + { + return; + } + m_TargetValue = value; + targetValueChanged(); + } + + Core* clone() const override; + void copy(const OpenUrlEventBase& object) + { + m_Url = object.m_Url; + m_TargetValue = object.m_TargetValue; + Event::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case urlPropertyKey: + m_Url = CoreStringType::deserialize(reader); + return true; + case targetValuePropertyKey: + m_TargetValue = CoreUintType::deserialize(reader); + return true; + } + return Event::deserialize(propertyKey, reader); + } + +protected: + virtual void urlChanged() {} + virtual void targetValueChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/shapes/clipping_shape_base.hpp b/third_party/rive/include/rive/generated/shapes/clipping_shape_base.hpp new file mode 100644 index 0000000..b57e7fb --- /dev/null +++ b/third_party/rive/include/rive/generated/shapes/clipping_shape_base.hpp @@ -0,0 +1,108 @@ +#ifndef _RIVE_CLIPPING_SHAPE_BASE_HPP_ +#define _RIVE_CLIPPING_SHAPE_BASE_HPP_ +#include "rive/component.hpp" +#include "rive/core/field_types/core_bool_type.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +namespace rive +{ +class ClippingShapeBase : public Component +{ +protected: + typedef Component Super; + +public: + static const uint16_t typeKey = 42; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case ClippingShapeBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t sourceIdPropertyKey = 92; + static const uint16_t fillRulePropertyKey = 93; + static const uint16_t isVisiblePropertyKey = 94; + +protected: + uint32_t m_SourceId = -1; + uint32_t m_FillRule = 0; + bool m_IsVisible = true; + +public: + inline uint32_t sourceId() const { return m_SourceId; } + void sourceId(uint32_t value) + { + if (m_SourceId == value) + { + return; + } + m_SourceId = value; + sourceIdChanged(); + } + + inline uint32_t fillRule() const { return m_FillRule; } + void fillRule(uint32_t value) + { + if (m_FillRule == value) + { + return; + } + m_FillRule = value; + fillRuleChanged(); + } + + inline bool isVisible() const { return m_IsVisible; } + void isVisible(bool value) + { + if (m_IsVisible == value) + { + return; + } + m_IsVisible = value; + isVisibleChanged(); + } + + Core* clone() const override; + void copy(const ClippingShapeBase& object) + { + m_SourceId = object.m_SourceId; + m_FillRule = object.m_FillRule; + m_IsVisible = object.m_IsVisible; + Component::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case sourceIdPropertyKey: + m_SourceId = CoreUintType::deserialize(reader); + return true; + case fillRulePropertyKey: + m_FillRule = CoreUintType::deserialize(reader); + return true; + case isVisiblePropertyKey: + m_IsVisible = CoreBoolType::deserialize(reader); + return true; + } + return Component::deserialize(propertyKey, reader); + } + +protected: + virtual void sourceIdChanged() {} + virtual void fillRuleChanged() {} + virtual void isVisibleChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/shapes/contour_mesh_vertex_base.hpp b/third_party/rive/include/rive/generated/shapes/contour_mesh_vertex_base.hpp new file mode 100644 index 0000000..3af5130 --- /dev/null +++ b/third_party/rive/include/rive/generated/shapes/contour_mesh_vertex_base.hpp @@ -0,0 +1,39 @@ +#ifndef _RIVE_CONTOUR_MESH_VERTEX_BASE_HPP_ +#define _RIVE_CONTOUR_MESH_VERTEX_BASE_HPP_ +#include "rive/shapes/mesh_vertex.hpp" +namespace rive +{ +class ContourMeshVertexBase : public MeshVertex +{ +protected: + typedef MeshVertex Super; + +public: + static const uint16_t typeKey = 111; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case ContourMeshVertexBase::typeKey: + case MeshVertexBase::typeKey: + case VertexBase::typeKey: + case ContainerComponentBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/shapes/cubic_asymmetric_vertex_base.hpp b/third_party/rive/include/rive/generated/shapes/cubic_asymmetric_vertex_base.hpp new file mode 100644 index 0000000..cc1d059 --- /dev/null +++ b/third_party/rive/include/rive/generated/shapes/cubic_asymmetric_vertex_base.hpp @@ -0,0 +1,111 @@ +#ifndef _RIVE_CUBIC_ASYMMETRIC_VERTEX_BASE_HPP_ +#define _RIVE_CUBIC_ASYMMETRIC_VERTEX_BASE_HPP_ +#include "rive/core/field_types/core_double_type.hpp" +#include "rive/shapes/cubic_vertex.hpp" +namespace rive +{ +class CubicAsymmetricVertexBase : public CubicVertex +{ +protected: + typedef CubicVertex Super; + +public: + static const uint16_t typeKey = 34; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case CubicAsymmetricVertexBase::typeKey: + case CubicVertexBase::typeKey: + case PathVertexBase::typeKey: + case VertexBase::typeKey: + case ContainerComponentBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t rotationPropertyKey = 79; + static const uint16_t inDistancePropertyKey = 80; + static const uint16_t outDistancePropertyKey = 81; + +protected: + float m_Rotation = 0.0f; + float m_InDistance = 0.0f; + float m_OutDistance = 0.0f; + +public: + inline float rotation() const { return m_Rotation; } + void rotation(float value) + { + if (m_Rotation == value) + { + return; + } + m_Rotation = value; + rotationChanged(); + } + + inline float inDistance() const { return m_InDistance; } + void inDistance(float value) + { + if (m_InDistance == value) + { + return; + } + m_InDistance = value; + inDistanceChanged(); + } + + inline float outDistance() const { return m_OutDistance; } + void outDistance(float value) + { + if (m_OutDistance == value) + { + return; + } + m_OutDistance = value; + outDistanceChanged(); + } + + Core* clone() const override; + void copy(const CubicAsymmetricVertexBase& object) + { + m_Rotation = object.m_Rotation; + m_InDistance = object.m_InDistance; + m_OutDistance = object.m_OutDistance; + CubicVertex::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case rotationPropertyKey: + m_Rotation = CoreDoubleType::deserialize(reader); + return true; + case inDistancePropertyKey: + m_InDistance = CoreDoubleType::deserialize(reader); + return true; + case outDistancePropertyKey: + m_OutDistance = CoreDoubleType::deserialize(reader); + return true; + } + return CubicVertex::deserialize(propertyKey, reader); + } + +protected: + virtual void rotationChanged() {} + virtual void inDistanceChanged() {} + virtual void outDistanceChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/shapes/cubic_detached_vertex_base.hpp b/third_party/rive/include/rive/generated/shapes/cubic_detached_vertex_base.hpp new file mode 100644 index 0000000..14555cb --- /dev/null +++ b/third_party/rive/include/rive/generated/shapes/cubic_detached_vertex_base.hpp @@ -0,0 +1,129 @@ +#ifndef _RIVE_CUBIC_DETACHED_VERTEX_BASE_HPP_ +#define _RIVE_CUBIC_DETACHED_VERTEX_BASE_HPP_ +#include "rive/core/field_types/core_double_type.hpp" +#include "rive/shapes/cubic_vertex.hpp" +namespace rive +{ +class CubicDetachedVertexBase : public CubicVertex +{ +protected: + typedef CubicVertex Super; + +public: + static const uint16_t typeKey = 6; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case CubicDetachedVertexBase::typeKey: + case CubicVertexBase::typeKey: + case PathVertexBase::typeKey: + case VertexBase::typeKey: + case ContainerComponentBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t inRotationPropertyKey = 84; + static const uint16_t inDistancePropertyKey = 85; + static const uint16_t outRotationPropertyKey = 86; + static const uint16_t outDistancePropertyKey = 87; + +protected: + float m_InRotation = 0.0f; + float m_InDistance = 0.0f; + float m_OutRotation = 0.0f; + float m_OutDistance = 0.0f; + +public: + inline float inRotation() const { return m_InRotation; } + void inRotation(float value) + { + if (m_InRotation == value) + { + return; + } + m_InRotation = value; + inRotationChanged(); + } + + inline float inDistance() const { return m_InDistance; } + void inDistance(float value) + { + if (m_InDistance == value) + { + return; + } + m_InDistance = value; + inDistanceChanged(); + } + + inline float outRotation() const { return m_OutRotation; } + void outRotation(float value) + { + if (m_OutRotation == value) + { + return; + } + m_OutRotation = value; + outRotationChanged(); + } + + inline float outDistance() const { return m_OutDistance; } + void outDistance(float value) + { + if (m_OutDistance == value) + { + return; + } + m_OutDistance = value; + outDistanceChanged(); + } + + Core* clone() const override; + void copy(const CubicDetachedVertexBase& object) + { + m_InRotation = object.m_InRotation; + m_InDistance = object.m_InDistance; + m_OutRotation = object.m_OutRotation; + m_OutDistance = object.m_OutDistance; + CubicVertex::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case inRotationPropertyKey: + m_InRotation = CoreDoubleType::deserialize(reader); + return true; + case inDistancePropertyKey: + m_InDistance = CoreDoubleType::deserialize(reader); + return true; + case outRotationPropertyKey: + m_OutRotation = CoreDoubleType::deserialize(reader); + return true; + case outDistancePropertyKey: + m_OutDistance = CoreDoubleType::deserialize(reader); + return true; + } + return CubicVertex::deserialize(propertyKey, reader); + } + +protected: + virtual void inRotationChanged() {} + virtual void inDistanceChanged() {} + virtual void outRotationChanged() {} + virtual void outDistanceChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/shapes/cubic_mirrored_vertex_base.hpp b/third_party/rive/include/rive/generated/shapes/cubic_mirrored_vertex_base.hpp new file mode 100644 index 0000000..7bcf5af --- /dev/null +++ b/third_party/rive/include/rive/generated/shapes/cubic_mirrored_vertex_base.hpp @@ -0,0 +1,93 @@ +#ifndef _RIVE_CUBIC_MIRRORED_VERTEX_BASE_HPP_ +#define _RIVE_CUBIC_MIRRORED_VERTEX_BASE_HPP_ +#include "rive/core/field_types/core_double_type.hpp" +#include "rive/shapes/cubic_vertex.hpp" +namespace rive +{ +class CubicMirroredVertexBase : public CubicVertex +{ +protected: + typedef CubicVertex Super; + +public: + static const uint16_t typeKey = 35; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case CubicMirroredVertexBase::typeKey: + case CubicVertexBase::typeKey: + case PathVertexBase::typeKey: + case VertexBase::typeKey: + case ContainerComponentBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t rotationPropertyKey = 82; + static const uint16_t distancePropertyKey = 83; + +protected: + float m_Rotation = 0.0f; + float m_Distance = 0.0f; + +public: + inline float rotation() const { return m_Rotation; } + void rotation(float value) + { + if (m_Rotation == value) + { + return; + } + m_Rotation = value; + rotationChanged(); + } + + inline float distance() const { return m_Distance; } + void distance(float value) + { + if (m_Distance == value) + { + return; + } + m_Distance = value; + distanceChanged(); + } + + Core* clone() const override; + void copy(const CubicMirroredVertexBase& object) + { + m_Rotation = object.m_Rotation; + m_Distance = object.m_Distance; + CubicVertex::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case rotationPropertyKey: + m_Rotation = CoreDoubleType::deserialize(reader); + return true; + case distancePropertyKey: + m_Distance = CoreDoubleType::deserialize(reader); + return true; + } + return CubicVertex::deserialize(propertyKey, reader); + } + +protected: + virtual void rotationChanged() {} + virtual void distanceChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/shapes/cubic_vertex_base.hpp b/third_party/rive/include/rive/generated/shapes/cubic_vertex_base.hpp new file mode 100644 index 0000000..9d16f9a --- /dev/null +++ b/third_party/rive/include/rive/generated/shapes/cubic_vertex_base.hpp @@ -0,0 +1,37 @@ +#ifndef _RIVE_CUBIC_VERTEX_BASE_HPP_ +#define _RIVE_CUBIC_VERTEX_BASE_HPP_ +#include "rive/shapes/path_vertex.hpp" +namespace rive +{ +class CubicVertexBase : public PathVertex +{ +protected: + typedef PathVertex Super; + +public: + static const uint16_t typeKey = 36; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case CubicVertexBase::typeKey: + case PathVertexBase::typeKey: + case VertexBase::typeKey: + case ContainerComponentBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/shapes/ellipse_base.hpp b/third_party/rive/include/rive/generated/shapes/ellipse_base.hpp new file mode 100644 index 0000000..2d816aa --- /dev/null +++ b/third_party/rive/include/rive/generated/shapes/ellipse_base.hpp @@ -0,0 +1,42 @@ +#ifndef _RIVE_ELLIPSE_BASE_HPP_ +#define _RIVE_ELLIPSE_BASE_HPP_ +#include "rive/shapes/parametric_path.hpp" +namespace rive +{ +class EllipseBase : public ParametricPath +{ +protected: + typedef ParametricPath Super; + +public: + static const uint16_t typeKey = 4; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case EllipseBase::typeKey: + case ParametricPathBase::typeKey: + case PathBase::typeKey: + case NodeBase::typeKey: + case TransformComponentBase::typeKey: + case WorldTransformComponentBase::typeKey: + case ContainerComponentBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/shapes/image_base.hpp b/third_party/rive/include/rive/generated/shapes/image_base.hpp new file mode 100644 index 0000000..05b85f9 --- /dev/null +++ b/third_party/rive/include/rive/generated/shapes/image_base.hpp @@ -0,0 +1,113 @@ +#ifndef _RIVE_IMAGE_BASE_HPP_ +#define _RIVE_IMAGE_BASE_HPP_ +#include "rive/core/field_types/core_double_type.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +#include "rive/drawable.hpp" +namespace rive +{ +class ImageBase : public Drawable +{ +protected: + typedef Drawable Super; + +public: + static const uint16_t typeKey = 100; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case ImageBase::typeKey: + case DrawableBase::typeKey: + case NodeBase::typeKey: + case TransformComponentBase::typeKey: + case WorldTransformComponentBase::typeKey: + case ContainerComponentBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t assetIdPropertyKey = 206; + static const uint16_t originXPropertyKey = 380; + static const uint16_t originYPropertyKey = 381; + +protected: + uint32_t m_AssetId = -1; + float m_OriginX = 0.5f; + float m_OriginY = 0.5f; + +public: + inline uint32_t assetId() const { return m_AssetId; } + void assetId(uint32_t value) + { + if (m_AssetId == value) + { + return; + } + m_AssetId = value; + assetIdChanged(); + } + + inline float originX() const { return m_OriginX; } + void originX(float value) + { + if (m_OriginX == value) + { + return; + } + m_OriginX = value; + originXChanged(); + } + + inline float originY() const { return m_OriginY; } + void originY(float value) + { + if (m_OriginY == value) + { + return; + } + m_OriginY = value; + originYChanged(); + } + + Core* clone() const override; + void copy(const ImageBase& object) + { + m_AssetId = object.m_AssetId; + m_OriginX = object.m_OriginX; + m_OriginY = object.m_OriginY; + Drawable::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case assetIdPropertyKey: + m_AssetId = CoreUintType::deserialize(reader); + return true; + case originXPropertyKey: + m_OriginX = CoreDoubleType::deserialize(reader); + return true; + case originYPropertyKey: + m_OriginY = CoreDoubleType::deserialize(reader); + return true; + } + return Drawable::deserialize(propertyKey, reader); + } + +protected: + virtual void assetIdChanged() {} + virtual void originXChanged() {} + virtual void originYChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/shapes/mesh_base.hpp b/third_party/rive/include/rive/generated/shapes/mesh_base.hpp new file mode 100644 index 0000000..0ac5399 --- /dev/null +++ b/third_party/rive/include/rive/generated/shapes/mesh_base.hpp @@ -0,0 +1,62 @@ +#ifndef _RIVE_MESH_BASE_HPP_ +#define _RIVE_MESH_BASE_HPP_ +#include "rive/container_component.hpp" +#include "rive/core/field_types/core_bytes_type.hpp" +#include "rive/span.hpp" +namespace rive +{ +class MeshBase : public ContainerComponent +{ +protected: + typedef ContainerComponent Super; + +public: + static const uint16_t typeKey = 109; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case MeshBase::typeKey: + case ContainerComponentBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t triangleIndexBytesPropertyKey = 223; + +public: + virtual void decodeTriangleIndexBytes(Span value) = 0; + virtual void copyTriangleIndexBytes(const MeshBase& object) = 0; + + Core* clone() const override; + void copy(const MeshBase& object) + { + copyTriangleIndexBytes(object); + ContainerComponent::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case triangleIndexBytesPropertyKey: + decodeTriangleIndexBytes(CoreBytesType::deserialize(reader)); + return true; + } + return ContainerComponent::deserialize(propertyKey, reader); + } + +protected: + virtual void triangleIndexBytesChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/shapes/mesh_vertex_base.hpp b/third_party/rive/include/rive/generated/shapes/mesh_vertex_base.hpp new file mode 100644 index 0000000..ff53419 --- /dev/null +++ b/third_party/rive/include/rive/generated/shapes/mesh_vertex_base.hpp @@ -0,0 +1,91 @@ +#ifndef _RIVE_MESH_VERTEX_BASE_HPP_ +#define _RIVE_MESH_VERTEX_BASE_HPP_ +#include "rive/core/field_types/core_double_type.hpp" +#include "rive/shapes/vertex.hpp" +namespace rive +{ +class MeshVertexBase : public Vertex +{ +protected: + typedef Vertex Super; + +public: + static const uint16_t typeKey = 108; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case MeshVertexBase::typeKey: + case VertexBase::typeKey: + case ContainerComponentBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t uPropertyKey = 215; + static const uint16_t vPropertyKey = 216; + +protected: + float m_U = 0.0f; + float m_V = 0.0f; + +public: + inline float u() const { return m_U; } + void u(float value) + { + if (m_U == value) + { + return; + } + m_U = value; + uChanged(); + } + + inline float v() const { return m_V; } + void v(float value) + { + if (m_V == value) + { + return; + } + m_V = value; + vChanged(); + } + + Core* clone() const override; + void copy(const MeshVertexBase& object) + { + m_U = object.m_U; + m_V = object.m_V; + Vertex::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case uPropertyKey: + m_U = CoreDoubleType::deserialize(reader); + return true; + case vPropertyKey: + m_V = CoreDoubleType::deserialize(reader); + return true; + } + return Vertex::deserialize(propertyKey, reader); + } + +protected: + virtual void uChanged() {} + virtual void vChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/shapes/paint/dash_base.hpp b/third_party/rive/include/rive/generated/shapes/paint/dash_base.hpp new file mode 100644 index 0000000..ce8b324 --- /dev/null +++ b/third_party/rive/include/rive/generated/shapes/paint/dash_base.hpp @@ -0,0 +1,90 @@ +#ifndef _RIVE_DASH_BASE_HPP_ +#define _RIVE_DASH_BASE_HPP_ +#include "rive/component.hpp" +#include "rive/core/field_types/core_bool_type.hpp" +#include "rive/core/field_types/core_double_type.hpp" +namespace rive +{ +class DashBase : public Component +{ +protected: + typedef Component Super; + +public: + static const uint16_t typeKey = 507; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case DashBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t lengthPropertyKey = 692; + static const uint16_t lengthIsPercentagePropertyKey = 693; + +protected: + float m_Length = 0.0f; + bool m_LengthIsPercentage = false; + +public: + inline float length() const { return m_Length; } + void length(float value) + { + if (m_Length == value) + { + return; + } + m_Length = value; + lengthChanged(); + } + + inline bool lengthIsPercentage() const { return m_LengthIsPercentage; } + void lengthIsPercentage(bool value) + { + if (m_LengthIsPercentage == value) + { + return; + } + m_LengthIsPercentage = value; + lengthIsPercentageChanged(); + } + + Core* clone() const override; + void copy(const DashBase& object) + { + m_Length = object.m_Length; + m_LengthIsPercentage = object.m_LengthIsPercentage; + Component::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case lengthPropertyKey: + m_Length = CoreDoubleType::deserialize(reader); + return true; + case lengthIsPercentagePropertyKey: + m_LengthIsPercentage = CoreBoolType::deserialize(reader); + return true; + } + return Component::deserialize(propertyKey, reader); + } + +protected: + virtual void lengthChanged() {} + virtual void lengthIsPercentageChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/shapes/paint/dash_path_base.hpp b/third_party/rive/include/rive/generated/shapes/paint/dash_path_base.hpp new file mode 100644 index 0000000..9d14422 --- /dev/null +++ b/third_party/rive/include/rive/generated/shapes/paint/dash_path_base.hpp @@ -0,0 +1,91 @@ +#ifndef _RIVE_DASH_PATH_BASE_HPP_ +#define _RIVE_DASH_PATH_BASE_HPP_ +#include "rive/container_component.hpp" +#include "rive/core/field_types/core_bool_type.hpp" +#include "rive/core/field_types/core_double_type.hpp" +namespace rive +{ +class DashPathBase : public ContainerComponent +{ +protected: + typedef ContainerComponent Super; + +public: + static const uint16_t typeKey = 506; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case DashPathBase::typeKey: + case ContainerComponentBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t offsetPropertyKey = 690; + static const uint16_t offsetIsPercentagePropertyKey = 691; + +protected: + float m_Offset = 0.0f; + bool m_OffsetIsPercentage = false; + +public: + inline float offset() const { return m_Offset; } + void offset(float value) + { + if (m_Offset == value) + { + return; + } + m_Offset = value; + offsetChanged(); + } + + inline bool offsetIsPercentage() const { return m_OffsetIsPercentage; } + void offsetIsPercentage(bool value) + { + if (m_OffsetIsPercentage == value) + { + return; + } + m_OffsetIsPercentage = value; + offsetIsPercentageChanged(); + } + + Core* clone() const override; + void copy(const DashPathBase& object) + { + m_Offset = object.m_Offset; + m_OffsetIsPercentage = object.m_OffsetIsPercentage; + ContainerComponent::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case offsetPropertyKey: + m_Offset = CoreDoubleType::deserialize(reader); + return true; + case offsetIsPercentagePropertyKey: + m_OffsetIsPercentage = CoreBoolType::deserialize(reader); + return true; + } + return ContainerComponent::deserialize(propertyKey, reader); + } + +protected: + virtual void offsetChanged() {} + virtual void offsetIsPercentageChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/shapes/paint/feather_base.hpp b/third_party/rive/include/rive/generated/shapes/paint/feather_base.hpp new file mode 100644 index 0000000..2daeb55 --- /dev/null +++ b/third_party/rive/include/rive/generated/shapes/paint/feather_base.hpp @@ -0,0 +1,146 @@ +#ifndef _RIVE_FEATHER_BASE_HPP_ +#define _RIVE_FEATHER_BASE_HPP_ +#include "rive/container_component.hpp" +#include "rive/core/field_types/core_bool_type.hpp" +#include "rive/core/field_types/core_double_type.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +namespace rive +{ +class FeatherBase : public ContainerComponent +{ +protected: + typedef ContainerComponent Super; + +public: + static const uint16_t typeKey = 533; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case FeatherBase::typeKey: + case ContainerComponentBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t spaceValuePropertyKey = 748; + static const uint16_t strengthPropertyKey = 749; + static const uint16_t offsetXPropertyKey = 750; + static const uint16_t offsetYPropertyKey = 751; + static const uint16_t innerPropertyKey = 752; + +protected: + uint32_t m_SpaceValue = 0; + float m_Strength = 12.0f; + float m_OffsetX = 0.0f; + float m_OffsetY = 0.0f; + bool m_Inner = false; + +public: + inline uint32_t spaceValue() const { return m_SpaceValue; } + void spaceValue(uint32_t value) + { + if (m_SpaceValue == value) + { + return; + } + m_SpaceValue = value; + spaceValueChanged(); + } + + inline float strength() const { return m_Strength; } + void strength(float value) + { + if (m_Strength == value) + { + return; + } + m_Strength = value; + strengthChanged(); + } + + inline float offsetX() const { return m_OffsetX; } + void offsetX(float value) + { + if (m_OffsetX == value) + { + return; + } + m_OffsetX = value; + offsetXChanged(); + } + + inline float offsetY() const { return m_OffsetY; } + void offsetY(float value) + { + if (m_OffsetY == value) + { + return; + } + m_OffsetY = value; + offsetYChanged(); + } + + inline bool inner() const { return m_Inner; } + void inner(bool value) + { + if (m_Inner == value) + { + return; + } + m_Inner = value; + innerChanged(); + } + + Core* clone() const override; + void copy(const FeatherBase& object) + { + m_SpaceValue = object.m_SpaceValue; + m_Strength = object.m_Strength; + m_OffsetX = object.m_OffsetX; + m_OffsetY = object.m_OffsetY; + m_Inner = object.m_Inner; + ContainerComponent::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case spaceValuePropertyKey: + m_SpaceValue = CoreUintType::deserialize(reader); + return true; + case strengthPropertyKey: + m_Strength = CoreDoubleType::deserialize(reader); + return true; + case offsetXPropertyKey: + m_OffsetX = CoreDoubleType::deserialize(reader); + return true; + case offsetYPropertyKey: + m_OffsetY = CoreDoubleType::deserialize(reader); + return true; + case innerPropertyKey: + m_Inner = CoreBoolType::deserialize(reader); + return true; + } + return ContainerComponent::deserialize(propertyKey, reader); + } + +protected: + virtual void spaceValueChanged() {} + virtual void strengthChanged() {} + virtual void offsetXChanged() {} + virtual void offsetYChanged() {} + virtual void innerChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/shapes/paint/fill_base.hpp b/third_party/rive/include/rive/generated/shapes/paint/fill_base.hpp new file mode 100644 index 0000000..38e83ac --- /dev/null +++ b/third_party/rive/include/rive/generated/shapes/paint/fill_base.hpp @@ -0,0 +1,73 @@ +#ifndef _RIVE_FILL_BASE_HPP_ +#define _RIVE_FILL_BASE_HPP_ +#include "rive/core/field_types/core_uint_type.hpp" +#include "rive/shapes/paint/shape_paint.hpp" +namespace rive +{ +class FillBase : public ShapePaint +{ +protected: + typedef ShapePaint Super; + +public: + static const uint16_t typeKey = 20; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case FillBase::typeKey: + case ShapePaintBase::typeKey: + case ContainerComponentBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t fillRulePropertyKey = 40; + +protected: + uint32_t m_FillRule = 0; + +public: + inline uint32_t fillRule() const { return m_FillRule; } + void fillRule(uint32_t value) + { + if (m_FillRule == value) + { + return; + } + m_FillRule = value; + fillRuleChanged(); + } + + Core* clone() const override; + void copy(const FillBase& object) + { + m_FillRule = object.m_FillRule; + ShapePaint::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case fillRulePropertyKey: + m_FillRule = CoreUintType::deserialize(reader); + return true; + } + return ShapePaint::deserialize(propertyKey, reader); + } + +protected: + virtual void fillRuleChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/shapes/paint/gradient_stop_base.hpp b/third_party/rive/include/rive/generated/shapes/paint/gradient_stop_base.hpp new file mode 100644 index 0000000..99f7d2f --- /dev/null +++ b/third_party/rive/include/rive/generated/shapes/paint/gradient_stop_base.hpp @@ -0,0 +1,90 @@ +#ifndef _RIVE_GRADIENT_STOP_BASE_HPP_ +#define _RIVE_GRADIENT_STOP_BASE_HPP_ +#include "rive/component.hpp" +#include "rive/core/field_types/core_color_type.hpp" +#include "rive/core/field_types/core_double_type.hpp" +namespace rive +{ +class GradientStopBase : public Component +{ +protected: + typedef Component Super; + +public: + static const uint16_t typeKey = 19; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case GradientStopBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t colorValuePropertyKey = 38; + static const uint16_t positionPropertyKey = 39; + +protected: + int m_ColorValue = 0xFFFFFFFF; + float m_Position = 0.0f; + +public: + inline int colorValue() const { return m_ColorValue; } + void colorValue(int value) + { + if (m_ColorValue == value) + { + return; + } + m_ColorValue = value; + colorValueChanged(); + } + + inline float position() const { return m_Position; } + void position(float value) + { + if (m_Position == value) + { + return; + } + m_Position = value; + positionChanged(); + } + + Core* clone() const override; + void copy(const GradientStopBase& object) + { + m_ColorValue = object.m_ColorValue; + m_Position = object.m_Position; + Component::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case colorValuePropertyKey: + m_ColorValue = CoreColorType::deserialize(reader); + return true; + case positionPropertyKey: + m_Position = CoreDoubleType::deserialize(reader); + return true; + } + return Component::deserialize(propertyKey, reader); + } + +protected: + virtual void colorValueChanged() {} + virtual void positionChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/shapes/paint/linear_gradient_base.hpp b/third_party/rive/include/rive/generated/shapes/paint/linear_gradient_base.hpp new file mode 100644 index 0000000..71042f1 --- /dev/null +++ b/third_party/rive/include/rive/generated/shapes/paint/linear_gradient_base.hpp @@ -0,0 +1,144 @@ +#ifndef _RIVE_LINEAR_GRADIENT_BASE_HPP_ +#define _RIVE_LINEAR_GRADIENT_BASE_HPP_ +#include "rive/container_component.hpp" +#include "rive/core/field_types/core_double_type.hpp" +namespace rive +{ +class LinearGradientBase : public ContainerComponent +{ +protected: + typedef ContainerComponent Super; + +public: + static const uint16_t typeKey = 22; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case LinearGradientBase::typeKey: + case ContainerComponentBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t startXPropertyKey = 42; + static const uint16_t startYPropertyKey = 33; + static const uint16_t endXPropertyKey = 34; + static const uint16_t endYPropertyKey = 35; + static const uint16_t opacityPropertyKey = 46; + +protected: + float m_StartX = 0.0f; + float m_StartY = 0.0f; + float m_EndX = 0.0f; + float m_EndY = 0.0f; + float m_Opacity = 1.0f; + +public: + inline float startX() const { return m_StartX; } + void startX(float value) + { + if (m_StartX == value) + { + return; + } + m_StartX = value; + startXChanged(); + } + + inline float startY() const { return m_StartY; } + void startY(float value) + { + if (m_StartY == value) + { + return; + } + m_StartY = value; + startYChanged(); + } + + inline float endX() const { return m_EndX; } + void endX(float value) + { + if (m_EndX == value) + { + return; + } + m_EndX = value; + endXChanged(); + } + + inline float endY() const { return m_EndY; } + void endY(float value) + { + if (m_EndY == value) + { + return; + } + m_EndY = value; + endYChanged(); + } + + inline float opacity() const { return m_Opacity; } + void opacity(float value) + { + if (m_Opacity == value) + { + return; + } + m_Opacity = value; + opacityChanged(); + } + + Core* clone() const override; + void copy(const LinearGradientBase& object) + { + m_StartX = object.m_StartX; + m_StartY = object.m_StartY; + m_EndX = object.m_EndX; + m_EndY = object.m_EndY; + m_Opacity = object.m_Opacity; + ContainerComponent::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case startXPropertyKey: + m_StartX = CoreDoubleType::deserialize(reader); + return true; + case startYPropertyKey: + m_StartY = CoreDoubleType::deserialize(reader); + return true; + case endXPropertyKey: + m_EndX = CoreDoubleType::deserialize(reader); + return true; + case endYPropertyKey: + m_EndY = CoreDoubleType::deserialize(reader); + return true; + case opacityPropertyKey: + m_Opacity = CoreDoubleType::deserialize(reader); + return true; + } + return ContainerComponent::deserialize(propertyKey, reader); + } + +protected: + virtual void startXChanged() {} + virtual void startYChanged() {} + virtual void endXChanged() {} + virtual void endYChanged() {} + virtual void opacityChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/shapes/paint/radial_gradient_base.hpp b/third_party/rive/include/rive/generated/shapes/paint/radial_gradient_base.hpp new file mode 100644 index 0000000..07e2a1c --- /dev/null +++ b/third_party/rive/include/rive/generated/shapes/paint/radial_gradient_base.hpp @@ -0,0 +1,38 @@ +#ifndef _RIVE_RADIAL_GRADIENT_BASE_HPP_ +#define _RIVE_RADIAL_GRADIENT_BASE_HPP_ +#include "rive/shapes/paint/linear_gradient.hpp" +namespace rive +{ +class RadialGradientBase : public LinearGradient +{ +protected: + typedef LinearGradient Super; + +public: + static const uint16_t typeKey = 17; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case RadialGradientBase::typeKey: + case LinearGradientBase::typeKey: + case ContainerComponentBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/shapes/paint/shape_paint_base.hpp b/third_party/rive/include/rive/generated/shapes/paint/shape_paint_base.hpp new file mode 100644 index 0000000..25796ba --- /dev/null +++ b/third_party/rive/include/rive/generated/shapes/paint/shape_paint_base.hpp @@ -0,0 +1,90 @@ +#ifndef _RIVE_SHAPE_PAINT_BASE_HPP_ +#define _RIVE_SHAPE_PAINT_BASE_HPP_ +#include "rive/container_component.hpp" +#include "rive/core/field_types/core_bool_type.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +namespace rive +{ +class ShapePaintBase : public ContainerComponent +{ +protected: + typedef ContainerComponent Super; + +public: + static const uint16_t typeKey = 21; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case ShapePaintBase::typeKey: + case ContainerComponentBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t isVisiblePropertyKey = 41; + static const uint16_t blendModeValuePropertyKey = 747; + +protected: + bool m_IsVisible = true; + uint32_t m_BlendModeValue = 127; + +public: + virtual bool isVisible() const { return m_IsVisible; } + void isVisible(bool value) + { + if (m_IsVisible == value) + { + return; + } + m_IsVisible = value; + isVisibleChanged(); + } + + inline uint32_t blendModeValue() const { return m_BlendModeValue; } + void blendModeValue(uint32_t value) + { + if (m_BlendModeValue == value) + { + return; + } + m_BlendModeValue = value; + blendModeValueChanged(); + } + + void copy(const ShapePaintBase& object) + { + m_IsVisible = object.m_IsVisible; + m_BlendModeValue = object.m_BlendModeValue; + ContainerComponent::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case isVisiblePropertyKey: + m_IsVisible = CoreBoolType::deserialize(reader); + return true; + case blendModeValuePropertyKey: + m_BlendModeValue = CoreUintType::deserialize(reader); + return true; + } + return ContainerComponent::deserialize(propertyKey, reader); + } + +protected: + virtual void isVisibleChanged() {} + virtual void blendModeValueChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/shapes/paint/solid_color_base.hpp b/third_party/rive/include/rive/generated/shapes/paint/solid_color_base.hpp new file mode 100644 index 0000000..a6acb23 --- /dev/null +++ b/third_party/rive/include/rive/generated/shapes/paint/solid_color_base.hpp @@ -0,0 +1,71 @@ +#ifndef _RIVE_SOLID_COLOR_BASE_HPP_ +#define _RIVE_SOLID_COLOR_BASE_HPP_ +#include "rive/component.hpp" +#include "rive/core/field_types/core_color_type.hpp" +namespace rive +{ +class SolidColorBase : public Component +{ +protected: + typedef Component Super; + +public: + static const uint16_t typeKey = 18; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case SolidColorBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t colorValuePropertyKey = 37; + +protected: + int m_ColorValue = 0xFF747474; + +public: + inline int colorValue() const { return m_ColorValue; } + void colorValue(int value) + { + if (m_ColorValue == value) + { + return; + } + m_ColorValue = value; + colorValueChanged(); + } + + Core* clone() const override; + void copy(const SolidColorBase& object) + { + m_ColorValue = object.m_ColorValue; + Component::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case colorValuePropertyKey: + m_ColorValue = CoreColorType::deserialize(reader); + return true; + } + return Component::deserialize(propertyKey, reader); + } + +protected: + virtual void colorValueChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/shapes/paint/stroke_base.hpp b/third_party/rive/include/rive/generated/shapes/paint/stroke_base.hpp new file mode 100644 index 0000000..4173868 --- /dev/null +++ b/third_party/rive/include/rive/generated/shapes/paint/stroke_base.hpp @@ -0,0 +1,132 @@ +#ifndef _RIVE_STROKE_BASE_HPP_ +#define _RIVE_STROKE_BASE_HPP_ +#include "rive/core/field_types/core_bool_type.hpp" +#include "rive/core/field_types/core_double_type.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +#include "rive/shapes/paint/shape_paint.hpp" +namespace rive +{ +class StrokeBase : public ShapePaint +{ +protected: + typedef ShapePaint Super; + +public: + static const uint16_t typeKey = 24; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case StrokeBase::typeKey: + case ShapePaintBase::typeKey: + case ContainerComponentBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t thicknessPropertyKey = 47; + static const uint16_t capPropertyKey = 48; + static const uint16_t joinPropertyKey = 49; + static const uint16_t transformAffectsStrokePropertyKey = 50; + +protected: + float m_Thickness = 1.0f; + uint32_t m_Cap = 0; + uint32_t m_Join = 0; + bool m_TransformAffectsStroke = true; + +public: + inline float thickness() const { return m_Thickness; } + void thickness(float value) + { + if (m_Thickness == value) + { + return; + } + m_Thickness = value; + thicknessChanged(); + } + + inline uint32_t cap() const { return m_Cap; } + void cap(uint32_t value) + { + if (m_Cap == value) + { + return; + } + m_Cap = value; + capChanged(); + } + + inline uint32_t join() const { return m_Join; } + void join(uint32_t value) + { + if (m_Join == value) + { + return; + } + m_Join = value; + joinChanged(); + } + + inline bool transformAffectsStroke() const + { + return m_TransformAffectsStroke; + } + void transformAffectsStroke(bool value) + { + if (m_TransformAffectsStroke == value) + { + return; + } + m_TransformAffectsStroke = value; + transformAffectsStrokeChanged(); + } + + Core* clone() const override; + void copy(const StrokeBase& object) + { + m_Thickness = object.m_Thickness; + m_Cap = object.m_Cap; + m_Join = object.m_Join; + m_TransformAffectsStroke = object.m_TransformAffectsStroke; + ShapePaint::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case thicknessPropertyKey: + m_Thickness = CoreDoubleType::deserialize(reader); + return true; + case capPropertyKey: + m_Cap = CoreUintType::deserialize(reader); + return true; + case joinPropertyKey: + m_Join = CoreUintType::deserialize(reader); + return true; + case transformAffectsStrokePropertyKey: + m_TransformAffectsStroke = CoreBoolType::deserialize(reader); + return true; + } + return ShapePaint::deserialize(propertyKey, reader); + } + +protected: + virtual void thicknessChanged() {} + virtual void capChanged() {} + virtual void joinChanged() {} + virtual void transformAffectsStrokeChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/shapes/paint/trim_path_base.hpp b/third_party/rive/include/rive/generated/shapes/paint/trim_path_base.hpp new file mode 100644 index 0000000..9c5a6eb --- /dev/null +++ b/third_party/rive/include/rive/generated/shapes/paint/trim_path_base.hpp @@ -0,0 +1,126 @@ +#ifndef _RIVE_TRIM_PATH_BASE_HPP_ +#define _RIVE_TRIM_PATH_BASE_HPP_ +#include "rive/component.hpp" +#include "rive/core/field_types/core_double_type.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +namespace rive +{ +class TrimPathBase : public Component +{ +protected: + typedef Component Super; + +public: + static const uint16_t typeKey = 47; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case TrimPathBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t startPropertyKey = 114; + static const uint16_t endPropertyKey = 115; + static const uint16_t offsetPropertyKey = 116; + static const uint16_t modeValuePropertyKey = 117; + +protected: + float m_Start = 0.0f; + float m_End = 0.0f; + float m_Offset = 0.0f; + uint32_t m_ModeValue = 0; + +public: + inline float start() const { return m_Start; } + void start(float value) + { + if (m_Start == value) + { + return; + } + m_Start = value; + startChanged(); + } + + inline float end() const { return m_End; } + void end(float value) + { + if (m_End == value) + { + return; + } + m_End = value; + endChanged(); + } + + inline float offset() const { return m_Offset; } + void offset(float value) + { + if (m_Offset == value) + { + return; + } + m_Offset = value; + offsetChanged(); + } + + inline uint32_t modeValue() const { return m_ModeValue; } + void modeValue(uint32_t value) + { + if (m_ModeValue == value) + { + return; + } + m_ModeValue = value; + modeValueChanged(); + } + + Core* clone() const override; + void copy(const TrimPathBase& object) + { + m_Start = object.m_Start; + m_End = object.m_End; + m_Offset = object.m_Offset; + m_ModeValue = object.m_ModeValue; + Component::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case startPropertyKey: + m_Start = CoreDoubleType::deserialize(reader); + return true; + case endPropertyKey: + m_End = CoreDoubleType::deserialize(reader); + return true; + case offsetPropertyKey: + m_Offset = CoreDoubleType::deserialize(reader); + return true; + case modeValuePropertyKey: + m_ModeValue = CoreUintType::deserialize(reader); + return true; + } + return Component::deserialize(propertyKey, reader); + } + +protected: + virtual void startChanged() {} + virtual void endChanged() {} + virtual void offsetChanged() {} + virtual void modeValueChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/shapes/parametric_path_base.hpp b/third_party/rive/include/rive/generated/shapes/parametric_path_base.hpp new file mode 100644 index 0000000..5b8e8f6 --- /dev/null +++ b/third_party/rive/include/rive/generated/shapes/parametric_path_base.hpp @@ -0,0 +1,129 @@ +#ifndef _RIVE_PARAMETRIC_PATH_BASE_HPP_ +#define _RIVE_PARAMETRIC_PATH_BASE_HPP_ +#include "rive/core/field_types/core_double_type.hpp" +#include "rive/shapes/path.hpp" +namespace rive +{ +class ParametricPathBase : public Path +{ +protected: + typedef Path Super; + +public: + static const uint16_t typeKey = 15; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case ParametricPathBase::typeKey: + case PathBase::typeKey: + case NodeBase::typeKey: + case TransformComponentBase::typeKey: + case WorldTransformComponentBase::typeKey: + case ContainerComponentBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t widthPropertyKey = 20; + static const uint16_t heightPropertyKey = 21; + static const uint16_t originXPropertyKey = 123; + static const uint16_t originYPropertyKey = 124; + +protected: + float m_Width = 0.0f; + float m_Height = 0.0f; + float m_OriginX = 0.5f; + float m_OriginY = 0.5f; + +public: + inline float width() const { return m_Width; } + void width(float value) + { + if (m_Width == value) + { + return; + } + m_Width = value; + widthChanged(); + } + + inline float height() const { return m_Height; } + void height(float value) + { + if (m_Height == value) + { + return; + } + m_Height = value; + heightChanged(); + } + + inline float originX() const { return m_OriginX; } + void originX(float value) + { + if (m_OriginX == value) + { + return; + } + m_OriginX = value; + originXChanged(); + } + + inline float originY() const { return m_OriginY; } + void originY(float value) + { + if (m_OriginY == value) + { + return; + } + m_OriginY = value; + originYChanged(); + } + + void copy(const ParametricPathBase& object) + { + m_Width = object.m_Width; + m_Height = object.m_Height; + m_OriginX = object.m_OriginX; + m_OriginY = object.m_OriginY; + Path::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case widthPropertyKey: + m_Width = CoreDoubleType::deserialize(reader); + return true; + case heightPropertyKey: + m_Height = CoreDoubleType::deserialize(reader); + return true; + case originXPropertyKey: + m_OriginX = CoreDoubleType::deserialize(reader); + return true; + case originYPropertyKey: + m_OriginY = CoreDoubleType::deserialize(reader); + return true; + } + return Path::deserialize(propertyKey, reader); + } + +protected: + virtual void widthChanged() {} + virtual void heightChanged() {} + virtual void originXChanged() {} + virtual void originYChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/shapes/path_base.hpp b/third_party/rive/include/rive/generated/shapes/path_base.hpp new file mode 100644 index 0000000..29a5b53 --- /dev/null +++ b/third_party/rive/include/rive/generated/shapes/path_base.hpp @@ -0,0 +1,93 @@ +#ifndef _RIVE_PATH_BASE_HPP_ +#define _RIVE_PATH_BASE_HPP_ +#include "rive/core/field_types/core_bool_type.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +#include "rive/node.hpp" +namespace rive +{ +class PathBase : public Node +{ +protected: + typedef Node Super; + +public: + static const uint16_t typeKey = 12; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case PathBase::typeKey: + case NodeBase::typeKey: + case TransformComponentBase::typeKey: + case WorldTransformComponentBase::typeKey: + case ContainerComponentBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t pathFlagsPropertyKey = 128; + static const uint16_t isHolePropertyKey = 770; + +protected: + uint32_t m_PathFlags = 0; + bool m_IsHole = false; + +public: + inline uint32_t pathFlags() const { return m_PathFlags; } + void pathFlags(uint32_t value) + { + if (m_PathFlags == value) + { + return; + } + m_PathFlags = value; + pathFlagsChanged(); + } + + inline bool isHole() const { return m_IsHole; } + void isHole(bool value) + { + if (m_IsHole == value) + { + return; + } + m_IsHole = value; + isHoleChanged(); + } + + void copy(const PathBase& object) + { + m_PathFlags = object.m_PathFlags; + m_IsHole = object.m_IsHole; + Node::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case pathFlagsPropertyKey: + m_PathFlags = CoreUintType::deserialize(reader); + return true; + case isHolePropertyKey: + m_IsHole = CoreBoolType::deserialize(reader); + return true; + } + return Node::deserialize(propertyKey, reader); + } + +protected: + virtual void pathFlagsChanged() {} + virtual void isHoleChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/shapes/path_vertex_base.hpp b/third_party/rive/include/rive/generated/shapes/path_vertex_base.hpp new file mode 100644 index 0000000..7fcbbb2 --- /dev/null +++ b/third_party/rive/include/rive/generated/shapes/path_vertex_base.hpp @@ -0,0 +1,36 @@ +#ifndef _RIVE_PATH_VERTEX_BASE_HPP_ +#define _RIVE_PATH_VERTEX_BASE_HPP_ +#include "rive/shapes/vertex.hpp" +namespace rive +{ +class PathVertexBase : public Vertex +{ +protected: + typedef Vertex Super; + +public: + static const uint16_t typeKey = 14; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case PathVertexBase::typeKey: + case VertexBase::typeKey: + case ContainerComponentBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/shapes/points_path_base.hpp b/third_party/rive/include/rive/generated/shapes/points_path_base.hpp new file mode 100644 index 0000000..29cee49 --- /dev/null +++ b/third_party/rive/include/rive/generated/shapes/points_path_base.hpp @@ -0,0 +1,76 @@ +#ifndef _RIVE_POINTS_PATH_BASE_HPP_ +#define _RIVE_POINTS_PATH_BASE_HPP_ +#include "rive/core/field_types/core_bool_type.hpp" +#include "rive/shapes/path.hpp" +namespace rive +{ +class PointsPathBase : public Path +{ +protected: + typedef Path Super; + +public: + static const uint16_t typeKey = 16; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case PointsPathBase::typeKey: + case PathBase::typeKey: + case NodeBase::typeKey: + case TransformComponentBase::typeKey: + case WorldTransformComponentBase::typeKey: + case ContainerComponentBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t isClosedPropertyKey = 32; + +protected: + bool m_IsClosed = false; + +public: + inline bool isClosed() const { return m_IsClosed; } + void isClosed(bool value) + { + if (m_IsClosed == value) + { + return; + } + m_IsClosed = value; + isClosedChanged(); + } + + Core* clone() const override; + void copy(const PointsPathBase& object) + { + m_IsClosed = object.m_IsClosed; + Path::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case isClosedPropertyKey: + m_IsClosed = CoreBoolType::deserialize(reader); + return true; + } + return Path::deserialize(propertyKey, reader); + } + +protected: + virtual void isClosedChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/shapes/polygon_base.hpp b/third_party/rive/include/rive/generated/shapes/polygon_base.hpp new file mode 100644 index 0000000..21ccf57 --- /dev/null +++ b/third_party/rive/include/rive/generated/shapes/polygon_base.hpp @@ -0,0 +1,96 @@ +#ifndef _RIVE_POLYGON_BASE_HPP_ +#define _RIVE_POLYGON_BASE_HPP_ +#include "rive/core/field_types/core_double_type.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +#include "rive/shapes/parametric_path.hpp" +namespace rive +{ +class PolygonBase : public ParametricPath +{ +protected: + typedef ParametricPath Super; + +public: + static const uint16_t typeKey = 51; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case PolygonBase::typeKey: + case ParametricPathBase::typeKey: + case PathBase::typeKey: + case NodeBase::typeKey: + case TransformComponentBase::typeKey: + case WorldTransformComponentBase::typeKey: + case ContainerComponentBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t pointsPropertyKey = 125; + static const uint16_t cornerRadiusPropertyKey = 126; + +protected: + uint32_t m_Points = 5; + float m_CornerRadius = 0.0f; + +public: + inline uint32_t points() const { return m_Points; } + void points(uint32_t value) + { + if (m_Points == value) + { + return; + } + m_Points = value; + pointsChanged(); + } + + inline float cornerRadius() const { return m_CornerRadius; } + void cornerRadius(float value) + { + if (m_CornerRadius == value) + { + return; + } + m_CornerRadius = value; + cornerRadiusChanged(); + } + + Core* clone() const override; + void copy(const PolygonBase& object) + { + m_Points = object.m_Points; + m_CornerRadius = object.m_CornerRadius; + ParametricPath::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case pointsPropertyKey: + m_Points = CoreUintType::deserialize(reader); + return true; + case cornerRadiusPropertyKey: + m_CornerRadius = CoreDoubleType::deserialize(reader); + return true; + } + return ParametricPath::deserialize(propertyKey, reader); + } + +protected: + virtual void pointsChanged() {} + virtual void cornerRadiusChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/shapes/rectangle_base.hpp b/third_party/rive/include/rive/generated/shapes/rectangle_base.hpp new file mode 100644 index 0000000..5044e6d --- /dev/null +++ b/third_party/rive/include/rive/generated/shapes/rectangle_base.hpp @@ -0,0 +1,150 @@ +#ifndef _RIVE_RECTANGLE_BASE_HPP_ +#define _RIVE_RECTANGLE_BASE_HPP_ +#include "rive/core/field_types/core_bool_type.hpp" +#include "rive/core/field_types/core_double_type.hpp" +#include "rive/shapes/parametric_path.hpp" +namespace rive +{ +class RectangleBase : public ParametricPath +{ +protected: + typedef ParametricPath Super; + +public: + static const uint16_t typeKey = 7; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case RectangleBase::typeKey: + case ParametricPathBase::typeKey: + case PathBase::typeKey: + case NodeBase::typeKey: + case TransformComponentBase::typeKey: + case WorldTransformComponentBase::typeKey: + case ContainerComponentBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t linkCornerRadiusPropertyKey = 164; + static const uint16_t cornerRadiusTLPropertyKey = 31; + static const uint16_t cornerRadiusTRPropertyKey = 161; + static const uint16_t cornerRadiusBLPropertyKey = 162; + static const uint16_t cornerRadiusBRPropertyKey = 163; + +protected: + bool m_LinkCornerRadius = true; + float m_CornerRadiusTL = 0.0f; + float m_CornerRadiusTR = 0.0f; + float m_CornerRadiusBL = 0.0f; + float m_CornerRadiusBR = 0.0f; + +public: + inline bool linkCornerRadius() const { return m_LinkCornerRadius; } + void linkCornerRadius(bool value) + { + if (m_LinkCornerRadius == value) + { + return; + } + m_LinkCornerRadius = value; + linkCornerRadiusChanged(); + } + + inline float cornerRadiusTL() const { return m_CornerRadiusTL; } + void cornerRadiusTL(float value) + { + if (m_CornerRadiusTL == value) + { + return; + } + m_CornerRadiusTL = value; + cornerRadiusTLChanged(); + } + + inline float cornerRadiusTR() const { return m_CornerRadiusTR; } + void cornerRadiusTR(float value) + { + if (m_CornerRadiusTR == value) + { + return; + } + m_CornerRadiusTR = value; + cornerRadiusTRChanged(); + } + + inline float cornerRadiusBL() const { return m_CornerRadiusBL; } + void cornerRadiusBL(float value) + { + if (m_CornerRadiusBL == value) + { + return; + } + m_CornerRadiusBL = value; + cornerRadiusBLChanged(); + } + + inline float cornerRadiusBR() const { return m_CornerRadiusBR; } + void cornerRadiusBR(float value) + { + if (m_CornerRadiusBR == value) + { + return; + } + m_CornerRadiusBR = value; + cornerRadiusBRChanged(); + } + + Core* clone() const override; + void copy(const RectangleBase& object) + { + m_LinkCornerRadius = object.m_LinkCornerRadius; + m_CornerRadiusTL = object.m_CornerRadiusTL; + m_CornerRadiusTR = object.m_CornerRadiusTR; + m_CornerRadiusBL = object.m_CornerRadiusBL; + m_CornerRadiusBR = object.m_CornerRadiusBR; + ParametricPath::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case linkCornerRadiusPropertyKey: + m_LinkCornerRadius = CoreBoolType::deserialize(reader); + return true; + case cornerRadiusTLPropertyKey: + m_CornerRadiusTL = CoreDoubleType::deserialize(reader); + return true; + case cornerRadiusTRPropertyKey: + m_CornerRadiusTR = CoreDoubleType::deserialize(reader); + return true; + case cornerRadiusBLPropertyKey: + m_CornerRadiusBL = CoreDoubleType::deserialize(reader); + return true; + case cornerRadiusBRPropertyKey: + m_CornerRadiusBR = CoreDoubleType::deserialize(reader); + return true; + } + return ParametricPath::deserialize(propertyKey, reader); + } + +protected: + virtual void linkCornerRadiusChanged() {} + virtual void cornerRadiusTLChanged() {} + virtual void cornerRadiusTRChanged() {} + virtual void cornerRadiusBLChanged() {} + virtual void cornerRadiusBRChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/shapes/shape_base.hpp b/third_party/rive/include/rive/generated/shapes/shape_base.hpp new file mode 100644 index 0000000..55fbbf6 --- /dev/null +++ b/third_party/rive/include/rive/generated/shapes/shape_base.hpp @@ -0,0 +1,59 @@ +#ifndef _RIVE_SHAPE_BASE_HPP_ +#define _RIVE_SHAPE_BASE_HPP_ +#include "rive/core/field_types/core_double_type.hpp" +#include "rive/drawable.hpp" +namespace rive +{ +class ShapeBase : public Drawable +{ +protected: + typedef Drawable Super; + +public: + static const uint16_t typeKey = 3; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case ShapeBase::typeKey: + case DrawableBase::typeKey: + case NodeBase::typeKey: + case TransformComponentBase::typeKey: + case WorldTransformComponentBase::typeKey: + case ContainerComponentBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t lengthPropertyKey = 781; + +protected: +public: + virtual void setLength(float value) = 0; + virtual float length() = 0; + void length(float value) + { + if (length() == value) + { + return; + } + setLength(value); + lengthChanged(); + } + + Core* clone() const override; + +protected: + virtual void lengthChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/shapes/star_base.hpp b/third_party/rive/include/rive/generated/shapes/star_base.hpp new file mode 100644 index 0000000..e27b4ff --- /dev/null +++ b/third_party/rive/include/rive/generated/shapes/star_base.hpp @@ -0,0 +1,78 @@ +#ifndef _RIVE_STAR_BASE_HPP_ +#define _RIVE_STAR_BASE_HPP_ +#include "rive/core/field_types/core_double_type.hpp" +#include "rive/shapes/polygon.hpp" +namespace rive +{ +class StarBase : public Polygon +{ +protected: + typedef Polygon Super; + +public: + static const uint16_t typeKey = 52; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case StarBase::typeKey: + case PolygonBase::typeKey: + case ParametricPathBase::typeKey: + case PathBase::typeKey: + case NodeBase::typeKey: + case TransformComponentBase::typeKey: + case WorldTransformComponentBase::typeKey: + case ContainerComponentBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t innerRadiusPropertyKey = 127; + +protected: + float m_InnerRadius = 0.5f; + +public: + inline float innerRadius() const { return m_InnerRadius; } + void innerRadius(float value) + { + if (m_InnerRadius == value) + { + return; + } + m_InnerRadius = value; + innerRadiusChanged(); + } + + Core* clone() const override; + void copy(const StarBase& object) + { + m_InnerRadius = object.m_InnerRadius; + Polygon::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case innerRadiusPropertyKey: + m_InnerRadius = CoreDoubleType::deserialize(reader); + return true; + } + return Polygon::deserialize(propertyKey, reader); + } + +protected: + virtual void innerRadiusChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/shapes/straight_vertex_base.hpp b/third_party/rive/include/rive/generated/shapes/straight_vertex_base.hpp new file mode 100644 index 0000000..a27364d --- /dev/null +++ b/third_party/rive/include/rive/generated/shapes/straight_vertex_base.hpp @@ -0,0 +1,74 @@ +#ifndef _RIVE_STRAIGHT_VERTEX_BASE_HPP_ +#define _RIVE_STRAIGHT_VERTEX_BASE_HPP_ +#include "rive/core/field_types/core_double_type.hpp" +#include "rive/shapes/path_vertex.hpp" +namespace rive +{ +class StraightVertexBase : public PathVertex +{ +protected: + typedef PathVertex Super; + +public: + static const uint16_t typeKey = 5; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case StraightVertexBase::typeKey: + case PathVertexBase::typeKey: + case VertexBase::typeKey: + case ContainerComponentBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t radiusPropertyKey = 26; + +protected: + float m_Radius = 0.0f; + +public: + inline float radius() const { return m_Radius; } + void radius(float value) + { + if (m_Radius == value) + { + return; + } + m_Radius = value; + radiusChanged(); + } + + Core* clone() const override; + void copy(const StraightVertexBase& object) + { + m_Radius = object.m_Radius; + PathVertex::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case radiusPropertyKey: + m_Radius = CoreDoubleType::deserialize(reader); + return true; + } + return PathVertex::deserialize(propertyKey, reader); + } + +protected: + virtual void radiusChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/shapes/triangle_base.hpp b/third_party/rive/include/rive/generated/shapes/triangle_base.hpp new file mode 100644 index 0000000..fae2cd9 --- /dev/null +++ b/third_party/rive/include/rive/generated/shapes/triangle_base.hpp @@ -0,0 +1,42 @@ +#ifndef _RIVE_TRIANGLE_BASE_HPP_ +#define _RIVE_TRIANGLE_BASE_HPP_ +#include "rive/shapes/parametric_path.hpp" +namespace rive +{ +class TriangleBase : public ParametricPath +{ +protected: + typedef ParametricPath Super; + +public: + static const uint16_t typeKey = 8; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case TriangleBase::typeKey: + case ParametricPathBase::typeKey: + case PathBase::typeKey: + case NodeBase::typeKey: + case TransformComponentBase::typeKey: + case WorldTransformComponentBase::typeKey: + case ContainerComponentBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/shapes/vertex_base.hpp b/third_party/rive/include/rive/generated/shapes/vertex_base.hpp new file mode 100644 index 0000000..f7da277 --- /dev/null +++ b/third_party/rive/include/rive/generated/shapes/vertex_base.hpp @@ -0,0 +1,89 @@ +#ifndef _RIVE_VERTEX_BASE_HPP_ +#define _RIVE_VERTEX_BASE_HPP_ +#include "rive/container_component.hpp" +#include "rive/core/field_types/core_double_type.hpp" +namespace rive +{ +class VertexBase : public ContainerComponent +{ +protected: + typedef ContainerComponent Super; + +public: + static const uint16_t typeKey = 107; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case VertexBase::typeKey: + case ContainerComponentBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t xPropertyKey = 24; + static const uint16_t yPropertyKey = 25; + +protected: + float m_X = 0.0f; + float m_Y = 0.0f; + +public: + inline float x() const { return m_X; } + void x(float value) + { + if (m_X == value) + { + return; + } + m_X = value; + xChanged(); + } + + inline float y() const { return m_Y; } + void y(float value) + { + if (m_Y == value) + { + return; + } + m_Y = value; + yChanged(); + } + + void copy(const VertexBase& object) + { + m_X = object.m_X; + m_Y = object.m_Y; + ContainerComponent::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case xPropertyKey: + m_X = CoreDoubleType::deserialize(reader); + return true; + case yPropertyKey: + m_Y = CoreDoubleType::deserialize(reader); + return true; + } + return ContainerComponent::deserialize(propertyKey, reader); + } + +protected: + virtual void xChanged() {} + virtual void yChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/solo_base.hpp b/third_party/rive/include/rive/generated/solo_base.hpp new file mode 100644 index 0000000..107432b --- /dev/null +++ b/third_party/rive/include/rive/generated/solo_base.hpp @@ -0,0 +1,75 @@ +#ifndef _RIVE_SOLO_BASE_HPP_ +#define _RIVE_SOLO_BASE_HPP_ +#include "rive/core/field_types/core_uint_type.hpp" +#include "rive/node.hpp" +namespace rive +{ +class SoloBase : public Node +{ +protected: + typedef Node Super; + +public: + static const uint16_t typeKey = 147; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case SoloBase::typeKey: + case NodeBase::typeKey: + case TransformComponentBase::typeKey: + case WorldTransformComponentBase::typeKey: + case ContainerComponentBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t activeComponentIdPropertyKey = 296; + +protected: + uint32_t m_ActiveComponentId = 0; + +public: + inline uint32_t activeComponentId() const { return m_ActiveComponentId; } + void activeComponentId(uint32_t value) + { + if (m_ActiveComponentId == value) + { + return; + } + m_ActiveComponentId = value; + activeComponentIdChanged(); + } + + Core* clone() const override; + void copy(const SoloBase& object) + { + m_ActiveComponentId = object.m_ActiveComponentId; + Node::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case activeComponentIdPropertyKey: + m_ActiveComponentId = CoreUintType::deserialize(reader); + return true; + } + return Node::deserialize(propertyKey, reader); + } + +protected: + virtual void activeComponentIdChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/text/text_base.hpp b/third_party/rive/include/rive/generated/text/text_base.hpp new file mode 100644 index 0000000..f835ff2 --- /dev/null +++ b/third_party/rive/include/rive/generated/text/text_base.hpp @@ -0,0 +1,276 @@ +#ifndef _RIVE_TEXT_BASE_HPP_ +#define _RIVE_TEXT_BASE_HPP_ +#include "rive/core/field_types/core_bool_type.hpp" +#include "rive/core/field_types/core_double_type.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +#include "rive/drawable.hpp" +namespace rive +{ +class TextBase : public Drawable +{ +protected: + typedef Drawable Super; + +public: + static const uint16_t typeKey = 134; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case TextBase::typeKey: + case DrawableBase::typeKey: + case NodeBase::typeKey: + case TransformComponentBase::typeKey: + case WorldTransformComponentBase::typeKey: + case ContainerComponentBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t alignValuePropertyKey = 281; + static const uint16_t sizingValuePropertyKey = 284; + static const uint16_t overflowValuePropertyKey = 287; + static const uint16_t widthPropertyKey = 285; + static const uint16_t heightPropertyKey = 286; + static const uint16_t originXPropertyKey = 366; + static const uint16_t originYPropertyKey = 367; + static const uint16_t paragraphSpacingPropertyKey = 371; + static const uint16_t originValuePropertyKey = 377; + static const uint16_t wrapValuePropertyKey = 683; + static const uint16_t verticalAlignValuePropertyKey = 685; + static const uint16_t fitFromBaselinePropertyKey = 703; + +protected: + uint32_t m_AlignValue = 0; + uint32_t m_SizingValue = 0; + uint32_t m_OverflowValue = 0; + float m_Width = 0.0f; + float m_Height = 0.0f; + float m_OriginX = 0.0f; + float m_OriginY = 0.0f; + float m_ParagraphSpacing = 0.0f; + uint32_t m_OriginValue = 0; + uint32_t m_WrapValue = 0; + uint32_t m_VerticalAlignValue = 0; + bool m_FitFromBaseline = true; + +public: + inline uint32_t alignValue() const { return m_AlignValue; } + void alignValue(uint32_t value) + { + if (m_AlignValue == value) + { + return; + } + m_AlignValue = value; + alignValueChanged(); + } + + inline uint32_t sizingValue() const { return m_SizingValue; } + void sizingValue(uint32_t value) + { + if (m_SizingValue == value) + { + return; + } + m_SizingValue = value; + sizingValueChanged(); + } + + inline uint32_t overflowValue() const { return m_OverflowValue; } + void overflowValue(uint32_t value) + { + if (m_OverflowValue == value) + { + return; + } + m_OverflowValue = value; + overflowValueChanged(); + } + + inline float width() const { return m_Width; } + void width(float value) + { + if (m_Width == value) + { + return; + } + m_Width = value; + widthChanged(); + } + + inline float height() const { return m_Height; } + void height(float value) + { + if (m_Height == value) + { + return; + } + m_Height = value; + heightChanged(); + } + + inline float originX() const { return m_OriginX; } + void originX(float value) + { + if (m_OriginX == value) + { + return; + } + m_OriginX = value; + originXChanged(); + } + + inline float originY() const { return m_OriginY; } + void originY(float value) + { + if (m_OriginY == value) + { + return; + } + m_OriginY = value; + originYChanged(); + } + + inline float paragraphSpacing() const { return m_ParagraphSpacing; } + void paragraphSpacing(float value) + { + if (m_ParagraphSpacing == value) + { + return; + } + m_ParagraphSpacing = value; + paragraphSpacingChanged(); + } + + inline uint32_t originValue() const { return m_OriginValue; } + void originValue(uint32_t value) + { + if (m_OriginValue == value) + { + return; + } + m_OriginValue = value; + originValueChanged(); + } + + inline uint32_t wrapValue() const { return m_WrapValue; } + void wrapValue(uint32_t value) + { + if (m_WrapValue == value) + { + return; + } + m_WrapValue = value; + wrapValueChanged(); + } + + inline uint32_t verticalAlignValue() const { return m_VerticalAlignValue; } + void verticalAlignValue(uint32_t value) + { + if (m_VerticalAlignValue == value) + { + return; + } + m_VerticalAlignValue = value; + verticalAlignValueChanged(); + } + + inline bool fitFromBaseline() const { return m_FitFromBaseline; } + void fitFromBaseline(bool value) + { + if (m_FitFromBaseline == value) + { + return; + } + m_FitFromBaseline = value; + fitFromBaselineChanged(); + } + + Core* clone() const override; + void copy(const TextBase& object) + { + m_AlignValue = object.m_AlignValue; + m_SizingValue = object.m_SizingValue; + m_OverflowValue = object.m_OverflowValue; + m_Width = object.m_Width; + m_Height = object.m_Height; + m_OriginX = object.m_OriginX; + m_OriginY = object.m_OriginY; + m_ParagraphSpacing = object.m_ParagraphSpacing; + m_OriginValue = object.m_OriginValue; + m_WrapValue = object.m_WrapValue; + m_VerticalAlignValue = object.m_VerticalAlignValue; + m_FitFromBaseline = object.m_FitFromBaseline; + Drawable::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case alignValuePropertyKey: + m_AlignValue = CoreUintType::deserialize(reader); + return true; + case sizingValuePropertyKey: + m_SizingValue = CoreUintType::deserialize(reader); + return true; + case overflowValuePropertyKey: + m_OverflowValue = CoreUintType::deserialize(reader); + return true; + case widthPropertyKey: + m_Width = CoreDoubleType::deserialize(reader); + return true; + case heightPropertyKey: + m_Height = CoreDoubleType::deserialize(reader); + return true; + case originXPropertyKey: + m_OriginX = CoreDoubleType::deserialize(reader); + return true; + case originYPropertyKey: + m_OriginY = CoreDoubleType::deserialize(reader); + return true; + case paragraphSpacingPropertyKey: + m_ParagraphSpacing = CoreDoubleType::deserialize(reader); + return true; + case originValuePropertyKey: + m_OriginValue = CoreUintType::deserialize(reader); + return true; + case wrapValuePropertyKey: + m_WrapValue = CoreUintType::deserialize(reader); + return true; + case verticalAlignValuePropertyKey: + m_VerticalAlignValue = CoreUintType::deserialize(reader); + return true; + case fitFromBaselinePropertyKey: + m_FitFromBaseline = CoreBoolType::deserialize(reader); + return true; + } + return Drawable::deserialize(propertyKey, reader); + } + +protected: + virtual void alignValueChanged() {} + virtual void sizingValueChanged() {} + virtual void overflowValueChanged() {} + virtual void widthChanged() {} + virtual void heightChanged() {} + virtual void originXChanged() {} + virtual void originYChanged() {} + virtual void paragraphSpacingChanged() {} + virtual void originValueChanged() {} + virtual void wrapValueChanged() {} + virtual void verticalAlignValueChanged() {} + virtual void fitFromBaselineChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/text/text_follow_path_modifier_base.hpp b/third_party/rive/include/rive/generated/text/text_follow_path_modifier_base.hpp new file mode 100644 index 0000000..dae1872 --- /dev/null +++ b/third_party/rive/include/rive/generated/text/text_follow_path_modifier_base.hpp @@ -0,0 +1,164 @@ +#ifndef _RIVE_TEXT_FOLLOW_PATH_MODIFIER_BASE_HPP_ +#define _RIVE_TEXT_FOLLOW_PATH_MODIFIER_BASE_HPP_ +#include "rive/core/field_types/core_bool_type.hpp" +#include "rive/core/field_types/core_double_type.hpp" +#include "rive/text/text_target_modifier.hpp" +namespace rive +{ +class TextFollowPathModifierBase : public TextTargetModifier +{ +protected: + typedef TextTargetModifier Super; + +public: + static const uint16_t typeKey = 547; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case TextFollowPathModifierBase::typeKey: + case TextTargetModifierBase::typeKey: + case TextModifierBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t radialPropertyKey = 779; + static const uint16_t orientPropertyKey = 782; + static const uint16_t startPropertyKey = 783; + static const uint16_t endPropertyKey = 784; + static const uint16_t strengthPropertyKey = 785; + static const uint16_t offsetPropertyKey = 786; + +protected: + bool m_Radial = false; + bool m_Orient = true; + float m_Start = 0.0f; + float m_End = 1.0f; + float m_Strength = 1.0f; + float m_Offset = 0.0f; + +public: + inline bool radial() const { return m_Radial; } + void radial(bool value) + { + if (m_Radial == value) + { + return; + } + m_Radial = value; + radialChanged(); + } + + inline bool orient() const { return m_Orient; } + void orient(bool value) + { + if (m_Orient == value) + { + return; + } + m_Orient = value; + orientChanged(); + } + + inline float start() const { return m_Start; } + void start(float value) + { + if (m_Start == value) + { + return; + } + m_Start = value; + startChanged(); + } + + inline float end() const { return m_End; } + void end(float value) + { + if (m_End == value) + { + return; + } + m_End = value; + endChanged(); + } + + inline float strength() const { return m_Strength; } + void strength(float value) + { + if (m_Strength == value) + { + return; + } + m_Strength = value; + strengthChanged(); + } + + inline float offset() const { return m_Offset; } + void offset(float value) + { + if (m_Offset == value) + { + return; + } + m_Offset = value; + offsetChanged(); + } + + Core* clone() const override; + void copy(const TextFollowPathModifierBase& object) + { + m_Radial = object.m_Radial; + m_Orient = object.m_Orient; + m_Start = object.m_Start; + m_End = object.m_End; + m_Strength = object.m_Strength; + m_Offset = object.m_Offset; + TextTargetModifier::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case radialPropertyKey: + m_Radial = CoreBoolType::deserialize(reader); + return true; + case orientPropertyKey: + m_Orient = CoreBoolType::deserialize(reader); + return true; + case startPropertyKey: + m_Start = CoreDoubleType::deserialize(reader); + return true; + case endPropertyKey: + m_End = CoreDoubleType::deserialize(reader); + return true; + case strengthPropertyKey: + m_Strength = CoreDoubleType::deserialize(reader); + return true; + case offsetPropertyKey: + m_Offset = CoreDoubleType::deserialize(reader); + return true; + } + return TextTargetModifier::deserialize(propertyKey, reader); + } + +protected: + virtual void radialChanged() {} + virtual void orientChanged() {} + virtual void startChanged() {} + virtual void endChanged() {} + virtual void strengthChanged() {} + virtual void offsetChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/text/text_input_base.hpp b/third_party/rive/include/rive/generated/text/text_input_base.hpp new file mode 100644 index 0000000..461045e --- /dev/null +++ b/third_party/rive/include/rive/generated/text/text_input_base.hpp @@ -0,0 +1,96 @@ +#ifndef _RIVE_TEXT_INPUT_BASE_HPP_ +#define _RIVE_TEXT_INPUT_BASE_HPP_ +#include +#include "rive/core/field_types/core_double_type.hpp" +#include "rive/core/field_types/core_string_type.hpp" +#include "rive/drawable.hpp" +namespace rive +{ +class TextInputBase : public Drawable +{ +protected: + typedef Drawable Super; + +public: + static const uint16_t typeKey = 569; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case TextInputBase::typeKey: + case DrawableBase::typeKey: + case NodeBase::typeKey: + case TransformComponentBase::typeKey: + case WorldTransformComponentBase::typeKey: + case ContainerComponentBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t textPropertyKey = 817; + static const uint16_t selectionRadiusPropertyKey = 818; + +protected: + std::string m_Text = ""; + float m_SelectionRadius = 5.0f; + +public: + inline const std::string& text() const { return m_Text; } + void text(std::string value) + { + if (m_Text == value) + { + return; + } + m_Text = value; + textChanged(); + } + + inline float selectionRadius() const { return m_SelectionRadius; } + void selectionRadius(float value) + { + if (m_SelectionRadius == value) + { + return; + } + m_SelectionRadius = value; + selectionRadiusChanged(); + } + + Core* clone() const override; + void copy(const TextInputBase& object) + { + m_Text = object.m_Text; + m_SelectionRadius = object.m_SelectionRadius; + Drawable::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case textPropertyKey: + m_Text = CoreStringType::deserialize(reader); + return true; + case selectionRadiusPropertyKey: + m_SelectionRadius = CoreDoubleType::deserialize(reader); + return true; + } + return Drawable::deserialize(propertyKey, reader); + } + +protected: + virtual void textChanged() {} + virtual void selectionRadiusChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/text/text_input_cursor_base.hpp b/third_party/rive/include/rive/generated/text/text_input_cursor_base.hpp new file mode 100644 index 0000000..80d8fc0 --- /dev/null +++ b/third_party/rive/include/rive/generated/text/text_input_cursor_base.hpp @@ -0,0 +1,42 @@ +#ifndef _RIVE_TEXT_INPUT_CURSOR_BASE_HPP_ +#define _RIVE_TEXT_INPUT_CURSOR_BASE_HPP_ +#include "rive/text/text_input_drawable.hpp" +namespace rive +{ +class TextInputCursorBase : public TextInputDrawable +{ +protected: + typedef TextInputDrawable Super; + +public: + static const uint16_t typeKey = 571; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case TextInputCursorBase::typeKey: + case TextInputDrawableBase::typeKey: + case DrawableBase::typeKey: + case NodeBase::typeKey: + case TransformComponentBase::typeKey: + case WorldTransformComponentBase::typeKey: + case ContainerComponentBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/text/text_input_drawable_base.hpp b/third_party/rive/include/rive/generated/text/text_input_drawable_base.hpp new file mode 100644 index 0000000..3dddacd --- /dev/null +++ b/third_party/rive/include/rive/generated/text/text_input_drawable_base.hpp @@ -0,0 +1,39 @@ +#ifndef _RIVE_TEXT_INPUT_DRAWABLE_BASE_HPP_ +#define _RIVE_TEXT_INPUT_DRAWABLE_BASE_HPP_ +#include "rive/drawable.hpp" +namespace rive +{ +class TextInputDrawableBase : public Drawable +{ +protected: + typedef Drawable Super; + +public: + static const uint16_t typeKey = 570; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case TextInputDrawableBase::typeKey: + case DrawableBase::typeKey: + case NodeBase::typeKey: + case TransformComponentBase::typeKey: + case WorldTransformComponentBase::typeKey: + case ContainerComponentBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/text/text_input_selected_text_base.hpp b/third_party/rive/include/rive/generated/text/text_input_selected_text_base.hpp new file mode 100644 index 0000000..b66e50e --- /dev/null +++ b/third_party/rive/include/rive/generated/text/text_input_selected_text_base.hpp @@ -0,0 +1,42 @@ +#ifndef _RIVE_TEXT_INPUT_SELECTED_TEXT_BASE_HPP_ +#define _RIVE_TEXT_INPUT_SELECTED_TEXT_BASE_HPP_ +#include "rive/text/text_input_drawable.hpp" +namespace rive +{ +class TextInputSelectedTextBase : public TextInputDrawable +{ +protected: + typedef TextInputDrawable Super; + +public: + static const uint16_t typeKey = 575; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case TextInputSelectedTextBase::typeKey: + case TextInputDrawableBase::typeKey: + case DrawableBase::typeKey: + case NodeBase::typeKey: + case TransformComponentBase::typeKey: + case WorldTransformComponentBase::typeKey: + case ContainerComponentBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/text/text_input_selection_base.hpp b/third_party/rive/include/rive/generated/text/text_input_selection_base.hpp new file mode 100644 index 0000000..f57efb9 --- /dev/null +++ b/third_party/rive/include/rive/generated/text/text_input_selection_base.hpp @@ -0,0 +1,42 @@ +#ifndef _RIVE_TEXT_INPUT_SELECTION_BASE_HPP_ +#define _RIVE_TEXT_INPUT_SELECTION_BASE_HPP_ +#include "rive/text/text_input_drawable.hpp" +namespace rive +{ +class TextInputSelectionBase : public TextInputDrawable +{ +protected: + typedef TextInputDrawable Super; + +public: + static const uint16_t typeKey = 574; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case TextInputSelectionBase::typeKey: + case TextInputDrawableBase::typeKey: + case DrawableBase::typeKey: + case NodeBase::typeKey: + case TransformComponentBase::typeKey: + case WorldTransformComponentBase::typeKey: + case ContainerComponentBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/text/text_input_text_base.hpp b/third_party/rive/include/rive/generated/text/text_input_text_base.hpp new file mode 100644 index 0000000..61d8706 --- /dev/null +++ b/third_party/rive/include/rive/generated/text/text_input_text_base.hpp @@ -0,0 +1,42 @@ +#ifndef _RIVE_TEXT_INPUT_TEXT_BASE_HPP_ +#define _RIVE_TEXT_INPUT_TEXT_BASE_HPP_ +#include "rive/text/text_input_drawable.hpp" +namespace rive +{ +class TextInputTextBase : public TextInputDrawable +{ +protected: + typedef TextInputDrawable Super; + +public: + static const uint16_t typeKey = 572; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case TextInputTextBase::typeKey: + case TextInputDrawableBase::typeKey: + case DrawableBase::typeKey: + case NodeBase::typeKey: + case TransformComponentBase::typeKey: + case WorldTransformComponentBase::typeKey: + case ContainerComponentBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/text/text_modifier_base.hpp b/third_party/rive/include/rive/generated/text/text_modifier_base.hpp new file mode 100644 index 0000000..b588b60 --- /dev/null +++ b/third_party/rive/include/rive/generated/text/text_modifier_base.hpp @@ -0,0 +1,34 @@ +#ifndef _RIVE_TEXT_MODIFIER_BASE_HPP_ +#define _RIVE_TEXT_MODIFIER_BASE_HPP_ +#include "rive/component.hpp" +namespace rive +{ +class TextModifierBase : public Component +{ +protected: + typedef Component Super; + +public: + static const uint16_t typeKey = 160; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case TextModifierBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/text/text_modifier_group_base.hpp b/third_party/rive/include/rive/generated/text/text_modifier_group_base.hpp new file mode 100644 index 0000000..93b87c4 --- /dev/null +++ b/third_party/rive/include/rive/generated/text/text_modifier_group_base.hpp @@ -0,0 +1,217 @@ +#ifndef _RIVE_TEXT_MODIFIER_GROUP_BASE_HPP_ +#define _RIVE_TEXT_MODIFIER_GROUP_BASE_HPP_ +#include "rive/container_component.hpp" +#include "rive/core/field_types/core_double_type.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +namespace rive +{ +class TextModifierGroupBase : public ContainerComponent +{ +protected: + typedef ContainerComponent Super; + +public: + static const uint16_t typeKey = 159; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case TextModifierGroupBase::typeKey: + case ContainerComponentBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t modifierFlagsPropertyKey = 335; + static const uint16_t originXPropertyKey = 328; + static const uint16_t originYPropertyKey = 329; + static const uint16_t opacityPropertyKey = 324; + static const uint16_t xPropertyKey = 322; + static const uint16_t yPropertyKey = 323; + static const uint16_t rotationPropertyKey = 332; + static const uint16_t scaleXPropertyKey = 330; + static const uint16_t scaleYPropertyKey = 331; + +protected: + uint32_t m_ModifierFlags = 0; + float m_OriginX = 0.0f; + float m_OriginY = 0.0f; + float m_Opacity = 1.0f; + float m_X = 0.0f; + float m_Y = 0.0f; + float m_Rotation = 0.0f; + float m_ScaleX = 1.0f; + float m_ScaleY = 1.0f; + +public: + inline uint32_t modifierFlags() const { return m_ModifierFlags; } + void modifierFlags(uint32_t value) + { + if (m_ModifierFlags == value) + { + return; + } + m_ModifierFlags = value; + modifierFlagsChanged(); + } + + inline float originX() const { return m_OriginX; } + void originX(float value) + { + if (m_OriginX == value) + { + return; + } + m_OriginX = value; + originXChanged(); + } + + inline float originY() const { return m_OriginY; } + void originY(float value) + { + if (m_OriginY == value) + { + return; + } + m_OriginY = value; + originYChanged(); + } + + inline float opacity() const { return m_Opacity; } + void opacity(float value) + { + if (m_Opacity == value) + { + return; + } + m_Opacity = value; + opacityChanged(); + } + + inline float x() const { return m_X; } + void x(float value) + { + if (m_X == value) + { + return; + } + m_X = value; + xChanged(); + } + + inline float y() const { return m_Y; } + void y(float value) + { + if (m_Y == value) + { + return; + } + m_Y = value; + yChanged(); + } + + inline float rotation() const { return m_Rotation; } + void rotation(float value) + { + if (m_Rotation == value) + { + return; + } + m_Rotation = value; + rotationChanged(); + } + + inline float scaleX() const { return m_ScaleX; } + void scaleX(float value) + { + if (m_ScaleX == value) + { + return; + } + m_ScaleX = value; + scaleXChanged(); + } + + inline float scaleY() const { return m_ScaleY; } + void scaleY(float value) + { + if (m_ScaleY == value) + { + return; + } + m_ScaleY = value; + scaleYChanged(); + } + + Core* clone() const override; + void copy(const TextModifierGroupBase& object) + { + m_ModifierFlags = object.m_ModifierFlags; + m_OriginX = object.m_OriginX; + m_OriginY = object.m_OriginY; + m_Opacity = object.m_Opacity; + m_X = object.m_X; + m_Y = object.m_Y; + m_Rotation = object.m_Rotation; + m_ScaleX = object.m_ScaleX; + m_ScaleY = object.m_ScaleY; + ContainerComponent::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case modifierFlagsPropertyKey: + m_ModifierFlags = CoreUintType::deserialize(reader); + return true; + case originXPropertyKey: + m_OriginX = CoreDoubleType::deserialize(reader); + return true; + case originYPropertyKey: + m_OriginY = CoreDoubleType::deserialize(reader); + return true; + case opacityPropertyKey: + m_Opacity = CoreDoubleType::deserialize(reader); + return true; + case xPropertyKey: + m_X = CoreDoubleType::deserialize(reader); + return true; + case yPropertyKey: + m_Y = CoreDoubleType::deserialize(reader); + return true; + case rotationPropertyKey: + m_Rotation = CoreDoubleType::deserialize(reader); + return true; + case scaleXPropertyKey: + m_ScaleX = CoreDoubleType::deserialize(reader); + return true; + case scaleYPropertyKey: + m_ScaleY = CoreDoubleType::deserialize(reader); + return true; + } + return ContainerComponent::deserialize(propertyKey, reader); + } + +protected: + virtual void modifierFlagsChanged() {} + virtual void originXChanged() {} + virtual void originYChanged() {} + virtual void opacityChanged() {} + virtual void xChanged() {} + virtual void yChanged() {} + virtual void rotationChanged() {} + virtual void scaleXChanged() {} + virtual void scaleYChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/text/text_modifier_range_base.hpp b/third_party/rive/include/rive/generated/text/text_modifier_range_base.hpp new file mode 100644 index 0000000..1dd8e10 --- /dev/null +++ b/third_party/rive/include/rive/generated/text/text_modifier_range_base.hpp @@ -0,0 +1,254 @@ +#ifndef _RIVE_TEXT_MODIFIER_RANGE_BASE_HPP_ +#define _RIVE_TEXT_MODIFIER_RANGE_BASE_HPP_ +#include "rive/container_component.hpp" +#include "rive/core/field_types/core_bool_type.hpp" +#include "rive/core/field_types/core_double_type.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +namespace rive +{ +class TextModifierRangeBase : public ContainerComponent +{ +protected: + typedef ContainerComponent Super; + +public: + static const uint16_t typeKey = 158; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case TextModifierRangeBase::typeKey: + case ContainerComponentBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t modifyFromPropertyKey = 327; + static const uint16_t modifyToPropertyKey = 336; + static const uint16_t strengthPropertyKey = 334; + static const uint16_t unitsValuePropertyKey = 316; + static const uint16_t typeValuePropertyKey = 325; + static const uint16_t modeValuePropertyKey = 326; + static const uint16_t clampPropertyKey = 333; + static const uint16_t falloffFromPropertyKey = 317; + static const uint16_t falloffToPropertyKey = 318; + static const uint16_t offsetPropertyKey = 319; + static const uint16_t runIdPropertyKey = 378; + +protected: + float m_ModifyFrom = 0.0f; + float m_ModifyTo = 1.0f; + float m_Strength = 1.0f; + uint32_t m_UnitsValue = 0; + uint32_t m_TypeValue = 0; + uint32_t m_ModeValue = 0; + bool m_Clamp = false; + float m_FalloffFrom = 0.0f; + float m_FalloffTo = 1.0f; + float m_Offset = 0.0f; + uint32_t m_RunId = -1; + +public: + inline float modifyFrom() const { return m_ModifyFrom; } + void modifyFrom(float value) + { + if (m_ModifyFrom == value) + { + return; + } + m_ModifyFrom = value; + modifyFromChanged(); + } + + inline float modifyTo() const { return m_ModifyTo; } + void modifyTo(float value) + { + if (m_ModifyTo == value) + { + return; + } + m_ModifyTo = value; + modifyToChanged(); + } + + inline float strength() const { return m_Strength; } + void strength(float value) + { + if (m_Strength == value) + { + return; + } + m_Strength = value; + strengthChanged(); + } + + inline uint32_t unitsValue() const { return m_UnitsValue; } + void unitsValue(uint32_t value) + { + if (m_UnitsValue == value) + { + return; + } + m_UnitsValue = value; + unitsValueChanged(); + } + + inline uint32_t typeValue() const { return m_TypeValue; } + void typeValue(uint32_t value) + { + if (m_TypeValue == value) + { + return; + } + m_TypeValue = value; + typeValueChanged(); + } + + inline uint32_t modeValue() const { return m_ModeValue; } + void modeValue(uint32_t value) + { + if (m_ModeValue == value) + { + return; + } + m_ModeValue = value; + modeValueChanged(); + } + + inline bool clamp() const { return m_Clamp; } + void clamp(bool value) + { + if (m_Clamp == value) + { + return; + } + m_Clamp = value; + clampChanged(); + } + + inline float falloffFrom() const { return m_FalloffFrom; } + void falloffFrom(float value) + { + if (m_FalloffFrom == value) + { + return; + } + m_FalloffFrom = value; + falloffFromChanged(); + } + + inline float falloffTo() const { return m_FalloffTo; } + void falloffTo(float value) + { + if (m_FalloffTo == value) + { + return; + } + m_FalloffTo = value; + falloffToChanged(); + } + + inline float offset() const { return m_Offset; } + void offset(float value) + { + if (m_Offset == value) + { + return; + } + m_Offset = value; + offsetChanged(); + } + + inline uint32_t runId() const { return m_RunId; } + void runId(uint32_t value) + { + if (m_RunId == value) + { + return; + } + m_RunId = value; + runIdChanged(); + } + + Core* clone() const override; + void copy(const TextModifierRangeBase& object) + { + m_ModifyFrom = object.m_ModifyFrom; + m_ModifyTo = object.m_ModifyTo; + m_Strength = object.m_Strength; + m_UnitsValue = object.m_UnitsValue; + m_TypeValue = object.m_TypeValue; + m_ModeValue = object.m_ModeValue; + m_Clamp = object.m_Clamp; + m_FalloffFrom = object.m_FalloffFrom; + m_FalloffTo = object.m_FalloffTo; + m_Offset = object.m_Offset; + m_RunId = object.m_RunId; + ContainerComponent::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case modifyFromPropertyKey: + m_ModifyFrom = CoreDoubleType::deserialize(reader); + return true; + case modifyToPropertyKey: + m_ModifyTo = CoreDoubleType::deserialize(reader); + return true; + case strengthPropertyKey: + m_Strength = CoreDoubleType::deserialize(reader); + return true; + case unitsValuePropertyKey: + m_UnitsValue = CoreUintType::deserialize(reader); + return true; + case typeValuePropertyKey: + m_TypeValue = CoreUintType::deserialize(reader); + return true; + case modeValuePropertyKey: + m_ModeValue = CoreUintType::deserialize(reader); + return true; + case clampPropertyKey: + m_Clamp = CoreBoolType::deserialize(reader); + return true; + case falloffFromPropertyKey: + m_FalloffFrom = CoreDoubleType::deserialize(reader); + return true; + case falloffToPropertyKey: + m_FalloffTo = CoreDoubleType::deserialize(reader); + return true; + case offsetPropertyKey: + m_Offset = CoreDoubleType::deserialize(reader); + return true; + case runIdPropertyKey: + m_RunId = CoreUintType::deserialize(reader); + return true; + } + return ContainerComponent::deserialize(propertyKey, reader); + } + +protected: + virtual void modifyFromChanged() {} + virtual void modifyToChanged() {} + virtual void strengthChanged() {} + virtual void unitsValueChanged() {} + virtual void typeValueChanged() {} + virtual void modeValueChanged() {} + virtual void clampChanged() {} + virtual void falloffFromChanged() {} + virtual void falloffToChanged() {} + virtual void offsetChanged() {} + virtual void runIdChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/text/text_shape_modifier_base.hpp b/third_party/rive/include/rive/generated/text/text_shape_modifier_base.hpp new file mode 100644 index 0000000..6ee9d98 --- /dev/null +++ b/third_party/rive/include/rive/generated/text/text_shape_modifier_base.hpp @@ -0,0 +1,35 @@ +#ifndef _RIVE_TEXT_SHAPE_MODIFIER_BASE_HPP_ +#define _RIVE_TEXT_SHAPE_MODIFIER_BASE_HPP_ +#include "rive/text/text_modifier.hpp" +namespace rive +{ +class TextShapeModifierBase : public TextModifier +{ +protected: + typedef TextModifier Super; + +public: + static const uint16_t typeKey = 161; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case TextShapeModifierBase::typeKey: + case TextModifierBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/text/text_style_axis_base.hpp b/third_party/rive/include/rive/generated/text/text_style_axis_base.hpp new file mode 100644 index 0000000..85ddf41 --- /dev/null +++ b/third_party/rive/include/rive/generated/text/text_style_axis_base.hpp @@ -0,0 +1,90 @@ +#ifndef _RIVE_TEXT_STYLE_AXIS_BASE_HPP_ +#define _RIVE_TEXT_STYLE_AXIS_BASE_HPP_ +#include "rive/component.hpp" +#include "rive/core/field_types/core_double_type.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +namespace rive +{ +class TextStyleAxisBase : public Component +{ +protected: + typedef Component Super; + +public: + static const uint16_t typeKey = 144; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case TextStyleAxisBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t tagPropertyKey = 289; + static const uint16_t axisValuePropertyKey = 288; + +protected: + uint32_t m_Tag = 0; + float m_AxisValue = 0.0f; + +public: + inline uint32_t tag() const { return m_Tag; } + void tag(uint32_t value) + { + if (m_Tag == value) + { + return; + } + m_Tag = value; + tagChanged(); + } + + inline float axisValue() const { return m_AxisValue; } + void axisValue(float value) + { + if (m_AxisValue == value) + { + return; + } + m_AxisValue = value; + axisValueChanged(); + } + + Core* clone() const override; + void copy(const TextStyleAxisBase& object) + { + m_Tag = object.m_Tag; + m_AxisValue = object.m_AxisValue; + Component::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case tagPropertyKey: + m_Tag = CoreUintType::deserialize(reader); + return true; + case axisValuePropertyKey: + m_AxisValue = CoreDoubleType::deserialize(reader); + return true; + } + return Component::deserialize(propertyKey, reader); + } + +protected: + virtual void tagChanged() {} + virtual void axisValueChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/text/text_style_base.hpp b/third_party/rive/include/rive/generated/text/text_style_base.hpp new file mode 100644 index 0000000..044b684 --- /dev/null +++ b/third_party/rive/include/rive/generated/text/text_style_base.hpp @@ -0,0 +1,127 @@ +#ifndef _RIVE_TEXT_STYLE_BASE_HPP_ +#define _RIVE_TEXT_STYLE_BASE_HPP_ +#include "rive/container_component.hpp" +#include "rive/core/field_types/core_double_type.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +namespace rive +{ +class TextStyleBase : public ContainerComponent +{ +protected: + typedef ContainerComponent Super; + +public: + static const uint16_t typeKey = 573; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case TextStyleBase::typeKey: + case ContainerComponentBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t fontSizePropertyKey = 274; + static const uint16_t lineHeightPropertyKey = 370; + static const uint16_t letterSpacingPropertyKey = 390; + static const uint16_t fontAssetIdPropertyKey = 279; + +protected: + float m_FontSize = 12.0f; + float m_LineHeight = -1.0f; + float m_LetterSpacing = 0.0f; + uint32_t m_FontAssetId = -1; + +public: + inline float fontSize() const { return m_FontSize; } + void fontSize(float value) + { + if (m_FontSize == value) + { + return; + } + m_FontSize = value; + fontSizeChanged(); + } + + inline float lineHeight() const { return m_LineHeight; } + void lineHeight(float value) + { + if (m_LineHeight == value) + { + return; + } + m_LineHeight = value; + lineHeightChanged(); + } + + inline float letterSpacing() const { return m_LetterSpacing; } + void letterSpacing(float value) + { + if (m_LetterSpacing == value) + { + return; + } + m_LetterSpacing = value; + letterSpacingChanged(); + } + + inline uint32_t fontAssetId() const { return m_FontAssetId; } + void fontAssetId(uint32_t value) + { + if (m_FontAssetId == value) + { + return; + } + m_FontAssetId = value; + fontAssetIdChanged(); + } + + Core* clone() const override; + void copy(const TextStyleBase& object) + { + m_FontSize = object.m_FontSize; + m_LineHeight = object.m_LineHeight; + m_LetterSpacing = object.m_LetterSpacing; + m_FontAssetId = object.m_FontAssetId; + ContainerComponent::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case fontSizePropertyKey: + m_FontSize = CoreDoubleType::deserialize(reader); + return true; + case lineHeightPropertyKey: + m_LineHeight = CoreDoubleType::deserialize(reader); + return true; + case letterSpacingPropertyKey: + m_LetterSpacing = CoreDoubleType::deserialize(reader); + return true; + case fontAssetIdPropertyKey: + m_FontAssetId = CoreUintType::deserialize(reader); + return true; + } + return ContainerComponent::deserialize(propertyKey, reader); + } + +protected: + virtual void fontSizeChanged() {} + virtual void lineHeightChanged() {} + virtual void letterSpacingChanged() {} + virtual void fontAssetIdChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/text/text_style_feature_base.hpp b/third_party/rive/include/rive/generated/text/text_style_feature_base.hpp new file mode 100644 index 0000000..c590db1 --- /dev/null +++ b/third_party/rive/include/rive/generated/text/text_style_feature_base.hpp @@ -0,0 +1,89 @@ +#ifndef _RIVE_TEXT_STYLE_FEATURE_BASE_HPP_ +#define _RIVE_TEXT_STYLE_FEATURE_BASE_HPP_ +#include "rive/component.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +namespace rive +{ +class TextStyleFeatureBase : public Component +{ +protected: + typedef Component Super; + +public: + static const uint16_t typeKey = 164; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case TextStyleFeatureBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t tagPropertyKey = 356; + static const uint16_t featureValuePropertyKey = 357; + +protected: + uint32_t m_Tag = 0; + uint32_t m_FeatureValue = 1; + +public: + inline uint32_t tag() const { return m_Tag; } + void tag(uint32_t value) + { + if (m_Tag == value) + { + return; + } + m_Tag = value; + tagChanged(); + } + + inline uint32_t featureValue() const { return m_FeatureValue; } + void featureValue(uint32_t value) + { + if (m_FeatureValue == value) + { + return; + } + m_FeatureValue = value; + featureValueChanged(); + } + + Core* clone() const override; + void copy(const TextStyleFeatureBase& object) + { + m_Tag = object.m_Tag; + m_FeatureValue = object.m_FeatureValue; + Component::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case tagPropertyKey: + m_Tag = CoreUintType::deserialize(reader); + return true; + case featureValuePropertyKey: + m_FeatureValue = CoreUintType::deserialize(reader); + return true; + } + return Component::deserialize(propertyKey, reader); + } + +protected: + virtual void tagChanged() {} + virtual void featureValueChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/text/text_style_paint_base.hpp b/third_party/rive/include/rive/generated/text/text_style_paint_base.hpp new file mode 100644 index 0000000..43deafb --- /dev/null +++ b/third_party/rive/include/rive/generated/text/text_style_paint_base.hpp @@ -0,0 +1,40 @@ +#ifndef _RIVE_TEXT_STYLE_PAINT_BASE_HPP_ +#define _RIVE_TEXT_STYLE_PAINT_BASE_HPP_ + +#include "rive/text/text_style.hpp" + +namespace rive +{ +class TextStylePaintBase : public TextStyle +{ +protected: + typedef TextStyle Super; + +public: + static const uint16_t typeKey = 137; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case TextStylePaintBase::typeKey: + case TextStyleBase::typeKey: + case ContainerComponentBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/text/text_target_modifier_base.hpp b/third_party/rive/include/rive/generated/text/text_target_modifier_base.hpp new file mode 100644 index 0000000..5db9f13 --- /dev/null +++ b/third_party/rive/include/rive/generated/text/text_target_modifier_base.hpp @@ -0,0 +1,71 @@ +#ifndef _RIVE_TEXT_TARGET_MODIFIER_BASE_HPP_ +#define _RIVE_TEXT_TARGET_MODIFIER_BASE_HPP_ +#include "rive/core/field_types/core_uint_type.hpp" +#include "rive/text/text_modifier.hpp" +namespace rive +{ +class TextTargetModifierBase : public TextModifier +{ +protected: + typedef TextModifier Super; + +public: + static const uint16_t typeKey = 546; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case TextTargetModifierBase::typeKey: + case TextModifierBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t targetIdPropertyKey = 778; + +protected: + uint32_t m_TargetId = -1; + +public: + inline uint32_t targetId() const { return m_TargetId; } + void targetId(uint32_t value) + { + if (m_TargetId == value) + { + return; + } + m_TargetId = value; + targetIdChanged(); + } + + void copy(const TextTargetModifierBase& object) + { + m_TargetId = object.m_TargetId; + TextModifier::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case targetIdPropertyKey: + m_TargetId = CoreUintType::deserialize(reader); + return true; + } + return TextModifier::deserialize(propertyKey, reader); + } + +protected: + virtual void targetIdChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/text/text_value_run_base.hpp b/third_party/rive/include/rive/generated/text/text_value_run_base.hpp new file mode 100644 index 0000000..24080a6 --- /dev/null +++ b/third_party/rive/include/rive/generated/text/text_value_run_base.hpp @@ -0,0 +1,91 @@ +#ifndef _RIVE_TEXT_VALUE_RUN_BASE_HPP_ +#define _RIVE_TEXT_VALUE_RUN_BASE_HPP_ +#include +#include "rive/component.hpp" +#include "rive/core/field_types/core_string_type.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +namespace rive +{ +class TextValueRunBase : public Component +{ +protected: + typedef Component Super; + +public: + static const uint16_t typeKey = 135; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case TextValueRunBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t styleIdPropertyKey = 272; + static const uint16_t textPropertyKey = 268; + +protected: + uint32_t m_StyleId = -1; + std::string m_Text = ""; + +public: + inline uint32_t styleId() const { return m_StyleId; } + void styleId(uint32_t value) + { + if (m_StyleId == value) + { + return; + } + m_StyleId = value; + styleIdChanged(); + } + + inline const std::string& text() const { return m_Text; } + void text(std::string value) + { + if (m_Text == value) + { + return; + } + m_Text = value; + textChanged(); + } + + Core* clone() const override; + void copy(const TextValueRunBase& object) + { + m_StyleId = object.m_StyleId; + m_Text = object.m_Text; + Component::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case styleIdPropertyKey: + m_StyleId = CoreUintType::deserialize(reader); + return true; + case textPropertyKey: + m_Text = CoreStringType::deserialize(reader); + return true; + } + return Component::deserialize(propertyKey, reader); + } + +protected: + virtual void styleIdChanged() {} + virtual void textChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/text/text_variation_modifier_base.hpp b/third_party/rive/include/rive/generated/text/text_variation_modifier_base.hpp new file mode 100644 index 0000000..188fdf4 --- /dev/null +++ b/third_party/rive/include/rive/generated/text/text_variation_modifier_base.hpp @@ -0,0 +1,92 @@ +#ifndef _RIVE_TEXT_VARIATION_MODIFIER_BASE_HPP_ +#define _RIVE_TEXT_VARIATION_MODIFIER_BASE_HPP_ +#include "rive/core/field_types/core_double_type.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +#include "rive/text/text_shape_modifier.hpp" +namespace rive +{ +class TextVariationModifierBase : public TextShapeModifier +{ +protected: + typedef TextShapeModifier Super; + +public: + static const uint16_t typeKey = 162; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case TextVariationModifierBase::typeKey: + case TextShapeModifierBase::typeKey: + case TextModifierBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t axisTagPropertyKey = 320; + static const uint16_t axisValuePropertyKey = 321; + +protected: + uint32_t m_AxisTag = 0; + float m_AxisValue = 0.0f; + +public: + inline uint32_t axisTag() const { return m_AxisTag; } + void axisTag(uint32_t value) + { + if (m_AxisTag == value) + { + return; + } + m_AxisTag = value; + axisTagChanged(); + } + + inline float axisValue() const { return m_AxisValue; } + void axisValue(float value) + { + if (m_AxisValue == value) + { + return; + } + m_AxisValue = value; + axisValueChanged(); + } + + Core* clone() const override; + void copy(const TextVariationModifierBase& object) + { + m_AxisTag = object.m_AxisTag; + m_AxisValue = object.m_AxisValue; + TextShapeModifier::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case axisTagPropertyKey: + m_AxisTag = CoreUintType::deserialize(reader); + return true; + case axisValuePropertyKey: + m_AxisValue = CoreDoubleType::deserialize(reader); + return true; + } + return TextShapeModifier::deserialize(propertyKey, reader); + } + +protected: + virtual void axisTagChanged() {} + virtual void axisValueChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/transform_component_base.hpp b/third_party/rive/include/rive/generated/transform_component_base.hpp new file mode 100644 index 0000000..3634367 --- /dev/null +++ b/third_party/rive/include/rive/generated/transform_component_base.hpp @@ -0,0 +1,108 @@ +#ifndef _RIVE_TRANSFORM_COMPONENT_BASE_HPP_ +#define _RIVE_TRANSFORM_COMPONENT_BASE_HPP_ +#include "rive/core/field_types/core_double_type.hpp" +#include "rive/world_transform_component.hpp" +namespace rive +{ +class TransformComponentBase : public WorldTransformComponent +{ +protected: + typedef WorldTransformComponent Super; + +public: + static const uint16_t typeKey = 38; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case TransformComponentBase::typeKey: + case WorldTransformComponentBase::typeKey: + case ContainerComponentBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t rotationPropertyKey = 15; + static const uint16_t scaleXPropertyKey = 16; + static const uint16_t scaleYPropertyKey = 17; + +protected: + float m_Rotation = 0.0f; + float m_ScaleX = 1.0f; + float m_ScaleY = 1.0f; + +public: + inline float rotation() const { return m_Rotation; } + void rotation(float value) + { + if (m_Rotation == value) + { + return; + } + m_Rotation = value; + rotationChanged(); + } + + inline float scaleX() const { return m_ScaleX; } + void scaleX(float value) + { + if (m_ScaleX == value) + { + return; + } + m_ScaleX = value; + scaleXChanged(); + } + + inline float scaleY() const { return m_ScaleY; } + void scaleY(float value) + { + if (m_ScaleY == value) + { + return; + } + m_ScaleY = value; + scaleYChanged(); + } + + void copy(const TransformComponentBase& object) + { + m_Rotation = object.m_Rotation; + m_ScaleX = object.m_ScaleX; + m_ScaleY = object.m_ScaleY; + WorldTransformComponent::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case rotationPropertyKey: + m_Rotation = CoreDoubleType::deserialize(reader); + return true; + case scaleXPropertyKey: + m_ScaleX = CoreDoubleType::deserialize(reader); + return true; + case scaleYPropertyKey: + m_ScaleY = CoreDoubleType::deserialize(reader); + return true; + } + return WorldTransformComponent::deserialize(propertyKey, reader); + } + +protected: + virtual void rotationChanged() {} + virtual void scaleXChanged() {} + virtual void scaleYChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/viewmodel/data_enum_base.hpp b/third_party/rive/include/rive/generated/viewmodel/data_enum_base.hpp new file mode 100644 index 0000000..1bc7a7f --- /dev/null +++ b/third_party/rive/include/rive/generated/viewmodel/data_enum_base.hpp @@ -0,0 +1,41 @@ +#ifndef _RIVE_DATA_ENUM_BASE_HPP_ +#define _RIVE_DATA_ENUM_BASE_HPP_ +#include "rive/core.hpp" +namespace rive +{ +class DataEnumBase : public Core +{ +protected: + typedef Core Super; + +public: + static const uint16_t typeKey = 510; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case DataEnumBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + void copy(const DataEnumBase& object) {} + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + return false; + } + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/viewmodel/data_enum_custom_base.hpp b/third_party/rive/include/rive/generated/viewmodel/data_enum_custom_base.hpp new file mode 100644 index 0000000..a62f18a --- /dev/null +++ b/third_party/rive/include/rive/generated/viewmodel/data_enum_custom_base.hpp @@ -0,0 +1,72 @@ +#ifndef _RIVE_DATA_ENUM_CUSTOM_BASE_HPP_ +#define _RIVE_DATA_ENUM_CUSTOM_BASE_HPP_ +#include +#include "rive/core/field_types/core_string_type.hpp" +#include "rive/viewmodel/data_enum.hpp" +namespace rive +{ +class DataEnumCustomBase : public DataEnum +{ +protected: + typedef DataEnum Super; + +public: + static const uint16_t typeKey = 438; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case DataEnumCustomBase::typeKey: + case DataEnumBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t namePropertyKey = 572; + +protected: + std::string m_Name = ""; + +public: + inline const std::string& name() const { return m_Name; } + void name(std::string value) + { + if (m_Name == value) + { + return; + } + m_Name = value; + nameChanged(); + } + + Core* clone() const override; + void copy(const DataEnumCustomBase& object) + { + m_Name = object.m_Name; + DataEnum::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case namePropertyKey: + m_Name = CoreStringType::deserialize(reader); + return true; + } + return DataEnum::deserialize(propertyKey, reader); + } + +protected: + virtual void nameChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/viewmodel/data_enum_system_base.hpp b/third_party/rive/include/rive/generated/viewmodel/data_enum_system_base.hpp new file mode 100644 index 0000000..9e3323f --- /dev/null +++ b/third_party/rive/include/rive/generated/viewmodel/data_enum_system_base.hpp @@ -0,0 +1,71 @@ +#ifndef _RIVE_DATA_ENUM_SYSTEM_BASE_HPP_ +#define _RIVE_DATA_ENUM_SYSTEM_BASE_HPP_ +#include "rive/core/field_types/core_uint_type.hpp" +#include "rive/viewmodel/data_enum.hpp" +namespace rive +{ +class DataEnumSystemBase : public DataEnum +{ +protected: + typedef DataEnum Super; + +public: + static const uint16_t typeKey = 512; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case DataEnumSystemBase::typeKey: + case DataEnumBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t enumTypePropertyKey = 709; + +protected: + uint32_t m_EnumType = 0; + +public: + inline uint32_t enumType() const { return m_EnumType; } + void enumType(uint32_t value) + { + if (m_EnumType == value) + { + return; + } + m_EnumType = value; + enumTypeChanged(); + } + + Core* clone() const override; + void copy(const DataEnumSystemBase& object) + { + m_EnumType = object.m_EnumType; + DataEnum::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case enumTypePropertyKey: + m_EnumType = CoreUintType::deserialize(reader); + return true; + } + return DataEnum::deserialize(propertyKey, reader); + } + +protected: + virtual void enumTypeChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/viewmodel/data_enum_value_base.hpp b/third_party/rive/include/rive/generated/viewmodel/data_enum_value_base.hpp new file mode 100644 index 0000000..1a0488f --- /dev/null +++ b/third_party/rive/include/rive/generated/viewmodel/data_enum_value_base.hpp @@ -0,0 +1,88 @@ +#ifndef _RIVE_DATA_ENUM_VALUE_BASE_HPP_ +#define _RIVE_DATA_ENUM_VALUE_BASE_HPP_ +#include +#include "rive/core.hpp" +#include "rive/core/field_types/core_string_type.hpp" +namespace rive +{ +class DataEnumValueBase : public Core +{ +protected: + typedef Core Super; + +public: + static const uint16_t typeKey = 445; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case DataEnumValueBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t keyPropertyKey = 578; + static const uint16_t valuePropertyKey = 579; + +protected: + std::string m_Key = ""; + std::string m_Value = ""; + +public: + inline const std::string& key() const { return m_Key; } + void key(std::string value) + { + if (m_Key == value) + { + return; + } + m_Key = value; + keyChanged(); + } + + inline const std::string& value() const { return m_Value; } + void value(std::string value) + { + if (m_Value == value) + { + return; + } + m_Value = value; + valueChanged(); + } + + Core* clone() const override; + void copy(const DataEnumValueBase& object) + { + m_Key = object.m_Key; + m_Value = object.m_Value; + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case keyPropertyKey: + m_Key = CoreStringType::deserialize(reader); + return true; + case valuePropertyKey: + m_Value = CoreStringType::deserialize(reader); + return true; + } + return false; + } + +protected: + virtual void keyChanged() {} + virtual void valueChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/viewmodel/viewmodel_base.hpp b/third_party/rive/include/rive/generated/viewmodel/viewmodel_base.hpp new file mode 100644 index 0000000..4f05cdc --- /dev/null +++ b/third_party/rive/include/rive/generated/viewmodel/viewmodel_base.hpp @@ -0,0 +1,36 @@ +#ifndef _RIVE_VIEW_MODEL_BASE_HPP_ +#define _RIVE_VIEW_MODEL_BASE_HPP_ +#include "rive/viewmodel/viewmodel_component.hpp" +namespace rive +{ +class ViewModelBase : public ViewModelComponent +{ +protected: + typedef ViewModelComponent Super; + +public: + static const uint16_t typeKey = 435; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case ViewModelBase::typeKey: + case ViewModelComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/viewmodel/viewmodel_component_base.hpp b/third_party/rive/include/rive/generated/viewmodel/viewmodel_component_base.hpp new file mode 100644 index 0000000..e8def96 --- /dev/null +++ b/third_party/rive/include/rive/generated/viewmodel/viewmodel_component_base.hpp @@ -0,0 +1,67 @@ +#ifndef _RIVE_VIEW_MODEL_COMPONENT_BASE_HPP_ +#define _RIVE_VIEW_MODEL_COMPONENT_BASE_HPP_ +#include +#include "rive/core.hpp" +#include "rive/core/field_types/core_string_type.hpp" +namespace rive +{ +class ViewModelComponentBase : public Core +{ +protected: + typedef Core Super; + +public: + static const uint16_t typeKey = 429; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case ViewModelComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t namePropertyKey = 557; + +protected: + std::string m_Name = ""; + +public: + inline const std::string& name() const { return m_Name; } + void name(std::string value) + { + if (m_Name == value) + { + return; + } + m_Name = value; + nameChanged(); + } + + Core* clone() const override; + void copy(const ViewModelComponentBase& object) { m_Name = object.m_Name; } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case namePropertyKey: + m_Name = CoreStringType::deserialize(reader); + return true; + } + return false; + } + +protected: + virtual void nameChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/viewmodel/viewmodel_instance_asset_base.hpp b/third_party/rive/include/rive/generated/viewmodel/viewmodel_instance_asset_base.hpp new file mode 100644 index 0000000..e40a727 --- /dev/null +++ b/third_party/rive/include/rive/generated/viewmodel/viewmodel_instance_asset_base.hpp @@ -0,0 +1,71 @@ +#ifndef _RIVE_VIEW_MODEL_INSTANCE_ASSET_BASE_HPP_ +#define _RIVE_VIEW_MODEL_INSTANCE_ASSET_BASE_HPP_ +#include "rive/core/field_types/core_uint_type.hpp" +#include "rive/viewmodel/viewmodel_instance_value.hpp" +namespace rive +{ +class ViewModelInstanceAssetBase : public ViewModelInstanceValue +{ +protected: + typedef ViewModelInstanceValue Super; + +public: + static const uint16_t typeKey = 586; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case ViewModelInstanceAssetBase::typeKey: + case ViewModelInstanceValueBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t propertyValuePropertyKey = 824; + +protected: + uint32_t m_PropertyValue = -1; + +public: + inline uint32_t propertyValue() const { return m_PropertyValue; } + void propertyValue(uint32_t value) + { + if (m_PropertyValue == value) + { + return; + } + m_PropertyValue = value; + propertyValueChanged(); + } + + Core* clone() const override; + void copy(const ViewModelInstanceAssetBase& object) + { + m_PropertyValue = object.m_PropertyValue; + ViewModelInstanceValue::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case propertyValuePropertyKey: + m_PropertyValue = CoreUintType::deserialize(reader); + return true; + } + return ViewModelInstanceValue::deserialize(propertyKey, reader); + } + +protected: + virtual void propertyValueChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/viewmodel/viewmodel_instance_asset_image_base.hpp b/third_party/rive/include/rive/generated/viewmodel/viewmodel_instance_asset_image_base.hpp new file mode 100644 index 0000000..542e8b7 --- /dev/null +++ b/third_party/rive/include/rive/generated/viewmodel/viewmodel_instance_asset_image_base.hpp @@ -0,0 +1,37 @@ +#ifndef _RIVE_VIEW_MODEL_INSTANCE_ASSET_IMAGE_BASE_HPP_ +#define _RIVE_VIEW_MODEL_INSTANCE_ASSET_IMAGE_BASE_HPP_ +#include "rive/viewmodel/viewmodel_instance_asset.hpp" +namespace rive +{ +class ViewModelInstanceAssetImageBase : public ViewModelInstanceAsset +{ +protected: + typedef ViewModelInstanceAsset Super; + +public: + static const uint16_t typeKey = 587; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case ViewModelInstanceAssetImageBase::typeKey: + case ViewModelInstanceAssetBase::typeKey: + case ViewModelInstanceValueBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/viewmodel/viewmodel_instance_base.hpp b/third_party/rive/include/rive/generated/viewmodel/viewmodel_instance_base.hpp new file mode 100644 index 0000000..2f40103 --- /dev/null +++ b/third_party/rive/include/rive/generated/viewmodel/viewmodel_instance_base.hpp @@ -0,0 +1,71 @@ +#ifndef _RIVE_VIEW_MODEL_INSTANCE_BASE_HPP_ +#define _RIVE_VIEW_MODEL_INSTANCE_BASE_HPP_ +#include "rive/component.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +namespace rive +{ +class ViewModelInstanceBase : public Component +{ +protected: + typedef Component Super; + +public: + static const uint16_t typeKey = 437; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case ViewModelInstanceBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t viewModelIdPropertyKey = 566; + +protected: + uint32_t m_ViewModelId = 0; + +public: + inline uint32_t viewModelId() const { return m_ViewModelId; } + void viewModelId(uint32_t value) + { + if (m_ViewModelId == value) + { + return; + } + m_ViewModelId = value; + viewModelIdChanged(); + } + + Core* clone() const override; + void copy(const ViewModelInstanceBase& object) + { + m_ViewModelId = object.m_ViewModelId; + Component::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case viewModelIdPropertyKey: + m_ViewModelId = CoreUintType::deserialize(reader); + return true; + } + return Component::deserialize(propertyKey, reader); + } + +protected: + virtual void viewModelIdChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/viewmodel/viewmodel_instance_boolean_base.hpp b/third_party/rive/include/rive/generated/viewmodel/viewmodel_instance_boolean_base.hpp new file mode 100644 index 0000000..628fb0b --- /dev/null +++ b/third_party/rive/include/rive/generated/viewmodel/viewmodel_instance_boolean_base.hpp @@ -0,0 +1,71 @@ +#ifndef _RIVE_VIEW_MODEL_INSTANCE_BOOLEAN_BASE_HPP_ +#define _RIVE_VIEW_MODEL_INSTANCE_BOOLEAN_BASE_HPP_ +#include "rive/core/field_types/core_bool_type.hpp" +#include "rive/viewmodel/viewmodel_instance_value.hpp" +namespace rive +{ +class ViewModelInstanceBooleanBase : public ViewModelInstanceValue +{ +protected: + typedef ViewModelInstanceValue Super; + +public: + static const uint16_t typeKey = 449; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case ViewModelInstanceBooleanBase::typeKey: + case ViewModelInstanceValueBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t propertyValuePropertyKey = 593; + +protected: + bool m_PropertyValue = false; + +public: + inline bool propertyValue() const { return m_PropertyValue; } + void propertyValue(bool value) + { + if (m_PropertyValue == value) + { + return; + } + m_PropertyValue = value; + propertyValueChanged(); + } + + Core* clone() const override; + void copy(const ViewModelInstanceBooleanBase& object) + { + m_PropertyValue = object.m_PropertyValue; + ViewModelInstanceValue::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case propertyValuePropertyKey: + m_PropertyValue = CoreBoolType::deserialize(reader); + return true; + } + return ViewModelInstanceValue::deserialize(propertyKey, reader); + } + +protected: + virtual void propertyValueChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/viewmodel/viewmodel_instance_color_base.hpp b/third_party/rive/include/rive/generated/viewmodel/viewmodel_instance_color_base.hpp new file mode 100644 index 0000000..f74b073 --- /dev/null +++ b/third_party/rive/include/rive/generated/viewmodel/viewmodel_instance_color_base.hpp @@ -0,0 +1,71 @@ +#ifndef _RIVE_VIEW_MODEL_INSTANCE_COLOR_BASE_HPP_ +#define _RIVE_VIEW_MODEL_INSTANCE_COLOR_BASE_HPP_ +#include "rive/core/field_types/core_color_type.hpp" +#include "rive/viewmodel/viewmodel_instance_value.hpp" +namespace rive +{ +class ViewModelInstanceColorBase : public ViewModelInstanceValue +{ +protected: + typedef ViewModelInstanceValue Super; + +public: + static const uint16_t typeKey = 426; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case ViewModelInstanceColorBase::typeKey: + case ViewModelInstanceValueBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t propertyValuePropertyKey = 555; + +protected: + int m_PropertyValue = 0xFF000000; + +public: + inline int propertyValue() const { return m_PropertyValue; } + void propertyValue(int value) + { + if (m_PropertyValue == value) + { + return; + } + m_PropertyValue = value; + propertyValueChanged(); + } + + Core* clone() const override; + void copy(const ViewModelInstanceColorBase& object) + { + m_PropertyValue = object.m_PropertyValue; + ViewModelInstanceValue::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case propertyValuePropertyKey: + m_PropertyValue = CoreColorType::deserialize(reader); + return true; + } + return ViewModelInstanceValue::deserialize(propertyKey, reader); + } + +protected: + virtual void propertyValueChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/viewmodel/viewmodel_instance_enum_base.hpp b/third_party/rive/include/rive/generated/viewmodel/viewmodel_instance_enum_base.hpp new file mode 100644 index 0000000..de624a5 --- /dev/null +++ b/third_party/rive/include/rive/generated/viewmodel/viewmodel_instance_enum_base.hpp @@ -0,0 +1,71 @@ +#ifndef _RIVE_VIEW_MODEL_INSTANCE_ENUM_BASE_HPP_ +#define _RIVE_VIEW_MODEL_INSTANCE_ENUM_BASE_HPP_ +#include "rive/core/field_types/core_uint_type.hpp" +#include "rive/viewmodel/viewmodel_instance_value.hpp" +namespace rive +{ +class ViewModelInstanceEnumBase : public ViewModelInstanceValue +{ +protected: + typedef ViewModelInstanceValue Super; + +public: + static const uint16_t typeKey = 432; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case ViewModelInstanceEnumBase::typeKey: + case ViewModelInstanceValueBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t propertyValuePropertyKey = 560; + +protected: + uint32_t m_PropertyValue = 0; + +public: + inline uint32_t propertyValue() const { return m_PropertyValue; } + void propertyValue(uint32_t value) + { + if (m_PropertyValue == value) + { + return; + } + m_PropertyValue = value; + propertyValueChanged(); + } + + Core* clone() const override; + void copy(const ViewModelInstanceEnumBase& object) + { + m_PropertyValue = object.m_PropertyValue; + ViewModelInstanceValue::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case propertyValuePropertyKey: + m_PropertyValue = CoreUintType::deserialize(reader); + return true; + } + return ViewModelInstanceValue::deserialize(propertyKey, reader); + } + +protected: + virtual void propertyValueChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/viewmodel/viewmodel_instance_list_base.hpp b/third_party/rive/include/rive/generated/viewmodel/viewmodel_instance_list_base.hpp new file mode 100644 index 0000000..ec14bda --- /dev/null +++ b/third_party/rive/include/rive/generated/viewmodel/viewmodel_instance_list_base.hpp @@ -0,0 +1,36 @@ +#ifndef _RIVE_VIEW_MODEL_INSTANCE_LIST_BASE_HPP_ +#define _RIVE_VIEW_MODEL_INSTANCE_LIST_BASE_HPP_ +#include "rive/viewmodel/viewmodel_instance_value.hpp" +namespace rive +{ +class ViewModelInstanceListBase : public ViewModelInstanceValue +{ +protected: + typedef ViewModelInstanceValue Super; + +public: + static const uint16_t typeKey = 441; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case ViewModelInstanceListBase::typeKey: + case ViewModelInstanceValueBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/viewmodel/viewmodel_instance_list_item_base.hpp b/third_party/rive/include/rive/generated/viewmodel/viewmodel_instance_list_item_base.hpp new file mode 100644 index 0000000..7220b91 --- /dev/null +++ b/third_party/rive/include/rive/generated/viewmodel/viewmodel_instance_list_item_base.hpp @@ -0,0 +1,90 @@ +#ifndef _RIVE_VIEW_MODEL_INSTANCE_LIST_ITEM_BASE_HPP_ +#define _RIVE_VIEW_MODEL_INSTANCE_LIST_ITEM_BASE_HPP_ +#include "rive/core.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +namespace rive +{ +class ViewModelInstanceListItemBase : public Core +{ +protected: + typedef Core Super; + +public: + static const uint16_t typeKey = 427; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case ViewModelInstanceListItemBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t viewModelIdPropertyKey = 549; + static const uint16_t viewModelInstanceIdPropertyKey = 550; + +protected: + uint32_t m_ViewModelId = -1; + uint32_t m_ViewModelInstanceId = -1; + +public: + inline uint32_t viewModelId() const { return m_ViewModelId; } + void viewModelId(uint32_t value) + { + if (m_ViewModelId == value) + { + return; + } + m_ViewModelId = value; + viewModelIdChanged(); + } + + inline uint32_t viewModelInstanceId() const + { + return m_ViewModelInstanceId; + } + void viewModelInstanceId(uint32_t value) + { + if (m_ViewModelInstanceId == value) + { + return; + } + m_ViewModelInstanceId = value; + viewModelInstanceIdChanged(); + } + + Core* clone() const override; + void copy(const ViewModelInstanceListItemBase& object) + { + m_ViewModelId = object.m_ViewModelId; + m_ViewModelInstanceId = object.m_ViewModelInstanceId; + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case viewModelIdPropertyKey: + m_ViewModelId = CoreUintType::deserialize(reader); + return true; + case viewModelInstanceIdPropertyKey: + m_ViewModelInstanceId = CoreUintType::deserialize(reader); + return true; + } + return false; + } + +protected: + virtual void viewModelIdChanged() {} + virtual void viewModelInstanceIdChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/viewmodel/viewmodel_instance_number_base.hpp b/third_party/rive/include/rive/generated/viewmodel/viewmodel_instance_number_base.hpp new file mode 100644 index 0000000..57c2356 --- /dev/null +++ b/third_party/rive/include/rive/generated/viewmodel/viewmodel_instance_number_base.hpp @@ -0,0 +1,71 @@ +#ifndef _RIVE_VIEW_MODEL_INSTANCE_NUMBER_BASE_HPP_ +#define _RIVE_VIEW_MODEL_INSTANCE_NUMBER_BASE_HPP_ +#include "rive/core/field_types/core_double_type.hpp" +#include "rive/viewmodel/viewmodel_instance_value.hpp" +namespace rive +{ +class ViewModelInstanceNumberBase : public ViewModelInstanceValue +{ +protected: + typedef ViewModelInstanceValue Super; + +public: + static const uint16_t typeKey = 442; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case ViewModelInstanceNumberBase::typeKey: + case ViewModelInstanceValueBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t propertyValuePropertyKey = 575; + +protected: + float m_PropertyValue = 0.0f; + +public: + inline float propertyValue() const { return m_PropertyValue; } + void propertyValue(float value) + { + if (m_PropertyValue == value) + { + return; + } + m_PropertyValue = value; + propertyValueChanged(); + } + + Core* clone() const override; + void copy(const ViewModelInstanceNumberBase& object) + { + m_PropertyValue = object.m_PropertyValue; + ViewModelInstanceValue::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case propertyValuePropertyKey: + m_PropertyValue = CoreDoubleType::deserialize(reader); + return true; + } + return ViewModelInstanceValue::deserialize(propertyKey, reader); + } + +protected: + virtual void propertyValueChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/viewmodel/viewmodel_instance_string_base.hpp b/third_party/rive/include/rive/generated/viewmodel/viewmodel_instance_string_base.hpp new file mode 100644 index 0000000..a757c2d --- /dev/null +++ b/third_party/rive/include/rive/generated/viewmodel/viewmodel_instance_string_base.hpp @@ -0,0 +1,72 @@ +#ifndef _RIVE_VIEW_MODEL_INSTANCE_STRING_BASE_HPP_ +#define _RIVE_VIEW_MODEL_INSTANCE_STRING_BASE_HPP_ +#include +#include "rive/core/field_types/core_string_type.hpp" +#include "rive/viewmodel/viewmodel_instance_value.hpp" +namespace rive +{ +class ViewModelInstanceStringBase : public ViewModelInstanceValue +{ +protected: + typedef ViewModelInstanceValue Super; + +public: + static const uint16_t typeKey = 433; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case ViewModelInstanceStringBase::typeKey: + case ViewModelInstanceValueBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t propertyValuePropertyKey = 561; + +protected: + std::string m_PropertyValue = ""; + +public: + inline const std::string& propertyValue() const { return m_PropertyValue; } + void propertyValue(std::string value) + { + if (m_PropertyValue == value) + { + return; + } + m_PropertyValue = value; + propertyValueChanged(); + } + + Core* clone() const override; + void copy(const ViewModelInstanceStringBase& object) + { + m_PropertyValue = object.m_PropertyValue; + ViewModelInstanceValue::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case propertyValuePropertyKey: + m_PropertyValue = CoreStringType::deserialize(reader); + return true; + } + return ViewModelInstanceValue::deserialize(propertyKey, reader); + } + +protected: + virtual void propertyValueChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/viewmodel/viewmodel_instance_symbol_base.hpp b/third_party/rive/include/rive/generated/viewmodel/viewmodel_instance_symbol_base.hpp new file mode 100644 index 0000000..204cd1b --- /dev/null +++ b/third_party/rive/include/rive/generated/viewmodel/viewmodel_instance_symbol_base.hpp @@ -0,0 +1,34 @@ +#ifndef _RIVE_VIEW_MODEL_INSTANCE_SYMBOL_BASE_HPP_ +#define _RIVE_VIEW_MODEL_INSTANCE_SYMBOL_BASE_HPP_ +#include "rive/viewmodel/viewmodel_instance_value.hpp" +namespace rive +{ +class ViewModelInstanceSymbolBase : public ViewModelInstanceValue +{ +protected: + typedef ViewModelInstanceValue Super; + +public: + static const uint16_t typeKey = 565; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case ViewModelInstanceSymbolBase::typeKey: + case ViewModelInstanceValueBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/viewmodel/viewmodel_instance_symbol_list_index_base.hpp b/third_party/rive/include/rive/generated/viewmodel/viewmodel_instance_symbol_list_index_base.hpp new file mode 100644 index 0000000..43454f5 --- /dev/null +++ b/third_party/rive/include/rive/generated/viewmodel/viewmodel_instance_symbol_list_index_base.hpp @@ -0,0 +1,72 @@ +#ifndef _RIVE_VIEW_MODEL_INSTANCE_SYMBOL_LIST_INDEX_BASE_HPP_ +#define _RIVE_VIEW_MODEL_INSTANCE_SYMBOL_LIST_INDEX_BASE_HPP_ +#include "rive/core/field_types/core_uint_type.hpp" +#include "rive/viewmodel/viewmodel_instance_symbol.hpp" +namespace rive +{ +class ViewModelInstanceSymbolListIndexBase : public ViewModelInstanceSymbol +{ +protected: + typedef ViewModelInstanceSymbol Super; + +public: + static const uint16_t typeKey = 566; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case ViewModelInstanceSymbolListIndexBase::typeKey: + case ViewModelInstanceSymbolBase::typeKey: + case ViewModelInstanceValueBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t propertyValuePropertyKey = 814; + +protected: + uint32_t m_PropertyValue = 0; + +public: + inline uint32_t propertyValue() const { return m_PropertyValue; } + void propertyValue(uint32_t value) + { + if (m_PropertyValue == value) + { + return; + } + m_PropertyValue = value; + propertyValueChanged(); + } + + Core* clone() const override; + void copy(const ViewModelInstanceSymbolListIndexBase& object) + { + m_PropertyValue = object.m_PropertyValue; + ViewModelInstanceSymbol::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case propertyValuePropertyKey: + m_PropertyValue = CoreUintType::deserialize(reader); + return true; + } + return ViewModelInstanceSymbol::deserialize(propertyKey, reader); + } + +protected: + virtual void propertyValueChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/viewmodel/viewmodel_instance_trigger_base.hpp b/third_party/rive/include/rive/generated/viewmodel/viewmodel_instance_trigger_base.hpp new file mode 100644 index 0000000..0529b31 --- /dev/null +++ b/third_party/rive/include/rive/generated/viewmodel/viewmodel_instance_trigger_base.hpp @@ -0,0 +1,71 @@ +#ifndef _RIVE_VIEW_MODEL_INSTANCE_TRIGGER_BASE_HPP_ +#define _RIVE_VIEW_MODEL_INSTANCE_TRIGGER_BASE_HPP_ +#include "rive/core/field_types/core_uint_type.hpp" +#include "rive/viewmodel/viewmodel_instance_value.hpp" +namespace rive +{ +class ViewModelInstanceTriggerBase : public ViewModelInstanceValue +{ +protected: + typedef ViewModelInstanceValue Super; + +public: + static const uint16_t typeKey = 501; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case ViewModelInstanceTriggerBase::typeKey: + case ViewModelInstanceValueBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t propertyValuePropertyKey = 687; + +protected: + uint32_t m_PropertyValue = 0; + +public: + inline uint32_t propertyValue() const { return m_PropertyValue; } + void propertyValue(uint32_t value) + { + if (m_PropertyValue == value) + { + return; + } + m_PropertyValue = value; + propertyValueChanged(); + } + + Core* clone() const override; + void copy(const ViewModelInstanceTriggerBase& object) + { + m_PropertyValue = object.m_PropertyValue; + ViewModelInstanceValue::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case propertyValuePropertyKey: + m_PropertyValue = CoreUintType::deserialize(reader); + return true; + } + return ViewModelInstanceValue::deserialize(propertyKey, reader); + } + +protected: + virtual void propertyValueChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/viewmodel/viewmodel_instance_value_base.hpp b/third_party/rive/include/rive/generated/viewmodel/viewmodel_instance_value_base.hpp new file mode 100644 index 0000000..3278f33 --- /dev/null +++ b/third_party/rive/include/rive/generated/viewmodel/viewmodel_instance_value_base.hpp @@ -0,0 +1,71 @@ +#ifndef _RIVE_VIEW_MODEL_INSTANCE_VALUE_BASE_HPP_ +#define _RIVE_VIEW_MODEL_INSTANCE_VALUE_BASE_HPP_ +#include "rive/core.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +namespace rive +{ +class ViewModelInstanceValueBase : public Core +{ +protected: + typedef Core Super; + +public: + static const uint16_t typeKey = 428; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case ViewModelInstanceValueBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t viewModelPropertyIdPropertyKey = 554; + +protected: + uint32_t m_ViewModelPropertyId = 0; + +public: + inline uint32_t viewModelPropertyId() const + { + return m_ViewModelPropertyId; + } + void viewModelPropertyId(uint32_t value) + { + if (m_ViewModelPropertyId == value) + { + return; + } + m_ViewModelPropertyId = value; + viewModelPropertyIdChanged(); + } + + void copy(const ViewModelInstanceValueBase& object) + { + m_ViewModelPropertyId = object.m_ViewModelPropertyId; + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case viewModelPropertyIdPropertyKey: + m_ViewModelPropertyId = CoreUintType::deserialize(reader); + return true; + } + return false; + } + +protected: + virtual void viewModelPropertyIdChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/viewmodel/viewmodel_instance_viewmodel_base.hpp b/third_party/rive/include/rive/generated/viewmodel/viewmodel_instance_viewmodel_base.hpp new file mode 100644 index 0000000..ee303f0 --- /dev/null +++ b/third_party/rive/include/rive/generated/viewmodel/viewmodel_instance_viewmodel_base.hpp @@ -0,0 +1,71 @@ +#ifndef _RIVE_VIEW_MODEL_INSTANCE_VIEW_MODEL_BASE_HPP_ +#define _RIVE_VIEW_MODEL_INSTANCE_VIEW_MODEL_BASE_HPP_ +#include "rive/core/field_types/core_uint_type.hpp" +#include "rive/viewmodel/viewmodel_instance_value.hpp" +namespace rive +{ +class ViewModelInstanceViewModelBase : public ViewModelInstanceValue +{ +protected: + typedef ViewModelInstanceValue Super; + +public: + static const uint16_t typeKey = 444; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case ViewModelInstanceViewModelBase::typeKey: + case ViewModelInstanceValueBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t propertyValuePropertyKey = 577; + +protected: + uint32_t m_PropertyValue = 0; + +public: + inline uint32_t propertyValue() const { return m_PropertyValue; } + void propertyValue(uint32_t value) + { + if (m_PropertyValue == value) + { + return; + } + m_PropertyValue = value; + propertyValueChanged(); + } + + Core* clone() const override; + void copy(const ViewModelInstanceViewModelBase& object) + { + m_PropertyValue = object.m_PropertyValue; + ViewModelInstanceValue::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case propertyValuePropertyKey: + m_PropertyValue = CoreUintType::deserialize(reader); + return true; + } + return ViewModelInstanceValue::deserialize(propertyKey, reader); + } + +protected: + virtual void propertyValueChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/viewmodel/viewmodel_property_asset_base.hpp b/third_party/rive/include/rive/generated/viewmodel/viewmodel_property_asset_base.hpp new file mode 100644 index 0000000..367bfea --- /dev/null +++ b/third_party/rive/include/rive/generated/viewmodel/viewmodel_property_asset_base.hpp @@ -0,0 +1,37 @@ +#ifndef _RIVE_VIEW_MODEL_PROPERTY_ASSET_BASE_HPP_ +#define _RIVE_VIEW_MODEL_PROPERTY_ASSET_BASE_HPP_ +#include "rive/viewmodel/viewmodel_property.hpp" +namespace rive +{ +class ViewModelPropertyAssetBase : public ViewModelProperty +{ +protected: + typedef ViewModelProperty Super; + +public: + static const uint16_t typeKey = 584; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case ViewModelPropertyAssetBase::typeKey: + case ViewModelPropertyBase::typeKey: + case ViewModelComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/viewmodel/viewmodel_property_asset_image_base.hpp b/third_party/rive/include/rive/generated/viewmodel/viewmodel_property_asset_image_base.hpp new file mode 100644 index 0000000..d532bc1 --- /dev/null +++ b/third_party/rive/include/rive/generated/viewmodel/viewmodel_property_asset_image_base.hpp @@ -0,0 +1,38 @@ +#ifndef _RIVE_VIEW_MODEL_PROPERTY_ASSET_IMAGE_BASE_HPP_ +#define _RIVE_VIEW_MODEL_PROPERTY_ASSET_IMAGE_BASE_HPP_ +#include "rive/viewmodel/viewmodel_property_asset.hpp" +namespace rive +{ +class ViewModelPropertyAssetImageBase : public ViewModelPropertyAsset +{ +protected: + typedef ViewModelPropertyAsset Super; + +public: + static const uint16_t typeKey = 585; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case ViewModelPropertyAssetImageBase::typeKey: + case ViewModelPropertyAssetBase::typeKey: + case ViewModelPropertyBase::typeKey: + case ViewModelComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/viewmodel/viewmodel_property_base.hpp b/third_party/rive/include/rive/generated/viewmodel/viewmodel_property_base.hpp new file mode 100644 index 0000000..f016c18 --- /dev/null +++ b/third_party/rive/include/rive/generated/viewmodel/viewmodel_property_base.hpp @@ -0,0 +1,36 @@ +#ifndef _RIVE_VIEW_MODEL_PROPERTY_BASE_HPP_ +#define _RIVE_VIEW_MODEL_PROPERTY_BASE_HPP_ +#include "rive/viewmodel/viewmodel_component.hpp" +namespace rive +{ +class ViewModelPropertyBase : public ViewModelComponent +{ +protected: + typedef ViewModelComponent Super; + +public: + static const uint16_t typeKey = 430; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case ViewModelPropertyBase::typeKey: + case ViewModelComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/viewmodel/viewmodel_property_boolean_base.hpp b/third_party/rive/include/rive/generated/viewmodel/viewmodel_property_boolean_base.hpp new file mode 100644 index 0000000..e69e21a --- /dev/null +++ b/third_party/rive/include/rive/generated/viewmodel/viewmodel_property_boolean_base.hpp @@ -0,0 +1,37 @@ +#ifndef _RIVE_VIEW_MODEL_PROPERTY_BOOLEAN_BASE_HPP_ +#define _RIVE_VIEW_MODEL_PROPERTY_BOOLEAN_BASE_HPP_ +#include "rive/viewmodel/viewmodel_property.hpp" +namespace rive +{ +class ViewModelPropertyBooleanBase : public ViewModelProperty +{ +protected: + typedef ViewModelProperty Super; + +public: + static const uint16_t typeKey = 448; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case ViewModelPropertyBooleanBase::typeKey: + case ViewModelPropertyBase::typeKey: + case ViewModelComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/viewmodel/viewmodel_property_color_base.hpp b/third_party/rive/include/rive/generated/viewmodel/viewmodel_property_color_base.hpp new file mode 100644 index 0000000..70af9f8 --- /dev/null +++ b/third_party/rive/include/rive/generated/viewmodel/viewmodel_property_color_base.hpp @@ -0,0 +1,37 @@ +#ifndef _RIVE_VIEW_MODEL_PROPERTY_COLOR_BASE_HPP_ +#define _RIVE_VIEW_MODEL_PROPERTY_COLOR_BASE_HPP_ +#include "rive/viewmodel/viewmodel_property.hpp" +namespace rive +{ +class ViewModelPropertyColorBase : public ViewModelProperty +{ +protected: + typedef ViewModelProperty Super; + +public: + static const uint16_t typeKey = 440; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case ViewModelPropertyColorBase::typeKey: + case ViewModelPropertyBase::typeKey: + case ViewModelComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/viewmodel/viewmodel_property_enum_base.hpp b/third_party/rive/include/rive/generated/viewmodel/viewmodel_property_enum_base.hpp new file mode 100644 index 0000000..837303b --- /dev/null +++ b/third_party/rive/include/rive/generated/viewmodel/viewmodel_property_enum_base.hpp @@ -0,0 +1,37 @@ +#ifndef _RIVE_VIEW_MODEL_PROPERTY_ENUM_BASE_HPP_ +#define _RIVE_VIEW_MODEL_PROPERTY_ENUM_BASE_HPP_ +#include "rive/viewmodel/viewmodel_property.hpp" +namespace rive +{ +class ViewModelPropertyEnumBase : public ViewModelProperty +{ +protected: + typedef ViewModelProperty Super; + +public: + static const uint16_t typeKey = 509; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case ViewModelPropertyEnumBase::typeKey: + case ViewModelPropertyBase::typeKey: + case ViewModelComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/viewmodel/viewmodel_property_enum_custom_base.hpp b/third_party/rive/include/rive/generated/viewmodel/viewmodel_property_enum_custom_base.hpp new file mode 100644 index 0000000..9734abf --- /dev/null +++ b/third_party/rive/include/rive/generated/viewmodel/viewmodel_property_enum_custom_base.hpp @@ -0,0 +1,73 @@ +#ifndef _RIVE_VIEW_MODEL_PROPERTY_ENUM_CUSTOM_BASE_HPP_ +#define _RIVE_VIEW_MODEL_PROPERTY_ENUM_CUSTOM_BASE_HPP_ +#include "rive/core/field_types/core_uint_type.hpp" +#include "rive/viewmodel/viewmodel_property_enum.hpp" +namespace rive +{ +class ViewModelPropertyEnumCustomBase : public ViewModelPropertyEnum +{ +protected: + typedef ViewModelPropertyEnum Super; + +public: + static const uint16_t typeKey = 439; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case ViewModelPropertyEnumCustomBase::typeKey: + case ViewModelPropertyEnumBase::typeKey: + case ViewModelPropertyBase::typeKey: + case ViewModelComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t enumIdPropertyKey = 574; + +protected: + uint32_t m_EnumId = -1; + +public: + inline uint32_t enumId() const { return m_EnumId; } + void enumId(uint32_t value) + { + if (m_EnumId == value) + { + return; + } + m_EnumId = value; + enumIdChanged(); + } + + Core* clone() const override; + void copy(const ViewModelPropertyEnumCustomBase& object) + { + m_EnumId = object.m_EnumId; + ViewModelPropertyEnum::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case enumIdPropertyKey: + m_EnumId = CoreUintType::deserialize(reader); + return true; + } + return ViewModelPropertyEnum::deserialize(propertyKey, reader); + } + +protected: + virtual void enumIdChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/viewmodel/viewmodel_property_enum_system_base.hpp b/third_party/rive/include/rive/generated/viewmodel/viewmodel_property_enum_system_base.hpp new file mode 100644 index 0000000..48422d5 --- /dev/null +++ b/third_party/rive/include/rive/generated/viewmodel/viewmodel_property_enum_system_base.hpp @@ -0,0 +1,73 @@ +#ifndef _RIVE_VIEW_MODEL_PROPERTY_ENUM_SYSTEM_BASE_HPP_ +#define _RIVE_VIEW_MODEL_PROPERTY_ENUM_SYSTEM_BASE_HPP_ +#include "rive/core/field_types/core_uint_type.hpp" +#include "rive/viewmodel/viewmodel_property_enum.hpp" +namespace rive +{ +class ViewModelPropertyEnumSystemBase : public ViewModelPropertyEnum +{ +protected: + typedef ViewModelPropertyEnum Super; + +public: + static const uint16_t typeKey = 511; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case ViewModelPropertyEnumSystemBase::typeKey: + case ViewModelPropertyEnumBase::typeKey: + case ViewModelPropertyBase::typeKey: + case ViewModelComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t enumTypePropertyKey = 708; + +protected: + uint32_t m_EnumType = 0; + +public: + inline uint32_t enumType() const { return m_EnumType; } + void enumType(uint32_t value) + { + if (m_EnumType == value) + { + return; + } + m_EnumType = value; + enumTypeChanged(); + } + + Core* clone() const override; + void copy(const ViewModelPropertyEnumSystemBase& object) + { + m_EnumType = object.m_EnumType; + ViewModelPropertyEnum::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case enumTypePropertyKey: + m_EnumType = CoreUintType::deserialize(reader); + return true; + } + return ViewModelPropertyEnum::deserialize(propertyKey, reader); + } + +protected: + virtual void enumTypeChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/viewmodel/viewmodel_property_list_base.hpp b/third_party/rive/include/rive/generated/viewmodel/viewmodel_property_list_base.hpp new file mode 100644 index 0000000..6cd3d65 --- /dev/null +++ b/third_party/rive/include/rive/generated/viewmodel/viewmodel_property_list_base.hpp @@ -0,0 +1,37 @@ +#ifndef _RIVE_VIEW_MODEL_PROPERTY_LIST_BASE_HPP_ +#define _RIVE_VIEW_MODEL_PROPERTY_LIST_BASE_HPP_ +#include "rive/viewmodel/viewmodel_property.hpp" +namespace rive +{ +class ViewModelPropertyListBase : public ViewModelProperty +{ +protected: + typedef ViewModelProperty Super; + +public: + static const uint16_t typeKey = 434; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case ViewModelPropertyListBase::typeKey: + case ViewModelPropertyBase::typeKey: + case ViewModelComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/viewmodel/viewmodel_property_number_base.hpp b/third_party/rive/include/rive/generated/viewmodel/viewmodel_property_number_base.hpp new file mode 100644 index 0000000..aa6733b --- /dev/null +++ b/third_party/rive/include/rive/generated/viewmodel/viewmodel_property_number_base.hpp @@ -0,0 +1,37 @@ +#ifndef _RIVE_VIEW_MODEL_PROPERTY_NUMBER_BASE_HPP_ +#define _RIVE_VIEW_MODEL_PROPERTY_NUMBER_BASE_HPP_ +#include "rive/viewmodel/viewmodel_property.hpp" +namespace rive +{ +class ViewModelPropertyNumberBase : public ViewModelProperty +{ +protected: + typedef ViewModelProperty Super; + +public: + static const uint16_t typeKey = 431; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case ViewModelPropertyNumberBase::typeKey: + case ViewModelPropertyBase::typeKey: + case ViewModelComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/viewmodel/viewmodel_property_string_base.hpp b/third_party/rive/include/rive/generated/viewmodel/viewmodel_property_string_base.hpp new file mode 100644 index 0000000..b5103f5 --- /dev/null +++ b/third_party/rive/include/rive/generated/viewmodel/viewmodel_property_string_base.hpp @@ -0,0 +1,37 @@ +#ifndef _RIVE_VIEW_MODEL_PROPERTY_STRING_BASE_HPP_ +#define _RIVE_VIEW_MODEL_PROPERTY_STRING_BASE_HPP_ +#include "rive/viewmodel/viewmodel_property.hpp" +namespace rive +{ +class ViewModelPropertyStringBase : public ViewModelProperty +{ +protected: + typedef ViewModelProperty Super; + +public: + static const uint16_t typeKey = 443; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case ViewModelPropertyStringBase::typeKey: + case ViewModelPropertyBase::typeKey: + case ViewModelComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/viewmodel/viewmodel_property_symbol_base.hpp b/third_party/rive/include/rive/generated/viewmodel/viewmodel_property_symbol_base.hpp new file mode 100644 index 0000000..8d0e33c --- /dev/null +++ b/third_party/rive/include/rive/generated/viewmodel/viewmodel_property_symbol_base.hpp @@ -0,0 +1,35 @@ +#ifndef _RIVE_VIEW_MODEL_PROPERTY_SYMBOL_BASE_HPP_ +#define _RIVE_VIEW_MODEL_PROPERTY_SYMBOL_BASE_HPP_ +#include "rive/viewmodel/viewmodel_property.hpp" +namespace rive +{ +class ViewModelPropertySymbolBase : public ViewModelProperty +{ +protected: + typedef ViewModelProperty Super; + +public: + static const uint16_t typeKey = 563; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case ViewModelPropertySymbolBase::typeKey: + case ViewModelPropertyBase::typeKey: + case ViewModelComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/viewmodel/viewmodel_property_symbol_list_index_base.hpp b/third_party/rive/include/rive/generated/viewmodel/viewmodel_property_symbol_list_index_base.hpp new file mode 100644 index 0000000..0d855b8 --- /dev/null +++ b/third_party/rive/include/rive/generated/viewmodel/viewmodel_property_symbol_list_index_base.hpp @@ -0,0 +1,38 @@ +#ifndef _RIVE_VIEW_MODEL_PROPERTY_SYMBOL_LIST_INDEX_BASE_HPP_ +#define _RIVE_VIEW_MODEL_PROPERTY_SYMBOL_LIST_INDEX_BASE_HPP_ +#include "rive/viewmodel/viewmodel_property_symbol.hpp" +namespace rive +{ +class ViewModelPropertySymbolListIndexBase : public ViewModelPropertySymbol +{ +protected: + typedef ViewModelPropertySymbol Super; + +public: + static const uint16_t typeKey = 564; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case ViewModelPropertySymbolListIndexBase::typeKey: + case ViewModelPropertySymbolBase::typeKey: + case ViewModelPropertyBase::typeKey: + case ViewModelComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/viewmodel/viewmodel_property_trigger_base.hpp b/third_party/rive/include/rive/generated/viewmodel/viewmodel_property_trigger_base.hpp new file mode 100644 index 0000000..dbe3715 --- /dev/null +++ b/third_party/rive/include/rive/generated/viewmodel/viewmodel_property_trigger_base.hpp @@ -0,0 +1,37 @@ +#ifndef _RIVE_VIEW_MODEL_PROPERTY_TRIGGER_BASE_HPP_ +#define _RIVE_VIEW_MODEL_PROPERTY_TRIGGER_BASE_HPP_ +#include "rive/viewmodel/viewmodel_property.hpp" +namespace rive +{ +class ViewModelPropertyTriggerBase : public ViewModelProperty +{ +protected: + typedef ViewModelProperty Super; + +public: + static const uint16_t typeKey = 502; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case ViewModelPropertyTriggerBase::typeKey: + case ViewModelPropertyBase::typeKey: + case ViewModelComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/viewmodel/viewmodel_property_viewmodel_base.hpp b/third_party/rive/include/rive/generated/viewmodel/viewmodel_property_viewmodel_base.hpp new file mode 100644 index 0000000..113cc88 --- /dev/null +++ b/third_party/rive/include/rive/generated/viewmodel/viewmodel_property_viewmodel_base.hpp @@ -0,0 +1,75 @@ +#ifndef _RIVE_VIEW_MODEL_PROPERTY_VIEW_MODEL_BASE_HPP_ +#define _RIVE_VIEW_MODEL_PROPERTY_VIEW_MODEL_BASE_HPP_ +#include "rive/core/field_types/core_uint_type.hpp" +#include "rive/viewmodel/viewmodel_property.hpp" +namespace rive +{ +class ViewModelPropertyViewModelBase : public ViewModelProperty +{ +protected: + typedef ViewModelProperty Super; + +public: + static const uint16_t typeKey = 436; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case ViewModelPropertyViewModelBase::typeKey: + case ViewModelPropertyBase::typeKey: + case ViewModelComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t viewModelReferenceIdPropertyKey = 565; + +protected: + uint32_t m_ViewModelReferenceId = 0; + +public: + inline uint32_t viewModelReferenceId() const + { + return m_ViewModelReferenceId; + } + void viewModelReferenceId(uint32_t value) + { + if (m_ViewModelReferenceId == value) + { + return; + } + m_ViewModelReferenceId = value; + viewModelReferenceIdChanged(); + } + + Core* clone() const override; + void copy(const ViewModelPropertyViewModelBase& object) + { + m_ViewModelReferenceId = object.m_ViewModelReferenceId; + ViewModelProperty::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case viewModelReferenceIdPropertyKey: + m_ViewModelReferenceId = CoreUintType::deserialize(reader); + return true; + } + return ViewModelProperty::deserialize(propertyKey, reader); + } + +protected: + virtual void viewModelReferenceIdChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/generated/world_transform_component_base.hpp b/third_party/rive/include/rive/generated/world_transform_component_base.hpp new file mode 100644 index 0000000..48828e6 --- /dev/null +++ b/third_party/rive/include/rive/generated/world_transform_component_base.hpp @@ -0,0 +1,71 @@ +#ifndef _RIVE_WORLD_TRANSFORM_COMPONENT_BASE_HPP_ +#define _RIVE_WORLD_TRANSFORM_COMPONENT_BASE_HPP_ +#include "rive/container_component.hpp" +#include "rive/core/field_types/core_double_type.hpp" +namespace rive +{ +class WorldTransformComponentBase : public ContainerComponent +{ +protected: + typedef ContainerComponent Super; + +public: + static const uint16_t typeKey = 91; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case WorldTransformComponentBase::typeKey: + case ContainerComponentBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t opacityPropertyKey = 18; + +protected: + float m_Opacity = 1.0f; + +public: + inline float opacity() const { return m_Opacity; } + void opacity(float value) + { + if (m_Opacity == value) + { + return; + } + m_Opacity = value; + opacityChanged(); + } + + void copy(const WorldTransformComponentBase& object) + { + m_Opacity = object.m_Opacity; + ContainerComponent::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case opacityPropertyKey: + m_Opacity = CoreDoubleType::deserialize(reader); + return true; + } + return ContainerComponent::deserialize(propertyKey, reader); + } + +protected: + virtual void opacityChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/gesture_click_phase.hpp b/third_party/rive/include/rive/gesture_click_phase.hpp new file mode 100644 index 0000000..2daf21a --- /dev/null +++ b/third_party/rive/include/rive/gesture_click_phase.hpp @@ -0,0 +1,12 @@ +#ifndef _RIVE_GESTURE_CLICK_PHASE_HPP_ +#define _RIVE_GESTURE_CLICK_PHASE_HPP_ +namespace rive +{ +enum class GestureClickPhase : int +{ + out = 0, + down = 1, + clicked = 2, +}; +} +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/hit_info.hpp b/third_party/rive/include/rive/hit_info.hpp new file mode 100644 index 0000000..efbd03a --- /dev/null +++ b/third_party/rive/include/rive/hit_info.hpp @@ -0,0 +1,23 @@ +/* + * Copyright 2022 Rive + */ + +#ifndef _RIVE_HITINFO_HPP_ +#define _RIVE_HITINFO_HPP_ + +#include "rive/math/aabb.hpp" +#include + +namespace rive +{ + +class NestedArtboard; + +struct HitInfo +{ + IAABB area; // input + std::vector mounts; // output +}; + +} // namespace rive +#endif diff --git a/third_party/rive/include/rive/hit_result.hpp b/third_party/rive/include/rive/hit_result.hpp new file mode 100644 index 0000000..ec0c7fd --- /dev/null +++ b/third_party/rive/include/rive/hit_result.hpp @@ -0,0 +1,13 @@ +#ifndef _RIVE_HIT_RESULT_HPP_ +#define _RIVE_HIT_RESULT_HPP_ + +namespace rive +{ +enum class HitResult : uint8_t +{ + none, + hit, + hitOpaque, +}; +} // namespace rive +#endif diff --git a/third_party/rive/include/rive/hittest_command_path.hpp b/third_party/rive/include/rive/hittest_command_path.hpp new file mode 100644 index 0000000..28ecc4d --- /dev/null +++ b/third_party/rive/include/rive/hittest_command_path.hpp @@ -0,0 +1,45 @@ +/* + * Copyright 2022 Rive + */ + +#ifndef _RIVE_HITTEST_COMMAND_PATH_HPP_ +#define _RIVE_HITTEST_COMMAND_PATH_HPP_ + +#include "rive/command_path.hpp" +#include "rive/math/hit_test.hpp" + +namespace rive +{ +class HitTester; + +class HitTestCommandPath : public CommandPath +{ + HitTester m_Tester; + Mat2D m_Xform; + IAABB m_Area; + FillRule m_FillRule = FillRule::nonZero; + +public: + HitTestCommandPath(const IAABB& area); + + // can call this between calls to move/line/etc. + void setXform(const Mat2D& xform) { m_Xform = xform; } + + bool wasHit(); + + // These 4 are not a good for the hit-tester + void rewind() override; + void fillRule(FillRule value) override; + void addPath(CommandPath* path, const Mat2D& transform) override; + + RenderPath* renderPath() override; + const RenderPath* renderPath() const override; + + void moveTo(float x, float y) override; + void lineTo(float x, float y) override; + void cubicTo(float ox, float oy, float ix, float iy, float x, float y) + override; + void close() override; +}; +} // namespace rive +#endif diff --git a/third_party/rive/include/rive/importers/artboard_importer.hpp b/third_party/rive/include/rive/importers/artboard_importer.hpp new file mode 100644 index 0000000..102bfd0 --- /dev/null +++ b/third_party/rive/include/rive/importers/artboard_importer.hpp @@ -0,0 +1,32 @@ +#ifndef _RIVE_ARTBOARD_IMPORTER_HPP_ +#define _RIVE_ARTBOARD_IMPORTER_HPP_ + +#include "rive/importers/import_stack.hpp" + +namespace rive +{ +class Core; +class Artboard; +class LinearAnimation; +class StateMachine; +class TextValueRun; +class Event; +class DataBind; +class ArtboardImporter : public ImportStackObject +{ +private: + Artboard* m_Artboard; + +public: + ArtboardImporter(Artboard* artboard); + void addComponent(Core* object); + void addAnimation(LinearAnimation* animation); + void addStateMachine(StateMachine* stateMachine); + void addDataBind(DataBind* dataBind); + StatusCode resolve() override; + const Artboard* artboard() const { return m_Artboard; } + + bool readNullObject() override; +}; +} // namespace rive +#endif diff --git a/third_party/rive/include/rive/importers/backboard_importer.hpp b/third_party/rive/include/rive/importers/backboard_importer.hpp new file mode 100644 index 0000000..693cf9b --- /dev/null +++ b/third_party/rive/include/rive/importers/backboard_importer.hpp @@ -0,0 +1,59 @@ +#ifndef _RIVE_BACKBOARD_IMPORTER_HPP_ +#define _RIVE_BACKBOARD_IMPORTER_HPP_ + +#include "rive/importers/import_stack.hpp" +#include "rive/animation/keyframe_interpolator.hpp" +#include +#include + +namespace rive +{ +class Artboard; +class File; +class NestedArtboard; +class Backboard; +class FileAsset; +class FileAssetReferencer; +class DataConverter; +class DataBind; +class DataConverterGroupItem; +class ScrollPhysics; +class BackboardImporter : public ImportStackObject +{ +private: + Backboard* m_Backboard; + std::unordered_map m_ArtboardLookup; + std::vector m_NestedArtboards; + std::vector m_FileAssets; + std::vector m_FileAssetReferencers; + std::vector m_DataConverters; + std::vector m_DataConverterReferencers; + std::vector m_DataConverterGroupItemReferencers; + std::vector m_interpolators; + std::vector m_physics; + int m_NextArtboardId; + File* m_file; + +public: + BackboardImporter(Backboard* backboard); + void addArtboard(Artboard* artboard); + void addMissingArtboard(); + void addNestedArtboard(NestedArtboard* artboard); + void addFileAsset(FileAsset* asset); + void addFileAssetReferencer(FileAssetReferencer* referencer); + void addDataConverterReferencer(DataBind* referencer); + void addDataConverter(DataConverter* converter); + void addDataConverterGroupItemReferencer( + DataConverterGroupItem* referencer); + void addInterpolator(KeyFrameInterpolator* interpolator); + void addPhysics(ScrollPhysics* physics); + std::vector physics() { return m_physics; } + std::vector* assets() { return &m_FileAssets; } + void file(File* value); + File* file() { return m_file; }; + + StatusCode resolve() override; + const Backboard* backboard() const { return m_Backboard; } +}; +} // namespace rive +#endif diff --git a/third_party/rive/include/rive/importers/bindable_property_importer.hpp b/third_party/rive/include/rive/importers/bindable_property_importer.hpp new file mode 100644 index 0000000..c23a450 --- /dev/null +++ b/third_party/rive/include/rive/importers/bindable_property_importer.hpp @@ -0,0 +1,25 @@ +#ifndef _RIVE_BINDABLE_PROPERTY_IMPORTER_HPP_ +#define _RIVE_BINDABLE_PROPERTY_IMPORTER_HPP_ + +#include "rive/importers/import_stack.hpp" + +namespace rive +{ +class Core; +class BindableProperty; +class BindablePropertyImporter : public ImportStackObject +{ +private: + BindableProperty* m_bindableProperty; + +public: + BindablePropertyImporter(BindableProperty* bindableProperty); + BindableProperty* bindableProperty() + { + auto bindableProperty = m_bindableProperty; + m_bindableProperty = nullptr; + return bindableProperty; + } +}; +} // namespace rive +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/importers/data_converter_formula_importer.hpp b/third_party/rive/include/rive/importers/data_converter_formula_importer.hpp new file mode 100644 index 0000000..bfe2bc1 --- /dev/null +++ b/third_party/rive/include/rive/importers/data_converter_formula_importer.hpp @@ -0,0 +1,21 @@ +#ifndef _RIVE_DATA_CONVERTER_FORMULA_IMPORTER_HPP_ +#define _RIVE_DATA_CONVERTER_FORMULA_IMPORTER_HPP_ + +#include "rive/importers/import_stack.hpp" + +namespace rive +{ +class Core; +class DataConverterFormula; +class DataConverterFormulaImporter : public ImportStackObject +{ +private: + DataConverterFormula* m_dataConverterFormula; + +public: + DataConverterFormulaImporter(DataConverterFormula* formula); + DataConverterFormula* formula() { return m_dataConverterFormula; } + StatusCode resolve() override; +}; +} // namespace rive +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/importers/data_converter_group_importer.hpp b/third_party/rive/include/rive/importers/data_converter_group_importer.hpp new file mode 100644 index 0000000..61ba8ab --- /dev/null +++ b/third_party/rive/include/rive/importers/data_converter_group_importer.hpp @@ -0,0 +1,20 @@ +#ifndef _RIVE_DATA_CONVERTER_GROUP_IMPORTER_HPP_ +#define _RIVE_DATA_CONVERTER_GROUP_IMPORTER_HPP_ + +#include "rive/importers/import_stack.hpp" + +namespace rive +{ +class Core; +class DataConverterGroup; +class DataConverterGroupImporter : public ImportStackObject +{ +private: + DataConverterGroup* m_dataConverterGroup; + +public: + DataConverterGroupImporter(DataConverterGroup* group); + DataConverterGroup* group() { return m_dataConverterGroup; } +}; +} // namespace rive +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/importers/enum_importer.hpp b/third_party/rive/include/rive/importers/enum_importer.hpp new file mode 100644 index 0000000..a79b1b6 --- /dev/null +++ b/third_party/rive/include/rive/importers/enum_importer.hpp @@ -0,0 +1,23 @@ +#ifndef _RIVE_ENUM_IMPORTER_HPP_ +#define _RIVE_ENUM_IMPORTER_HPP_ + +#include "rive/importers/import_stack.hpp" + +namespace rive +{ +class Core; +class DataEnum; +class DataEnumValue; +class EnumImporter : public ImportStackObject +{ +private: + DataEnum* m_DataEnum; + +public: + EnumImporter(DataEnum* dataEnum); + void addValue(DataEnumValue* object); + StatusCode resolve() override; + const DataEnum* dataEnum() const { return m_DataEnum; } +}; +} // namespace rive +#endif diff --git a/third_party/rive/include/rive/importers/file_asset_importer.hpp b/third_party/rive/include/rive/importers/file_asset_importer.hpp new file mode 100644 index 0000000..9e82463 --- /dev/null +++ b/third_party/rive/include/rive/importers/file_asset_importer.hpp @@ -0,0 +1,31 @@ +#ifndef _RIVE_FILE_ASSET_IMPORTER_HPP_ +#define _RIVE_FILE_ASSET_IMPORTER_HPP_ + +#include "rive/refcnt.hpp" +#include "rive/importers/import_stack.hpp" +#include +#include + +namespace rive +{ +class FileAsset; +class FileAssetContents; +class FileAssetLoader; +class Factory; + +class FileAssetImporter : public ImportStackObject +{ +private: + FileAsset* m_FileAsset; + rcp m_FileAssetLoader; + Factory* m_Factory; + // we will delete this when we go out of scope + std::unique_ptr m_Content; + +public: + FileAssetImporter(FileAsset*, rcp, Factory*); + void onFileAssetContents(std::unique_ptr contents); + StatusCode resolve() override; +}; +} // namespace rive +#endif diff --git a/third_party/rive/include/rive/importers/import_stack.hpp b/third_party/rive/include/rive/importers/import_stack.hpp new file mode 100644 index 0000000..e26f76e --- /dev/null +++ b/third_party/rive/include/rive/importers/import_stack.hpp @@ -0,0 +1,110 @@ +#ifndef _RIVE_IMPORT_STACK_HPP_ +#define _RIVE_IMPORT_STACK_HPP_ +#include "rive/status_code.hpp" +#include +#include +#include +#include +#include + +namespace rive +{ +class ImportStackObject +{ +public: + virtual ~ImportStackObject() {} + virtual StatusCode resolve() { return StatusCode::Ok; } + virtual bool readNullObject() { return false; } +}; + +class ImportStack +{ +public: + template T* latest(uint16_t coreType) + { + auto itr = m_latests.find(coreType); + if (itr == m_latests.end()) + { + return nullptr; + } + return static_cast(itr->second.get()); + } + + StatusCode makeLatest(uint16_t coreType, + std::unique_ptr object) + { + // Clean up the old object in the stack. + auto itr = m_latests.find(coreType); + if (itr != m_latests.end()) + { + auto stackObject = itr->second.get(); + + // Remove it from latests. + auto lastAddedItr = + std::find(m_lastAdded.begin(), m_lastAdded.end(), stackObject); + if (lastAddedItr != m_lastAdded.end()) + { + m_lastAdded.erase(lastAddedItr); + } + + StatusCode code = stackObject->resolve(); + if (code != StatusCode::Ok) + { + m_latests.erase(coreType); + return code; + } + } + + // Set the new one. + if (object == nullptr) + { + m_latests.erase(coreType); + } + else + { + m_lastAdded.push_back(object.get()); + m_latests[coreType] = std::move(object); + } + return StatusCode::Ok; + } + + StatusCode resolve() + { + StatusCode returnCode = StatusCode::Ok; + + // Reverse iterate the last added import stack objects and resolve them. + // If any don't resolve, capture the return code and stop resolving. + for (auto itr = m_lastAdded.rbegin(); itr != m_lastAdded.rend(); itr++) + { + StatusCode code = (*itr)->resolve(); + if (code != StatusCode::Ok) + { + returnCode = code; + break; + } + } + + m_latests.clear(); + m_lastAdded.clear(); + + return returnCode; + } + + bool readNullObject() + { + for (auto itr = m_lastAdded.rbegin(); itr != m_lastAdded.rend(); itr++) + { + if ((*itr)->readNullObject()) + { + return true; + } + } + return false; + } + +private: + std::unordered_map> m_latests; + std::vector m_lastAdded; +}; +} // namespace rive +#endif diff --git a/third_party/rive/include/rive/importers/keyed_object_importer.hpp b/third_party/rive/include/rive/importers/keyed_object_importer.hpp new file mode 100644 index 0000000..fd7abf1 --- /dev/null +++ b/third_party/rive/include/rive/importers/keyed_object_importer.hpp @@ -0,0 +1,21 @@ +#ifndef _RIVE_KEYED_OBJECT_IMPORTER_HPP_ +#define _RIVE_KEYED_OBJECT_IMPORTER_HPP_ + +#include "rive/importers/import_stack.hpp" + +namespace rive +{ +class Core; +class KeyedObject; +class KeyedProperty; +class KeyedObjectImporter : public ImportStackObject +{ +private: + KeyedObject* m_KeyedObject; + +public: + KeyedObjectImporter(KeyedObject* keyedObject); + void addKeyedProperty(std::unique_ptr); +}; +} // namespace rive +#endif diff --git a/third_party/rive/include/rive/importers/keyed_property_importer.hpp b/third_party/rive/include/rive/importers/keyed_property_importer.hpp new file mode 100644 index 0000000..945f475 --- /dev/null +++ b/third_party/rive/include/rive/importers/keyed_property_importer.hpp @@ -0,0 +1,25 @@ +#ifndef _RIVE_KEYED_PROPERTY_IMPORTER_HPP_ +#define _RIVE_KEYED_PROPERTY_IMPORTER_HPP_ + +#include "rive/importers/import_stack.hpp" + +namespace rive +{ +class Core; +class KeyFrame; +class KeyedProperty; +class LinearAnimation; +class KeyedPropertyImporter : public ImportStackObject +{ +private: + LinearAnimation* m_Animation; + KeyedProperty* m_KeyedProperty; + +public: + KeyedPropertyImporter(LinearAnimation* animation, + KeyedProperty* keyedProperty); + void addKeyFrame(std::unique_ptr); + bool readNullObject() override; +}; +} // namespace rive +#endif diff --git a/third_party/rive/include/rive/importers/layer_state_importer.hpp b/third_party/rive/include/rive/importers/layer_state_importer.hpp new file mode 100644 index 0000000..d11d39a --- /dev/null +++ b/third_party/rive/include/rive/importers/layer_state_importer.hpp @@ -0,0 +1,24 @@ +#ifndef _RIVE_LAYER_STATE_IMPORTER_HPP_ +#define _RIVE_LAYER_STATE_IMPORTER_HPP_ + +#include "rive/importers/import_stack.hpp" + +namespace rive +{ +class LayerState; +class StateTransition; +class BlendAnimation; + +class LayerStateImporter : public ImportStackObject +{ +private: + LayerState* m_State; + +public: + LayerStateImporter(LayerState* state); + void addTransition(StateTransition* transition); + bool addBlendAnimation(BlendAnimation* animation); + StatusCode resolve() override; +}; +} // namespace rive +#endif diff --git a/third_party/rive/include/rive/importers/linear_animation_importer.hpp b/third_party/rive/include/rive/importers/linear_animation_importer.hpp new file mode 100644 index 0000000..64a27bc --- /dev/null +++ b/third_party/rive/include/rive/importers/linear_animation_importer.hpp @@ -0,0 +1,22 @@ +#ifndef _RIVE_LINEAR_ANIMATION_IMPORTER_HPP_ +#define _RIVE_LINEAR_ANIMATION_IMPORTER_HPP_ + +#include "rive/importers/import_stack.hpp" + +namespace rive +{ +class Core; +class LinearAnimation; +class KeyedObject; +class LinearAnimationImporter : public ImportStackObject +{ +private: + LinearAnimation* m_Animation; + +public: + LinearAnimation* animation() const { return m_Animation; } + LinearAnimationImporter(LinearAnimation* animation); + void addKeyedObject(std::unique_ptr); +}; +} // namespace rive +#endif diff --git a/third_party/rive/include/rive/importers/state_machine_importer.hpp b/third_party/rive/include/rive/importers/state_machine_importer.hpp new file mode 100644 index 0000000..dc08236 --- /dev/null +++ b/third_party/rive/include/rive/importers/state_machine_importer.hpp @@ -0,0 +1,31 @@ +#ifndef _RIVE_STATE_MACHINE_IMPORTER_HPP_ +#define _RIVE_STATE_MACHINE_IMPORTER_HPP_ + +#include "rive/importers/import_stack.hpp" + +namespace rive +{ +class StateMachineInput; +class StateMachineLayer; +class StateMachineListener; +class StateMachine; +class DataBind; +class StateMachineImporter : public ImportStackObject +{ +private: + StateMachine* m_StateMachine; + +public: + StateMachineImporter(StateMachine* machine); + const StateMachine* stateMachine() const { return m_StateMachine; } + + void addLayer(std::unique_ptr); + void addInput(std::unique_ptr); + void addListener(std::unique_ptr); + void addDataBind(std::unique_ptr); + + StatusCode resolve() override; + bool readNullObject() override; +}; +} // namespace rive +#endif diff --git a/third_party/rive/include/rive/importers/state_machine_layer_component_importer.hpp b/third_party/rive/include/rive/importers/state_machine_layer_component_importer.hpp new file mode 100644 index 0000000..b9132a2 --- /dev/null +++ b/third_party/rive/include/rive/importers/state_machine_layer_component_importer.hpp @@ -0,0 +1,22 @@ +#ifndef _RIVE_STATE_MACHINE_LAYER_COMPONENT_IMPORTER_HPP_ +#define _RIVE_STATE_MACHINE_LAYER_COMPONENT_IMPORTER_HPP_ + +#include "rive/importers/import_stack.hpp" + +namespace rive +{ +class StateMachineLayerComponent; +class StateMachineFireEvent; + +class StateMachineLayerComponentImporter : public ImportStackObject +{ +public: + StateMachineLayerComponentImporter(StateMachineLayerComponent* component); + + void addFireEvent(StateMachineFireEvent* fireEvent); + +private: + StateMachineLayerComponent* m_stateMachineLayerComponent; +}; +} // namespace rive +#endif diff --git a/third_party/rive/include/rive/importers/state_machine_layer_importer.hpp b/third_party/rive/include/rive/importers/state_machine_layer_importer.hpp new file mode 100644 index 0000000..ef829d1 --- /dev/null +++ b/third_party/rive/include/rive/importers/state_machine_layer_importer.hpp @@ -0,0 +1,26 @@ +#ifndef _RIVE_STATE_MACHINE_LAYER_IMPORTER_HPP_ +#define _RIVE_STATE_MACHINE_LAYER_IMPORTER_HPP_ + +#include "rive/importers/import_stack.hpp" + +namespace rive +{ +class StateMachineLayer; +class LayerState; +class Artboard; + +class StateMachineLayerImporter : public ImportStackObject +{ +private: + StateMachineLayer* m_Layer; + const Artboard* m_Artboard; + +public: + StateMachineLayerImporter(StateMachineLayer* layer, + const Artboard* artboard); + void addState(LayerState* state); + StatusCode resolve() override; + bool readNullObject() override; +}; +} // namespace rive +#endif diff --git a/third_party/rive/include/rive/importers/state_machine_listener_importer.hpp b/third_party/rive/include/rive/importers/state_machine_listener_importer.hpp new file mode 100644 index 0000000..6dc6404 --- /dev/null +++ b/third_party/rive/include/rive/importers/state_machine_listener_importer.hpp @@ -0,0 +1,26 @@ +#ifndef _RIVE_STATE_MACHINE_LISTENER_IMPORTER_HPP_ +#define _RIVE_STATE_MACHINE_LISTENER_IMPORTER_HPP_ + +#include "rive/importers/import_stack.hpp" + +namespace rive +{ +class StateMachineListener; +class StateMachine; +class ListenerAction; +class StateMachineListenerImporter : public ImportStackObject +{ +private: + StateMachineListener* m_StateMachineListener; + +public: + StateMachineListenerImporter(StateMachineListener* listener); + const StateMachineListener* stateMachineListener() const + { + return m_StateMachineListener; + } + void addAction(std::unique_ptr); + StatusCode resolve() override; +}; +} // namespace rive +#endif diff --git a/third_party/rive/include/rive/importers/state_transition_importer.hpp b/third_party/rive/include/rive/importers/state_transition_importer.hpp new file mode 100644 index 0000000..f683cc2 --- /dev/null +++ b/third_party/rive/include/rive/importers/state_transition_importer.hpp @@ -0,0 +1,22 @@ +#ifndef _RIVE_TRANSITION_IMPORTER_HPP_ +#define _RIVE_TRANSITION_IMPORTER_HPP_ + +#include "rive/importers/import_stack.hpp" + +namespace rive +{ +class StateTransition; +class TransitionCondition; + +class StateTransitionImporter : public ImportStackObject +{ +private: + StateTransition* m_Transition; + +public: + StateTransitionImporter(StateTransition* transition); + void addCondition(TransitionCondition* condition); + StatusCode resolve() override; +}; +} // namespace rive +#endif diff --git a/third_party/rive/include/rive/importers/transition_viewmodel_condition_importer.hpp b/third_party/rive/include/rive/importers/transition_viewmodel_condition_importer.hpp new file mode 100644 index 0000000..7cf92bd --- /dev/null +++ b/third_party/rive/include/rive/importers/transition_viewmodel_condition_importer.hpp @@ -0,0 +1,23 @@ +#ifndef _RIVE_TRANSITION_VIEWMODEL_CONDITION_IMPORTER_HPP_ +#define _RIVE_TRANSITION_VIEWMODEL_CONDITION_IMPORTER_HPP_ + +#include "rive/importers/import_stack.hpp" + +namespace rive +{ +class TransitionViewModelCondition; +class TransitionComparator; +class DataBind; + +class TransitionViewModelConditionImporter : public ImportStackObject +{ +private: + TransitionViewModelCondition* m_TransitionViewModelCondition; + +public: + TransitionViewModelConditionImporter( + TransitionViewModelCondition* transitionViewModelCondition); + void setComparator(TransitionComparator* comparator); +}; +} // namespace rive +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/importers/viewmodel_importer.hpp b/third_party/rive/include/rive/importers/viewmodel_importer.hpp new file mode 100644 index 0000000..8298c26 --- /dev/null +++ b/third_party/rive/include/rive/importers/viewmodel_importer.hpp @@ -0,0 +1,24 @@ +#ifndef _RIVE_VIEWMODEL_IMPORTER_HPP_ +#define _RIVE_VIEWMODEL_IMPORTER_HPP_ + +#include "rive/importers/import_stack.hpp" + +namespace rive +{ +class ViewModel; +class ViewModelProperty; +class ViewModelInstance; + +class ViewModelImporter : public ImportStackObject +{ +private: + ViewModel* m_ViewModel; + +public: + ViewModelImporter(ViewModel* viewModel); + void addProperty(ViewModelProperty* property); + void addInstance(ViewModelInstance* value); + StatusCode resolve() override; +}; +} // namespace rive +#endif diff --git a/third_party/rive/include/rive/importers/viewmodel_instance_importer.hpp b/third_party/rive/include/rive/importers/viewmodel_instance_importer.hpp new file mode 100644 index 0000000..d70c858 --- /dev/null +++ b/third_party/rive/include/rive/importers/viewmodel_instance_importer.hpp @@ -0,0 +1,22 @@ +#ifndef _RIVE_VIEWMODEL_INSTANCE_IMPORTER_HPP_ +#define _RIVE_VIEWMODEL_INSTANCE_IMPORTER_HPP_ + +#include "rive/importers/import_stack.hpp" + +namespace rive +{ +class ViewModelInstance; +class ViewModelInstanceValue; + +class ViewModelInstanceImporter : public ImportStackObject +{ +private: + ViewModelInstance* m_ViewModelInstance; + +public: + ViewModelInstanceImporter(ViewModelInstance* viewModelInstance); + void addValue(ViewModelInstanceValue* value); + StatusCode resolve() override; +}; +} // namespace rive +#endif diff --git a/third_party/rive/include/rive/importers/viewmodel_instance_list_importer.hpp b/third_party/rive/include/rive/importers/viewmodel_instance_list_importer.hpp new file mode 100644 index 0000000..3833b2e --- /dev/null +++ b/third_party/rive/include/rive/importers/viewmodel_instance_list_importer.hpp @@ -0,0 +1,22 @@ +#ifndef _RIVE_VIEWMODEL_INSTANCE_LIST_IMPORTER_HPP_ +#define _RIVE_VIEWMODEL_INSTANCE_LIST_IMPORTER_HPP_ + +#include "rive/importers/import_stack.hpp" + +namespace rive +{ +class Core; +class ViewModelInstanceList; +class ViewModelInstanceListItem; +class ViewModelInstanceListImporter : public ImportStackObject +{ +private: + ViewModelInstanceList* m_ViewModelInstanceList; + +public: + ViewModelInstanceListImporter(ViewModelInstanceList* viewModelInstanceList); + void addItem(ViewModelInstanceListItem* listItem); + StatusCode resolve() override; +}; +} // namespace rive +#endif diff --git a/third_party/rive/include/rive/internal/assert_internal_only.hpp b/third_party/rive/include/rive/internal/assert_internal_only.hpp new file mode 100644 index 0000000..8183bb0 --- /dev/null +++ b/third_party/rive/include/rive/internal/assert_internal_only.hpp @@ -0,0 +1,3 @@ +#ifndef _RIVE_INTERNAL_ +static_assert(false, "This file should never be included by public headers."); +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/intrinsically_sizeable.hpp b/third_party/rive/include/rive/intrinsically_sizeable.hpp new file mode 100644 index 0000000..b8f1c34 --- /dev/null +++ b/third_party/rive/include/rive/intrinsically_sizeable.hpp @@ -0,0 +1,32 @@ +#ifndef _RIVE_INTRINSICALLY_SIZEABLE_HPP_ +#define _RIVE_INTRINSICALLY_SIZEABLE_HPP_ + +#include +#include "rive/component.hpp" +#include "rive/layout/layout_enums.hpp" +#include "rive/layout/layout_measure_mode.hpp" +#include "rive/math/vec2d.hpp" + +namespace rive +{ +class IntrinsicallySizeable +{ +public: + virtual Vec2D measureLayout(float width, + LayoutMeasureMode widthMode, + float height, + LayoutMeasureMode heightMode) + { + return Vec2D(); + } + + virtual void controlSize(Vec2D size, + LayoutScaleType widthScaleType, + LayoutScaleType heightScaleType, + LayoutDirection direction) + {} + virtual bool shouldPropagateSizeToChildren() { return true; } + static IntrinsicallySizeable* from(Component* component); +}; +} // namespace rive +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/joystick.hpp b/third_party/rive/include/rive/joystick.hpp new file mode 100644 index 0000000..fb317e0 --- /dev/null +++ b/third_party/rive/include/rive/joystick.hpp @@ -0,0 +1,63 @@ +#ifndef _RIVE_JOYSTICK_HPP_ +#define _RIVE_JOYSTICK_HPP_ +#include "rive/generated/joystick_base.hpp" +#include "rive/intrinsically_sizeable.hpp" +#include "rive/joystick_flags.hpp" +#include "rive/animation/nested_remap_animation.hpp" +#include "rive/math/mat2d.hpp" +#include + +namespace rive +{ +class Artboard; +class LinearAnimation; +class TransformComponent; +class Joystick : public JoystickBase, public IntrinsicallySizeable +{ +public: + void update(ComponentDirt value) override; + void apply(Artboard* artboard) const; + StatusCode onAddedClean(CoreContext* context) override; + StatusCode onAddedDirty(CoreContext* context) override; + void xChanged() override; + void yChanged() override; + void posXChanged() override; + void posYChanged() override; + void widthChanged() override; + void heightChanged() override; + + bool isJoystickFlagged(JoystickFlags flag) const + { + return ((JoystickFlags)joystickFlags()) & flag; + } + + bool canApplyBeforeUpdate() const { return m_handleSource == nullptr; } + + void addDependents(Artboard* artboard); + + Vec2D measureLayout(float width, + LayoutMeasureMode widthMode, + float height, + LayoutMeasureMode heightMode) override; + void controlSize(Vec2D size, + LayoutScaleType widthScaleType, + LayoutScaleType heightScaleType, + LayoutDirection direction) override; + bool shouldPropagateSizeToChildren() override { return false; } + +protected: + void buildDependencies() override; + +private: + Mat2D m_worldTransform; + Mat2D m_inverseWorldTransform; + LinearAnimation* m_xAnimation = nullptr; + LinearAnimation* m_yAnimation = nullptr; + TransformComponent* m_handleSource = nullptr; + std::vector m_dependents; + + void addAnimationDependents(Artboard* artboard, LinearAnimation* animation); +}; +} // namespace rive + +#endif diff --git a/third_party/rive/include/rive/joystick_flags.hpp b/third_party/rive/include/rive/joystick_flags.hpp new file mode 100644 index 0000000..f4b2534 --- /dev/null +++ b/third_party/rive/include/rive/joystick_flags.hpp @@ -0,0 +1,21 @@ +#ifndef _RIVE_JOYSTICK_FLAGS_HPP_ +#define _RIVE_JOYSTICK_FLAGS_HPP_ + +#include "rive/enum_bitset.hpp" + +namespace rive +{ +enum class JoystickFlags : unsigned char +{ + /// Whether to invert the application of the x axis. + invertX = 1 << 0, + + /// Whether to invert the application of the y axis. + invertY = 1 << 1, + + /// Whether this Joystick works in world space. + worldSpace = 1 << 2 +}; +RIVE_MAKE_ENUM_BITSET(JoystickFlags) +} // namespace rive +#endif diff --git a/third_party/rive/include/rive/layout.hpp b/third_party/rive/include/rive/layout.hpp new file mode 100644 index 0000000..502abeb --- /dev/null +++ b/third_party/rive/include/rive/layout.hpp @@ -0,0 +1,41 @@ +#ifndef _RIVE_LAYOUT_HPP_ +#define _RIVE_LAYOUT_HPP_ +namespace rive +{ +enum class Fit : unsigned char +{ + fill, + contain, + cover, + fitWidth, + fitHeight, + none, + scaleDown, + layout +}; + +class Alignment +{ +public: + Alignment(float x, float y) : m_x(x), m_y(y) {} + Alignment() : m_x(0.0f), m_y(0.0f) {} + + float x() const { return m_x; } + float y() const { return m_y; } + + static const Alignment topLeft; + static const Alignment topCenter; + static const Alignment topRight; + static const Alignment centerLeft; + static const Alignment center; + static const Alignment centerRight; + static const Alignment bottomLeft; + static const Alignment bottomCenter; + static const Alignment bottomRight; + +private: + float m_x, m_y; +}; + +} // namespace rive +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/layout/axis.hpp b/third_party/rive/include/rive/layout/axis.hpp new file mode 100644 index 0000000..52a3279 --- /dev/null +++ b/third_party/rive/include/rive/layout/axis.hpp @@ -0,0 +1,21 @@ +#ifndef _RIVE_AXIS_HPP_ +#define _RIVE_AXIS_HPP_ +#include "rive/generated/layout/axis_base.hpp" +#include +namespace rive +{ +enum class AxisType : int +{ + X = 0, + Y = 1, +}; + +class Axis : public AxisBase +{ +public: + StatusCode onAddedDirty(CoreContext* context) override; + void offsetChanged() override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/layout/axis_x.hpp b/third_party/rive/include/rive/layout/axis_x.hpp new file mode 100644 index 0000000..9e2500d --- /dev/null +++ b/third_party/rive/include/rive/layout/axis_x.hpp @@ -0,0 +1,14 @@ +#ifndef _RIVE_AXIS_X_HPP_ +#define _RIVE_AXIS_X_HPP_ +#include "rive/generated/layout/axis_x_base.hpp" +#include +namespace rive +{ +class AxisX : public AxisXBase +{ +public: + StatusCode onAddedDirty(CoreContext* context) override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/layout/axis_y.hpp b/third_party/rive/include/rive/layout/axis_y.hpp new file mode 100644 index 0000000..e4961af --- /dev/null +++ b/third_party/rive/include/rive/layout/axis_y.hpp @@ -0,0 +1,14 @@ +#ifndef _RIVE_AXIS_Y_HPP_ +#define _RIVE_AXIS_Y_HPP_ +#include "rive/generated/layout/axis_y_base.hpp" +#include +namespace rive +{ +class AxisY : public AxisYBase +{ +public: + StatusCode onAddedDirty(CoreContext* context) override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/layout/layout_component_style.hpp b/third_party/rive/include/rive/layout/layout_component_style.hpp new file mode 100644 index 0000000..71d9693 --- /dev/null +++ b/third_party/rive/include/rive/layout/layout_component_style.hpp @@ -0,0 +1,156 @@ +#ifndef _RIVE_LAYOUT_COMPONENT_STYLE_HPP_ +#define _RIVE_LAYOUT_COMPONENT_STYLE_HPP_ +#include "rive/generated/layout/layout_component_style_base.hpp" +#include "rive/layout/layout_enums.hpp" +#ifndef TESTING +#include "rive/internal/assert_internal_only.hpp" +#endif +#ifdef WITH_RIVE_LAYOUT +#include "yoga/Yoga.h" +#endif +#include +namespace rive +{ + +class KeyFrameInterpolator; +class LayoutComponentStyle : public LayoutComponentStyleBase +{ +private: +#ifdef WITH_RIVE_LAYOUT + KeyFrameInterpolator* m_interpolator; +#endif + +public: + LayoutComponentStyle() {} + +#ifdef WITH_RIVE_LAYOUT + StatusCode onAddedDirty(CoreContext* context) override; + KeyFrameInterpolator* interpolator(); + LayoutStyleInterpolation interpolation(); + LayoutAnimationStyle animationStyle(); + YGDisplay display(); + YGPositionType positionType(); + LayoutAlignmentType alignmentType(); + LayoutScaleType widthScaleType(); + LayoutScaleType heightScaleType(); + + YGFlexDirection flexDirection(); + YGDirection direction(); + YGWrap flexWrap(); + YGOverflow overflow(); + + YGAlign alignItems(); + YGAlign alignSelf(); + YGAlign alignContent(); + YGJustify justifyContent(); + bool intrinsicallySized(); + YGUnit widthUnits(); + YGUnit heightUnits(); + + YGUnit borderLeftUnits(); + YGUnit borderRightUnits(); + YGUnit borderTopUnits(); + YGUnit borderBottomUnits(); + YGUnit marginLeftUnits(); + YGUnit marginRightUnits(); + YGUnit marginTopUnits(); + YGUnit marginBottomUnits(); + YGUnit paddingLeftUnits(); + YGUnit paddingRightUnits(); + YGUnit paddingTopUnits(); + YGUnit paddingBottomUnits(); + YGUnit positionLeftUnits(); + YGUnit positionRightUnits(); + YGUnit positionTopUnits(); + YGUnit positionBottomUnits(); + + YGUnit gapHorizontalUnits(); + YGUnit gapVerticalUnits(); + YGUnit maxWidthUnits(); + YGUnit maxHeightUnits(); + YGUnit minWidthUnits(); + YGUnit minHeightUnits(); + YGUnit flexBasisUnits(); +#endif + + void markLayoutNodeDirty(); + void markLayoutStyleDirty(); + void scaleTypeChanged(); + void displayChanged(); + + void interpolationTimeChanged() override; + void layoutAlignmentTypeChanged() override; + void layoutWidthScaleTypeChanged() override; + void layoutHeightScaleTypeChanged() override; + void displayValueChanged() override; + void positionTypeValueChanged() override; + void overflowValueChanged() override; + void intrinsicallySizedValueChanged() override; + void flexDirectionValueChanged() override; + void directionValueChanged() override; + void alignContentValueChanged() override; + void alignItemsValueChanged() override; + void alignSelfValueChanged() override; + void justifyContentValueChanged() override; + void flexWrapValueChanged() override; + void flexChanged() override; + void flexGrowChanged() override; + void flexShrinkChanged() override; + void flexBasisChanged() override; + void aspectRatioChanged() override; + void gapHorizontalChanged() override; + void gapVerticalChanged() override; + void maxWidthChanged() override; + void maxHeightChanged() override; + void minWidthChanged() override; + void minHeightChanged() override; + void borderLeftChanged() override; + void borderRightChanged() override; + void borderTopChanged() override; + void borderBottomChanged() override; + void marginLeftChanged() override; + void marginRightChanged() override; + void marginTopChanged() override; + void marginBottomChanged() override; + void paddingLeftChanged() override; + void paddingRightChanged() override; + void paddingTopChanged() override; + void paddingBottomChanged() override; + void positionLeftChanged() override; + void positionRightChanged() override; + void positionTopChanged() override; + void positionBottomChanged() override; + + void widthUnitsValueChanged() override; + void heightUnitsValueChanged() override; + void gapHorizontalUnitsValueChanged() override; + void gapVerticalUnitsValueChanged() override; + void maxWidthUnitsValueChanged() override; + void maxHeightUnitsValueChanged() override; + void minWidthUnitsValueChanged() override; + void minHeightUnitsValueChanged() override; + void borderLeftUnitsValueChanged() override; + void borderRightUnitsValueChanged() override; + void borderTopUnitsValueChanged() override; + void borderBottomUnitsValueChanged() override; + void marginLeftUnitsValueChanged() override; + void marginRightUnitsValueChanged() override; + void marginTopUnitsValueChanged() override; + void marginBottomUnitsValueChanged() override; + void paddingLeftUnitsValueChanged() override; + void paddingRightUnitsValueChanged() override; + void paddingTopUnitsValueChanged() override; + void paddingBottomUnitsValueChanged() override; + void positionLeftUnitsValueChanged() override; + void positionRightUnitsValueChanged() override; + void positionTopUnitsValueChanged() override; + void positionBottomUnitsValueChanged() override; + + void cornerRadiusTLChanged() override; + void cornerRadiusTRChanged() override; + void cornerRadiusBLChanged() override; + void cornerRadiusBRChanged() override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/layout/layout_data.hpp b/third_party/rive/include/rive/layout/layout_data.hpp new file mode 100644 index 0000000..519946a --- /dev/null +++ b/third_party/rive/include/rive/layout/layout_data.hpp @@ -0,0 +1,61 @@ +#ifndef _RIVE_LAYOUT_DATA_HPP_ +#define _RIVE_LAYOUT_DATA_HPP_ + +#ifdef WITH_RIVE_LAYOUT +#include "yoga/YGNode.h" +#include "yoga/YGStyle.h" +#include "yoga/Yoga.h" +#endif +#ifdef WITH_RIVE_TOOLS +#include "rive/refcnt.hpp" +#include +#endif + +namespace rive +{ +class LayoutData +#ifdef WITH_RIVE_TOOLS + : public RefCnt +#endif +{ +public: +#ifdef WITH_RIVE_LAYOUT + +#ifdef WITH_RIVE_TOOLS + std::unordered_set children; +#ifdef DEBUG + LayoutData() { count++; } +#endif + ~LayoutData() + { +#ifdef DEBUG + count--; +#endif + clearChildren(); + } + void clearChildren() + { + for (auto child : children) + { + child->unref(); + } + children.clear(); + } +#ifdef DEBUG + static uint32_t count; +#endif +#endif + + YGNode node; + YGStyle style; +#endif +}; + +#ifdef WITH_RIVE_TOOLS +typedef rcp LayoutDataRef; +#else +typedef LayoutData* LayoutDataRef; +#endif + +} // namespace rive +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/layout/layout_enums.hpp b/third_party/rive/include/rive/layout/layout_enums.hpp new file mode 100644 index 0000000..3ab24f7 --- /dev/null +++ b/third_party/rive/include/rive/layout/layout_enums.hpp @@ -0,0 +1,53 @@ +#ifndef _RIVE_LAYOUT_ENUMS_HPP_ +#define _RIVE_LAYOUT_ENUMS_HPP_ + +#include + +namespace rive +{ +enum class LayoutAnimationStyle : uint8_t +{ + none, + inherit, + custom +}; + +enum class LayoutStyleInterpolation : uint8_t +{ + hold, + linear, + cubic, + elastic +}; + +enum class LayoutAlignmentType : uint8_t +{ + topLeft, + topCenter, + topRight, + centerLeft, + center, + centerRight, + bottomLeft, + bottomCenter, + bottomRight, + spaceBetweenStart, + spaceBetweenCenter, + spaceBetweenEnd +}; + +enum class LayoutDirection : uint8_t +{ + inherit, + ltr, + rtl +}; + +enum class LayoutScaleType : uint8_t +{ + fixed, + fill, + hug +}; +} // namespace rive +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/layout/layout_measure_mode.hpp b/third_party/rive/include/rive/layout/layout_measure_mode.hpp new file mode 100644 index 0000000..50f6eb8 --- /dev/null +++ b/third_party/rive/include/rive/layout/layout_measure_mode.hpp @@ -0,0 +1,12 @@ +#ifndef _RIVE_LAYOUT_MEASURE_MODE_HPP_ +#define _RIVE_LAYOUT_MEASURE_MODE_HPP_ +namespace rive +{ +enum class LayoutMeasureMode : uint8_t +{ + undefined = 0, + exactly = 1, + atMost = 2 +}; +} +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/layout/layout_node_provider.hpp b/third_party/rive/include/rive/layout/layout_node_provider.hpp new file mode 100644 index 0000000..366511d --- /dev/null +++ b/third_party/rive/include/rive/layout/layout_node_provider.hpp @@ -0,0 +1,36 @@ +#ifndef _RIVE_LAYOUT_NODE_PROVIDER_HPP_ +#define _RIVE_LAYOUT_NODE_PROVIDER_HPP_ + +#include +#include + +namespace rive +{ +class AABB; +class Component; +class LayoutConstraint; +class TransformComponent; + +class LayoutNodeProvider +{ +protected: + std::vector m_layoutConstraints; + +public: +#ifdef WITH_RIVE_LAYOUT + virtual void* layoutNode(int index) = 0; +#endif + static LayoutNodeProvider* from(Component* component); + virtual TransformComponent* transformComponent() = 0; + void addLayoutConstraint(LayoutConstraint* constraint); + virtual AABB layoutBounds() = 0; + virtual AABB layoutBoundsForNode(int index) { return layoutBounds(); } + virtual bool syncStyleChanges() { return false; }; + virtual void updateLayoutBounds(bool animate = true){}; + virtual void markLayoutNodeDirty(bool shouldForceUpdateLayoutBounds = false) + {} + virtual size_t numLayoutNodes() = 0; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/layout/n_sliced_node.hpp b/third_party/rive/include/rive/layout/n_sliced_node.hpp new file mode 100644 index 0000000..7522aec --- /dev/null +++ b/third_party/rive/include/rive/layout/n_sliced_node.hpp @@ -0,0 +1,48 @@ +#ifndef _RIVE_N_SLICED_NODE_HPP_ +#define _RIVE_N_SLICED_NODE_HPP_ +#include "rive/generated/layout/n_sliced_node_base.hpp" +#include "rive/layout/n_slicer_details.hpp" +#include "rive/shapes/deformer.hpp" +#include +namespace rive +{ +class NSlicedNode : public NSlicedNodeBase, + public NSlicerDetails, + public RenderPathDeformer, + public PointDeformer +{ + void markPathDirtyRecursive(bool sendToLayout = true); + void updateMapWorldPoint(); + +public: + void axisChanged() override; + void widthChanged() override; + void heightChanged() override; + void update(ComponentDirt value) override; + + std::function mapWorldPoint = [](Vec2D& v) {}; + + Component* asComponent() override { return this; }; + void deformWorldRenderPath(RawPath& path) const override; + void deformLocalRenderPath(RawPath& path, + const Mat2D& worldTransform, + const Mat2D& inverseWorld) const override; + Vec2D deformLocalPoint(Vec2D point, + const Mat2D& worldTransform, + const Mat2D& inverseWorld) const override; + Vec2D deformWorldPoint(Vec2D point) const override; + Vec2D scaleForNSlicer() const; + + Vec2D measureLayout(float width, + LayoutMeasureMode widthMode, + float height, + LayoutMeasureMode heightMode) override; + void controlSize(Vec2D size, + LayoutScaleType widthScaleType, + LayoutScaleType heightScaleType, + LayoutDirection direction) override; + bool shouldPropagateSizeToChildren() override { return false; } +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/layout/n_slicer.hpp b/third_party/rive/include/rive/layout/n_slicer.hpp new file mode 100644 index 0000000..887e14b --- /dev/null +++ b/third_party/rive/include/rive/layout/n_slicer.hpp @@ -0,0 +1,30 @@ +#ifndef _RIVE_N_SLICER_HPP_ +#define _RIVE_N_SLICER_HPP_ +#include "rive/generated/layout/n_slicer_base.hpp" +#include "rive/layout/n_slicer_details.hpp" +#include +#include + +namespace rive +{ +class Image; +class SliceMesh; + +class NSlicer : public NSlicerBase, public NSlicerDetails +{ +private: + std::unique_ptr m_sliceMesh; // the mesh that gets drawn + +public: + NSlicer(); + StatusCode onAddedDirty(CoreContext* context) override; + void update(ComponentDirt value) override; + void buildDependencies() override; + + Image* image(); + SliceMesh* sliceMesh() { return m_sliceMesh.get(); }; + void axisChanged() override; +}; +} // namespace rive + +#endif diff --git a/third_party/rive/include/rive/layout/n_slicer_details.hpp b/third_party/rive/include/rive/layout/n_slicer_details.hpp new file mode 100644 index 0000000..92c5776 --- /dev/null +++ b/third_party/rive/include/rive/layout/n_slicer_details.hpp @@ -0,0 +1,43 @@ +#ifndef _RIVE_N_SLICER_DETAILS_HPP_ +#define _RIVE_N_SLICER_DETAILS_HPP_ +#include +#include + +namespace rive +{ +class AxisX; +class AxisY; +class Axis; +class Component; +class NSlicerTileMode; +enum class NSlicerTileModeType : int; + +class NSlicerDetails +{ + friend class Axis; + +protected: + std::vector m_xs; + std::vector m_ys; + std::unordered_map m_tileModes; // patchIndex key + +public: + static NSlicerDetails* from(Component* component); + int patchIndex(int patchX, int patchY); + const std::vector& xs() const { return m_xs; } + const std::vector& ys() const { return m_ys; } + const std::unordered_map& tileModes() + { + return m_tileModes; + } + + void addAxisX(Axis* axis); + void addAxisY(Axis* axis); + void addTileMode(int patchIndex, NSlicerTileModeType style); + virtual void axisChanged() = 0; // only axis gets animated at runtime + + virtual ~NSlicerDetails() {} +}; +} // namespace rive + +#endif diff --git a/third_party/rive/include/rive/layout/n_slicer_tile_mode.hpp b/third_party/rive/include/rive/layout/n_slicer_tile_mode.hpp new file mode 100644 index 0000000..9394c68 --- /dev/null +++ b/third_party/rive/include/rive/layout/n_slicer_tile_mode.hpp @@ -0,0 +1,21 @@ +#ifndef _RIVE_N_SLICER_TILE_MODE_HPP_ +#define _RIVE_N_SLICER_TILE_MODE_HPP_ +#include "rive/generated/layout/n_slicer_tile_mode_base.hpp" +#include +namespace rive +{ +enum class NSlicerTileModeType : int +{ + STRETCH = 0, + REPEAT = 1, + HIDDEN = 2, +}; + +class NSlicerTileMode : public NSlicerTileModeBase +{ +public: + StatusCode onAddedDirty(CoreContext* context) override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/layout_component.hpp b/third_party/rive/include/rive/layout_component.hpp new file mode 100644 index 0000000..bceb361 --- /dev/null +++ b/third_party/rive/include/rive/layout_component.hpp @@ -0,0 +1,318 @@ +#ifndef _RIVE_LAYOUT_COMPONENT_HPP_ +#define _RIVE_LAYOUT_COMPONENT_HPP_ +#include "rive/advance_flags.hpp" +#include "rive/animation/keyframe_interpolator.hpp" +#include "rive/drawable.hpp" +#include "rive/generated/layout_component_base.hpp" +#include "rive/layout/layout_measure_mode.hpp" +#include "rive/layout/layout_node_provider.hpp" +#include "rive/math/raw_path.hpp" +#include "rive/shapes/rectangle.hpp" +#include "rive/shapes/shape_paint_container.hpp" +#include "rive/advancing_component.hpp" +#include "rive/layout/layout_enums.hpp" + +namespace rive +{ +class AABB; +class KeyFrameInterpolator; +class LayoutData; +class LayoutComponentStyle; +class LayoutConstraint; +class Layout +{ +public: + Layout() : m_left(0.0f), m_top(0.0f), m_width(0.0f), m_height(0.0f) {} + Layout(float left, float top, float width, float height) : + m_left(left), m_top(top), m_width(width), m_height(height) + {} + + bool operator==(const Layout& o) const + { + return m_left == o.m_left && m_top == o.m_top && m_width == o.m_width && + m_height == o.m_height; + } + bool operator!=(const Layout& o) const { return !(*this == o); } + + static Layout lerp(const Layout& from, const Layout& to, float f) + { + float fi = 1.0f - f; + return Layout(to.m_left * f + from.m_left * fi, + to.m_top * f + from.m_top * fi, + to.m_width * f + from.m_width * fi, + to.m_height * f + from.m_height * fi); + } + + float left() const { return m_left; } + float top() const { return m_top; } + float width() const { return m_width; } + float height() const { return m_height; } + +private: + float m_left; + float m_top; + float m_width; + float m_height; +}; + +class LayoutPadding +{ +public: + LayoutPadding() : m_left(0.0f), m_top(0.0f), m_right(0.0f), m_bottom(0.0f) + {} + LayoutPadding(float left, float top, float right, float bottom) : + m_left(left), m_top(top), m_right(right), m_bottom(bottom) + {} + + bool operator==(const LayoutPadding& o) const + { + return m_left == o.m_left && m_top == o.m_top && m_right == o.m_right && + m_bottom == o.m_bottom; + } + bool operator!=(const LayoutPadding& o) const { return !(*this == o); } + + float left() const { return m_left; } + float top() const { return m_top; } + float right() const { return m_right; } + float bottom() const { return m_bottom; } + +private: + float m_left; + float m_top; + float m_right; + float m_bottom; +}; + +struct LayoutAnimationData +{ + float elapsedSeconds = 0.0f; + Layout from; + Layout to; + Layout interpolate(float f) const { return Layout::lerp(from, to, f); } + void copy(const LayoutAnimationData& from); +}; + +class LayoutComponent : public LayoutComponentBase, + public ProxyDrawing, + public ShapePaintContainer, + public AdvancingComponent, + public InterpolatorHost, + public LayoutNodeProvider +{ +protected: + LayoutComponentStyle* m_style = nullptr; + LayoutData* m_layoutData; + + Layout m_layout; + LayoutPadding m_layoutPadding; + + LayoutAnimationData m_animationDataA; + LayoutAnimationData m_animationDataB; + bool m_isSmoothingAnimation = false; + KeyFrameInterpolator* m_inheritedInterpolator; + LayoutStyleInterpolation m_inheritedInterpolation = + LayoutStyleInterpolation::hold; + float m_inheritedInterpolationTime = 0; + LayoutDirection m_inheritedDirection = LayoutDirection::inherit; + Rectangle m_backgroundRect; + ShapePaintPath m_localPath; + ShapePaintPath m_worldPath; + DrawableProxy m_proxy; + bool m_displayHidden = false; + + Artboard* getArtboard() override { return artboard(); } + LayoutAnimationData* currentAnimationData(); + + LayoutComponent* layoutParent() + { + auto p = parent(); + while (p != nullptr) + { + if (p->is()) + { + return p->as(); + } + p = p->parent(); + } + return nullptr; + } + bool isDisplayHidden() const; + void propagateCollapse(bool collapse); + bool collapse(bool value) override; + float computedLocalX() override { return m_layout.left(); }; + float computedLocalY() override { return m_layout.top(); }; + float computedWidth() override { return m_layout.width(); }; + float computedHeight() override { return m_layout.height(); }; + +private: + float m_widthOverride = NAN; + int m_widthUnitValueOverride = -1; + float m_heightOverride = NAN; + int m_heightUnitValueOverride = -1; + bool m_parentIsRow = true; + bool m_widthIntrinsicallySizeOverride = false; + bool m_heightIntrinsicallySizeOverride = false; + float m_forcedWidth = NAN; + float m_forcedHeight = NAN; + bool m_forceUpdateLayoutBounds = false; + +#ifdef WITH_RIVE_LAYOUT +protected: + void propagateSizeToChildren(ContainerComponent* component); + bool applyInterpolation(float elapsedSeconds, bool animate = true); + void calculateLayout(); + bool styleDisplayHidden(); +#endif + +public: + // Implemented for ShapePaintContainer. + const Mat2D& shapeWorldTransform() const override + { + return worldTransform(); + } + + LayoutComponentStyle* style() { return m_style; } + void style(LayoutComponentStyle* style) { m_style = style; } + + void draw(Renderer* renderer) override; + void drawProxy(Renderer* renderer) override; + bool isProxyHidden() override { return isHidden(); } + Core* hitTest(HitInfo*, const Mat2D&) override; + DrawableProxy* proxy() { return &m_proxy; }; + virtual void updateRenderPath(); + void update(ComponentDirt value) override; + void onDirty(ComponentDirt value) override; + AABB layoutBounds() override + { + return AABB::fromLTWH(m_layout.left(), + m_layout.top(), + m_layout.width(), + m_layout.height()); + } + size_t numLayoutNodes() override { return 1; } + AABB localBounds() const override + { + return AABB::fromLTWH(0.0f, 0.0f, m_layout.width(), m_layout.height()); + } + AABB worldBounds() const + { + auto transform = worldTransform(); + return AABB::fromLTWH(transform[4], + transform[5], + m_layout.width(), + m_layout.height()); + } + + float x() const override { return layoutX(); } + float y() const override { return layoutY(); } + float layoutX() const { return m_layout.left(); } + float layoutY() const { return m_layout.top(); } + float layoutWidth() { return m_layout.width(); } + float layoutHeight() { return m_layout.height(); } + float innerWidth() + { + return m_layout.width() - m_layoutPadding.left() - + m_layoutPadding.right(); + } + float innerHeight() + { + return m_layout.height() - m_layoutPadding.top() - + m_layoutPadding.bottom(); + } + float paddingLeft() { return m_layoutPadding.left(); } + float paddingRight() { return m_layoutPadding.right(); } + float paddingTop() { return m_layoutPadding.top(); } + float paddingBottom() { return m_layoutPadding.bottom(); } + + float gapHorizontal(); + float gapVertical(); + + // We provide a way for nested artboards (or other objects) to override this + // layout's width/height and unit values. + void widthOverride(float width, int unitValue = 1, bool isRow = true); + void heightOverride(float height, int unitValue = 1, bool isRow = true); + void parentIsRow(bool isRow); + void widthIntrinsicallySizeOverride(bool intrinsic); + void heightIntrinsicallySizeOverride(bool intrinsic); + virtual bool canHaveOverrides() { return false; } + bool mainAxisIsRow(); + bool mainAxisIsColumn(); + bool overridesKeyedInterpolation(int propertyKey) override; + bool hasShapePaints() const { return m_ShapePaints.size() > 0; } + const Rectangle* backgroundRect() const { return &m_backgroundRect; } + bool advanceComponent(float elapsedSeconds, + AdvanceFlags flags = AdvanceFlags::Animate | + AdvanceFlags::NewFrame) override; + bool isHidden() const override; + float forcedWidth() { return m_forcedWidth; } + float forcedHeight() { return m_forcedHeight; } + void forcedWidth(float width); + void forcedHeight(float height); + void updateConstraints() override; + TransformComponent* transformComponent() override + { + return this->as(); + } + + LayoutComponent(); + ~LayoutComponent(); +#ifdef WITH_RIVE_LAYOUT + + void* layoutNode(int index) override; + void syncStyle(); + void syncLayoutChildren(); + void clearLayoutChildren(); + virtual void propagateSize(); + void updateLayoutBounds(bool animate = true) override; + StatusCode onAddedDirty(CoreContext* context) override; + StatusCode onAddedClean(CoreContext* context) override; + bool advance(float elapsedSeconds); + bool animates(); + LayoutAnimationStyle animationStyle(); + KeyFrameInterpolator* interpolator(); + LayoutStyleInterpolation interpolation(); + float interpolationTime(); + + bool cascadeLayoutStyle(LayoutStyleInterpolation inheritedInterpolation, + KeyFrameInterpolator* inheritedInterpolator, + float inheritedInterpolationTime, + LayoutDirection direction); + bool setInheritedInterpolation( + LayoutStyleInterpolation inheritedInterpolation, + KeyFrameInterpolator* inheritedInterpolator, + float inheritedInterpolationTime); + void clearInheritedInterpolation(); + void interruptAnimation(); + bool isLeaf(); + void positionTypeChanged(); + void scaleTypeChanged(); + void displayChanged(); + void flexDirectionChanged(); + void directionChanged(); + LayoutDirection actualDirection(); +#endif + void buildDependencies() override; + + void markLayoutNodeDirty( + bool shouldForceUpdateLayoutBounds = false) override; + void markLayoutStyleDirty(); + void clipChanged() override; + void widthChanged() override; + void heightChanged() override; + void styleIdChanged() override; + void fractionalWidthChanged() override; + void fractionalHeightChanged() override; + + Vec2D measureLayout(float width, + LayoutMeasureMode widthMode, + float height, + LayoutMeasureMode heightMode) override; + + ShapePaintPath* worldPath() override; + ShapePaintPath* localPath() override; + ShapePaintPath* localClockwisePath() override; + Component* pathBuilder() override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/listener_type.hpp b/third_party/rive/include/rive/listener_type.hpp new file mode 100644 index 0000000..d31902e --- /dev/null +++ b/third_party/rive/include/rive/listener_type.hpp @@ -0,0 +1,17 @@ +#ifndef _RIVE_LISTENER_TYPE_HPP_ +#define _RIVE_LISTENER_TYPE_HPP_ +namespace rive +{ +enum class ListenerType : int +{ + enter = 0, + exit = 1, + down = 2, + up = 3, + move = 4, + event = 5, + click = 6, + draggableConstraint = 7, +}; +} +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/math/aabb.hpp b/third_party/rive/include/rive/math/aabb.hpp new file mode 100644 index 0000000..8d661a9 --- /dev/null +++ b/third_party/rive/include/rive/math/aabb.hpp @@ -0,0 +1,178 @@ +#ifndef _RIVE_AABB_HPP_ +#define _RIVE_AABB_HPP_ + +#include "rive/span.hpp" +#include "rive/math/vec2d.hpp" +#include + +namespace rive +{ +template struct TAABB +{ + int32_t left, top, right, bottom; + + constexpr T width() const { return right - left; } + constexpr T height() const { return bottom - top; } + constexpr bool empty() const { return left >= right || top >= bottom; } + + TAABB inset(T dx, T dy) const + { + return {left + dx, top + dy, right - dx, bottom - dy}; + } + TAABB outset(T dx, T dy) const { return inset(-dx, -dy); } + TAABB offset(T dx, T dy) const + { + return {left + dx, top + dy, right + dx, bottom + dy}; + } + TAABB join(TAABB b) const + { + return {std::min(left, b.left), + std::min(top, b.top), + std::max(right, b.right), + std::max(bottom, b.bottom)}; + } + TAABB intersect(TAABB b) const + { + return {std::max(left, b.left), + std::max(top, b.top), + std::min(right, b.right), + std::min(bottom, b.bottom)}; + } + + bool operator==(const TAABB& o) const + { + return left == o.left && top == o.top && right == o.right && + bottom == o.bottom; + } + bool operator!=(const TAABB& o) const { return !(*this == o); } + + bool contains(const TAABB& rhs) const + { + return left <= rhs.left && top <= rhs.top && right >= rhs.right && + bottom >= rhs.bottom; + } +}; + +using IAABB = TAABB; + +class AABB +{ +public: + float minX, minY, maxX, maxY; + + AABB() : minX(0), minY(0), maxX(0), maxY(0) {} + AABB(const Vec2D& min, const Vec2D& max) : + minX(min.x), minY(min.y), maxX(max.x), maxY(max.y) + {} + static AABB fromLTWH(float x, float y, float width, float height) + { + return {x, y, x + width, y + height}; + } + + AABB(float minX, float minY, float maxX, float maxY) : + minX(minX), minY(minY), maxX(maxX), maxY(maxY) + {} + + AABB(const IAABB& o) : + AABB((float)o.left, (float)o.top, (float)o.right, (float)o.bottom) + {} + + AABB(Span); // computes the union of all points, or 0,0,0,0 + + bool operator==(const AABB& o) const + { + return minX == o.minX && minY == o.minY && maxX == o.maxX && + maxY == o.maxY; + } + bool operator!=(const AABB& o) const { return !(*this == o); } + + inline float left() const { return minX; } + inline float top() const { return minY; } + inline float right() const { return maxX; } + inline float bottom() const { return maxY; } + + Vec2D min() const { return Vec2D(minX, minY); } + Vec2D max() const { return Vec2D(maxX, maxY); } + float width() const { return maxX - minX; } + float height() const { return maxY - minY; } + Vec2D size() const { return {width(), height()}; } + Vec2D center() const + { + return {(minX + maxX) * 0.5f, (minY + maxY) * 0.5f}; + } + + bool isEmptyOrNaN() const + { + // Use "inverse" logic so we return true if either of the comparisons + // fail due to a NaN. + return !(width() > 0 && height() > 0); + } + + AABB pad(float amount) const { return outset(amount, amount); } + + AABB inset(float dx, float dy) const + { + AABB r = {minX + dx, minY + dy, maxX - dx, maxY - dy}; + assert(r.width() >= 0); + assert(r.height() >= 0); + return r; + } + AABB outset(float dx, float dy) const { return inset(-dx, -dy); } + AABB offset(float dx, float dy) const + { + return {minX + dx, minY + dy, maxX + dx, maxY + dy}; + } + + IAABB round() const; + IAABB roundOut() + const; // Rounds out to integer bounds that fully contain the rectangle. + + /// + /// Initialize an AABB to values that represent an invalid/collapsed + /// AABB that can then expand to points that are added to it. + /// + inline static AABB forExpansion() + { + return AABB(std::numeric_limits::max(), + std::numeric_limits::max(), + -std::numeric_limits::max(), + -std::numeric_limits::max()); + } + + /// + /// Grow the AABB to fit the point. + /// + static void expandTo(AABB& out, const Vec2D& point); + static void expandTo(AABB& out, float x, float y); + + /// Join two AABBs. + static void join(AABB& out, const AABB& a, const AABB& b); + + void expand(const AABB& other) { join(*this, *this, other); } + + Vec2D factorFrom(Vec2D point) const + { + return Vec2D( + width() == 0.0f ? 0.0f : (point.x - left()) * 2.0f / width() - 1.0f, + (height() == 0.0f ? 0.0f : point.y - top()) * 2.0f / height() - + 1.0f); + } + + bool contains(Vec2D position) const; + + Vec2D operator[](size_t index) const + { + switch (index) + { + case 0: + return Vec2D(minX, minY); + case 1: + return Vec2D(maxX, maxY); + default: + RIVE_UNREACHABLE(); + } + } +}; + +} // namespace rive +#endif diff --git a/third_party/rive/include/rive/math/bezier_utils.hpp b/third_party/rive/include/rive/math/bezier_utils.hpp new file mode 100644 index 0000000..0c63dfe --- /dev/null +++ b/third_party/rive/include/rive/math/bezier_utils.hpp @@ -0,0 +1,178 @@ +/* + * Copyright 2021 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Initial import from skia:src/gpu/tessellate/Tessellation.h + * skia:src/core/SkGeometry.h + * + * Copyright 2022 Rive + */ + +#pragma once + +#include "rive/math/simd.hpp" +#include "rive/math/vec2d.hpp" +#include + +namespace rive +{ +namespace math +{ +// Finds the cubic bezier's power basis coefficients. These define the bezier +// curve as: +// +// |T^3| +// Cubic(T) = x,y = |A 3B 3C| * |T^2| + P0 +// |. . .| |T | +// +// And the tangent: +// +// |T^2| +// Tangent(T) = dx,dy = |3A 6B 3C| * |T | +// | . . .| |1 | +// +struct CubicCoeffs +{ + RIVE_ALWAYS_INLINE CubicCoeffs(const Vec2D pts[4]) : + CubicCoeffs(simd::load2f(&pts[0].x), + simd::load2f(&pts[1].x), + simd::load2f(&pts[2].x), + simd::load2f(&pts[3].x)) + {} + + RIVE_ALWAYS_INLINE CubicCoeffs(float2 p0, float2 p1, float2 p2, float2 p3) + { + C = p1 - p0; + float2 D = p2 - p1; + float2 E = p3 - p0; + B = D - C; + A = -3.f * D + E; + } + + float2 A, B, C; +}; + +// Optimized SIMD helper for evaluating a single cubic at many points. +class EvalCubic +{ +public: + RIVE_ALWAYS_INLINE EvalCubic(const Vec2D pts[]) : + EvalCubic(CubicCoeffs(pts), pts[0]) + {} + + RIVE_ALWAYS_INLINE EvalCubic(const CubicCoeffs& coeffs, Vec2D p0) : + EvalCubic(coeffs, simd::load2f(&p0)) + {} + + RIVE_ALWAYS_INLINE EvalCubic(const CubicCoeffs& coeffs, float2 p0) : + // Duplicate coefficients across a float4 so we can evaluate two at + // once. + A(coeffs.A.xyxy), + B((3.f * coeffs.B).xyxy), + C((3.f * coeffs.C).xyxy), + D(p0.xyxy) + {} + + // Evaluates [x, y] at location t. + RIVE_ALWAYS_INLINE float2 operator()(float t) const + { + // At^3 + Bt^2 + Ct + P0 + return ((A.xy * t + B.xy) * t + C.xy) * t + D.xy; + } + + // Evaluates [Xa, Ya, Xb, Yb] at locations [Ta, Ta, Tb, Tb]. + RIVE_ALWAYS_INLINE float4 operator()(float4 t) const + { + // At^3 + Bt^2 + Ct + P0 + return ((A * t + B) * t + C) * t + D; + } + + RIVE_ALWAYS_INLINE float4 at(float4 t) const + { + // At^3 + Bt^2 + Ct + P0 + return ((A * t + B) * t + C) * t + D; + } + +private: + const float4 A; + const float4 B; + const float4 C; + const float4 D; +}; + +// Decides the number of polar segments the tessellator adds for each curve. +// (Uniform steps in tangent angle.) The tessellator will add this number of +// polar segments for each radian of rotation in local path space. +template +float calc_polar_segments_per_radian(float approxDevStrokeRadius) +{ + float cosTheta = 1.f - (1.f / Precision) / approxDevStrokeRadius; + return .5f / acosf(std::max(cosTheta, -1.f)); +} + +Vec2D eval_cubic_at(const Vec2D p[4], float t); + +// Given a src cubic bezier, chop it at the specified t value, +// where 0 <= t <= 1, and return the two new cubics in dst: +// dst[0..3] and dst[3..6] +void chop_cubic_at(const Vec2D src[4], Vec2D dst[7], float t); + +// Given a src cubic bezier, chop it at the specified t0 and t1 values, +// where 0 <= t0 <= t1 <= 1, and return the three new cubics in dst: +// dst[0..3], dst[3..6], and dst[6..9] +void chop_cubic_at(const Vec2D src[4], Vec2D dst[10], float t0, float t1); + +// Given a src cubic bezier, chop it at the specified t values, +// where 0 <= t0 <= t1 <= ... <= 1, and return the new cubics in dst: +// dst[0..3],dst[3..6],...,dst[3*t_count..3*(t_count+1)] +void chop_cubic_at(const Vec2D src[4], + Vec2D dst[], + const float tValues[], + int tCount); + +// Measures the angle between two vectors, in the range [0, pi]. +float measure_angle_between_vectors(Vec2D a, Vec2D b); + +// Returns 0, 1, or 2 T values at which to chop the given curve in order to +// guarantee the resulting cubics are convex and rotate no more than 180 +// degrees. +// +// - If the cubic is "serpentine", then the T values are any inflection points +// in [0 < T < 1]. +// - If the cubic is linear, then the T values are any 180-degree cusp points +// in [0 < T < 1]. +// - Otherwise the T value is the point at which rotation reaches 180 degrees, +// iff in [0 < T < 1]. +// +// 'areCusps' is set to true if the chop point occurred at a cusp (within +// tolerance), or if the chop point(s) occurred at 180-degree turnaround points +// on a degenerate flat line. +int find_cubic_convex_180_chops(const Vec2D[], float T[2], bool* areCusps); + +// Finds the tangents of the curve at T=0 and T=1 respectively. +RIVE_ALWAYS_INLINE Vec2D find_cubic_tan0(const Vec2D p[4]) +{ + Vec2D tan0 = (p[0] != p[1] ? p[1] : p[1] != p[2] ? p[2] : p[3]) - p[0]; + return tan0; +} +RIVE_ALWAYS_INLINE Vec2D find_cubic_tan1(const Vec2D p[4]) +{ + Vec2D tan1 = p[3] - (p[3] != p[2] ? p[2] : p[2] != p[1] ? p[1] : p[0]); + return tan1; +} +RIVE_ALWAYS_INLINE void find_cubic_tangents(const Vec2D p[4], Vec2D tangents[2]) +{ + tangents[0] = find_cubic_tan0(p); + tangents[1] = find_cubic_tan1(p); +} + +RIVE_ALWAYS_INLINE constexpr float pow2(float x) { return x * x; } +RIVE_ALWAYS_INLINE constexpr float pow3(float x) { return x * pow2(x); } +RIVE_ALWAYS_INLINE constexpr float length_pow2(Vec2D v) +{ + return pow2(v.x) + pow2(v.y); +} +} // namespace math +} // namespace rive diff --git a/third_party/rive/include/rive/math/bit_field_loc.hpp b/third_party/rive/include/rive/math/bit_field_loc.hpp new file mode 100644 index 0000000..7c0c983 --- /dev/null +++ b/third_party/rive/include/rive/math/bit_field_loc.hpp @@ -0,0 +1,28 @@ +#ifndef _RIVE_BIT_FIELD_LOC_HPP_ +#define _RIVE_BIT_FIELD_LOC_HPP_ + +#include +#include +#include +#include +#include + +namespace rive +{ + +class BitFieldLoc +{ +public: + BitFieldLoc(uint32_t start, uint32_t end); + + uint32_t read(uint32_t bits); + uint32_t write(uint32_t bits, uint32_t value); + +private: + uint32_t m_start; + uint32_t m_count; + uint32_t m_mask; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/math/circle_constant.hpp b/third_party/rive/include/rive/math/circle_constant.hpp new file mode 100644 index 0000000..e2e9a4b --- /dev/null +++ b/third_party/rive/include/rive/math/circle_constant.hpp @@ -0,0 +1,12 @@ +#ifndef _RIVE_CIRCLE_CONSTANT_HPP_ +#define _RIVE_CIRCLE_CONSTANT_HPP_ + +#include "rive/rive_types.hpp" + +namespace rive +{ +constexpr float circleConstant = 0.552284749831f; +constexpr float icircleConstant = 1.0f - circleConstant; +} // namespace rive + +#endif diff --git a/third_party/rive/include/rive/math/contour_measure.hpp b/third_party/rive/include/rive/math/contour_measure.hpp new file mode 100644 index 0000000..0435692 --- /dev/null +++ b/third_party/rive/include/rive/math/contour_measure.hpp @@ -0,0 +1,159 @@ +/* + * Copyright 2022 Rive + */ + +#ifndef _RIVE_CONTOUR_MEASURE_HPP_ +#define _RIVE_CONTOUR_MEASURE_HPP_ + +#include "rive/math/raw_path.hpp" +#include "rive/math/vec2d.hpp" +#include "rive/refcnt.hpp" +#include + +namespace rive +{ + +class ContourMeasure : public RefCnt +{ +public: + static constexpr unsigned kMaxDot30 = (1 << 30) - 1; + static constexpr float kInvScaleD30 = 1.0f / (float)kMaxDot30; + + // Deliberately making this pack well (12 bytes) + struct Segment + { + float m_distance; // total distance up to this point + uint32_t m_ptIndex; // index of the first point for this line/quad/cubic + unsigned m_tValue : 30; // Dot30 t value for the end of this segment + unsigned m_type : 2; // [private enum] + + float getT() const { return (float)m_tValue * kInvScaleD30; } + + bool operator<(const Segment& other) const + { + return m_distance < other.m_distance; + } + + void extract(RawPath* dst, + float fromT, + float toT, + const Vec2D pts[], + bool moveTo) const; + void extract(RawPath* dst, const Vec2D pts[]) const; + }; + +private: + size_t findSegment(float distance) const; + + std::vector m_segments; + std::vector m_points; + const float m_length; + const bool m_isClosed; + + ContourMeasure(std::vector&&, + std::vector&&, + float length, + bool isClosed); + + friend class ContourMeasureIter; + +public: + float length() const { return m_length; } + bool isClosed() const { return m_isClosed; } + + struct PosTan + { + Vec2D pos, tan; + }; + struct PosTanDistance + { + Vec2D pos, tan; + /// Distance along the curve. + float distance; + + /// Squared distance to point projected to curve. + float sqDistanceToPoint; + + PosTanDistance() : distance(0.0f), sqDistanceToPoint(0.0f) {} + PosTanDistance(PosTan posTan, float dist) : + pos(posTan.pos), + tan(posTan.tan), + distance(dist), + sqDistanceToPoint(0.0f) + {} + }; + PosTan getPosTan(float distance) const; + + void getSegment(float startDistance, + float endDistance, + RawPath* dst, + bool startWithMove) const; + + Vec2D warp(Vec2D src) const + { + const auto result = this->getPosTan(src.x); + return { + result.pos.x - result.tan.y * src.y, + result.pos.y + result.tan.x * src.y, + }; + } + + void dump() const; +}; + +class ContourMeasureIter +{ + RawPath m_optionalCopy; + RawPath::Iter m_iter; + RawPath::Iter m_end; + const Vec2D* m_srcPoints; + float m_invTolerance; + + float addQuadSegs(ContourMeasure::Segment*, + const Vec2D[], + uint32_t segmentCount, + uint32_t ptIndex, + float distance) const; + float addCubicSegs(ContourMeasure::Segment*, + const Vec2D[], + uint32_t segmentCount, + uint32_t ptIndex, + float distance) const; + rcp tryNext(); + +public: + // Tolerance is the max deviation of the curve from its approximating line + // segments. A smaller tolerance means more line segments, but a better + // approximation for the curves actual length. + static constexpr float kDefaultTolerance = 0.5f; + + ContourMeasureIter(const RawPath* path, float tol = kDefaultTolerance) + { + this->rewind(path, tol); + } + + void rewind(const RawPath*, float = kDefaultTolerance); + + // Returns a measure object for each contour in the path + // (contours with zero-length are skipped over) + // and then returns nullptr when its finished. + // + // ContourMeasureIter iter(path); + // while ((auto meas = iter.next())) { + // ... meas can be used, and passed to other objects + // } + // + // Each measure object is stand-alone, and can outlive the + // ContourMeasureIter that created it. It contains no back pointers to the + // Iter or to the path. + // + rcp next(); + + // Temporary storage used during tryNext(), for counting up how many + // segments a contour will be divided into. + std::vector m_segmentCounts; +}; + +} // namespace rive + +#endif diff --git a/third_party/rive/include/rive/math/cubic_utilities.hpp b/third_party/rive/include/rive/math/cubic_utilities.hpp new file mode 100644 index 0000000..b1dac00 --- /dev/null +++ b/third_party/rive/include/rive/math/cubic_utilities.hpp @@ -0,0 +1,59 @@ +#ifndef _RIVE_CUBIC_UTILITIES_HPP_ +#define _RIVE_CUBIC_UTILITIES_HPP_ + +#include "rive/math/vec2d.hpp" +#include + +namespace rive +{ +/// +/// Utility functions for recursively subdividing a cubic. +/// +class CubicUtilities +{ +public: + static void computeHull(const Vec2D& from, + const Vec2D& fromOut, + const Vec2D& toIn, + const Vec2D& to, + float t, + Vec2D* hull) + { + hull[0] = Vec2D::lerp(from, fromOut, t); + hull[1] = Vec2D::lerp(fromOut, toIn, t); + hull[2] = Vec2D::lerp(toIn, to, t); + + hull[3] = Vec2D::lerp(hull[0], hull[1], t); + hull[4] = Vec2D::lerp(hull[1], hull[2], t); + + hull[5] = Vec2D::lerp(hull[3], hull[4], t); + } + + static bool tooFar(const Vec2D& a, const Vec2D& b, float threshold) + { + return std::max(std::abs(a.x - b.x), std::abs(a.y - b.y)) > threshold; + } + + static bool shouldSplitCubic(const Vec2D& from, + const Vec2D& fromOut, + const Vec2D& toIn, + const Vec2D& to, + float threshold) + { + + Vec2D oneThird = Vec2D::lerp(from, to, 1.0f / 3.0f); + Vec2D twoThird = Vec2D::lerp(from, to, 2.0f / 3.0f); + return tooFar(fromOut, oneThird, threshold) || + tooFar(toIn, twoThird, threshold); + } + + static float cubicAt(float t, float a, float b, float c, float d) + { + float ti = 1.0f - t; + float value = ti * ti * ti * a + 3.0f * ti * ti * t * b + + 3.0f * ti * t * t * c + t * t * t * d; + return value; + } +}; +} // namespace rive +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/math/hit_test.hpp b/third_party/rive/include/rive/math/hit_test.hpp new file mode 100644 index 0000000..5261a3f --- /dev/null +++ b/third_party/rive/include/rive/math/hit_test.hpp @@ -0,0 +1,56 @@ +/* + * Copyright 2022 Rive + */ + +#ifndef _RIVE_HITTEST_HPP_ +#define _RIVE_HITTEST_HPP_ + +#include "rive/span.hpp" +#include "rive/math/aabb.hpp" +#include "rive/math/path_types.hpp" +#include "rive/math/vec2d.hpp" + +#include +#include + +namespace rive +{ + +class HitTester +{ + std::vector m_DW; // width * height delta-windings + Vec2D m_First, m_Prev; + Vec2D m_offset; + float m_height; + int m_IWidth, m_IHeight; + bool m_ExpectsMove; + + void recurse_cubic(Vec2D b, Vec2D c, Vec2D d, int count); + +public: + HitTester() {} + HitTester(const IAABB& area) { reset(area); } + + void reset(); + void reset(const IAABB& area); + + void move(Vec2D); + void line(Vec2D); + void quad(Vec2D, Vec2D); + void cubic(Vec2D, Vec2D, Vec2D); + void close(); + + void addRect(const AABB&, const Mat2D&, PathDirection = PathDirection::ccw); + + bool test(FillRule = rive::FillRule::nonZero); + + static bool testMesh(Vec2D point, + Span verts, + Span indices); + static bool testMesh(const IAABB&, + Span verts, + Span indices); +}; + +} // namespace rive +#endif diff --git a/third_party/rive/include/rive/math/mat2d.hpp b/third_party/rive/include/rive/math/mat2d.hpp new file mode 100644 index 0000000..48fe993 --- /dev/null +++ b/third_party/rive/include/rive/math/mat2d.hpp @@ -0,0 +1,128 @@ +#ifndef _RIVE_MAT2D_HPP_ +#define _RIVE_MAT2D_HPP_ + +#include "rive/math/aabb.hpp" +#include "rive/math/vec2d.hpp" +#include +#include + +namespace rive +{ +class TransformComponents; +class Mat2D +{ +public: + constexpr Mat2D() : m_buffer{{1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f}} {} + constexpr Mat2D(float x1, + float y1, + float x2, + float y2, + float tx, + float ty) : + m_buffer{{x1, y1, x2, y2, tx, ty}} + {} + + inline const float* values() const { return &m_buffer[0]; } + + float& operator[](std::size_t idx) { return m_buffer[idx]; } + const float& operator[](std::size_t idx) const { return m_buffer[idx]; } + + static Mat2D fromRotation(float rad); + static Mat2D fromScale(float sx, float sy) { return {sx, 0, 0, sy, 0, 0}; } + static Mat2D fromTranslate(float tx, float ty) + { + return {1, 0, 0, 1, tx, ty}; + } + static Mat2D fromTranslation(Vec2D translation) + { + return {1, 0, 0, 1, translation.x, translation.y}; + } + static Mat2D fromScaleAndTranslation(float sx, float sy, float tx, float ty) + { + return {sx, 0, 0, sy, tx, ty}; + } + + void scaleByValues(float sx, float sy); + + Mat2D& operator*=(const Mat2D& rhs) + { + *this = Mat2D::multiply(*this, rhs); + return *this; + } + + // Sets dst[i] = M * pts[i] for i in 0..n-1. + void mapPoints(Vec2D dst[], const Vec2D pts[], size_t n) const; + + // Computes a bounding box that would tightly contain the given points if + // they were to all be transformed by this matrix, ignoring NaN values. + // Returns {0, 0, 0, 0} if the given points are empty or all NaN. + AABB mapBoundingBox(const Vec2D pts[], size_t n) const; + AABB mapBoundingBox(const AABB&) const; + + // If returns true, result holds the inverse. + // If returns false, result is unchnaged. + bool invert(Mat2D* result) const; + + Mat2D invertOrIdentity() const + { + Mat2D inverse; // initialized to identity + (void)invert(&inverse); // inverse is unchanged if invert() fails + return inverse; + } + + TransformComponents decompose() const; + static Mat2D compose(const TransformComponents&); + float findMaxScale() const; + Mat2D scale(Vec2D) const; + Mat2D translate(Vec2D) const; + + static Mat2D multiply(const Mat2D& a, const Mat2D& b); + + float xx() const { return m_buffer[0]; } + float xy() const { return m_buffer[1]; } + float yx() const { return m_buffer[2]; } + float yy() const { return m_buffer[3]; } + float tx() const { return m_buffer[4]; } + float ty() const { return m_buffer[5]; } + + Vec2D translation() const { return {m_buffer[4], m_buffer[5]}; } + + void xx(float value) { m_buffer[0] = value; } + void xy(float value) { m_buffer[1] = value; } + void yx(float value) { m_buffer[2] = value; } + void yy(float value) { m_buffer[3] = value; } + void tx(float value) { m_buffer[4] = value; } + void ty(float value) { m_buffer[5] = value; } + + float determinant() const + { + return m_buffer[0] * m_buffer[3] - m_buffer[2] * m_buffer[1]; + } + +private: + std::array m_buffer; +}; + +inline Vec2D operator*(const Mat2D& m, Vec2D v) +{ + return { + m[0] * v.x + m[2] * v.y + m[4], + m[1] * v.x + m[3] * v.y + m[5], + }; +} + +inline Mat2D operator*(const Mat2D& a, const Mat2D& b) +{ + return Mat2D::multiply(a, b); +} + +inline bool operator==(const Mat2D& a, const Mat2D& b) +{ + return a[0] == b[0] && a[1] == b[1] && a[2] == b[2] && a[3] == b[3] && + a[4] == b[4] && a[5] == b[5]; +} + +inline bool operator!=(const Mat2D& a, const Mat2D& b) { return !(a == b); } + +} // namespace rive +#endif diff --git a/third_party/rive/include/rive/math/math_types.hpp b/third_party/rive/include/rive/math/math_types.hpp new file mode 100644 index 0000000..4201265 --- /dev/null +++ b/third_party/rive/include/rive/math/math_types.hpp @@ -0,0 +1,190 @@ +/* + * Copyright 2022 Rive + */ + +#ifndef _RIVE_MATH_TYPES_DEFINED_ +#define _RIVE_MATH_TYPES_DEFINED_ + +#include "rive/rive_types.hpp" +#include +#include +#include + +namespace rive +{ + +namespace math +{ +constexpr float PI = 3.14159265f; +constexpr float SQRT2 = 1.41421356f; +constexpr float EPSILON = + 1.f / (1 << 12); // Common threshold for detecting values near zero. + +RIVE_MAYBE_UNUSED inline bool nearly_zero(float a, float tolerance = EPSILON) +{ + assert(tolerance >= 0); + return fabsf(a) <= tolerance; +} + +RIVE_MAYBE_UNUSED inline bool nearly_equal(float a, + float b, + float tolerance = EPSILON) +{ + return nearly_zero(b - a, tolerance); +} + +// Performs a floating point division with conformant IEEE 754 behavior for NaN +// and Inf. +// +// Returns +/-Inf if b == 0. +// Returns 0 if b == +/-Inf. +// Returns NaN if a and b are both zero. +// Returns NaN if a and b are both infinite. +// Returns NaN a or b is NaN. +// +// Reference: +// https://stackoverflow.com/questions/42926763/the-behaviour-of-floating-point-division-by-zero +RIVE_MAYBE_UNUSED +#if defined(__clang__) || defined(__GNUC__) +__attribute__((no_sanitize("float-divide-by-zero"), always_inline)) +#endif +inline static float +ieee_float_divide(float a, float b) +{ + static_assert(std::numeric_limits::is_iec559, + "conformant IEEE 754 behavior for NaN and Inf is required"); + return a / b; +} + +// Reinterprets the underlying bits of src as the given type. +template Dst bit_cast(const Src& src) +{ + static_assert(sizeof(Dst) == sizeof(Src), "sizes of both types must match"); + Dst dst; + RIVE_INLINE_MEMCPY(&dst, &src, sizeof(Dst)); + return dst; +} + +// Lossless cast function that asserts on overflow +template T lossless_numeric_cast(U u) +{ + T t = static_cast(u); + assert(static_cast(t) == u); + return t; +} + +// Attempt to generate a "clz" assembly instruction. +RIVE_ALWAYS_INLINE static int clz32(uint32_t x) +{ + assert(x != 0); +#if __has_builtin(__builtin_clz) + return __builtin_clz(x); +#else + uint64_t doubleBits = bit_cast(static_cast(x)); + return 1054 - (doubleBits >> 52); +#endif +} + +RIVE_ALWAYS_INLINE static int clz64(uint64_t x) +{ + assert(x != 0); +#if __has_builtin(__builtin_clzll) + return __builtin_clzll(x); +#else + uint32_t hi32 = x >> 32; + return hi32 != 0 ? clz32(hi32) : 32 + clz32(x & 0xffffffff); +#endif +} + +// Returns the 1-based index of the most significat bit in x. +// +// 0 -> 0 +// 1 -> 1 +// 2..3 -> 2 +// 4..7 -> 3 +// ... +// +RIVE_ALWAYS_INLINE static uint32_t msb(uint32_t x) +{ + return x != 0 ? 32 - clz32(x) : 0; +} + +// Attempt to generate a "rotl" (rotate-left) assembly instruction. +RIVE_ALWAYS_INLINE static uint32_t rotateleft32(uint32_t x, int y) +{ +#if __has_builtin(__builtin_rotateleft32) + return __builtin_rotateleft32(x, y); +#else + return (x << y) | (x >> (32 - y)); +#endif +} + +// Returns x rounded up to the next multiple of N. +// If x is already a multiple of N, returns x. +template +RIVE_ALWAYS_INLINE constexpr T round_up_to_multiple_of(T x) +{ + static_assert(N != 0 && (N & (N - 1)) == 0, + "math::round_up_to_multiple_of<> only supports powers of 2."); + return (x + (N - 1)) & ~static_cast(N - 1); +} + +// Behaves better with NaN than std::clamp(). (Matching simd::clamp().) +// +// Returns lo if x == NaN (but std::clamp() returns NaN). +// Returns hi if hi <= lo. +// Ignores hi and/or lo if they are NaN. +// +RIVE_ALWAYS_INLINE static float clamp(float x, float lo, float hi) +{ + return fminf(fmaxf(lo, x), hi); +} + +// Matches Dart modulus: +// https://api.dart.dev/stable/2.19.0/dart-core/double/operator_modulo.html +RIVE_ALWAYS_INLINE static float positive_mod(float value, float range) +{ + // assert(range > 0.0f); + if (range < 0) + { + range = -range; + } + float v = fmodf(value, range); + if (v < 0.0f) + { + v += range; + } + return v; +} + +inline float degrees_to_radians(float degrees) { return degrees * PI / 180.0f; } + +RIVE_ALWAYS_INLINE static float degreesToRadians(float degrees) +{ + return degrees * (PI / 180.0f); +} + +// Returns the smallest number that can be added to 'value', such that +// 'value % alignment' == 0. +template uint32_t padding_to_align_up(uintptr_t value) +{ + constexpr uintptr_t MAX_MULTIPLE_OF_ALIGNMENT = + std::numeric_limits::max() / ALIGNMENT * ALIGNMENT; + uint32_t padding = (MAX_MULTIPLE_OF_ALIGNMENT - value) % ALIGNMENT; + assert((value + padding) % ALIGNMENT == 0); + return padding; +} + +template uint32_t padding_to_align_up(void* ptr) +{ + return padding_to_align_up(reinterpret_cast(ptr)); +} +} // namespace math + +template T lerp(const T& a, const T& b, float t) +{ + return a * (1 - t) + b * t; +} +} // namespace rive + +#endif diff --git a/third_party/rive/include/rive/math/n_slicer_helpers.hpp b/third_party/rive/include/rive/math/n_slicer_helpers.hpp new file mode 100644 index 0000000..5331f10 --- /dev/null +++ b/third_party/rive/include/rive/math/n_slicer_helpers.hpp @@ -0,0 +1,44 @@ +#ifndef _RIVE_N_SLICER_HELPERS_HPP_ +#define _RIVE_N_SLICER_HELPERS_HPP_ +#include + +namespace rive +{ +class Axis; +class NSlicedNode; +class RawPath; +class Mat2D; + +struct ScaleInfo +{ + bool useScale; + float scaleFactor; + float fallbackSize; +}; + +struct NSlicerHelpers +{ + static std::vector uvStops(const std::vector& axes, + float size); + static std::vector pxStops(const std::vector& axes, + float size); + + static ScaleInfo analyzeUVStops(const std::vector& uvs, + float size, + float scale); + + static float mapValue(const std::vector& stops, + const ScaleInfo& scaleInfo, + float size, + float value); + + static bool isFixedSegment(int i) { return i % 2 == 0; }; + static void deformLocalRenderPathWithNSlicer(const NSlicedNode& nslicedNode, + RawPath& localPath, + const Mat2D& world, + const Mat2D& inverseWorld); + static void deformWorldRenderPathWithNSlicer(const NSlicedNode& nslicedNode, + RawPath& worldPath); +}; +} // namespace rive +#endif diff --git a/third_party/rive/include/rive/math/path_measure.hpp b/third_party/rive/include/rive/math/path_measure.hpp new file mode 100644 index 0000000..5e79901 --- /dev/null +++ b/third_party/rive/include/rive/math/path_measure.hpp @@ -0,0 +1,26 @@ +#ifndef _RIVE_PATH_MEASURE_HPP_ +#define _RIVE_PATH_MEASURE_HPP_ + +#include "rive/math/contour_measure.hpp" +#include + +namespace rive +{ +class PathMeasure +{ +public: + PathMeasure(); + PathMeasure(const RawPath* path, + float tol = ContourMeasureIter::kDefaultTolerance); + ContourMeasure::PosTanDistance atDistance(float distance) const; + ContourMeasure::PosTanDistance atPercentage(float percentageDistance) const; + + float length() const { return m_length; } + +private: + float m_length; + std::vector> m_contours; +}; +} // namespace rive + +#endif diff --git a/third_party/rive/include/rive/math/path_types.hpp b/third_party/rive/include/rive/math/path_types.hpp new file mode 100644 index 0000000..e717ca4 --- /dev/null +++ b/third_party/rive/include/rive/math/path_types.hpp @@ -0,0 +1,43 @@ +/* + * Copyright 2022 Rive + */ + +#ifndef _RIVE_PATH_TYPES_HPP_ +#define _RIVE_PATH_TYPES_HPP_ + +#include "rive/rive_types.hpp" + +namespace rive +{ + +enum class FillRule +{ + nonZero, + evenOdd, + clockwise, +}; + +enum class PathDirection +{ + cw, + ccw, + // aliases + clockwise = cw, + counterclockwise = ccw, +}; + +enum class PathVerb : uint8_t +{ + // These deliberately match Skia's values + move = 0, + line = 1, + quad = 2, + // conic + cubic = 4, + close = 5, +}; + +int path_verb_to_point_count(PathVerb); + +} // namespace rive +#endif diff --git a/third_party/rive/include/rive/math/raw_path.hpp b/third_party/rive/include/rive/math/raw_path.hpp new file mode 100644 index 0000000..ce26d1c --- /dev/null +++ b/third_party/rive/include/rive/math/raw_path.hpp @@ -0,0 +1,290 @@ +/* + * Copyright 2022 Rive + */ + +#ifndef _RIVE_RAW_PATH_HPP_ +#define _RIVE_RAW_PATH_HPP_ + +#include "rive/span.hpp" +#include "rive/math/aabb.hpp" +#include "rive/math/mat2d.hpp" +#include "rive/math/path_types.hpp" +#include "rive/math/vec2d.hpp" + +#include +#include +#include +#include +#include + +namespace rive +{ + +class CommandPath; + +class RawPath +{ +public: + bool operator==(const RawPath& o) const; + bool operator!=(const RawPath& o) const { return !(*this == o); } + + bool empty() const { return m_Points.empty(); } + AABB bounds() const; +#ifdef DEBUG + void printCode() const; +#endif +#ifdef WITH_RIVE_TOOLS + AABB preciseBounds() const; +#endif + size_t countMoveTos() const; + + void move(Vec2D); + void line(Vec2D); + void quad(Vec2D, Vec2D); + void cubic(Vec2D, Vec2D, Vec2D); + void close(); + bool isClosed() const; + + void swap(RawPath&); + + // Makes the path empty and frees any memory allocated by the drawing + // (line, curve, move, close) calls. + void reset(); + + // Makes the path empty but keeps the memory for the drawing calls reserved. + void rewind(); + + RawPath transform(const Mat2D&) const; + void transformInPlace(const Mat2D&); + + Span points() const { return m_Points; } + Span points() { return m_Points; } + + Span verbs() const { return m_Verbs; } + Span verbs() { return m_Verbs; } + + Span verbsU8() const + { + const uint8_t* ptr = (const uint8_t*)m_Verbs.data(); + return Span(ptr, m_Verbs.size()); + } + + // Syntactic sugar for x,y -vs- vec2d + + void moveTo(float x, float y) { move({x, y}); } + void lineTo(float x, float y) { line({x, y}); } + void quadTo(float x, float y, float x1, float y1) + { + quad({x, y}, {x1, y1}); + } + void cubicTo(float x, float y, float x1, float y1, float x2, float y2) + { + cubic({x, y}, {x1, y1}, {x2, y2}); + } + void quadToCubic(float x, float y, float x1, float y1); + + // Helpers for adding new contours + + void addRect(const AABB&, PathDirection = PathDirection::cw); + void addOval(const AABB&, PathDirection = PathDirection::cw); + void addPoly(Span, bool isClosed); + + // Simple STL-style iterator. To traverse using range-for: + // + // for (auto [verb, pts] : rawPath) { ... } + // + class Iter + { + public: + Iter() = default; + Iter(const PathVerb* verbs, const Vec2D* pts) : + m_verbs(verbs), m_pts(pts) + {} + + bool operator!=(const Iter& that) const + { + assert(m_verbs != that.m_verbs || m_pts == that.m_pts); + return m_verbs != that.m_verbs; + } + bool operator==(const Iter& that) const + { + assert(m_verbs != that.m_verbs || m_pts == that.m_pts); + return m_verbs == that.m_verbs; + } + + // Generic accessors. The points pointer is adjusted to point to p0 for + // each specific verb. + PathVerb verb() const { return *m_verbs; } + const Vec2D* pts() const { return m_pts + PtsBacksetForVerb(verb()); } + std::tuple operator*() const + { + PathVerb verb = *m_verbs; + return {verb, m_pts + PtsBacksetForVerb(verb)}; + } + + // Specific point accessors for callers who already know the verb. + // (These may be a tiny bit faster in some cases since the iterator + // doesn't have to check the verb.) + Vec2D movePt() const + { + assert(verb() == PathVerb::move); + return m_pts[0]; + } + const Vec2D* linePts() const + { + assert(verb() == PathVerb::line); + return m_pts - 1; + } + const Vec2D* quadPts() const + { + assert(verb() == PathVerb::quad); + return m_pts - 1; + } + const Vec2D* cubicPts() const + { + assert(verb() == PathVerb::cubic); + return m_pts - 1; + } + Vec2D ptBeforeClose() const + { + assert(verb() == PathVerb::close); + return m_pts[-1]; + } + // P0 for a close can be accessed via rawPtsPtr()[-1]. Note than p1 for + // a close is not in the array at this location. + + // Internal pointers held by the iterator. See PtsBacksetForVerb() for + // how pts() relates to the data for specific verbs. + const PathVerb* rawVerbsPtr() const { return m_verbs; } + const Vec2D* rawPtsPtr() const { return m_pts; } + + Iter& operator++() // "++iter" + { + m_pts += PtsAdvanceAfterVerb(*m_verbs++); + return *this; + } + + // How much should we advance pts after encountering this verb? + inline static int PtsAdvanceAfterVerb(PathVerb verb) + { + switch (verb) + { + case PathVerb::move: + return 1; + case PathVerb::line: + return 1; + case PathVerb::quad: + return 2; + case PathVerb::cubic: + return 3; + case PathVerb::close: + return 0; + } + RIVE_UNREACHABLE(); + } + + // Where is p0 relative to our m_pts pointer? We find the start point of + // segments by peeking backwards from the current point, which works as + // long as there is always a PathVerb::move before any geometry. + // (injectImplicitMoveToIfNeeded() guarantees this to be the case.) + inline static int PtsBacksetForVerb(PathVerb verb) + { + switch (verb) + { + case PathVerb::move: + return 0; + case PathVerb::line: + return -1; + case PathVerb::quad: + return -1; + case PathVerb::cubic: + return -1; + case PathVerb::close: + return -1; + } + RIVE_UNREACHABLE(); + } + + private: + const PathVerb* m_verbs; + const Vec2D* m_pts; + }; + Iter begin() const { return {m_Verbs.data(), m_Points.data()}; } + Iter end() const + { + return {m_Verbs.data() + m_Verbs.size(), + m_Points.data() + m_Points.size()}; + } + + template RawPath morph(Handler proc) const + { + RawPath dst; + // todo: dst.reserve(src.ptCount, src.verbCount); + for (auto iter : *this) + { + PathVerb verb = std::get<0>(iter); + const Vec2D* pts = std::get<1>(iter); + switch (verb) + { + case PathVerb::move: + dst.move(proc(pts[0])); + break; + case PathVerb::line: + dst.line(proc(pts[1])); + break; + case PathVerb::quad: + dst.quad(proc(pts[1]), proc(pts[2])); + break; + case PathVerb::cubic: + dst.cubic(proc(pts[1]), proc(pts[2]), proc(pts[3])); + break; + case PathVerb::close: + dst.close(); + break; + } + } + return dst; + } + + // Adds the given RawPath to the end of this path, with an optional + // transform. Returns an iterator at the beginning of the newly added + // geometry. + Iter addPath(const RawPath&, const Mat2D* = nullptr); + Iter addPathBackwards(const RawPath&, const Mat2D* = nullptr); + + void pruneEmptySegments(Iter start); + void pruneEmptySegments() { pruneEmptySegments(begin()); } + + // Utility for pouring a RawPath into a CommandPath + void addTo(CommandPath*) const; + + // If there is not currently an open contour, this method opens a new + // contour at the current pen location, or [0,0] if the path is empty. + // Otherwise it does nothing. + void injectImplicitMoveIfNeeded(); + + void reserve(size_t numVerbs, size_t numPts) + { + m_Verbs.reserve(numVerbs); + m_Points.reserve(numPts); + } + // Approximates the area of the path by linearizing it with a coarse + // tolerance of 8px in artboard space. + constexpr static float kCoarseAreaTolerance = 8; + float computeCoarseArea() const; + +private: + std::vector m_Points; + std::vector m_Verbs; + size_t m_lastMoveIdx; + // True of the path is nonempty and the most recent verb is not "close". + bool m_contourIsOpen = false; + + void addPoints(std::vector::const_iterator& rev_iter, + int count, + const Mat2D* = nullptr); +}; + +} // namespace rive + +#endif diff --git a/third_party/rive/include/rive/math/raw_path_utils.hpp b/third_party/rive/include/rive/math/raw_path_utils.hpp new file mode 100644 index 0000000..56aab47 --- /dev/null +++ b/third_party/rive/include/rive/math/raw_path_utils.hpp @@ -0,0 +1,67 @@ +/* + * Copyright 2022 Rive + */ + +#ifndef _RIVE_RAW_PATH_UTILS_HPP_ +#define _RIVE_RAW_PATH_UTILS_HPP_ + +#include "rive/math/vec2d.hpp" + +namespace rive +{ +static inline Vec2D two(Vec2D v) { return v + v; } + +// Caches the setup to evaluate a quadratic bezier. Useful if you +// want to evaluate the save curve at multiple t values. +// clang-format off + struct EvalQuad { + const Vec2D a, b, c; // at^2 + bt + c + + // pts are the 3 quadratic bezier control points + EvalQuad(const Vec2D pts[3]) : + a(pts[0] - two(pts[1]) + pts[2]), + b(two(pts[1] - pts[0])), + c(pts[0]) {} + + Vec2D operator()(float t) const { return (a * t + b) * t + c; } + }; +// clang-format on + +// Caches the setup to evaluate a cubic bezier. Useful if you +// want to evaluate the save curve at multiple t values. +struct EvalCubic +{ + const Vec2D a, b, c, d; // at^3 + bt^2 + ct + d + + // pts are the 4 cubic bezier control points + EvalCubic(const Vec2D pts[4]) : + a(pts[3] + 3 * (pts[1] - pts[2]) - pts[0]), + b(3 * (pts[2] - two(pts[1]) + pts[0])), + c(3 * (pts[1] - pts[0])), + d(pts[0]) + {} + + Vec2D operator()(float t) const { return ((a * t + b) * t + c) * t + d; } +}; + +// Extract a subcurve from the curve (given start and end t-values) + +extern void quad_subdivide(const Vec2D src[3], float t, Vec2D dst[5]); +extern void cubic_subdivide(const Vec2D src[4], float t, Vec2D dst[7]); + +extern void line_extract(const Vec2D src[2], + float startT, + float endT, + Vec2D dst[2]); +extern void quad_extract(const Vec2D src[3], + float startT, + float endT, + Vec2D dst[3]); +extern void cubic_extract(const Vec2D src[4], + float startT, + float endT, + Vec2D dst[4]); + +} // namespace rive + +#endif diff --git a/third_party/rive/include/rive/math/rectangles_to_contour.hpp b/third_party/rive/include/rive/math/rectangles_to_contour.hpp new file mode 100644 index 0000000..7ac4cdf --- /dev/null +++ b/third_party/rive/include/rive/math/rectangles_to_contour.hpp @@ -0,0 +1,197 @@ +#ifndef _RIVE_RECTANGLES_TO_CONTOUR_HPP_ +#define _RIVE_RECTANGLES_TO_CONTOUR_HPP_ +#include +#include + +#include "rive/math/mat2d.hpp" +#include "rive/math/aabb.hpp" + +#ifdef TESTING +// When building for testing we use an ordered map for the EdgeMap so we can get +// crossplatform stable order of contours. Visually this doesn't matter but for +// testing across results across different platforms, it does. +#include +struct EdgeMapTesting +{ + bool operator()(const rive::Vec2D& a, const rive::Vec2D& b) const + { + return a.x < b.x || (a.x == b.x && a.y < b.y); + } +}; +using EdgeMap = std::map; +#else +#include +using EdgeMap = std::unordered_map; +#endif + +namespace rive +{ +struct ContourPoint +{ + Vec2D vec; + int dir; // 0 for horizontal, 1 for vertical + + ContourPoint(const Vec2D& vec, int dir) : vec(vec), dir(dir) {} + + bool operator==(const ContourPoint& other) const + { + return vec == other.vec && dir == other.dir; + } +}; + +class RectanglesToContour; +class Contour; + +// A helper for iterating the points in a contour, lazily skipping points which +// have the same value. +class ContourPointItr +{ +public: + ContourPointItr() = default; + ContourPointItr(const Span contour, size_t pointIndex) : + m_contour(contour), m_pointIndex(pointIndex) + {} + + bool operator!=(const ContourPointItr& that) const + { + return m_pointIndex != that.m_pointIndex || m_contour != that.m_contour; + } + bool operator==(const ContourPointItr& that) const + { + return m_pointIndex == that.m_pointIndex && m_contour == that.m_contour; + } + + ContourPointItr& operator++(); + + Vec2D operator*() const; + +private: + const Span m_contour; + size_t m_pointIndex; +}; + +class Contour +{ +public: + Contour(Span points) : m_points(points) {} + ContourPointItr begin() const { return ContourPointItr(m_points, 0); } + ContourPointItr end() const + { + return ContourPointItr(m_points, m_points.size()); + } + + size_t size() const { return m_points.size(); } + Vec2D point(size_t index) const { return m_points[index].vec; } + Vec2D point(size_t index, bool reversed) const + { + if (reversed) + { + return m_points[m_points.size() - 1 - index].vec; + } + return m_points[index].vec; + } + bool isClockwise() const; + +private: + Span m_points; +}; + +// A helper for iterating the contours computed by RectanglesToContour. This +// allows RectanglesToContour to store a linear array of contour points for all +// contours. +class ContourItr +{ +public: + ContourItr() = default; + ContourItr(const RectanglesToContour* rectanglesToContour, + size_t contourIndex) : + m_rectanglesToContour(rectanglesToContour), m_contourIndex(contourIndex) + {} + + bool operator!=(const ContourItr& that) const + { + return m_contourIndex != that.m_contourIndex || + m_rectanglesToContour != that.m_rectanglesToContour; + } + bool operator==(const ContourItr& that) const + { + return m_contourIndex == that.m_contourIndex && + m_rectanglesToContour == that.m_rectanglesToContour; + } + + ContourItr& operator++(); + + Contour operator*() const; + +private: + const RectanglesToContour* m_rectanglesToContour; + size_t m_contourIndex; +}; + +class RectanglesToContour +{ +public: + // Add a rectangle to the contour computation. + void addRect(const AABB& rect); + // Compute the contours once all rects have been added. + void computeContours(); + // Reset everything to start adding rects again. + void reset(); + + // Results can be queried via the utilities below. + // + // For example you can iterate the result: + // for (auto contour : converter) + // { + // for (auto point : contour) + // { + // printf("contour point: %f %f\n", point.x, point.y); + // } + // } + size_t contourCount() const { return m_contourOffsets.size(); } + Contour contour(size_t index) const; + + ContourItr begin() const { return ContourItr(this, 0); } + ContourItr end() const { return ContourItr(this, m_contourOffsets.size()); } + + struct RectEvent + { + size_t index = 0; + float size = 0; + uint8_t type = 0; + float x = 0; + float y = 0; + + float getValue(uint8_t axis) const { return axis == 0 ? x : y; } + }; + +private: + // These arrays and maps are built up accumulating temporary data used to + // build the contours from the rectangles. We store them on the + // RectanglesToContour class to leverage re-using their reserved memory on + // re-runs. For this reason it's encouraged to keep the RectanglesToContour + // around when you know you'll need to recompute the contour from a set of + // rectangles often/in rapid succession. + std::vector m_rectEvents; + EdgeMap m_edgesH; + EdgeMap m_edgesV; + std::unordered_set m_uniquePoints; + std::vector m_rects; + std::vector m_subdividedRects; + std::vector m_rectInclusionBitset; + std::vector m_sortedPointsX; + std::vector m_sortedPointsY; + + // The entire set of contour points where each contour is tightly packed + // after the previous at offsets defined in m_contourOffsets. + std::vector m_contourPoints; + std::vector m_contourOffsets; + + bool isRectIncluded(size_t rectIndex); + void markRectIncluded(size_t rectIndex, bool isIt); + + void addUniquePoint(const Vec2D& point); + void subdivideRectangles(); +}; +} // namespace rive +#endif diff --git a/third_party/rive/include/rive/math/simd.hpp b/third_party/rive/include/rive/math/simd.hpp new file mode 100644 index 0000000..d8d1e91 --- /dev/null +++ b/third_party/rive/include/rive/math/simd.hpp @@ -0,0 +1,790 @@ +/* + * Copyright 2022 Rive + */ + +// An SSE / NEON / WASM_SIMD library based on clang vector types. +// +// This header makes use of the clang vector builtins specified in +// https://reviews.llvm.org/D111529. This effort in clang is still a work in +// progress, so getting maximum performance from this header requires an +// extremely recent version of clang. +// +// To explore the codegen from this header, paste it into https://godbolt.org/, +// select a recent clang compiler, and add an -O3 flag. + +#ifndef _RIVE_SIMD_HPP_ +#define _RIVE_SIMD_HPP_ + +// #define RIVE_SIMD_PERF_WARNINGS + +#include +#include +#include +#include +#include +#include +#include + +#ifdef __SSE__ +#include +#endif + +#if defined(__ARM_NEON__) || defined(__aarch64__) +#include +#endif + +#if defined(__GNUC__) || defined(__clang__) +#ifndef __has_builtin +#define __has_builtin(x) 0 +#endif +#define SIMD_ALWAYS_INLINE inline __attribute__((always_inline)) +#else +#define __has_builtin(x) 0 +#define SIMD_ALWAYS_INLINE inline +#endif + +#if __has_builtin(__builtin_memcpy) +#define SIMD_INLINE_MEMCPY __builtin_memcpy +#else +#define SIMD_INLINE_MEMCPY memcpy +#endif + +// SIMD math can expect conformant IEEE 754 behavior for NaN and Inf. +static_assert(std::numeric_limits::is_iec559, + "Conformant IEEE 754 behavior for NaN and Inf is required."); + +#if defined(__clang__) + +namespace rive +{ +namespace simd +{ +// gvec can be native vectors inside the compiler. +// (The GLSL spec uses "gvec" to denote a vector of unspecified type.) +template +using gvec = T __attribute__((ext_vector_type(N))) +__attribute__((aligned(sizeof(T) * N))); + +// Vector booleans are masks of integer type, where true is -1 and false is 0. +// Vector booleans masks are generated using the builtin boolean operators: ==, +// !=, <=, >=, <, > +template struct extract_element_type; +template struct extract_element_type> +{ + using type = T; +}; +template struct boolean_mask_type +{ + using type = typename extract_element_type() == + gvec())>::type; +}; +} // namespace simd +} // namespace rive + +#define SIMD_NATIVE_GVEC 1 + +#else + +// gvec needs to be polyfilled with templates. +#ifdef RIVE_SIMD_PERF_WARNINGS +#pragma message( \ + "performance: ext_vector_type not supported. Consider using clang.") +#endif +#include "simd_gvec_polyfill.hpp" + +#define SIMD_NATIVE_GVEC 0 + +#endif + +namespace rive +{ +namespace simd +{ +////// Boolean logic ////// +// +// Vector booleans are masks of integer type, where true is -1 and false is 0. +// Vector booleans masks can be generated using the builtin boolean operators: +// ==, !=, <=, >=, <, > +// + +// Returns true if all elements in x are equal to 0. +template SIMD_ALWAYS_INLINE bool any(gvec x) +{ +#if __has_builtin(__builtin_reduce_or) && SIMD_NATIVE_GVEC + return __builtin_reduce_or(x); +#else +#ifdef RIVE_SIMD_PERF_WARNINGS +#pragma message( \ + "performance: __builtin_reduce_or() not supported. Consider updating clang.") +#endif + // This particular logic structure gets decent codegen in clang. + for (int i = 0; i < N; ++i) + { + if (x[i]) + return true; + } + return false; +#endif +} + +// Returns true if all elements in x are equal to ~0. +template SIMD_ALWAYS_INLINE bool all(gvec x) +{ +#if __has_builtin(__builtin_reduce_and) && SIMD_NATIVE_GVEC + return __builtin_reduce_and(x); +#else +#ifdef RIVE_SIMD_PERF_WARNINGS +#pragma message( \ + "performance: __builtin_reduce_and() not supported. Consider updating clang.") +#endif + // In vector, true is represented by -1 exactly, so we use ~x for "not". + return !any(~x); +#endif +} + +template < + typename T, + int N, + typename std::enable_if::value>::type* = nullptr> +SIMD_ALWAYS_INLINE gvec::type, N> isnan( + gvec x) +{ + return ~(x == x); +} + +template ::value>::type* = nullptr> +constexpr gvec::type, N> isnan(gvec) +{ + return {}; // Integer types are never NaN. +} + +////// Math ////// + +// Elementwise ternary expression: "_if ? _then : _else" for each component. +template +SIMD_ALWAYS_INLINE gvec if_then_else( + gvec::type, N> _if, + gvec _then, + gvec _else) +{ +#if defined(__clang_major__) && __clang_major__ >= 13 + // The '?:' operator supports a vector condition beginning in clang 13. + return _if ? _then : _else; +#else +#ifdef RIVE_SIMD_PERF_WARNINGS +#pragma message( \ + "performance: vectorized '?:' operator not supported. Consider updating clang.") +#endif + gvec ret{}; + for (int i = 0; i < N; ++i) + ret[i] = _if[i] ? _then[i] : _else[i]; + return ret; +#endif +} + +// Similar to std::min(), with a noteworthy difference: +// If a[i] or b[i] is NaN and the other is not, returns whichever is _not_ NaN. +template +SIMD_ALWAYS_INLINE gvec min(gvec a, gvec b) +{ +#if __has_builtin(__builtin_elementwise_min) && SIMD_NATIVE_GVEC + return __builtin_elementwise_min(a, b); +#else +#ifdef RIVE_SIMD_PERF_WARNINGS +#pragma message( \ + "performance: __builtin_elementwise_min() not supported. Consider updating clang.") +#endif + // Generate the same behavior for NaN as the SIMD builtins. (isnan() is a + // no-op for int types.) + return if_then_else(b < a || isnan(a), b, a); +#endif +} + +// Similar to std::max(), with a noteworthy difference: +// If a[i] or b[i] is NaN and the other is not, returns whichever is _not_ NaN. +template +SIMD_ALWAYS_INLINE gvec max(gvec a, gvec b) +{ +#if __has_builtin(__builtin_elementwise_max) && SIMD_NATIVE_GVEC + return __builtin_elementwise_max(a, b); +#else +#ifdef RIVE_SIMD_PERF_WARNINGS +#pragma message( \ + "performance: __builtin_elementwise_max() not supported. Consider updating clang.") +#endif + // Generate the same behavior for NaN as the SIMD builtins. (isnan() is a + // no-op for int types.) + return if_then_else(a < b || isnan(a), b, a); +#endif +} + +// Unlike std::clamp(), simd::clamp() always returns a value between lo and hi. +// +// Returns lo if x == NaN, but std::clamp() returns NaN. +// Returns hi if hi <= lo. +// Ignores hi and/or lo if they are NaN. +// +template +SIMD_ALWAYS_INLINE gvec clamp(gvec x, gvec lo, gvec hi) +{ + return min(max(lo, x), hi); +} + +// Returns the absolute value of x per element, with one exception: +// If x[i] is an integer type and equal to the minimum representable value, +// returns x[i]. +template SIMD_ALWAYS_INLINE gvec abs(gvec x) +{ +#if __has_builtin(__builtin_elementwise_abs) && SIMD_NATIVE_GVEC + return __builtin_elementwise_abs(x); +#else +#ifdef RIVE_SIMD_PERF_WARNINGS +#pragma message( \ + "performance: __builtin_elementwise_abs() not supported. Consider updating clang.") +#endif + return if_then_else(x < (T)0, + -x, + x); // Negate on the "true" side so we never negate NaN. +#endif +} + +template +SIMD_ALWAYS_INLINE typename std::enable_if::value, T>::type +reduce_add(gvec x) +{ +#if __has_builtin(__builtin_reduce_add) && SIMD_NATIVE_GVEC + return __builtin_reduce_add(x); +#else +#ifdef RIVE_SIMD_PERF_WARNINGS +#pragma message( \ + "performance: __builtin_reduce_and() not supported. Consider updating clang.") +#endif + T s = x[0]; + for (int i = 1; i < N; ++i) + s += x[i]; + return s; +#endif +} + +template +SIMD_ALWAYS_INLINE typename std::enable_if::value, T>::type +reduce_add(gvec x) +{ +#ifdef RIVE_SIMD_PERF_WARNINGS +#pragma message( \ + "performance: __builtin_reduce_and() not supported. Consider updating clang.") +#endif + T s = x[0]; + for (int i = 1; i < N; ++i) + s += x[i]; + return s; +} + +template SIMD_ALWAYS_INLINE T reduce_min(gvec x) +{ +#if __has_builtin(__builtin_reduce_and) && SIMD_NATIVE_GVEC + return __builtin_reduce_min(x); +#else +#ifdef RIVE_SIMD_PERF_WARNINGS +#pragma message( \ + "performance: __builtin_reduce_and() not supported. Consider updating clang.") +#endif + T reduced = x[0]; + for (int i = 1; i < N; ++i) + reduced = std::min(reduced, x[i]); + return reduced; +#endif +} + +template SIMD_ALWAYS_INLINE T reduce_max(gvec x) +{ +#if __has_builtin(__builtin_reduce_and) && SIMD_NATIVE_GVEC + return __builtin_reduce_max(x); +#else +#ifdef RIVE_SIMD_PERF_WARNINGS +#pragma message( \ + "performance: __builtin_reduce_and() not supported. Consider updating clang.") +#endif + T reduced = x[0]; + for (int i = 1; i < N; ++i) + reduced = std::max(reduced, x[i]); + return reduced; +#endif +} + +template SIMD_ALWAYS_INLINE T reduce_and(gvec x) +{ +#if __has_builtin(__builtin_reduce_and) && SIMD_NATIVE_GVEC + return __builtin_reduce_and(x); +#else +#ifdef RIVE_SIMD_PERF_WARNINGS +#pragma message( \ + "performance: __builtin_reduce_and() not supported. Consider updating clang.") +#endif + T reduced = x[0]; + for (int i = 1; i < N; ++i) + reduced &= x[i]; + return reduced; +#endif +} + +template SIMD_ALWAYS_INLINE T reduce_or(gvec x) +{ +#if __has_builtin(__builtin_reduce_and) && SIMD_NATIVE_GVEC + return __builtin_reduce_or(x); +#else +#ifdef RIVE_SIMD_PERF_WARNINGS +#pragma message( \ + "performance: __builtin_reduce_and() not supported. Consider updating clang.") +#endif + T reduced = x[0]; + for (int i = 1; i < N; ++i) + reduced |= x[i]; + return reduced; +#endif +} + +////// Floating Point Functions ////// + +template SIMD_ALWAYS_INLINE gvec floor(gvec x) +{ +#if __has_builtin(__builtin_elementwise_floor) && SIMD_NATIVE_GVEC + return __builtin_elementwise_floor(x); +#else +#ifdef RIVE_SIMD_PERF_WARNINGS +#pragma message( \ + "performance: __builtin_elementwise_floor() not supported. Consider updating clang.") +#endif + for (int i = 0; i < N; ++i) + x[i] = floorf(x[i]); + return x; +#endif +} + +template SIMD_ALWAYS_INLINE gvec ceil(gvec x) +{ +#if __has_builtin(__builtin_elementwise_ceil) && SIMD_NATIVE_GVEC + return __builtin_elementwise_ceil(x); +#else +#ifdef RIVE_SIMD_PERF_WARNINGS +#pragma message( \ + "performance: __builtin_elementwise_ceil() not supported. Consider updating clang.") +#endif + for (int i = 0; i < N; ++i) + x[i] = ceilf(x[i]); + return x; +#endif +} + +template +SIMD_ALWAYS_INLINE gvec copysign(gvec x, gvec y) +{ + constexpr static uint32_t SIGN_BIT = 0x80000000u; + // Type punning is free in vector registers. + gvec bitsX, bitsY; + SIMD_INLINE_MEMCPY(&bitsX, &x, sizeof(x)); + SIMD_INLINE_MEMCPY(&bitsY, &y, sizeof(y)); + gvec bitsRet = (bitsY & SIGN_BIT) | (bitsX & ~SIGN_BIT); + gvec ret; + SIMD_INLINE_MEMCPY(&ret, &bitsRet, sizeof(ret)); + return ret; +} + +// IEEE compliant sqrt. +template SIMD_ALWAYS_INLINE gvec sqrt(gvec x) +{ + // There isn't an elementwise builtin for sqrt. We define + // architecture-specific specializations of this function later. + for (int i = 0; i < N; ++i) + x[i] = sqrtf(x[i]); + return x; +} + +#ifdef __SSE__ +template <> SIMD_ALWAYS_INLINE gvec sqrt(gvec x) +{ + __m128 _x; + SIMD_INLINE_MEMCPY(&_x, &x, sizeof(float) * 4); + _x = _mm_sqrt_ps(_x); + SIMD_INLINE_MEMCPY(&x, &_x, sizeof(float) * 4); + return x; +} + +template <> SIMD_ALWAYS_INLINE gvec sqrt(gvec x) +{ + __m128 _x; + SIMD_INLINE_MEMCPY(&_x, &x, sizeof(float) * 2); + _x = _mm_sqrt_ps(_x); + SIMD_INLINE_MEMCPY(&x, &_x, sizeof(float) * 2); + return x; +} +#endif + +#ifdef __aarch64__ +template <> SIMD_ALWAYS_INLINE gvec sqrt(gvec x) +{ + float32x4_t _x; + SIMD_INLINE_MEMCPY(&_x, &x, sizeof(float) * 4); + _x = vsqrtq_f32(_x); + SIMD_INLINE_MEMCPY(&x, &_x, sizeof(float) * 4); + return x; +} + +template <> SIMD_ALWAYS_INLINE gvec sqrt(gvec x) +{ + float32x2_t _x; + SIMD_INLINE_MEMCPY(&_x, &x, sizeof(float) * 2); + _x = vsqrt_f32(_x); + SIMD_INLINE_MEMCPY(&x, &_x, sizeof(float) * 2); + return x; +} +#endif + +// This will only be present when building with Emscripten and "-msimd128". +#if __has_builtin(__builtin_wasm_sqrt_f32x4) && SIMD_NATIVE_GVEC +template <> SIMD_ALWAYS_INLINE gvec sqrt(gvec x) +{ + return __builtin_wasm_sqrt_f32x4(x); +} + +template <> SIMD_ALWAYS_INLINE gvec sqrt(gvec x) +{ + gvec _x{x.x, x.y}; + _x = __builtin_wasm_sqrt_f32x4(_x); + return _x.xy; +} +#endif + +// Returns "(x + 127) / 255", for x in the range 0..255*255. +template +SIMD_ALWAYS_INLINE gvec div255(gvec x) +{ + assert(all(x <= 255u * 255u)); + x += 128; + return (x + (x >> 8)) >> 8; +} + +// Approximates acos(x) within 0.96 degrees, using the rational polynomial: +// +// acos(x) ~= (bx^3 + ax) / (dx^4 + cx^2 + 1) + pi/2 +// +// See: https://stackoverflow.com/a/36387954 +#define SIMD_FAST_ACOS_MAX_ERROR 0.0167552f // .96 degrees +template SIMD_ALWAYS_INLINE gvec fast_acos(gvec x) +{ + constexpr static float a = -0.939115566365855f; + constexpr static float b = 0.9217841528914573f; + constexpr static float c = -1.2845906244690837f; + constexpr static float d = 0.295624144969963174f; + constexpr static float pi_over_2 = 1.5707963267948966f; + auto xx = x * x; + auto numer = b * xx + a; + auto denom = xx * (d * xx + c) + 1.f; + return x * (numer / denom) + pi_over_2; +} + +////// Type conversion ////// + +template +SIMD_ALWAYS_INLINE gvec cast(gvec x) +{ +#if __has_builtin(__builtin_convertvector) && SIMD_NATIVE_GVEC + return __builtin_convertvector(x, gvec); +#else + gvec y{}; + for (int i = 0; i < N; ++i) + y[i] = static_cast(x[i]); + return y; +#endif +} + +////// Loading and storing ////// + +template SIMD_ALWAYS_INLINE gvec load(const void* ptr) +{ + gvec ret; + SIMD_INLINE_MEMCPY(&ret, ptr, sizeof(T) * N); + return ret; +} +SIMD_ALWAYS_INLINE gvec load2f(const void* ptr) +{ + return load(ptr); +} +SIMD_ALWAYS_INLINE gvec load4f(const void* ptr) +{ + return load(ptr); +} +SIMD_ALWAYS_INLINE gvec load2i(const void* ptr) +{ + return load(ptr); +} +SIMD_ALWAYS_INLINE gvec load4i(const void* ptr) +{ + return load(ptr); +} +SIMD_ALWAYS_INLINE gvec load2ui(const void* ptr) +{ + return load(ptr); +} +SIMD_ALWAYS_INLINE gvec load4ui(const void* ptr) +{ + return load(ptr); +} + +template +SIMD_ALWAYS_INLINE void store(void* dst, gvec vec) +{ + SIMD_INLINE_MEMCPY(dst, &vec, sizeof(T) * N); +} + +////// Column-major (transposed) loads ////// + +#if defined(__ARM_NEON__) || defined(__aarch64__) +SIMD_ALWAYS_INLINE std:: + tuple, gvec, gvec, gvec> + load4x4f(const float* matrix) +{ + float32x4x4_t m = vld4q_f32(matrix); + gvec c0, c1, c2, c3; + SIMD_INLINE_MEMCPY(&c0, &m.val[0], sizeof(c0)); + SIMD_INLINE_MEMCPY(&c1, &m.val[1], sizeof(c1)); + SIMD_INLINE_MEMCPY(&c2, &m.val[2], sizeof(c2)); + SIMD_INLINE_MEMCPY(&c3, &m.val[3], sizeof(c3)); + return {c0, c1, c2, c3}; +} +#elif defined(__SSE__) +SIMD_ALWAYS_INLINE std:: + tuple, gvec, gvec, gvec> + load4x4f(const float* m) +{ + __m128 r0, r1, r2, r3; + SIMD_INLINE_MEMCPY(&r0, m + 4 * 0, sizeof(r0)); + SIMD_INLINE_MEMCPY(&r1, m + 4 * 1, sizeof(r1)); + SIMD_INLINE_MEMCPY(&r2, m + 4 * 2, sizeof(r2)); + SIMD_INLINE_MEMCPY(&r3, m + 4 * 3, sizeof(r3)); + _MM_TRANSPOSE4_PS(r0, r1, r2, r3); + gvec c0, c1, c2, c3; + SIMD_INLINE_MEMCPY(&c0, &r0, sizeof(c0)); + SIMD_INLINE_MEMCPY(&c1, &r1, sizeof(c1)); + SIMD_INLINE_MEMCPY(&c2, &r2, sizeof(c2)); + SIMD_INLINE_MEMCPY(&c3, &r3, sizeof(c3)); + return {c0, c1, c2, c3}; +} +#else +SIMD_ALWAYS_INLINE std:: + tuple, gvec, gvec, gvec> + load4x4f(const float* m) +{ + gvec c0 = {m[0], m[4], m[8], m[12]}; + gvec c1 = {m[1], m[5], m[9], m[13]}; + gvec c2 = {m[2], m[6], m[10], m[14]}; + gvec c3 = {m[3], m[7], m[11], m[15]}; + return {c0, c1, c2, c3}; +} +#endif + +template +SIMD_ALWAYS_INLINE gvec join(gvec a, gvec b) +{ + T data[M + N]; + SIMD_INLINE_MEMCPY(data, &a, sizeof(T) * M); + SIMD_INLINE_MEMCPY(data + M, &b, sizeof(T) * N); + return load(data); +} + +template +SIMD_ALWAYS_INLINE gvec join(gvec a, + gvec b, + gvec c) +{ + T data[M + N + O]; + SIMD_INLINE_MEMCPY(data, &a, sizeof(T) * M); + SIMD_INLINE_MEMCPY(data + M, &b, sizeof(T) * N); + SIMD_INLINE_MEMCPY(data + M + N, &c, sizeof(T) * O); + return load(data); +} + +template +SIMD_ALWAYS_INLINE gvec join(gvec a, + gvec b, + gvec c, + gvec d) +{ + T data[M + N + O + P]; + SIMD_INLINE_MEMCPY(data, &a, sizeof(T) * M); + SIMD_INLINE_MEMCPY(data + M, &b, sizeof(T) * N); + SIMD_INLINE_MEMCPY(data + M + N, &c, sizeof(T) * O); + SIMD_INLINE_MEMCPY(data + M + N + O, &d, sizeof(T) * P); + return load(data); +} + +template +SIMD_ALWAYS_INLINE gvec zip(gvec a, gvec b) +{ +#if __has_builtin(__builtin_shufflevector) && SIMD_NATIVE_GVEC + return __builtin_shufflevector(a, b, 0, 2, 1, 3); +#else + return gvec{a.x, b.x, a.y, b.y}; +#endif +} + +template +SIMD_ALWAYS_INLINE gvec zip(gvec a, gvec b) +{ +#if __has_builtin(__builtin_shufflevector) && SIMD_NATIVE_GVEC + return __builtin_shufflevector(a, b, 0, 4, 1, 5, 2, 6, 3, 7); +#else + return gvec{a.x, b.x, a.y, b.y, a.z, b.z, a.w, b.w}; +#endif +} + +template +SIMD_ALWAYS_INLINE gvec zip(gvec a, gvec b) +{ +#if __has_builtin(__builtin_shufflevector) && SIMD_NATIVE_GVEC + return __builtin_shufflevector(a, + b, + 0, + 8, + 1, + 9, + 2, + 10, + 3, + 11, + 4, + 12, + 5, + 13, + 6, + 14, + 7, + 15); +#else + return gvec{a[0], + b[0], + a[1], + b[1], + a[2], + b[2], + a[3], + b[3], + a[4], + b[4], + a[5], + b[5], + a[6], + b[6], + a[7], + b[7]}; +#endif +} + +template +SIMD_ALWAYS_INLINE + typename std::enable_if>::type + zip(gvec a, gvec b) +{ + gvec ret{}; + for (int i = 0; i < N; ++i) + { + ret[i * 2] = a[i]; + ret[i * 2 + 1] = b[i]; + } + return ret; +} + +////// Basic linear algebra ////// + +template +SIMD_ALWAYS_INLINE T dot(gvec a, gvec b) +{ + return reduce_add(a * b); +} + +SIMD_ALWAYS_INLINE float cross(gvec a, gvec b) +{ + auto c = a * b.yx; + return c.x - c.y; +} + +// Linearly interpolates between a and b. +// +// NOTE: mix(a, b, 1) !== b (!!) +// +// The floating point numerics are not precise in the case where t === 1. But +// overall, this structure seems to get better precision for things like +// chopping cubics on exact cusp points than "a*(1 - t) + b*t" (which would +// return exactly b when t == 1). +template +SIMD_ALWAYS_INLINE gvec mix(gvec a, + gvec b, + gvec t) +{ + assert(simd::all(0.f <= t && t < 1.f)); + return (b - a) * t + a; +} +// Called when it doesn't matter if mix(a, b, 1) is only ~= b (it may not be +// precisely b). +template +SIMD_ALWAYS_INLINE gvec unchecked_mix(gvec a, + gvec b, + gvec t) +{ + return (b - a) * t + a; +} +// Returns precisely 'a' if t==0 and precisely 'b' if t==1. +template +SIMD_ALWAYS_INLINE gvec precise_mix(gvec a, + gvec b, + gvec t) +{ + return a * (1.f - t) + b * t; +} +} // namespace simd +} // namespace rive + +namespace rive +{ +template using vec = simd::gvec; +using float2 = vec<2>; +using float4 = vec<4>; + +template using ivec = simd::gvec; +using int2 = ivec<2>; +using int4 = ivec<4>; + +template using uvec = simd::gvec; +using uint2 = uvec<2>; +using uint4 = uvec<4>; + +using int8x8 = simd::gvec; +using int8x16 = simd::gvec; +using int8x32 = simd::gvec; + +using uint8x8 = simd::gvec; +using uint8x16 = simd::gvec; +using uint8x32 = simd::gvec; + +using int16x4 = simd::gvec; +using int16x8 = simd::gvec; +using int16x16 = simd::gvec; + +using uint16x4 = simd::gvec; +using uint16x8 = simd::gvec; +using uint16x16 = simd::gvec; + +using int64x2 = simd::gvec; +using int64x4 = simd::gvec; + +using uint64x2 = simd::gvec; +using uint64x4 = simd::gvec; + +} // namespace rive + +#undef SIMD_INLINE_MEMCPY +#undef SIMD_ALWAYS_INLINE + +#endif diff --git a/third_party/rive/include/rive/math/simd_gvec_polyfill.hpp b/third_party/rive/include/rive/math/simd_gvec_polyfill.hpp new file mode 100644 index 0000000..83f90c1 --- /dev/null +++ b/third_party/rive/include/rive/math/simd_gvec_polyfill.hpp @@ -0,0 +1,412 @@ +/* + * Copyright 2022 Rive + */ + +// This header provides a fallback gvec<> implementation for when we don't have +// gcc/clang vector extensions. Swizzles are implemented as unions, which is +// questionably undefined due to the "active member" C++ restriction on unions, +// however, since the members all have the same underlying type, this is a gray +// area. See: +// +// https://stackoverflow.com/questions/11373203/accessing-inactive-union-member-and-undefined-behavior +// +// This works in Visual Studio, which is the main reason for having this header. + +#ifndef _RIVE_SIMD_GVEC_POLYFILL_HPP_ +#define _RIVE_SIMD_GVEC_POLYFILL_HPP_ + +#include +#include +#include +#include + +namespace rive +{ +namespace simd +{ +using Swizzle = uint32_t; +constexpr static Swizzle PackSwizzle2(uint32_t sourceVectorLength, + uint32_t i0, + uint32_t i1) +{ + return (i1 << 5) | (i0 << 3) | sourceVectorLength; +} +constexpr static Swizzle PackSwizzle4(uint32_t sourceVectorLength, + uint32_t i0, + uint32_t i1, + uint32_t i2, + uint32_t i3) +{ + return (i3 << 9) | (i2 << 7) | PackSwizzle2(sourceVectorLength, i0, i1); +} +constexpr static uint32_t UnpackSwizzleSourceVectorLength(Swizzle swizzle) +{ + return swizzle & 7; +} +constexpr static uint32_t UnpackSwizzleIdx(Swizzle swizzle, uint32_t i) +{ + return (swizzle >> (i * 2 + 3)) & 3; +} + +template struct gvec +{ + T operator[](size_t i) const { return data[UnpackSwizzleIdx(Z, i)]; } + T& operator[](size_t i) { return data[UnpackSwizzleIdx(Z, i)]; } + operator gvec() const + { + gvec ret; + for (int i = 0; i < N; ++i) + ret[i] = (*this)[i]; + return ret; + } + T data[UnpackSwizzleSourceVectorLength(Z)]; +}; + +template struct gvec_data +{ + T data[N]; +}; + +template struct gvec_data +{ + union + { + T data[1]; + T x; + }; +}; + +template struct gvec_data +{ + union + { + T data[2]; + struct + { + T x, y; + }; + gvec yx; + gvec xyxy; + gvec yxyx; + gvec xxyy; + gvec yyxx; + }; +}; + +template struct gvec_data +{ + union + { + T data[2]; + struct + { + T x, y, z; + }; + }; +}; + +template struct gvec_data +{ + union + { + T data[4]; + gvec xyz; + struct + { + gvec xy, zw; + }; + struct + { + T x; + union + { + gvec yzw; + gvec yz; + struct + { + T y, z, w; + }; + }; + }; + // **WARNING**!! Only add swizzles that include ALL components of the + // vector. Since these types are POD, it's not possible to overwrite + // their default operator=, and their default operator= is just a + // memcpy. So: "float.xz = float4.xz" would also assign y and w. + gvec yxwz; + gvec zwxy; + gvec zyxw; + gvec xwzy; + gvec xzyw; + }; +}; + +template struct gvec : public gvec_data +{ + gvec() = default; + gvec(T val) + { + for (int i = 0; i < N; ++i) + gvec_data::data[i] = val; + } + gvec(std::initializer_list vals) + { + memset(gvec_data::data, 0, sizeof(gvec_data::data)); + std::copy(vals.begin(), + vals.begin() + std::min(vals.size(), N), + gvec_data::data); + } + T operator[](size_t i) const { return gvec_data::data[i]; } + T& operator[](size_t i) { return gvec_data::data[i]; } +}; + +static_assert(sizeof(gvec) == 4, + "gvec<1> is expected to be tightly packed"); +static_assert(sizeof(gvec) == 8, + "gvec<2> is expected to be tightly packed"); +static_assert(sizeof(gvec) == 16, + "gvec<4> is expected to be tightly packed"); + +// Vector booleans are masks of integer type, where true is -1 and false is 0. +// Vector booleans masks are generated using the builtin boolean operators: ==, +// !=, <=, >=, <, > +template struct boolean_mask_type_by_size; +template <> struct boolean_mask_type_by_size<1> +{ + using type = int8_t; +}; +template <> struct boolean_mask_type_by_size<2> +{ + using type = int16_t; +}; +template <> struct boolean_mask_type_by_size<4> +{ + using type = int32_t; +}; +template <> struct boolean_mask_type_by_size<8> +{ + using type = int64_t; +}; +template struct boolean_mask_type +{ + using type = typename boolean_mask_type_by_size::type; +}; + +#define DECL_UNARY_OP(_OP_) \ + template \ + gvec operator _OP_(gvec x) \ + { \ + gvec ret; \ + for (int i = 0; i < N; ++i) \ + ret[i] = _OP_ x[i]; \ + return ret; \ + } + +DECL_UNARY_OP(+) +DECL_UNARY_OP(-) +DECL_UNARY_OP(~) + +#undef DECL_UNARY_OP + +#define DECL_ARITHMETIC_OP(_OP_) \ + template \ + typename std::enable_if::value, \ + gvec>::type& \ + operator _OP_##=(gvec& a, gvec b) \ + { \ + for (int i = 0; i < N; ++i) \ + a[i] _OP_## = b[i]; \ + return a; \ + } \ + template \ + typename std::enable_if::value, \ + gvec>::type& \ + operator _OP_##=(gvec& a, U b) \ + { \ + for (int i = 0; i < N; ++i) \ + a[i] _OP_## = b; \ + return a; \ + } \ + template \ + typename std::enable_if::value, \ + gvec>::type \ + operator _OP_(gvec a, gvec b) \ + { \ + gvec ret; \ + for (int i = 0; i < N; ++i) \ + ret[i] = a[i] _OP_ b[i]; \ + return ret; \ + } \ + template \ + typename std::enable_if::value, \ + gvec>::type \ + operator _OP_(gvec a, U b) \ + { \ + gvec ret; \ + for (int i = 0; i < N; ++i) \ + ret[i] = a[i] _OP_ b; \ + return ret; \ + } \ + template \ + typename std::enable_if::value, \ + gvec>::type \ + operator _OP_(T a, gvec b) \ + { \ + gvec ret; \ + for (int i = 0; i < N; ++i) \ + ret[i] = a _OP_ b[i]; \ + return ret; \ + } + +DECL_ARITHMETIC_OP(+); +DECL_ARITHMETIC_OP(-); +DECL_ARITHMETIC_OP(*); +DECL_ARITHMETIC_OP(/); +DECL_ARITHMETIC_OP(%); +DECL_ARITHMETIC_OP(|); +DECL_ARITHMETIC_OP(&); +DECL_ARITHMETIC_OP(^); +DECL_ARITHMETIC_OP(<<); +DECL_ARITHMETIC_OP(>>); + +#undef DECL_ARITHMETIC_OP + +#define DECL_BOOLEAN_OP(_OP_) \ + template \ + gvec::type, N> operator _OP_( \ + gvec a, \ + gvec b) \ + { \ + gvec::type, N> ret; \ + for (int i = 0; i < N; ++i) \ + ret[i] = a[i] _OP_ b[i] ? ~0 : 0; \ + return ret; \ + } \ + template \ + typename std::enable_if< \ + std::is_convertible::value, \ + gvec::type, N>>::type \ + operator _OP_(gvec a, U b) \ + { \ + gvec::type, N> ret; \ + for (int i = 0; i < N; ++i) \ + ret[i] = a[i] _OP_ b ? ~0 : 0; \ + return ret; \ + } \ + template \ + typename std::enable_if< \ + std::is_convertible::value, \ + gvec::type, N>>::type \ + operator _OP_(U a, gvec b) \ + { \ + gvec::type, N> ret; \ + for (int i = 0; i < N; ++i) \ + ret[i] = a _OP_ b[i] ? ~0 : 0; \ + return ret; \ + } + +DECL_BOOLEAN_OP(==) +DECL_BOOLEAN_OP(!=) +DECL_BOOLEAN_OP(<) +DECL_BOOLEAN_OP(<=) +DECL_BOOLEAN_OP(>) +DECL_BOOLEAN_OP(>=) +DECL_BOOLEAN_OP(&&) +DECL_BOOLEAN_OP(||) + +#undef DECL_BOOLEAN_OP + +#define ENABLE_SWIZZLE1(F) \ + template gvec F(gvec x) \ + { \ + return F((gvec)x); \ + } +#define ENABLE_SWIZZLE_REDUCE(F) \ + template T F(gvec x) \ + { \ + return F((gvec)x); \ + } +#define ENABLE_SWIZZLE1F(F) \ + template gvec F(gvec x) \ + { \ + return F((gvec)x); \ + } +#define ENABLE_SWIZZLE1B(F) \ + template bool F(gvec x) \ + { \ + return F((gvec)x); \ + } +#define ENABLE_SWIZZLEUT(F) \ + template gvec F(gvec x) \ + { \ + return F((gvec)x); \ + } +#define ENABLE_SWIZZLE2(F) \ + template \ + gvec F(gvec a, gvec b) \ + { \ + return F((gvec)a, (gvec)b); \ + } +#define ENABLE_SWIZZLE3(F) \ + template \ + gvec F(gvec a, gvec b, gvec c) \ + { \ + return F((gvec)a, (gvec)b, (gvec)c); \ + } +#define ENABLE_SWIZZLE3F(F) \ + template \ + gvec F(gvec a, \ + gvec b, \ + gvec c) \ + { \ + return F((gvec)a, (gvec)b, (gvec)c); \ + } +#define ENABLE_SWIZZLE3IT(F) \ + template \ + gvec F(gvec::type, N, Z0> a, \ + gvec b, \ + gvec c) \ + { \ + return F((gvec)a, (gvec)b, (gvec)c); \ + } + +ENABLE_SWIZZLE1(abs) +ENABLE_SWIZZLE_REDUCE(reduce_add) +ENABLE_SWIZZLE_REDUCE(reduce_min) +ENABLE_SWIZZLE_REDUCE(reduce_max) +ENABLE_SWIZZLE_REDUCE(reduce_and) +ENABLE_SWIZZLE_REDUCE(reduce_or) +ENABLE_SWIZZLE1F(floor) +ENABLE_SWIZZLE1F(ceil) +ENABLE_SWIZZLE1F(sqrt) +ENABLE_SWIZZLE1F(fast_acos) +ENABLE_SWIZZLE1B(any) +ENABLE_SWIZZLE1B(all) +ENABLE_SWIZZLE2(min) +ENABLE_SWIZZLE2(max) +ENABLE_SWIZZLE3(clamp) +ENABLE_SWIZZLE3F(mix) +ENABLE_SWIZZLE3F(precise_mix) +ENABLE_SWIZZLE3IT(if_then_else) +template void store(void* dst, gvec vec) +{ + store(dst, (gvec)vec); +} +template +gvec cast(gvec x) +{ + return cast((gvec)x); +} + +#undef ENABLE_SWIZZLE1 +#undef ENABLE_SWIZZLE_REDUCE +#undef ENABLE_SWIZZLE1F +#undef ENABLE_SWIZZLE1B +#undef ENABLE_SWIZZLEUT +#undef ENABLE_SWIZZLE2 +#undef ENABLE_SWIZZLE3 +#undef ENABLE_SWIZZLE3F +#undef ENABLE_SWIZZLE3IT +} // namespace simd +} // namespace rive + +#endif diff --git a/third_party/rive/include/rive/math/transform_components.hpp b/third_party/rive/include/rive/math/transform_components.hpp new file mode 100644 index 0000000..f33c768 --- /dev/null +++ b/third_party/rive/include/rive/math/transform_components.hpp @@ -0,0 +1,64 @@ +#ifndef _RIVE_TRANSFORMCOMPONENTS_HPP_ +#define _RIVE_TRANSFORMCOMPONENTS_HPP_ + +#include "rive/math/vec2d.hpp" + +namespace rive +{ +class TransformComponents +{ +private: + float m_X; + float m_Y; + float m_ScaleX; + float m_ScaleY; + float m_Rotation; + float m_Skew; + +public: + TransformComponents() : + m_X(0.0f), + m_Y(0.0f), + m_ScaleX(1.0f), + m_ScaleY(1.0f), + m_Rotation(0.0f), + m_Skew(0.0f) + {} + TransformComponents(const TransformComponents& copy) : + m_X(copy.m_X), + m_Y(copy.m_Y), + m_ScaleX(copy.m_ScaleX), + m_ScaleY(copy.m_ScaleY), + m_Rotation(copy.m_Rotation), + m_Skew(copy.m_Skew) + {} + + float x() const { return m_X; } + void x(float value) { m_X = value; } + float y() const { return m_Y; } + void y(float value) { m_Y = value; } + float scaleX() const { return m_ScaleX; } + void scaleX(float value) { m_ScaleX = value; } + float scaleY() const { return m_ScaleY; } + void scaleY(float value) { m_ScaleY = value; } + float rotation() const { return m_Rotation; } + void rotation(float value) { m_Rotation = value; } + float skew() const { return m_Skew; } + void skew(float value) { m_Skew = value; } + + Vec2D translation() const { return {m_X, m_Y}; } + Vec2D scale() const { return {m_ScaleX, m_ScaleY}; } + + TransformComponents& operator=(const TransformComponents& a) + { + m_X = a.m_X; + m_Y = a.m_Y; + m_ScaleX = a.m_ScaleX; + m_ScaleY = a.m_ScaleY; + m_Rotation = a.m_Rotation; + m_Skew = a.m_Skew; + return *this; + } +}; +} // namespace rive +#endif diff --git a/third_party/rive/include/rive/math/vec2d.hpp b/third_party/rive/include/rive/math/vec2d.hpp new file mode 100644 index 0000000..597d912 --- /dev/null +++ b/third_party/rive/include/rive/math/vec2d.hpp @@ -0,0 +1,139 @@ +#ifndef _RIVE_VEC2D_HPP_ +#define _RIVE_VEC2D_HPP_ + +#include "rive/rive_types.hpp" + +namespace rive +{ +class Mat2D; +class Vec2D +{ +public: + float x, y; + + Vec2D() = default; + constexpr Vec2D(float x, float y) : x(x), y(y) {} + + float lengthSquared() const { return x * x + y * y; } + float length() const; + Vec2D normalized() const; + + // Normalize this Vec, and return its previous length + float normalizeLength() + { + const float len = this->length(); + if (len > 0) + { + x /= len; + y /= len; + } + return len; + } + + Vec2D operator-() const { return {-x, -y}; } + + void operator*=(float s) + { + x *= s; + y *= s; + } + + void operator/=(float s) + { + x /= s; + y /= s; + } + + friend inline Vec2D operator-(const Vec2D& a, const Vec2D& b) + { + return {a.x - b.x, a.y - b.y}; + } + + static inline Vec2D lerp(Vec2D a, Vec2D b, float f); + + static Vec2D transformDir(const Vec2D& a, const Mat2D& m); + static Vec2D transformMat2D(const Vec2D& a, const Mat2D& m); + + static float dot(Vec2D a, Vec2D b) { return a.x * b.x + a.y * b.y; } + static float cross(Vec2D a, Vec2D b) { return a.x * b.y - a.y * b.x; } + static Vec2D scaleAndAdd(Vec2D a, Vec2D b, float scale) + { + return { + a.x + b.x * scale, + a.y + b.y * scale, + }; + } + static float distance(const Vec2D& a, const Vec2D& b) + { + return (a - b).length(); + } + static float distanceSquared(const Vec2D& a, const Vec2D& b) + { + return (a - b).lengthSquared(); + } + + Vec2D& operator+=(Vec2D v) + { + x += v.x; + y += v.y; + return *this; + } + Vec2D& operator-=(Vec2D v) + { + x -= v.x; + y -= v.y; + return *this; + } + + float operator[](size_t index) const + { + switch (index) + { + case 0: + return x; + case 1: + return y; + default: + RIVE_UNREACHABLE(); + } + } +}; +static_assert(std::is_pod::value, "Vec2D must be plain-old-data"); + +inline Vec2D operator*(const Vec2D& v, float s) { return {v.x * s, v.y * s}; } +inline Vec2D operator*(float s, const Vec2D& v) { return {v.x * s, v.y * s}; } +inline Vec2D operator/(const Vec2D& v, float s) { return {v.x / s, v.y / s}; } + +inline Vec2D operator+(const Vec2D& a, const Vec2D& b) +{ + return {a.x + b.x, a.y + b.y}; +} + +inline bool operator==(const Vec2D& a, const Vec2D& b) +{ + return a.x == b.x && a.y == b.y; +} +inline bool operator!=(const Vec2D& a, const Vec2D& b) +{ + return a.x != b.x || a.y != b.y; +} + +Vec2D Vec2D::lerp(Vec2D a, Vec2D b, float t) { return a + (b - a) * t; } + +} // namespace rive + +namespace std +{ +template <> struct hash +{ + size_t operator()(const rive::Vec2D& v) const + { + // Combine the hashes of x and y to produce a hash for Vec2D + size_t h1 = std::hash()(v.x); // Hash for x component + size_t h2 = std::hash()(v.y); // Hash for y component + return h1 ^ (h2 << 1); // Combine them with bitwise XOR and shift + } +}; +} // namespace std + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/math/wangs_formula.hpp b/third_party/rive/include/rive/math/wangs_formula.hpp new file mode 100644 index 0000000..e6334bd --- /dev/null +++ b/third_party/rive/include/rive/math/wangs_formula.hpp @@ -0,0 +1,306 @@ +/* + * Copyright 2020 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Initial import from skia:src/gpu/tessellate/WangsFormula.h + * + * Copyright 2023 Rive + */ + +#pragma once + +#include "rive/math/simd.hpp" +#include "rive/math/vec2d.hpp" +#include "rive/math/mat2d.hpp" +#include + +#define AI RIVE_MAYBE_UNUSED RIVE_ALWAYS_INLINE + +// Wang's formula gives the minimum number of evenly spaced (in the parametric +// sense) line segments that a bezier curve must be chopped into in order to +// guarantee all lines stay within a distance of "1/precision" pixels from the +// true curve. Its definition for a bezier curve of degree "n" is as follows: +// +// maxLength = max([length(p[i+2] - 2p[i+1] + p[i]) for (0 <= i <= n-2)]) +// numParametricSegments = sqrt(maxLength * precision * n*(n - 1)/8) +// +// (Goldman, Ron. (2003). 5.6.3 Wang's Formula. "Pyramid Algorithms: A Dynamic +// Programming Approach to Curves and Surfaces for Geometric Modeling". Morgan +// Kaufmann Publishers.) +namespace rive +{ +namespace wangs_formula +{ +// Returns the value by which to multiply length in Wang's formula. (See above.) +template constexpr float length_term(float precision) +{ + return (Degree * (Degree - 1) / 8.f) * precision; +} +template constexpr float length_term_pow2(float precision) +{ + return ((Degree * Degree) * ((Degree - 1) * (Degree - 1)) / 64.f) * + (precision * precision); +} + +AI static float root4(float x) { return sqrtf(sqrtf(x)); } + +// Returns the log2 of the provided value, were that value to be rounded up to +// the next power of 2. Returns 0 if value <= 0: Never returns a negative +// number, even if value is NaN. +// +// sk_float_nextlog2((-inf..1]) -> 0 +// sk_float_nextlog2((1..2]) -> 1 +// sk_float_nextlog2((2..4]) -> 2 +// sk_float_nextlog2((4..8]) -> 3 +// ... +AI static int sk_float_nextlog2(float x) +{ + uint32_t bits; + RIVE_INLINE_MEMCPY(&bits, &x, 4); + bits += (1u << 23) - 1u; // Increment the exponent for non-powers-of-2. + int exp = ((int32_t)bits >> 23) - 127; + return exp & ~(exp >> 31); // Return 0 for negative or denormalized floats, + // and exponents < 0. +} + +// Returns nextlog2(sqrt(x)): +// +// log2(sqrt(x)) == log2(x^(1/2)) == log2(x)/2 == log2(x)/log2(4) == log4(x) +// +AI static int nextlog4(float x) { return (sk_float_nextlog2(x) + 1) >> 1; } + +// Returns nextlog2(sqrt(sqrt(x))): +// +// log2(sqrt(sqrt(x))) == log2(x^(1/4)) == log2(x)/4 == log2(x)/log2(16) == +// log16(x) +// +AI static int nextlog16(float x) { return (sk_float_nextlog2(x) + 3) >> 2; } + +// Represents the upper-left 2x2 matrix of an affine transform for applying to +// vectors: +// +// VectorXform(p1 - p0) == M * float3(p1, 1) - M * float3(p0, 1) +// +class alignas(32) VectorXform +{ +public: + AI VectorXform() : m_scale(1), m_skew(0) {} + AI explicit VectorXform(const Mat2D& m) { *this = m; } + + AI VectorXform& operator=(const Mat2D& m) + { + m_scale = float2{m[0], m[3]}.xyxy; + m_skew = simd::load2f(&m[1]).yxyx; + return *this; + } + + AI float2 operator()(float2 vector) const + { + return m_scale.xy * vector + m_skew.xy * vector.yx; + } + AI float4 operator()(float4 vectors) const + { + return m_scale * vectors + m_skew * vectors.yxwz; + } + +private: + float4 m_scale; + float4 m_skew; +}; + +// Returns Wang's formula, raised to the 4th power, specialized for a quadratic +// curve. +AI static float quadratic_pow4(float2 p0, + float2 p1, + float2 p2, + float precision, + const VectorXform& vectorXform = VectorXform()) +{ + float2 v = -2.f * p1 + p0 + p2; + v = vectorXform(v); + float2 vv = v * v; + return (vv[0] + vv[1]) * length_term_pow2<2>(precision); +} +AI static float quadratic_pow4(const Vec2D pts[], + float precision, + const VectorXform& vectorXform = VectorXform()) +{ + return quadratic_pow4(simd::load2f(&pts[0].x), + simd::load2f(&pts[1].x), + simd::load2f(&pts[2].x), + precision, + vectorXform); +} + +// Returns Wang's formula specialized for a quadratic curve. +AI static float quadratic(const Vec2D pts[], + float precision, + const VectorXform& vectorXform = VectorXform()) +{ + return root4(quadratic_pow4(pts, precision, vectorXform)); +} + +// Returns the log2 value of Wang's formula specialized for a quadratic curve, +// rounded up to the next int. +AI static int quadratic_log2(const Vec2D pts[], + float precision, + const VectorXform& vectorXform = VectorXform()) +{ + // nextlog16(x) == ceil(log2(sqrt(sqrt(x)))) + return nextlog16(quadratic_pow4(pts, precision, vectorXform)); +} + +// Returns Wang's formula, raised to the 4th power, specialized for a cubic +// curve. +AI static float cubic_pow4(const Vec2D pts[], + float precision, + const VectorXform& vectorXform = VectorXform()) +{ + float4 p01 = simd::load4f(pts); + float4 p12 = simd::load4f(pts + 1); + float4 p23 = simd::load4f(pts + 2); + float4 v = -2.f * p12 + p01 + p23; + v = vectorXform(v); + float4 vv = v * v; + return std::max(vv[0] + vv[1], vv[2] + vv[3]) * + length_term_pow2<3>(precision); +} + +// Returns Wang's formula specialized for a cubic curve. +AI static float cubic(const Vec2D pts[], + float precision, + const VectorXform& vectorXform = VectorXform()) +{ + return root4(cubic_pow4(pts, precision, vectorXform)); +} + +// Returns the log2 value of Wang's formula specialized for a cubic curve, +// rounded up to the next int. +AI static int cubic_log2(const Vec2D pts[], + float precision, + const VectorXform& vectorXform = VectorXform()) +{ + // nextlog16(x) == ceil(log2(sqrt(sqrt(x)))) + return nextlog16(cubic_pow4(pts, precision, vectorXform)); +} + +// Returns the maximum number of line segments a cubic with the given +// device-space bounding box size would ever need to be divided into, raised to +// the 4th power. This is simply a special case of the cubic formula where we +// maximize its value by placing control points on specific corners of the +// bounding box. +AI static float worst_case_cubic_pow4(float devWidth, + float devHeight, + float precision) +{ + float kk = length_term_pow2<3>(precision); + return 4 * kk * (devWidth * devWidth + devHeight * devHeight); +} + +// Returns the maximum number of line segments a cubic with the given +// device-space bounding box size would ever need to be divided into. +AI static float worst_case_cubic(float devWidth, + float devHeight, + float precision) +{ + return root4(worst_case_cubic_pow4(devWidth, devHeight, precision)); +} + +// Returns the maximum log2 number of line segments a cubic with the given +// device-space bounding box size would ever need to be divided into. +AI static int worst_case_cubic_log2(float devWidth, + float devHeight, + float precision) +{ + // nextlog16(x) == ceil(log2(sqrt(sqrt(x)))) + return nextlog16(worst_case_cubic_pow4(devWidth, devHeight, precision)); +} + +// Returns Wang's formula specialized for a conic curve, raised to the second +// power. Input points should be in projected space. +// +// This is not actually due to Wang, but is an analogue from (Theorem 3, +// corollary 1): +// J. Zheng, T. Sederberg. "Estimating Tessellation Parameter Intervals for +// Rational Curves and Surfaces." ACM Transactions on Graphics 19(1). 2000. +AI static float conic_pow2(float precision, + float2 p0, + float2 p1, + float2 p2, + float w, + const VectorXform& vectorXform = VectorXform()) +{ + p0 = vectorXform(p0); + p1 = vectorXform(p1); + p2 = vectorXform(p2); + + // Compute center of bounding box in projected space + const float2 C = 0.5f * (simd::min(simd::min(p0, p1), p2) + + simd::max(simd::max(p0, p1), p2)); + + // Translate by -C. This improves translation-invariance of the formula, + // see Sec. 3.3 of cited paper + p0 -= C; + p1 -= C; + p2 -= C; + + // Compute max length + const float max_len = + sqrtf(std::max(simd::dot(p0, p0), + std::max(simd::dot(p1, p1), simd::dot(p2, p2)))); + + // Compute forward differences + const float2 dp = -2.f * w * p1 + p0 + p2; + const float dw = fabsf(-2.f * w + 2); + + // Compute numerator and denominator for parametric step size of + // linearization. Here, the epsilon referenced from the cited paper is + // 1/precision. + const float rp_minus_1 = std::max(0.f, max_len * precision - 1); + const float numer = sqrtf(simd::dot(dp, dp)) * precision + rp_minus_1 * dw; + const float denom = 4 * std::min(w, 1.f); + + // Number of segments = sqrt(numer / denom). + // This assumes parametric interval of curve being linearized is [t0,t1] = + // [0, 1]. If not, the number of segments is (tmax - tmin) / sqrt(denom / + // numer). + return numer / denom; +} +AI static float conic_pow2(float precision, + const Vec2D pts[], + float w, + const VectorXform& vectorXform = VectorXform()) +{ + return conic_pow2(precision, + simd::load2f(&pts[0].x), + simd::load2f(&pts[1].x), + simd::load2f(&pts[2].x), + w, + vectorXform); +} + +// Returns the value of Wang's formula specialized for a conic curve. +AI static float conic(float tolerance, + const Vec2D pts[], + float w, + const VectorXform& vectorXform = VectorXform()) +{ + return sqrtf(conic_pow2(tolerance, pts, w, vectorXform)); +} + +// Returns the log2 value of Wang's formula specialized for a conic curve, +// rounded up to the next int. +AI static int conic_log2(float tolerance, + const Vec2D pts[], + float w, + const VectorXform& vectorXform = VectorXform()) +{ + // nextlog4(x) == ceil(log2(sqrt(x))) + return nextlog4(conic_pow2(tolerance, pts, w, vectorXform)); +} +} // namespace wangs_formula +} // namespace rive + +#undef AI diff --git a/third_party/rive/include/rive/nested_animation.hpp b/third_party/rive/include/rive/nested_animation.hpp new file mode 100644 index 0000000..95f2200 --- /dev/null +++ b/third_party/rive/include/rive/nested_animation.hpp @@ -0,0 +1,76 @@ +#ifndef _RIVE_NESTED_ANIMATION_HPP_ +#define _RIVE_NESTED_ANIMATION_HPP_ +#include "rive/event.hpp" +#include "rive/event_report.hpp" +#include "rive/generated/nested_animation_base.hpp" +#include "rive/nested_artboard.hpp" +#include +namespace rive +{ +class ArtboardInstance; + +class NestedEventListener +{ +public: + virtual ~NestedEventListener() {} + virtual void notify(const std::vector& events, + NestedArtboard* context) = 0; +}; + +class NestedEventNotifier +{ +public: + ~NestedEventNotifier() + { + m_nestedArtboard = nullptr; + m_nestedEventListeners.clear(); + } + void addNestedEventListener(NestedEventListener* listener) + { + m_nestedEventListeners.push_back(listener); + } + std::vector nestedEventListeners() + { + return m_nestedEventListeners; + } + + void setNestedArtboard(NestedArtboard* artboard) + { + m_nestedArtboard = artboard; + } + NestedArtboard* nestedArtboard() { return m_nestedArtboard; } + + void notifyListeners(const std::vector& events) + { + std::vector eventReports; + for (auto event : events) + { + eventReports.push_back(EventReport(event, 0)); + } + for (auto listener : m_nestedEventListeners) + { + listener->notify(eventReports, m_nestedArtboard); + } + } + +private: + NestedArtboard* m_nestedArtboard = nullptr; + std::vector m_nestedEventListeners; +}; + +class NestedAnimation : public NestedAnimationBase +{ +public: + bool validate(CoreContext* context) override; + StatusCode onAddedDirty(CoreContext* context) override; + + // Advance animations and apply them to the artboard. + virtual bool advance(float elapsedSeconds, bool newFrame) = 0; + + // Initialize the animation (make instances as necessary) from the + // source artboard. + virtual void initializeAnimation(ArtboardInstance*) = 0; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/nested_artboard.hpp b/third_party/rive/include/rive/nested_artboard.hpp new file mode 100644 index 0000000..6dedf63 --- /dev/null +++ b/third_party/rive/include/rive/nested_artboard.hpp @@ -0,0 +1,94 @@ +#ifndef _RIVE_NESTED_ARTBOARD_HPP_ +#define _RIVE_NESTED_ARTBOARD_HPP_ + +#include "rive/generated/nested_artboard_base.hpp" +#include "rive/artboard_host.hpp" +#include "rive/data_bind/data_context.hpp" +#include "rive/viewmodel/viewmodel_instance_value.hpp" +#include "rive/hit_info.hpp" +#include "rive/span.hpp" +#include "rive/advancing_component.hpp" +#include + +namespace rive +{ + +class ArtboardInstance; +class NestedAnimation; +class NestedInput; +class NestedStateMachine; +class StateMachineInstance; +class NestedArtboard : public NestedArtboardBase, + public AdvancingComponent, + public ArtboardHost +{ +protected: + Artboard* m_Artboard = nullptr; // might point to m_Instance, and might not + std::unique_ptr m_Instance; // may be null + std::vector m_NestedAnimations; + +protected: + std::vector m_DataBindPathIdsBuffer; + +public: + NestedArtboard(); + ~NestedArtboard() override; + StatusCode onAddedClean(CoreContext* context) override; + void draw(Renderer* renderer) override; + Core* hitTest(HitInfo*, const Mat2D&) override; + void addNestedAnimation(NestedAnimation* nestedAnimation); + + void nest(Artboard* artboard); + size_t artboardCount() override { return 1; } + ArtboardInstance* artboardInstance(int index = 0) override + { + return m_Instance.get(); + } + Artboard* sourceArtboard() { return m_Artboard; } + + StatusCode import(ImportStack& importStack) override; + Core* clone() const override; + void update(ComponentDirt value) override; + + bool hasNestedStateMachines() const; + Span nestedAnimations(); + NestedArtboard* nestedArtboard(std::string name) const; + NestedStateMachine* stateMachine(std::string name) const; + NestedInput* input(std::string name) const; + NestedInput* input(std::string name, std::string stateMachineName) const; + + Vec2D measureLayout(float width, + LayoutMeasureMode widthMode, + float height, + LayoutMeasureMode heightMode) override; + void controlSize(Vec2D size, + LayoutScaleType widthScaleType, + LayoutScaleType heightScaleType, + LayoutDirection direction) override; + + /// Convert a world space (relative to the artboard that this + /// NestedArtboard is a child of) to the local space of the Artboard + /// nested within. Returns true when the conversion succeeds, and false + /// when one is not possible. + bool worldToLocal(Vec2D world, Vec2D* local); + void decodeDataBindPathIds(Span value) override; + void copyDataBindPathIds(const NestedArtboardBase& object) override; + std::vector dataBindPathIds() override + { + return m_DataBindPathIdsBuffer; + }; + void populateDataBinds(std::vector* dataBinds) override; + void bindViewModelInstance(rcp viewModelInstance, + DataContext* parent) override; + void internalDataContext(DataContext* dataContext) override; + void clearDataContext() override; + + bool advanceComponent(float elapsedSeconds, + AdvanceFlags flags = AdvanceFlags::Animate | + AdvanceFlags::NewFrame) override; + Artboard* parentArtboard() override { return artboard(); } + void markHostTransformDirty() override { markTransformDirty(); } +}; +} // namespace rive + +#endif diff --git a/third_party/rive/include/rive/nested_artboard_layout.hpp b/third_party/rive/include/rive/nested_artboard_layout.hpp new file mode 100644 index 0000000..291cd2f --- /dev/null +++ b/third_party/rive/include/rive/nested_artboard_layout.hpp @@ -0,0 +1,52 @@ +#ifndef _RIVE_NESTED_ARTBOARD_LAYOUT_HPP_ +#define _RIVE_NESTED_ARTBOARD_LAYOUT_HPP_ +#include "rive/generated/nested_artboard_layout_base.hpp" +#include "rive/constraints/layout_constraint.hpp" +#include "rive/layout/layout_node_provider.hpp" + +namespace rive +{ +class ArtboardInstance; +class NestedArtboardLayout : public NestedArtboardLayoutBase, + public LayoutNodeProvider +{ +public: +#ifdef WITH_RIVE_LAYOUT + void* layoutNode(int index) override; +#endif + Core* clone() const override; + void markHostingLayoutDirty(ArtboardInstance* artboardInstance) override; + void markLayoutNodeDirty( + bool shouldForceUpdateLayoutBounds = false) override; + void update(ComponentDirt value) override; + void updateConstraints() override; + StatusCode onAddedClean(CoreContext* context) override; + + float actualInstanceWidth(); + float actualInstanceHeight(); + bool syncStyleChanges() override; + void updateLayoutBounds(bool animate = true) override; + AABB layoutBounds() override; + size_t numLayoutNodes() override { return 1; } + bool isLayoutProvider() override { return true; } + + TransformComponent* transformComponent() override + { + return this->as(); + } + +protected: + void instanceWidthChanged() override; + void instanceHeightChanged() override; + void instanceWidthUnitsValueChanged() override; + void instanceHeightUnitsValueChanged() override; + void instanceWidthScaleTypeChanged() override; + void instanceHeightScaleTypeChanged() override; + +private: + void updateWidthOverride(); + void updateHeightOverride(); +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/nested_artboard_leaf.hpp b/third_party/rive/include/rive/nested_artboard_leaf.hpp new file mode 100644 index 0000000..a7fa3d5 --- /dev/null +++ b/third_party/rive/include/rive/nested_artboard_leaf.hpp @@ -0,0 +1,15 @@ +#ifndef _RIVE_NESTED_ARTBOARD_LEAF_HPP_ +#define _RIVE_NESTED_ARTBOARD_LEAF_HPP_ +#include "rive/generated/nested_artboard_leaf_base.hpp" +#include +namespace rive +{ +class NestedArtboardLeaf : public NestedArtboardLeafBase +{ +public: + Core* clone() const override; + void update(ComponentDirt value) override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/node.hpp b/third_party/rive/include/rive/node.hpp new file mode 100644 index 0000000..79432e4 --- /dev/null +++ b/third_party/rive/include/rive/node.hpp @@ -0,0 +1,55 @@ +#ifndef _RIVE_NODE_HPP_ +#define _RIVE_NODE_HPP_ +#include "rive/generated/node_base.hpp" + +namespace rive +{ +/// A Rive Node +class Node : public NodeBase +{ +private: + Mat2D m_LocalTransform = Mat2D(); + bool m_LocalTransformNeedsRecompute = false; + + void computeLocalTransform(); + +public: + void setComputedLocalX(float value) override {} + void setComputedLocalY(float value) override {} + void setComputedWorldX(float value) override {} + void setComputedWorldY(float value) override {} + void setComputedWidth(float value) override {} + void setComputedHeight(float value) override {} + + float computedLocalX() override { return localTransform()[4]; }; + float computedLocalY() override { return localTransform()[5]; }; + float computedWorldX() override { return worldTransform()[4]; }; + float computedWorldY() override { return worldTransform()[5]; }; + float computedWidth() override { return 0; }; + float computedHeight() override { return 0; }; + + void updateWorldTransform() override + { + m_LocalTransformNeedsRecompute = true; + Super::updateWorldTransform(); + } + + Mat2D localTransform(); + +protected: + void xChanged() override; + void yChanged() override; + void computedLocalXChanged() override {} + void computedLocalYChanged() override {} + void computedWorldXChanged() override {} + void computedWorldYChanged() override {} + void computedWidthChanged() override {} + void computedHeightChanged() override {} + +#ifdef WITH_RIVE_LAYOUT + void markLayoutNodeDirty(); +#endif +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/object_stream.hpp b/third_party/rive/include/rive/object_stream.hpp new file mode 100644 index 0000000..6447bb9 --- /dev/null +++ b/third_party/rive/include/rive/object_stream.hpp @@ -0,0 +1,84 @@ +/* + * Copyright 2025 Rive + */ + +#pragma once + +#include "rive/refcnt.hpp" + +#include +#include + +namespace rive +{ +// Stream for recording objects of a specific type, using C++-style "<<" ">>" +// operators. +template class ObjectStream +{ +public: + bool empty() const { return m_stream.empty(); } + + ObjectStream& operator<<(T obj) + { + m_stream.push_back(std::move(obj)); + return *this; + } + + ObjectStream& operator>>(T& dst) + { + assert(!empty()); + dst = std::move(m_stream.front()); + m_stream.pop_front(); + return *this; + } + +private: + std::deque m_stream; +}; + +// Stream for recording objects of any trivially-copyable type, using C++-style +// "<<" ">>" operators. Object types must be read back in the same order they +// were writen. +class PODStream +{ +public: + bool empty() const { return m_byteStream.empty(); } + + template PODStream& operator<<(T obj) + { + static_assert(std::is_pod(), + "PODStream only accepts plain-old-data types"); + const char* data = reinterpret_cast(&obj); + m_byteStream.insert(m_byteStream.end(), data, data + sizeof(T)); + return *this; + } + + template PODStream& operator>>(T& dst) + { + static_assert(std::is_pod(), + "PODStream only accepts plain-old-data types"); + assert(m_byteStream.size() >= sizeof(T)); + char* data = reinterpret_cast(&dst); + std::copy(m_byteStream.begin(), m_byteStream.begin() + sizeof(T), data); + m_byteStream.erase(m_byteStream.begin(), + m_byteStream.begin() + sizeof(T)); + return *this; + } + + template PODStream& operator<<(rcp obj) + { + return *this << obj.release(); + } + + template PODStream& operator>>(rcp& obj) + { + T* raw; + *this >> raw; + obj = rcp(raw); + return *this; + } + +private: + std::deque m_byteStream; +}; +}; // namespace rive diff --git a/third_party/rive/include/rive/open_url_event.hpp b/third_party/rive/include/rive/open_url_event.hpp new file mode 100644 index 0000000..fb8bc0e --- /dev/null +++ b/third_party/rive/include/rive/open_url_event.hpp @@ -0,0 +1,13 @@ +#ifndef _RIVE_OPEN_URL_EVENT_HPP_ +#define _RIVE_OPEN_URL_EVENT_HPP_ +#include "rive/generated/open_url_event_base.hpp" +#include +namespace rive +{ +class OpenUrlEvent : public OpenUrlEventBase +{ +public: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/pointer_event.hpp b/third_party/rive/include/rive/pointer_event.hpp new file mode 100644 index 0000000..da1bb55 --- /dev/null +++ b/third_party/rive/include/rive/pointer_event.hpp @@ -0,0 +1,27 @@ +#ifndef _RIVE_POINTER_EVENT_HPP_ +#define _RIVE_POINTER_EVENT_HPP_ + +#include "rive/math/vec2d.hpp" + +namespace rive +{ + +enum class PointerEventType +{ + down, // The button has gone from up to down + move, // The pointer's position has changed + up, // The button has gone from down to up +}; + +struct PointerEvent +{ + PointerEventType m_Type; + Vec2D m_Position; + int m_PointerIndex; + + // add more fields as needed +}; + +} // namespace rive + +#endif diff --git a/third_party/rive/include/rive/process_event_result.hpp b/third_party/rive/include/rive/process_event_result.hpp new file mode 100644 index 0000000..fb06cd9 --- /dev/null +++ b/third_party/rive/include/rive/process_event_result.hpp @@ -0,0 +1,13 @@ +#ifndef _RIVE_PROCESS_EVENT_RESULT_HPP_ +#define _RIVE_PROCESS_EVENT_RESULT_HPP_ + +namespace rive +{ +enum class ProcessEventResult : uint8_t +{ + none, + pointer, + scroll, +}; +} // namespace rive +#endif diff --git a/third_party/rive/include/rive/refcnt.hpp b/third_party/rive/include/rive/refcnt.hpp new file mode 100644 index 0000000..7a1d69b --- /dev/null +++ b/third_party/rive/include/rive/refcnt.hpp @@ -0,0 +1,235 @@ +/* + * Copyright 2021 Rive + */ + +#ifndef _RIVE_REFCNT_HPP_ +#define _RIVE_REFCNT_HPP_ + +#include "rive/rive_types.hpp" + +#include +#include +#include +#include + +/* + * RefCnt : Threadsafe shared pointer baseclass. + * + * The reference count is set to one in the constructor, and goes up on every + * call to ref(), and down on every call to unref(). When a call to unref() + * brings the counter to 0, the object is casted to class "const T*" and + * deleted. Usage: + * + * class MyClass : public RefCnt + * + * rcp : template wrapper for subclasses of RefCnt, to manage assignment and + * parameter passing to safely keep track of shared ownership. + * + * Both of these inspired by Skia's SkRefCnt and sk_sp + */ + +namespace rive +{ + +template class RefCnt +{ +public: + RefCnt() : m_refcnt(1) {} + + void ref() const + { + (void)m_refcnt.fetch_add(+1, std::memory_order_relaxed); + } + + void unref() const + { + if (1 == m_refcnt.fetch_add(-1, std::memory_order_acq_rel)) + { + static_cast(this)->onRefCntReachedZero(); + } + } + + // not reliable in actual threaded scenarios, but useful (perhaps) for + // debugging + int32_t debugging_refcnt() const + { + return m_refcnt.load(std::memory_order_relaxed); + } + +protected: + // Can be overloaded in the subclass if specialized delete behavior is + // required. + void onRefCntReachedZero() const { delete static_cast(this); } + +private: + // mutable, so can be changed even on a const object + mutable std::atomic m_refcnt; + + RefCnt(RefCnt&&) = delete; + RefCnt(const RefCnt&) = delete; + RefCnt& operator=(RefCnt&&) = delete; + RefCnt& operator=(const RefCnt&) = delete; +}; + +template static inline T* safe_ref(T* obj) +{ + if (obj) + { + obj->ref(); + } + return obj; +} + +template static inline void safe_unref(T* obj) +{ + if (obj) + { + obj->unref(); + } +} + +// rcp : smart point template for holding subclasses of RefCnt + +template class rcp +{ +public: + constexpr rcp() : m_ptr(nullptr) {} + constexpr rcp(std::nullptr_t) : m_ptr(nullptr) {} + explicit rcp(T* ptr) : m_ptr(ptr) {} + + rcp(const rcp& other) : m_ptr(safe_ref(other.get())) {} + rcp(rcp&& other) : m_ptr(other.release()) {} + + template ::value>::type> + rcp(const rcp& other) : m_ptr(safe_ref(other.get())) + {} + + template ::value>::type> + rcp(rcp&& other) : m_ptr(other.release()) + {} + + /** + * Calls unref() on the underlying object pointer. + */ + ~rcp() { safe_unref(m_ptr); } + + rcp& operator=(std::nullptr_t) + { + this->reset(); + return *this; + } + + rcp& operator=(const rcp& other) + { + if (this != &other) + { + this->reset(safe_ref(other.get())); + } + return *this; + } + + // move assignment operator + rcp& operator=(rcp&& other) + { + this->reset(other.release()); + return *this; + } + + T& operator*() const + { + assert(this->get() != nullptr); + return *this->get(); + } + + explicit operator bool() const { return this->get() != nullptr; } + + T* get() const { return m_ptr; } + T* operator->() const { return m_ptr; } + + // Unrefs the current pointer, and accepts the new pointer, but + // DOES NOT increment ownership of the new pointer. + void reset(T* ptr = nullptr) + { + // Calling m_ptr->unref() may call this->~() or this->reset(T*). + // http://wg21.cmeerw.net/lwg/issue998 + // http://wg21.cmeerw.net/lwg/issue2262 + T* oldPtr = m_ptr; + m_ptr = ptr; + safe_unref(oldPtr); + } + + // This returns the bare point WITHOUT CHANGING ITS REFCNT, but removes it + // from this object, so the caller must manually manage its count. + T* release() + { + T* ptr = m_ptr; + m_ptr = nullptr; + return ptr; + } + + void swap(rcp& other) { std::swap(m_ptr, other.m_ptr); } + +private: + T* m_ptr; +}; + +template inline void swap(rcp& a, rcp& b) { a.swap(b); } + +template rcp inline make_rcp(Args&&... args) +{ + return rcp(new T(std::forward(args)...)); +} + +template rcp inline ref_rcp(T* ptr) +{ + return rcp(safe_ref(ptr)); +} + +template ::value>::type> +rcp static_rcp_cast(rcp ptr) +{ + return rcp(static_cast(ptr.release())); +} + +// == variants + +template inline bool operator==(const rcp& a, std::nullptr_t) +{ + return !a; +} +template inline bool operator==(std::nullptr_t, const rcp& b) +{ + return !b; +} +template +inline bool operator==(const rcp& a, const rcp& b) +{ + return a.get() == b.get(); +} + +// != variants + +template inline bool operator!=(const rcp& a, std::nullptr_t) +{ + return static_cast(a); +} +template inline bool operator!=(std::nullptr_t, const rcp& b) +{ + return static_cast(b); +} +template +inline bool operator!=(const rcp& a, const rcp& b) +{ + return a.get() != b.get(); +} + +} // namespace rive + +#endif diff --git a/third_party/rive/include/rive/relative_local_asset_loader.hpp b/third_party/rive/include/rive/relative_local_asset_loader.hpp new file mode 100644 index 0000000..c4dc317 --- /dev/null +++ b/third_party/rive/include/rive/relative_local_asset_loader.hpp @@ -0,0 +1,57 @@ +#ifndef _RIVE_RELATIVE_LOCAL_ASSET_RESOLVER_HPP_ +#define _RIVE_RELATIVE_LOCAL_ASSET_RESOLVER_HPP_ + +#include "rive/file_asset_loader.hpp" +#include "rive/assets/file_asset.hpp" +#include +#include +#include "rive/span.hpp" + +namespace rive +{ +class FileAsset; +class Factory; + +/// An implementation of FileAssetLoader which finds the assets in a local +/// path relative to the original .riv file looking for them. +class RelativeLocalAssetLoader : public FileAssetLoader +{ +private: + std::string m_Path; + +public: + RelativeLocalAssetLoader(std::string filename) + { + std::size_t finalSlash = filename.rfind('/'); + + if (finalSlash != std::string::npos) + { + m_Path = filename.substr(0, finalSlash + 1); + } + } + + bool loadContents(FileAsset& asset, + Span inBandBytes, + rive::Factory* factory) override + { + std::string filename = m_Path + asset.uniqueFilename(); + FILE* fp = fopen(filename.c_str(), "rb"); + if (fp == nullptr) + { + fprintf(stderr, "Failed to find file at %s\n", filename.c_str()); + return false; + } + + fseek(fp, 0, SEEK_END); + const size_t length = ftell(fp); + fseek(fp, 0, SEEK_SET); + SimpleArray bytes(length); + if (fread(bytes.data(), 1, length, fp) == length) + { + asset.decode(bytes, factory); + } + return true; + } +}; +} // namespace rive +#endif diff --git a/third_party/rive/include/rive/renderer.hpp b/third_party/rive/include/rive/renderer.hpp new file mode 100644 index 0000000..88cd39e --- /dev/null +++ b/third_party/rive/include/rive/renderer.hpp @@ -0,0 +1,240 @@ +/* + * Copyright 2022 Rive + */ + +#ifndef _RIVE_RENDERER_HPP_ +#define _RIVE_RENDERER_HPP_ + +#include "rive/enum_bitset.hpp" +#include "rive/shapes/paint/color.hpp" +#include "rive/command_path.hpp" +#include "rive/layout.hpp" +#include "rive/refcnt.hpp" +#include "rive/math/aabb.hpp" +#include "rive/math/mat2d.hpp" +#include "rive/shapes/paint/blend_mode.hpp" +#include "rive/shapes/paint/image_sampler.hpp" +#include "rive/shapes/paint/stroke_cap.hpp" +#include "rive/shapes/paint/stroke_join.hpp" +#include "utils/lite_rtti.hpp" +#include "rive/math/raw_path.hpp" +#include +#include + +namespace rive +{ +class Vec2D; + +// Helper that computes a matrix to "align" content (source) to fit inside frame +// (destination). +Mat2D computeAlignment(Fit, + Alignment, + const AABB& frame, + const AABB& content, + const float scaleFactor = 1.0f); + +enum class RenderBufferType +{ + index, + vertex, +}; + +enum class RenderBufferFlags +{ + none = 0, + mappedOnceAtInitialization = + 1 << 0, // The client will map the buffer exactly one time, before + // rendering, and will never update it again. +}; +RIVE_MAKE_ENUM_BITSET(RenderBufferFlags) + +class RenderBuffer : public RefCnt, + public ENABLE_LITE_RTTI(RenderBuffer) +{ +public: + RenderBuffer(RenderBufferType, RenderBufferFlags, size_t sizeInBytes); + virtual ~RenderBuffer(); + + RenderBufferType type() const { return m_type; } + RenderBufferFlags flags() const { return m_flags; } + size_t sizeInBytes() const { return m_sizeInBytes; } + + void* map(); + void unmap(); + +protected: + virtual void* onMap() = 0; + virtual void onUnmap() = 0; + + // Unset the dirty flag, and return whether it had been set. + bool checkAndResetDirty() + { + assert(m_mapCount == m_unmapCount); // Don't call this while mapped. + if (m_dirty) + { + m_dirty = false; + return true; + } + return false; + } + +private: + const RenderBufferType m_type; + const RenderBufferFlags m_flags; + const size_t m_sizeInBytes; + bool m_dirty = false; + RIVE_DEBUG_CODE(size_t m_mapCount = 0;) + RIVE_DEBUG_CODE(size_t m_unmapCount = 0;) +}; + +enum class RenderPaintStyle +{ + stroke, + fill +}; + +/* + * Base class for Render objects that specify the src colors. + * + * Shaders are immutable, and sharable between multiple paints, etc. + * + * It is common that a shader may be created with a 'localMatrix'. If this is + * not null, then it is applied to the shader's domain before the Renderer's + * CTM. + */ +class RenderShader : public RefCnt, + public ENABLE_LITE_RTTI(RenderShader) +{ +public: + RenderShader(); + virtual ~RenderShader(); +}; + +class RenderPaint : public RefCnt, + public ENABLE_LITE_RTTI(RenderPaint) +{ +public: + RenderPaint(); + virtual ~RenderPaint(); + + virtual void style(RenderPaintStyle style) = 0; + virtual void color(ColorInt value) = 0; + virtual void thickness(float value) = 0; + virtual void join(StrokeJoin value) = 0; + virtual void cap(StrokeCap value) = 0; + virtual void feather(float value) {} // Not supported on all renderers. + virtual void blendMode(BlendMode value) = 0; + virtual void shader(rcp) = 0; + virtual void invalidateStroke() = 0; +}; + +#if defined(__EMSCRIPTEN__) +class RenderImageDelegate +{ +public: + virtual void decodedAsync() = 0; +}; +#endif + +class RenderImage : public RefCnt, + public ENABLE_LITE_RTTI(RenderImage) +{ +protected: + int m_Width = 0; + int m_Height = 0; + Mat2D m_uvTransform; + +public: + RenderImage(); + RenderImage(const Mat2D& uvTransform); + virtual ~RenderImage(); + + int width() const { return m_Width; } + int height() const { return m_Height; } + const Mat2D& uvTransform() const { return m_uvTransform; } + +#if defined(__EMSCRIPTEN__) + void delegate(RenderImageDelegate* delegate) { m_delegate = delegate; } + void decodedAsync() const + { + if (m_delegate != nullptr) + { + m_delegate->decodedAsync(); + } + } + +private: + RenderImageDelegate* m_delegate = nullptr; +#endif +}; + +class RenderPath : public CommandPath, public ENABLE_LITE_RTTI(RenderPath) +{ +public: + RenderPath(); + ~RenderPath() override; + + RenderPath* renderPath() override { return this; } + const RenderPath* renderPath() const override { return this; } + + void addPath(CommandPath* path, const Mat2D& transform) override + { + addRenderPath(path->renderPath(), transform); + } + + void addPathBackwards(CommandPath* path, const Mat2D& transform) + { + addRenderPath(path->renderPath(), transform); + } + + virtual void addRenderPath(RenderPath* path, const Mat2D& transform) = 0; + virtual void addRenderPathBackwards(RenderPath* path, + const Mat2D& transform) + { + // No-op on non rive renderer. + } + + virtual void addRawPath(const RawPath& path) = 0; +}; + +class Renderer +{ +public: + virtual ~Renderer() {} + virtual void save() = 0; + virtual void restore() = 0; + virtual void transform(const Mat2D& transform) = 0; + virtual void drawPath(RenderPath* path, RenderPaint* paint) = 0; + virtual void clipPath(RenderPath* path) = 0; + virtual void drawImage(const RenderImage*, + ImageSampler, + BlendMode, + float opacity) = 0; + virtual void drawImageMesh(const RenderImage*, + ImageSampler, + rcp vertices_f32, + rcp uvCoords_f32, + rcp indices_u16, + uint32_t vertexCount, + uint32_t indexCount, + BlendMode, + float opacity) = 0; + + // helpers + + void translate(float x, float y); + void scale(float sx, float sy); + void rotate(float radians); + + void align(Fit fit, + Alignment alignment, + const AABB& frame, + const AABB& content, + const float scaleFactor = 1.0f) + { + transform( + computeAlignment(fit, alignment, frame, content, scaleFactor)); + } +}; +} // namespace rive +#endif diff --git a/third_party/rive/include/rive/renderer_utils.hpp b/third_party/rive/include/rive/renderer_utils.hpp new file mode 100644 index 0000000..5850689 --- /dev/null +++ b/third_party/rive/include/rive/renderer_utils.hpp @@ -0,0 +1,62 @@ +/* + * Copyright 2022 Rive + */ + +#ifndef _RIVE_RENDERER_UTILS_HPP_ +#define _RIVE_RENDERER_UTILS_HPP_ + +#include "rive/rive_types.hpp" +#include "rive/core/type_conversions.hpp" +#include + +template class AutoSTArray +{ + T m_storage[N]; + T* m_ptr; + const size_t m_count; + +public: + AutoSTArray(size_t n) : m_count(n) + { + m_ptr = m_storage; + if (n > N) + { + m_ptr = new T[n]; + } + } + ~AutoSTArray() + { + if (m_ptr != m_storage) + { + delete[] m_ptr; + } + } + + size_t size() const { return m_count; } + int count() const { return rive::castTo(m_count); } + + T* data() const { return m_ptr; } + + T& operator[](size_t index) + { + assert(index < m_count); + return m_ptr[index]; + } +}; + +constexpr inline uint32_t make_tag(uint8_t a, uint8_t b, uint8_t c, uint8_t d) +{ + return (a << 24) | (b << 16) | (c << 8) | d; +} + +static inline std::string tag2str(uint32_t tag) +{ + std::string str = "abcd"; + str[0] = (tag >> 24) & 0xFF; + str[1] = (tag >> 16) & 0xFF; + str[2] = (tag >> 8) & 0xFF; + str[3] = (tag >> 0) & 0xFF; + return str; +} + +#endif diff --git a/third_party/rive/include/rive/rive_types.hpp b/third_party/rive/include/rive/rive_types.hpp new file mode 100644 index 0000000..00f7d8f --- /dev/null +++ b/third_party/rive/include/rive/rive_types.hpp @@ -0,0 +1,138 @@ +/* + * Copyright 2022 Rive + */ + +// This should always be included by any other rive files, +// as it performs basic self-consistency checks, and provides +// shared common types and macros. + +#ifndef _RIVE_TYPES_HPP_ +#define _RIVE_TYPES_HPP_ + +#include // For unique_ptr. +#include // For memcpy. + +#if defined(DEBUG) && defined(NDEBUG) +#error "can't determine if we're debug or release" +#endif + +#if !defined(DEBUG) && !defined(NDEBUG) +// we have to make a decision what mode we're in +// historically this has been to look for NDEBUG, and in its +// absence assume we're DEBUG. +#define DEBUG 1 +// fyi - Xcode seems to set DEBUG (or not), so the above guess +// doesn't work for them - so our projects may need to explicitly +// set NDEBUG in our 'release' builds. +#endif + +#ifdef NDEBUG +#ifndef RELEASE +#define RELEASE 1 +#endif +#else // debug mode +#ifndef DEBUG +#define DEBUG 1 +#endif +#endif + +// Some checks to guess what platform we're building for + +#ifdef __APPLE__ + +#define RIVE_BUILD_FOR_APPLE +#include + +#if TARGET_OS_IPHONE +#define RIVE_BUILD_FOR_IOS +#elif TARGET_OS_MAC +#define RIVE_BUILD_FOR_OSX +#endif + +#define RIVE_NO_STD_SYSTEM + +#endif + +// We really like these headers, so we include them all the time. + +#include +#include +#include +#include +#include +#include + +// Annotations to assert unreachable control flow. +#if defined(__GNUC__) || defined(__clang__) +#define RIVE_UNREACHABLE \ + assert(!(bool)"unreachable reached"); \ + __builtin_unreachable +#elif _MSC_VER +#define RIVE_UNREACHABLE() \ + assert(!(bool)"unreachable reached"); \ + __assume(0) +#else +#define RIVE_UNREACHABLE() \ + do \ + { \ + assert(!(bool)"unreachable reached"); \ + } while (0) +#endif + +#if __cplusplus >= 201703L +#define RIVE_MAYBE_UNUSED [[maybe_unused]] +#else +#define RIVE_MAYBE_UNUSED +#endif + +#if __cplusplus >= 201703L +#define RIVE_FALLTHROUGH [[fallthrough]] +#elif defined(__clang__) +#define RIVE_FALLTHROUGH [[clang::fallthrough]] +#else +#define RIVE_FALLTHROUGH +#endif + +#if defined(__GNUC__) || defined(__clang__) +#define RIVE_ALWAYS_INLINE inline __attribute__((always_inline)) +#else +#define RIVE_ALWAYS_INLINE inline +#endif + +#if defined(__GNUC__) || defined(__clang__) +// Recommended in +// https://clang.llvm.org/docs/LanguageExtensions.html#feature-checking-macros +#ifndef __has_builtin +#define __has_builtin(x) 0 +#endif +#else +#define __has_builtin(x) 0 +#endif + +#if __has_builtin(__builtin_memcpy) +#define RIVE_INLINE_MEMCPY __builtin_memcpy +#else +#define RIVE_INLINE_MEMCPY memcpy +#endif + +#ifdef DEBUG +#define RIVE_DEBUG_CODE(CODE) CODE +#else +#define RIVE_DEBUG_CODE(CODE) +#endif + +// Backports of later stl functions. +namespace rivestd +{ +template std::unique_ptr make_unique(Args&&... args) +{ + return std::unique_ptr(new T(std::forward(args)...)); +} + +template static std::unique_ptr adopt_unique(T* window) +{ + return std::unique_ptr(window); +} +} // namespace rivestd + +#endif // rive_types diff --git a/third_party/rive/include/rive/runtime_header.hpp b/third_party/rive/include/rive/runtime_header.hpp new file mode 100644 index 0000000..4d76009 --- /dev/null +++ b/third_party/rive/include/rive/runtime_header.hpp @@ -0,0 +1,109 @@ +#ifndef _RIVE_RUNTIME_HEADER_HPP_ +#define _RIVE_RUNTIME_HEADER_HPP_ + +#include "rive/core/binary_reader.hpp" +#include + +namespace rive +{ + +/// Rive file runtime header. The header is fonud at the beginning of every +/// Rive runtime file, and begins with a specific 4-byte format: "RIVE". +/// This is followed by the major and minor version of Rive used to create +/// the file. Finally the owner and file ids are at the end of header; these +/// unsigned integers may be zero. +static constexpr char kRuntimeHeaderFingerprint[] = "RIVE"; +class RuntimeHeader +{ +private: + int m_MajorVersion; + int m_MinorVersion; + int m_FileId; + std::unordered_map m_PropertyToFieldIndex; + +public: + /// @returns the file's major version + int majorVersion() const { return m_MajorVersion; } + /// @returns the file's minor version + int minorVersion() const { return m_MinorVersion; } + /// @returns the file's id; may be zero + int fileId() const { return m_FileId; } + + int propertyFieldId(int propertyKey) const + { + auto itr = m_PropertyToFieldIndex.find(propertyKey); + if (itr == m_PropertyToFieldIndex.end()) + { + return -1; + } + + return itr->second; + } + + /// Reads the header from a binary buffer/ + /// @param reader the binary reader attached to the buffer + /// @param header a pointer to the header where the data will be stored. + /// @returns true if the header is successfully read + static bool read(BinaryReader& reader, RuntimeHeader& header) + { + for (int i = 0; i < 4; i++) + { + auto b = reader.readByte(); + if (kRuntimeHeaderFingerprint[i] != b) + { + return false; + } + } + + header.m_MajorVersion = reader.readVarUintAs(); + if (reader.didOverflow()) + { + return false; + } + header.m_MinorVersion = reader.readVarUintAs(); + if (reader.didOverflow()) + { + return false; + } + + header.m_FileId = reader.readVarUintAs(); + + if (reader.didOverflow()) + { + return false; + } + + std::vector propertyKeys; + for (int propertyKey = reader.readVarUintAs(); propertyKey != 0; + propertyKey = reader.readVarUintAs()) + { + propertyKeys.push_back(propertyKey); + if (reader.didOverflow()) + { + return false; + } + } + + int currentInt = 0; + int currentBit = 8; + for (auto propertyKey : propertyKeys) + { + if (currentBit == 8) + { + currentInt = reader.readUint32(); + currentBit = 0; + } + int fieldIndex = (currentInt >> currentBit) & 3; + header.m_PropertyToFieldIndex[propertyKey] = fieldIndex; + currentBit += 2; + if (reader.didOverflow()) + { + return false; + } + } + + return true; + } +}; +} // namespace rive +#endif diff --git a/third_party/rive/include/rive/scene.hpp b/third_party/rive/include/rive/scene.hpp new file mode 100644 index 0000000..a6ff80c --- /dev/null +++ b/third_party/rive/include/rive/scene.hpp @@ -0,0 +1,78 @@ +#ifndef _RIVE_SCENE_HPP_ +#define _RIVE_SCENE_HPP_ + +#include "rive/animation/loop.hpp" +#include "rive/math/aabb.hpp" +#include "rive/math/vec2d.hpp" +#include "rive/animation/keyed_callback_reporter.hpp" +#include "rive/core/field_types/core_callback_type.hpp" +#include "rive/hit_result.hpp" +#include "rive/refcnt.hpp" +#include + +namespace rive +{ +class ArtboardInstance; +class Renderer; +class ViewModelInstance; + +class SMIInput; +class SMIBool; +class SMINumber; +class SMITrigger; + +class Scene : public KeyedCallbackReporter, public CallbackContext +{ +protected: + Scene(ArtboardInstance*); + +public: + ~Scene() override {} + + Scene(Scene const& lhs) : m_artboardInstance(lhs.m_artboardInstance) {} + + float width() const; + float height() const; + AABB bounds() const { return {0, 0, this->width(), this->height()}; } + + virtual std::string name() const = 0; + + // Returns onShot if this has no looping (e.g. a statemachine) + virtual Loop loop() const = 0; + // Returns true iff the Scene is known to not be fully opaque + virtual bool isTranslucent() const = 0; + // returns -1 for continuous + virtual float durationSeconds() const = 0; + + // returns true if draw() should be called + virtual bool advanceAndApply(float elapsedSeconds) = 0; + + void draw(Renderer*); + + virtual void bindViewModelInstance( + rcp viewModelInstance); + + virtual HitResult pointerDown(Vec2D); + virtual HitResult pointerMove(Vec2D); + virtual HitResult pointerUp(Vec2D); + virtual HitResult pointerExit(Vec2D); + + virtual size_t inputCount() const; + virtual SMIInput* input(size_t index) const; + virtual SMIBool* getBool(const std::string&) const; + virtual SMINumber* getNumber(const std::string&) const; + virtual SMITrigger* getTrigger(const std::string&) const; + + /// Report which time based events have elapsed on a timeline within this + /// state machine. + void reportKeyedCallback(uint32_t objectId, + uint32_t propertyKey, + float elapsedSeconds) override; + +protected: + ArtboardInstance* m_artboardInstance; +}; + +} // namespace rive + +#endif diff --git a/third_party/rive/include/rive/shapes/clipping_shape.hpp b/third_party/rive/include/rive/shapes/clipping_shape.hpp new file mode 100644 index 0000000..a93a11e --- /dev/null +++ b/third_party/rive/include/rive/shapes/clipping_shape.hpp @@ -0,0 +1,35 @@ +#ifndef _RIVE_CLIPPING_SHAPE_HPP_ +#define _RIVE_CLIPPING_SHAPE_HPP_ +#include "rive/renderer.hpp" +#include "rive/generated/shapes/clipping_shape_base.hpp" +#include "rive/shapes/shape_paint_path.hpp" +#include + +namespace rive +{ +class Shape; +class Node; +class RenderPath; +class ClippingShape : public ClippingShapeBase +{ +private: + std::vector m_Shapes; + Node* m_Source = nullptr; + +public: + Node* source() const { return m_Source; } + const std::vector& shapes() const { return m_Shapes; } + StatusCode onAddedClean(CoreContext* context) override; + StatusCode onAddedDirty(CoreContext* context) override; + void buildDependencies() override; + void update(ComponentDirt value) override; + + ShapePaintPath* path() { return m_clipPath; } + +private: + ShapePaintPath m_path; + ShapePaintPath* m_clipPath = nullptr; +}; +} // namespace rive + +#endif diff --git a/third_party/rive/include/rive/shapes/contour_mesh_vertex.hpp b/third_party/rive/include/rive/shapes/contour_mesh_vertex.hpp new file mode 100644 index 0000000..850b4ac --- /dev/null +++ b/third_party/rive/include/rive/shapes/contour_mesh_vertex.hpp @@ -0,0 +1,13 @@ +#ifndef _RIVE_CONTOUR_MESH_VERTEX_HPP_ +#define _RIVE_CONTOUR_MESH_VERTEX_HPP_ +#include "rive/generated/shapes/contour_mesh_vertex_base.hpp" + +namespace rive +{ +class ContourMeshVertex : public ContourMeshVertexBase +{ +public: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/shapes/cubic_asymmetric_vertex.hpp b/third_party/rive/include/rive/shapes/cubic_asymmetric_vertex.hpp new file mode 100644 index 0000000..98701f0 --- /dev/null +++ b/third_party/rive/include/rive/shapes/cubic_asymmetric_vertex.hpp @@ -0,0 +1,17 @@ +#ifndef _RIVE_CUBIC_ASYMMETRIC_VERTEX_HPP_ +#define _RIVE_CUBIC_ASYMMETRIC_VERTEX_HPP_ +#include "rive/generated/shapes/cubic_asymmetric_vertex_base.hpp" +namespace rive +{ +class CubicAsymmetricVertex : public CubicAsymmetricVertexBase +{ +protected: + void computeIn() override; + void computeOut() override; + void rotationChanged() override; + void inDistanceChanged() override; + void outDistanceChanged() override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/shapes/cubic_detached_vertex.hpp b/third_party/rive/include/rive/shapes/cubic_detached_vertex.hpp new file mode 100644 index 0000000..14e679d --- /dev/null +++ b/third_party/rive/include/rive/shapes/cubic_detached_vertex.hpp @@ -0,0 +1,19 @@ +#ifndef _RIVE_CUBIC_DETACHED_VERTEX_HPP_ +#define _RIVE_CUBIC_DETACHED_VERTEX_HPP_ +#include "rive/generated/shapes/cubic_detached_vertex_base.hpp" +namespace rive +{ +class CubicDetachedVertex : public CubicDetachedVertexBase +{ +protected: + void computeIn() override; + void computeOut() override; + + void inRotationChanged() override; + void inDistanceChanged() override; + void outRotationChanged() override; + void outDistanceChanged() override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/shapes/cubic_mirrored_vertex.hpp b/third_party/rive/include/rive/shapes/cubic_mirrored_vertex.hpp new file mode 100644 index 0000000..c32df04 --- /dev/null +++ b/third_party/rive/include/rive/shapes/cubic_mirrored_vertex.hpp @@ -0,0 +1,16 @@ +#ifndef _RIVE_CUBIC_MIRRORED_VERTEX_HPP_ +#define _RIVE_CUBIC_MIRRORED_VERTEX_HPP_ +#include "rive/generated/shapes/cubic_mirrored_vertex_base.hpp" +namespace rive +{ +class CubicMirroredVertex : public CubicMirroredVertexBase +{ +protected: + void computeIn() override; + void computeOut() override; + void rotationChanged() override; + void distanceChanged() override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/shapes/cubic_vertex.hpp b/third_party/rive/include/rive/shapes/cubic_vertex.hpp new file mode 100644 index 0000000..a4d3a78 --- /dev/null +++ b/third_party/rive/include/rive/shapes/cubic_vertex.hpp @@ -0,0 +1,36 @@ +#ifndef _RIVE_CUBIC_VERTEX_HPP_ +#define _RIVE_CUBIC_VERTEX_HPP_ +#include "rive/generated/shapes/cubic_vertex_base.hpp" +#include "rive/math/vec2d.hpp" + +namespace rive +{ +class Vec2D; +class CubicVertex : public CubicVertexBase +{ +protected: + bool m_InValid = false; + bool m_OutValid = false; + Vec2D m_InPoint; + Vec2D m_OutPoint; + + virtual void computeIn() = 0; + virtual void computeOut() = 0; + +public: + const Vec2D& outPoint(); + const Vec2D& inPoint(); + const Vec2D& renderOut(); + const Vec2D& renderIn(); + + void outPoint(const Vec2D& value); + void inPoint(const Vec2D& value); + void xChanged() override; + void yChanged() override; + + void deform(const Mat2D& worldTransform, + const float* boneTransforms) override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/shapes/deformer.hpp b/third_party/rive/include/rive/shapes/deformer.hpp new file mode 100644 index 0000000..3a73ecb --- /dev/null +++ b/third_party/rive/include/rive/shapes/deformer.hpp @@ -0,0 +1,45 @@ +#ifndef _RIVE_DEFORMER_HPP_ +#define _RIVE_DEFORMER_HPP_ + +#include + +namespace rive +{ +class Component; +class RawPath; +class Mat2D; + +class Deformer +{ +public: + virtual Component* asComponent() = 0; + virtual ~Deformer() {} +}; + +class RenderPathDeformer : public Deformer +{ +public: + static RenderPathDeformer* from(Component* component); + virtual void deformLocalRenderPath(RawPath& path, + const Mat2D& worldTransform, + const Mat2D& inverseWorld) const = 0; + virtual void deformWorldRenderPath(RawPath& path) const = 0; + + virtual ~RenderPathDeformer() {} +}; + +class PointDeformer : public Deformer +{ +public: + static PointDeformer* from(Component* component); + virtual Vec2D deformLocalPoint(Vec2D point, + const Mat2D& worldTransform, + const Mat2D& inverseWorld) const = 0; + virtual Vec2D deformWorldPoint(Vec2D point) const = 0; + + virtual ~PointDeformer() {} +}; + +} // namespace rive + +#endif diff --git a/third_party/rive/include/rive/shapes/ellipse.hpp b/third_party/rive/include/rive/shapes/ellipse.hpp new file mode 100644 index 0000000..750ade0 --- /dev/null +++ b/third_party/rive/include/rive/shapes/ellipse.hpp @@ -0,0 +1,18 @@ +#ifndef _RIVE_ELLIPSE_HPP_ +#define _RIVE_ELLIPSE_HPP_ +#include "rive/generated/shapes/ellipse_base.hpp" +#include "rive/shapes/cubic_detached_vertex.hpp" + +namespace rive +{ +class Ellipse : public EllipseBase +{ + CubicDetachedVertex m_Vertex1, m_Vertex2, m_Vertex3, m_Vertex4; + +public: + Ellipse(); + void update(ComponentDirt value) override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/shapes/image.hpp b/third_party/rive/include/rive/shapes/image.hpp new file mode 100644 index 0000000..2e79921 --- /dev/null +++ b/third_party/rive/include/rive/shapes/image.hpp @@ -0,0 +1,52 @@ +#ifndef _RIVE_IMAGE_HPP_ +#define _RIVE_IMAGE_HPP_ + +#include "rive/hit_info.hpp" +#include "rive/generated/shapes/image_base.hpp" +#include "rive/assets/file_asset_referencer.hpp" + +namespace rive +{ +class ImageAsset; +class MeshDrawable; +#ifdef TESTING +class Mesh; +#endif +class Image : public ImageBase, public FileAssetReferencer +{ +private: + MeshDrawable* m_Mesh = nullptr; + // Since layouts only pass down width/height we store those + // and use the image width/height to compute the proper scale + float m_layoutWidth = NAN; + float m_layoutHeight = NAN; + void updateImageScale(); + +public: + void setMesh(MeshDrawable* mesh); + ImageAsset* imageAsset() const { return (ImageAsset*)m_fileAsset; } + void draw(Renderer* renderer) override; + Core* hitTest(HitInfo*, const Mat2D&) override; + StatusCode import(ImportStack& importStack) override; + void setAsset(FileAsset*) override; + uint32_t assetId() override; + Core* clone() const override; + Vec2D measureLayout(float width, + LayoutMeasureMode widthMode, + float height, + LayoutMeasureMode heightMode) override; + void controlSize(Vec2D size, + LayoutScaleType widthScaleType, + LayoutScaleType heightScaleType, + LayoutDirection direction) override; + float width() const; + float height() const; + void assetUpdated() override; + +#ifdef TESTING + Mesh* mesh() const; +#endif +}; +} // namespace rive + +#endif diff --git a/third_party/rive/include/rive/shapes/mesh.hpp b/third_party/rive/include/rive/shapes/mesh.hpp new file mode 100644 index 0000000..29f5589 --- /dev/null +++ b/third_party/rive/include/rive/shapes/mesh.hpp @@ -0,0 +1,53 @@ +#ifndef _RIVE_MESH_HPP_ +#define _RIVE_MESH_HPP_ +#include "rive/generated/shapes/mesh_base.hpp" +#include "rive/bones/skinnable.hpp" +#include "rive/shapes/mesh_drawable.hpp" +#include "rive/span.hpp" +#include "rive/refcnt.hpp" +#include "rive/renderer.hpp" + +namespace rive +{ +class MeshVertex; + +class Mesh : public MeshBase, public Skinnable, public MeshDrawable +{ + +protected: + class IndexBuffer : public std::vector, public RefCnt + {}; + bool m_VertexRenderBufferDirty = true; + rcp m_IndexBuffer; + std::vector m_Vertices; + +public: + StatusCode onAddedDirty(CoreContext* context) override; + StatusCode onAddedClean(CoreContext* context) override; + void markDrawableDirty(); + void addVertex(MeshVertex* vertex); + void decodeTriangleIndexBytes(Span value) override; + void copyTriangleIndexBytes(const MeshBase& object) override; + void buildDependencies() override; + void update(ComponentDirt value) override; + void draw(Renderer* renderer, + const RenderImage* image, + ImageSampler, + BlendMode blendMode, + float opacity) override; + + void markSkinDirty() override; + Core* clone() const override; + + /// Initialize the any buffers that will be shared amongst instances (the + /// instance are guaranteed to use the same RenderImage). + void onAssetLoaded(RenderImage* renderImage) override; + +#ifdef TESTING + std::vector& vertices() { return m_Vertices; } + rcp indices() { return m_IndexBuffer; } +#endif +}; +} // namespace rive + +#endif diff --git a/third_party/rive/include/rive/shapes/mesh_drawable.hpp b/third_party/rive/include/rive/shapes/mesh_drawable.hpp new file mode 100644 index 0000000..4148c7e --- /dev/null +++ b/third_party/rive/include/rive/shapes/mesh_drawable.hpp @@ -0,0 +1,36 @@ +#ifndef _RIVE_MESH_DRAWABLE_HPP_ +#define _RIVE_MESH_DRAWABLE_HPP_ +#include "rive/refcnt.hpp" +#include "rive/renderer.hpp" +#include + +namespace rive +{ +class RenderImage; +enum class MeshType : uint8_t +{ + vertex = 0, + nslice = 1, +}; +class MeshDrawable +{ +protected: + class IndexBuffer : public std::vector, public RefCnt + {}; + rcp m_IndexRenderBuffer; + rcp m_VertexRenderBuffer; + rcp m_UVRenderBuffer; + +public: + virtual MeshType type() { return MeshType::vertex; } + virtual ~MeshDrawable() = default; + virtual void onAssetLoaded(RenderImage* image) = 0; + virtual void draw(Renderer* renderer, + const RenderImage* image, + ImageSampler, + BlendMode blendMode, + float opacity) = 0; +}; +} // namespace rive + +#endif diff --git a/third_party/rive/include/rive/shapes/mesh_vertex.hpp b/third_party/rive/include/rive/shapes/mesh_vertex.hpp new file mode 100644 index 0000000..2b8c04f --- /dev/null +++ b/third_party/rive/include/rive/shapes/mesh_vertex.hpp @@ -0,0 +1,15 @@ +#ifndef _RIVE_MESH_VERTEX_HPP_ +#define _RIVE_MESH_VERTEX_HPP_ +#include "rive/generated/shapes/mesh_vertex_base.hpp" +#include +namespace rive +{ +class MeshVertex : public MeshVertexBase +{ +public: + void markGeometryDirty() override; + StatusCode onAddedDirty(CoreContext* context) override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/shapes/paint/blend_mode.hpp b/third_party/rive/include/rive/shapes/paint/blend_mode.hpp new file mode 100644 index 0000000..3b27246 --- /dev/null +++ b/third_party/rive/include/rive/shapes/paint/blend_mode.hpp @@ -0,0 +1,25 @@ +#ifndef _RIVE_BLEND_MODE_HPP_ +#define _RIVE_BLEND_MODE_HPP_ +namespace rive +{ +enum class BlendMode : unsigned char +{ + srcOver = 3, + screen = 14, + overlay = 15, + darken = 16, + lighten = 17, + colorDodge = 18, + colorBurn = 19, + hardLight = 20, + softLight = 21, + difference = 22, + exclusion = 23, + multiply = 24, + hue = 25, + saturation = 26, + color = 27, + luminosity = 28 +}; +} +#endif diff --git a/third_party/rive/include/rive/shapes/paint/color.hpp b/third_party/rive/include/rive/shapes/paint/color.hpp new file mode 100644 index 0000000..cf01a85 --- /dev/null +++ b/third_party/rive/include/rive/shapes/paint/color.hpp @@ -0,0 +1,36 @@ +#ifndef _RIVE_PAINT_COLOR_HPP_ +#define _RIVE_PAINT_COLOR_HPP_ +#include +#include + +namespace rive +{ +using ColorInt = uint32_t; + +ColorInt colorARGB(int a, int r, int g, int b); + +unsigned int colorRed(ColorInt value); + +unsigned int colorGreen(ColorInt value); + +unsigned int colorBlue(ColorInt value); + +unsigned int colorAlpha(ColorInt value); + +void UnpackColorToRGBA8(ColorInt color, uint8_t out[4]); + +void UnpackColorToRGBA32F(ColorInt color, float out[4]); + +void UnpackColorToRGBA32FPremul(ColorInt color, float out[4]); + +float colorOpacity(unsigned int value); + +ColorInt colorWithAlpha(ColorInt value, unsigned int a); + +ColorInt colorWithOpacity(ColorInt value, float opacity); + +ColorInt colorModulateOpacity(ColorInt value, float opacity); + +ColorInt colorLerp(ColorInt from, ColorInt to, float mix); +} // namespace rive +#endif diff --git a/third_party/rive/include/rive/shapes/paint/dash.hpp b/third_party/rive/include/rive/shapes/paint/dash.hpp new file mode 100644 index 0000000..444c753 --- /dev/null +++ b/third_party/rive/include/rive/shapes/paint/dash.hpp @@ -0,0 +1,22 @@ +#ifndef _RIVE_DASH_HPP_ +#define _RIVE_DASH_HPP_ +#include "rive/generated/shapes/paint/dash_base.hpp" +#include +namespace rive +{ +class Dash : public DashBase +{ +public: + Dash(); + Dash(float value, bool percentage); + + float normalizedLength(float length) const; + + StatusCode onAddedClean(CoreContext* context) override; + + void lengthChanged() override; + void lengthIsPercentageChanged() override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/shapes/paint/dash_path.hpp b/third_party/rive/include/rive/shapes/paint/dash_path.hpp new file mode 100644 index 0000000..890daf7 --- /dev/null +++ b/third_party/rive/include/rive/shapes/paint/dash_path.hpp @@ -0,0 +1,53 @@ +#ifndef _RIVE_DASH_PATH_HPP_ +#define _RIVE_DASH_PATH_HPP_ +#include "rive/generated/shapes/paint/dash_path_base.hpp" + +#include "rive/shapes/paint/stroke_effect.hpp" +#include "rive/shapes/paint/stroke_effect.hpp" +#include "rive/shapes/shape_paint_path.hpp" +#include "rive/renderer.hpp" +#include "rive/math/raw_path.hpp" +#include "rive/math/contour_measure.hpp" +#include + +namespace rive +{ +class Dash; +class PathDasher +{ + friend class Dash; + +protected: + void invalidateSourcePath(); + virtual void invalidateDash(); + ShapePaintPath* dash(const RawPath* source, + Dash* offset, + Span dashes); + ShapePaintPath* applyDash(const RawPath* source, + Dash* offset, + Span dashes); + +protected: + ShapePaintPath m_path; + std::vector> m_contours; + +public: + float pathLength() const; +}; + +class DashPath : public DashPathBase, public PathDasher, public StrokeEffect +{ +public: + StatusCode onAddedClean(CoreContext* context) override; + void invalidateEffect() override; + void offsetChanged() override; + void offsetIsPercentageChanged() override; + void updateEffect(const ShapePaintPath* source) override; + ShapePaintPath* effectPath() override; + void invalidateDash() override; + +private: + std::vector m_dashes; +}; +} // namespace rive +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/shapes/paint/feather.hpp b/third_party/rive/include/rive/shapes/paint/feather.hpp new file mode 100644 index 0000000..6f42ec5 --- /dev/null +++ b/third_party/rive/include/rive/shapes/paint/feather.hpp @@ -0,0 +1,36 @@ +#ifndef _RIVE_FEATHER_HPP_ +#define _RIVE_FEATHER_HPP_ +#include "rive/generated/shapes/paint/feather_base.hpp" +#include "rive/renderer.hpp" +#include "rive/shapes/shape_paint_path.hpp" +#include "rive/transform_space.hpp" + +namespace rive +{ + +class Feather : public FeatherBase +{ +public: + bool validate(CoreContext* context) override; + StatusCode onAddedDirty(CoreContext* context) override; + void update(ComponentDirt value) override; + TransformSpace space() const { return (TransformSpace)spaceValue(); } + void buildDependencies() override; + + ShapePaintPath* innerPath() { return &m_innerPath; } + +protected: + void strengthChanged() override; + void offsetXChanged() override; + void offsetYChanged() override; + +private: + ShapePaintPath m_innerPath; +#ifdef TESTING +public: + int renderCount = 0; +#endif +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/shapes/paint/fill.hpp b/third_party/rive/include/rive/shapes/paint/fill.hpp new file mode 100644 index 0000000..37f9fe9 --- /dev/null +++ b/third_party/rive/include/rive/shapes/paint/fill.hpp @@ -0,0 +1,17 @@ +#ifndef _RIVE_FILL_HPP_ +#define _RIVE_FILL_HPP_ +#include "rive/generated/shapes/paint/fill_base.hpp" +#include "rive/shapes/path_flags.hpp" +namespace rive +{ +class Fill : public FillBase +{ +public: + RenderPaint* initRenderPaint(ShapePaintMutator* mutator) override; + PathFlags pathFlags() const override; + void applyTo(RenderPaint* renderPaint, float opacityModifier) override; + ShapePaintPath* pickPath(ShapePaintContainer* shape) const override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/shapes/paint/gradient_stop.hpp b/third_party/rive/include/rive/shapes/paint/gradient_stop.hpp new file mode 100644 index 0000000..f0e7db8 --- /dev/null +++ b/third_party/rive/include/rive/shapes/paint/gradient_stop.hpp @@ -0,0 +1,17 @@ +#ifndef _RIVE_GRADIENT_STOP_HPP_ +#define _RIVE_GRADIENT_STOP_HPP_ +#include "rive/generated/shapes/paint/gradient_stop_base.hpp" +namespace rive +{ +class GradientStop : public GradientStopBase +{ +public: + StatusCode onAddedDirty(CoreContext* context) override; + +protected: + void colorValueChanged() override; + void positionChanged() override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/shapes/paint/image_sampler.hpp b/third_party/rive/include/rive/shapes/paint/image_sampler.hpp new file mode 100644 index 0000000..8fe04c7 --- /dev/null +++ b/third_party/rive/include/rive/shapes/paint/image_sampler.hpp @@ -0,0 +1,96 @@ +#ifndef IMAGE_SAMPLER +#define IMAGE_SAMPLER + +#include + +namespace rive +{ +enum class ImageFilter : uint8_t +{ + // High fidelity linear filter in all 3 directions: x, y, and between mip + // levels + trilinear = 0, + // Sample with low fidelity, good for things like pixel art. + nearest = 1 +}; + +constexpr size_t NUM_IMAGE_FILTERS = 2; + +enum class ImageWrap : uint8_t +{ + // Clamp to the color of the nearest edge when a texture sample falls + // outside 0..1. + clamp = 0, + // Repeat when a texture sample falls outside 0..1 (e.g., fmod(coord, 1)). + repeat = 1, + // Similar to repeat, but also mirror the coordinate with each repeat. + mirror = 2, +}; + +constexpr size_t NUM_IMAGE_WRAP = 4; + +struct ImageSampler +{ + static constexpr ImageSampler LinearClamp() { return {}; } + + constexpr static uint8_t LINEAR_CLAMP_SAMPLER_KEY = 0; + + ImageWrap wrapX = ImageWrap::clamp; + ImageWrap wrapY = ImageWrap::clamp; + // How to sample the texture, this will be for both MIN and MAG filtering. + ImageFilter filter = ImageFilter::trilinear; + + bool operator==(const ImageSampler other) const + { + return other.wrapX == wrapX && other.wrapY == wrapY && + other.filter == filter; + } + + bool operator!=(const ImageSampler other) const + { + return !(*this == other); + } + + // The maximum number of possible combinations of sampler options. Used for + // array length in implementations. + static constexpr size_t MAX_SAMPLER_PERMUTATIONS = + NUM_IMAGE_FILTERS * NUM_IMAGE_FILTERS * NUM_IMAGE_WRAP; + + // Convert struct to a key that can be used to index an array to get a + // unique sampler that represents these options. + const uint8_t asKey() const + { + return static_cast(wrapX) + (static_cast(wrapY) * 3) + + (static_cast(filter) * 9); + } + + static ImageSampler SamplerFromKey(uint8_t key) + { + // Android wouldn't compile with {} style initialization so do it this + // way instead. + ImageSampler sampler; + + sampler.wrapX = GetWrapXOptionFromKey(key); + sampler.wrapY = GetWrapYOptionFromKey(key); + sampler.filter = GetFilterOptionFromKey(key); + + return sampler; + } + + static ImageWrap GetWrapXOptionFromKey(uint8_t key) + { + return static_cast(key % 3); + } + + static ImageWrap GetWrapYOptionFromKey(uint8_t key) + { + return static_cast((key % 9) / 3); + } + + static ImageFilter GetFilterOptionFromKey(uint8_t key) + { + return static_cast((key - (key % 9)) % 2); + } +}; +} // namespace rive +#endif diff --git a/third_party/rive/include/rive/shapes/paint/linear_gradient.hpp b/third_party/rive/include/rive/shapes/paint/linear_gradient.hpp new file mode 100644 index 0000000..a023e1f --- /dev/null +++ b/third_party/rive/include/rive/shapes/paint/linear_gradient.hpp @@ -0,0 +1,52 @@ +#ifndef _RIVE_LINEAR_GRADIENT_HPP_ +#define _RIVE_LINEAR_GRADIENT_HPP_ +#include "rive/generated/shapes/paint/linear_gradient_base.hpp" +#include "rive/math/vec2d.hpp" +#include "rive/shapes/paint/color.hpp" +#include "rive/shapes/paint/shape_paint_mutator.hpp" +#include + +namespace rive +{ +class Node; +class GradientStop; +class PointDeformer; + +class LinearGradient : public LinearGradientBase, public ShapePaintMutator +{ +public: + StatusCode onAddedDirty(CoreContext* context) override; + void addStop(GradientStop* stop); + void update(ComponentDirt value) override; + void markGradientDirty(); + void markStopsDirty(); + void applyTo(RenderPaint* renderPaint, float opacityModifier) override; + +protected: + void buildDependencies() override; + void startXChanged() override; + void startYChanged() override; + void endXChanged() override; + void endYChanged() override; + void opacityChanged() override; + void renderOpacityChanged() override; + + virtual void makeGradient(RenderPaint* renderPaint, + Vec2D start, + Vec2D end, + const ColorInt[], + const float[], + size_t count) const; + +private: + // Set m_deformer from the shape paint container + void updateDeformer(); + + std::vector m_stops; + Node* m_shapePaintContainer = nullptr; + PointDeformer* m_deformer = nullptr; + std::vector m_colorStorage; +}; +} // namespace rive + +#endif diff --git a/third_party/rive/include/rive/shapes/paint/radial_gradient.hpp b/third_party/rive/include/rive/shapes/paint/radial_gradient.hpp new file mode 100644 index 0000000..ceb2f8f --- /dev/null +++ b/third_party/rive/include/rive/shapes/paint/radial_gradient.hpp @@ -0,0 +1,18 @@ +#ifndef _RIVE_RADIAL_GRADIENT_HPP_ +#define _RIVE_RADIAL_GRADIENT_HPP_ +#include "rive/generated/shapes/paint/radial_gradient_base.hpp" +namespace rive +{ +class RadialGradient : public RadialGradientBase +{ +public: + void makeGradient(RenderPaint* renderPaint, + Vec2D start, + Vec2D end, + const ColorInt[], + const float[], + size_t count) const override; +}; +} // namespace rive + +#endif diff --git a/third_party/rive/include/rive/shapes/paint/shape_paint.hpp b/third_party/rive/include/rive/shapes/paint/shape_paint.hpp new file mode 100644 index 0000000..cb98ed1 --- /dev/null +++ b/third_party/rive/include/rive/shapes/paint/shape_paint.hpp @@ -0,0 +1,79 @@ +#ifndef _RIVE_SHAPE_PAINT_HPP_ +#define _RIVE_SHAPE_PAINT_HPP_ +#include "rive/generated/shapes/paint/shape_paint_base.hpp" +#include "rive/renderer.hpp" +#include "rive/shapes/paint/blend_mode.hpp" +#include "rive/shapes/paint/shape_paint_mutator.hpp" +#include "rive/shapes/path_flags.hpp" +#include "rive/shapes/shape_paint_path.hpp" +#include "rive/math/raw_path.hpp" + +namespace rive +{ +class RenderPaint; +class ShapePaintMutator; +class Feather; +class ShapePaintContainer; +class ShapePaint : public ShapePaintBase +{ +protected: + rcp m_RenderPaint; + ShapePaintMutator* m_PaintMutator = nullptr; + +public: + StatusCode onAddedClean(CoreContext* context) override; + + float renderOpacity() const { return m_PaintMutator->renderOpacity(); } + void renderOpacity(float value) { m_PaintMutator->renderOpacity(value); } + + void blendMode(BlendMode value); + + /// Creates a RenderPaint object for the provided ShapePaintMutator*. + /// This should be called only once as the ShapePaint manages the + /// lifecycle of the RenderPaint. + virtual RenderPaint* initRenderPaint(ShapePaintMutator* mutator); + + virtual PathFlags pathFlags() const = 0; + bool isFlagged(PathFlags flags) const + { + return (int)(pathFlags() & flags) != 0x00; + } + + virtual void draw(Renderer* renderer, + ShapePaintPath* shapePaintPath, + const Mat2D& transform, + bool usePathFillRule = false, + RenderPaint* overridePaint = nullptr); + + RenderPaint* renderPaint() { return m_RenderPaint.get(); } + + /// Get the component that represents the ShapePaintMutator for this + /// ShapePaint. It'll be one of SolidColor, LinearGradient, or + /// RadialGradient. + Component* paint() const { return m_PaintMutator->component(); } + + bool isTranslucent() const + { + return !this->isVisible() || m_PaintMutator->isTranslucent(); + } + + bool shouldDraw() const + { + return this->isVisible() && m_PaintMutator->isVisible(); + } + + /// Apply this ShapePaint to an external RenderPaint and optionally modulate + /// the opacity by opacityModifer. + virtual void applyTo(RenderPaint* renderPaint, float opacityModifier) = 0; + + void feather(Feather* feather); + Feather* feather() const; + + virtual ShapePaintPath* pickPath(ShapePaintContainer* shape) const = 0; + +private: + Feather* m_feather = nullptr; +}; +} // namespace rive + +#endif diff --git a/third_party/rive/include/rive/shapes/paint/shape_paint_mutator.hpp b/third_party/rive/include/rive/shapes/paint/shape_paint_mutator.hpp new file mode 100644 index 0000000..8c52690 --- /dev/null +++ b/third_party/rive/include/rive/shapes/paint/shape_paint_mutator.hpp @@ -0,0 +1,57 @@ +#ifndef _RIVE_SHAPE_PAINT_MUTATOR_HPP_ +#define _RIVE_SHAPE_PAINT_MUTATOR_HPP_ + +#include "rive/status_code.hpp" +#include "rive/enum_bitset.hpp" + +namespace rive +{ +class Component; +class RenderPaint; + +class ShapePaintMutator +{ +protected: + /// Hook up this paint mutator as the mutator for the shape paint + /// expected to be the parent. + StatusCode initPaintMutator(Component* component); + virtual void renderOpacityChanged() = 0; + + RenderPaint* renderPaint() const { return m_renderPaint; } + +public: + enum class Flags : uint8_t + { + none = 0, + visible = 1 << 0, + translucent = 1 << 1 + }; + + virtual ~ShapePaintMutator() {} + + float renderOpacity() const { return m_renderOpacity; } + void renderOpacity(float value); + + Component* component() const { return m_component; } + + // Does this object have any alpha less than 0? + bool isTranslucent() const; + + // Is this object visible at all (effective opacity greater than 0). + bool isVisible() const; + + virtual void applyTo(RenderPaint* renderPaint, float opacityModifier) = 0; + +protected: + Flags m_flags; + +private: + /// The inherited opacity to modulate our color value by. + float m_renderOpacity = 1.0f; + RenderPaint* m_renderPaint = nullptr; + /// The Component providing this ShapePaintMutator interface. + Component* m_component = nullptr; +}; +RIVE_MAKE_ENUM_BITSET(ShapePaintMutator::Flags); +} // namespace rive +#endif diff --git a/third_party/rive/include/rive/shapes/paint/solid_color.hpp b/third_party/rive/include/rive/shapes/paint/solid_color.hpp new file mode 100644 index 0000000..7486222 --- /dev/null +++ b/third_party/rive/include/rive/shapes/paint/solid_color.hpp @@ -0,0 +1,19 @@ +#ifndef _RIVE_SOLID_COLOR_HPP_ +#define _RIVE_SOLID_COLOR_HPP_ +#include "rive/generated/shapes/paint/solid_color_base.hpp" +#include "rive/shapes/paint/shape_paint_mutator.hpp" +namespace rive +{ +class SolidColor : public SolidColorBase, public ShapePaintMutator +{ +public: + StatusCode onAddedDirty(CoreContext* context) override; + void applyTo(RenderPaint* renderPaint, float opacityModifier) override; + +protected: + void renderOpacityChanged() override; + void colorValueChanged() override; +}; +} // namespace rive + +#endif diff --git a/third_party/rive/include/rive/shapes/paint/stroke.hpp b/third_party/rive/include/rive/shapes/paint/stroke.hpp new file mode 100644 index 0000000..b677858 --- /dev/null +++ b/third_party/rive/include/rive/shapes/paint/stroke.hpp @@ -0,0 +1,42 @@ +#ifndef _RIVE_STROKE_HPP_ +#define _RIVE_STROKE_HPP_ +#include "rive/generated/shapes/paint/stroke_base.hpp" +#include "rive/shapes/path_flags.hpp" +namespace rive +{ +class StrokeEffect; +class Stroke : public StrokeBase +{ +private: + StrokeEffect* m_Effect = nullptr; + +public: + RenderPaint* initRenderPaint(ShapePaintMutator* mutator) override; + PathFlags pathFlags() const override; + void addStrokeEffect(StrokeEffect* effect); + bool hasStrokeEffect() { return m_Effect != nullptr; } + void invalidateEffects(); + bool isVisible() const override; + void invalidateRendering(); + void applyTo(RenderPaint* renderPaint, float opacityModifier) override; + ShapePaintPath* pickPath(ShapePaintContainer* shape) const override; + + void draw(Renderer* renderer, + ShapePaintPath* shapePaintPath, + const Mat2D& transform, + bool usePathFillRule, + RenderPaint* overridePaint) override; + void buildDependencies() override; + void update(ComponentDirt value) override; +#ifdef TESTING + StrokeEffect* effect() { return m_Effect; } +#endif + +protected: + void thicknessChanged() override; + void capChanged() override; + void joinChanged() override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/shapes/paint/stroke_cap.hpp b/third_party/rive/include/rive/shapes/paint/stroke_cap.hpp new file mode 100644 index 0000000..243a973 --- /dev/null +++ b/third_party/rive/include/rive/shapes/paint/stroke_cap.hpp @@ -0,0 +1,18 @@ +#ifndef _RIVE_STROKE_CAP_HPP_ +#define _RIVE_STROKE_CAP_HPP_ +namespace rive +{ +/// Style used for stroke line endings. +enum class StrokeCap : unsigned int +{ + /// Flat edge at the start/end of the stroke. + butt = 0, + + /// Circular edge at the start/end of the stroke. + round = 1, + + /// Flat protruding edge at the start/end of the stroke. + square = 2 +}; +} // namespace rive +#endif diff --git a/third_party/rive/include/rive/shapes/paint/stroke_effect.hpp b/third_party/rive/include/rive/shapes/paint/stroke_effect.hpp new file mode 100644 index 0000000..e73ba9e --- /dev/null +++ b/third_party/rive/include/rive/shapes/paint/stroke_effect.hpp @@ -0,0 +1,22 @@ +#ifndef _RIVE_STROKE_EFFECT_HPP_ +#define _RIVE_STROKE_EFFECT_HPP_ + +#include "rive/rive_types.hpp" + +namespace rive +{ +class Factory; +class RenderPath; +class RawPath; +class ShapePaintPath; + +class StrokeEffect +{ +public: + virtual ~StrokeEffect() {} + virtual void updateEffect(const ShapePaintPath* source) = 0; + virtual ShapePaintPath* effectPath() = 0; + virtual void invalidateEffect() = 0; +}; +} // namespace rive +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/shapes/paint/stroke_join.hpp b/third_party/rive/include/rive/shapes/paint/stroke_join.hpp new file mode 100644 index 0000000..b0f3810 --- /dev/null +++ b/third_party/rive/include/rive/shapes/paint/stroke_join.hpp @@ -0,0 +1,19 @@ +#ifndef _RIVE_STROKE_JOIN_HPP_ +#define _RIVE_STROKE_JOIN_HPP_ +namespace rive +{ +/// Style used for stroke segment joins when there is a sharp change. +enum class StrokeJoin : unsigned int +{ + /// Makes a sharp corner at the joint. + miter = 0, + + /// Smoothens the joint with a circular/semi-circular shape at the + /// joint. + round = 1, + + /// Creates a beveled edge at the joint. + bevel = 2 +}; +} // namespace rive +#endif diff --git a/third_party/rive/include/rive/shapes/paint/trim_path.hpp b/third_party/rive/include/rive/shapes/paint/trim_path.hpp new file mode 100644 index 0000000..2b02667 --- /dev/null +++ b/third_party/rive/include/rive/shapes/paint/trim_path.hpp @@ -0,0 +1,47 @@ +#ifndef _RIVE_TRIM_PATH_HPP_ +#define _RIVE_TRIM_PATH_HPP_ +#include "rive/generated/shapes/paint/trim_path_base.hpp" +#include "rive/shapes/shape_paint_path.hpp" +#include "rive/shapes/paint/stroke_effect.hpp" +#include "rive/renderer.hpp" +#include "rive/math/raw_path.hpp" +#include "rive/math/contour_measure.hpp" + +namespace rive +{ +enum class TrimPathMode : uint8_t +{ + sequential = 1, + synchronized = 2 + +}; + +class TrimPath : public TrimPathBase, public StrokeEffect +{ +public: + StatusCode onAddedClean(CoreContext* context) override; + void invalidateEffect() override; + + void updateEffect(const ShapePaintPath* source) override; + ShapePaintPath* effectPath() override; + + void startChanged() override; + void endChanged() override; + void offsetChanged() override; + void modeValueChanged() override; + + TrimPathMode mode() const { return (TrimPathMode)modeValue(); } + + StatusCode onAddedDirty(CoreContext* context) override; + + const ShapePaintPath& path() const { return m_path; } + +protected: + void invalidateTrim(); + void trimPath(const RawPath* source); + ShapePaintPath m_path; + std::vector> m_contours; +}; +} // namespace rive + +#endif diff --git a/third_party/rive/include/rive/shapes/parametric_path.hpp b/third_party/rive/include/rive/shapes/parametric_path.hpp new file mode 100644 index 0000000..7ef910b --- /dev/null +++ b/third_party/rive/include/rive/shapes/parametric_path.hpp @@ -0,0 +1,28 @@ +#ifndef _RIVE_PARAMETRIC_PATH_HPP_ +#define _RIVE_PARAMETRIC_PATH_HPP_ +#include "rive/math/aabb.hpp" +#include "rive/generated/shapes/parametric_path_base.hpp" +namespace rive +{ +class ParametricPath : public ParametricPathBase +{ +public: + Vec2D measureLayout(float width, + LayoutMeasureMode widthMode, + float height, + LayoutMeasureMode heightMode) override; + void controlSize(Vec2D size, + LayoutScaleType widthScaleType, + LayoutScaleType heightScaleType, + LayoutDirection direction) override; + void markPathDirty(bool sendToLayout = true) override; + +protected: + void widthChanged() override; + void heightChanged() override; + void originXChanged() override; + void originYChanged() override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/shapes/path.hpp b/third_party/rive/include/rive/shapes/path.hpp new file mode 100644 index 0000000..2d0d6e1 --- /dev/null +++ b/third_party/rive/include/rive/shapes/path.hpp @@ -0,0 +1,84 @@ +#ifndef _RIVE_PATH_HPP_ +#define _RIVE_PATH_HPP_ +#include "rive/command_path.hpp" +#include "rive/generated/shapes/path_base.hpp" +#include "rive/math/mat2d.hpp" +#include "rive/math/raw_path.hpp" +#include "rive/shapes/shape_paint_container.hpp" +#include + +namespace rive +{ +class Shape; +class PathVertex; +class RenderPathDeformer; + +#ifdef ENABLE_QUERY_FLAT_VERTICES +/// Optionally compiled in for tools that need to compute per frame world +/// transformed path vertices. These should not be used at runtime as it's +/// not optimized for performance (it does a lot of memory allocation). + +/// A flattened path is composed of only linear +/// and cubic vertices. No corner vertices and it's entirely in world space. +/// This is helpful for getting a close to identical representation of the +/// vertices used to issue the high level path draw commands. +class FlattenedPath +{ +private: + std::vector m_Vertices; + +public: + ~FlattenedPath(); + + const std::vector& vertices() const { return m_Vertices; } + void addVertex(PathVertex* vertex, const Mat2D& transform); +}; +#endif + +class Path : public PathBase +{ +protected: + Shape* m_Shape = nullptr; + std::vector m_Vertices; + bool m_deferredPathDirt = false; + PathFlags m_pathFlags = PathFlags::none; + RawPath m_rawPath; + RenderPathDeformer* deformer() const; + void isHoleChanged() override; + +public: + static float computeIdealControlPointDistance(const Vec2D& toPrev, + const Vec2D& toNext, + float radius); + + Shape* shape() const { return m_Shape; } + StatusCode onAddedClean(CoreContext* context) override; + void buildDependencies() override; + virtual const Mat2D& pathTransform() const; + bool collapse(bool value) override; + const RawPath& rawPath() const { return m_rawPath; } + void update(ComponentDirt value) override; + + void addFlags(PathFlags flags); + bool isFlagged(PathFlags flags) const; + + bool canDeferPathUpdate(); + void addVertex(PathVertex* vertex); + + virtual void markPathDirty(bool sendToLayout = true); + virtual bool isPathClosed() const { return true; } + void onDirty(ComponentDirt dirt) override; + inline bool isHidden() const { return (pathFlags() & 0x1) == 0x1; } +#ifdef ENABLE_QUERY_FLAT_VERTICES + FlattenedPath* makeFlat(bool transformToParent); +#endif + +#ifdef TESTING + std::vector& vertices() { return m_Vertices; } +#endif + + void buildPath(RawPath&) const; +}; +} // namespace rive + +#endif diff --git a/third_party/rive/include/rive/shapes/path_composer.hpp b/third_party/rive/include/rive/shapes/path_composer.hpp new file mode 100644 index 0000000..9b398fa --- /dev/null +++ b/third_party/rive/include/rive/shapes/path_composer.hpp @@ -0,0 +1,37 @@ +#ifndef _RIVE_PATH_COMPOSER_HPP_ +#define _RIVE_PATH_COMPOSER_HPP_ +#include "rive/component.hpp" +#include "rive/shapes/shape_paint_path.hpp" +#include "rive/refcnt.hpp" +#include "rive/math/raw_path.hpp" + +namespace rive +{ +class Shape; +class CommandPath; + +class PathComposer : public Component +{ + +public: + PathComposer(Shape* shape); + Shape* shape() const { return m_shape; } + void buildDependencies() override; + void onDirty(ComponentDirt dirt) override; + void update(ComponentDirt value) override; + + ShapePaintPath* localPath() { return &m_localPath; } + ShapePaintPath* worldPath() { return &m_worldPath; } + ShapePaintPath* localClockwisePath() { return &m_localClockwisePath; } + + void pathCollapseChanged(); + +private: + Shape* m_shape; + ShapePaintPath m_localPath; + ShapePaintPath m_worldPath; + ShapePaintPath m_localClockwisePath; + bool m_deferredPathDirt; +}; +} // namespace rive +#endif diff --git a/third_party/rive/include/rive/shapes/path_flags.hpp b/third_party/rive/include/rive/shapes/path_flags.hpp new file mode 100644 index 0000000..efe3ed0 --- /dev/null +++ b/third_party/rive/include/rive/shapes/path_flags.hpp @@ -0,0 +1,74 @@ +#ifndef _RIVE_PATH_FLAGS_HPP_ +#define _RIVE_PATH_FLAGS_HPP_ + +#include "rive/rive_types.hpp" + +namespace rive +{ +enum class PathFlags : uint8_t +{ + none = 0, + local = 1 << 1, + world = 1 << 2, + clipping = 1 << 3, + followPath = 1 << 4, + neverDeferUpdate = 1 << 5, + localClockwise = 1 << 6, +}; + +inline constexpr PathFlags operator&(PathFlags lhs, PathFlags rhs) +{ + return static_cast( + static_cast::type>(lhs) & + static_cast::type>(rhs)); +} + +inline constexpr PathFlags operator^(PathFlags lhs, PathFlags rhs) +{ + return static_cast( + static_cast::type>(lhs) ^ + static_cast::type>(rhs)); +} + +inline constexpr PathFlags operator|(PathFlags lhs, PathFlags rhs) +{ + return static_cast( + static_cast::type>(lhs) | + static_cast::type>(rhs)); +} + +inline constexpr PathFlags operator~(PathFlags rhs) +{ + return static_cast( + ~static_cast::type>(rhs)); +} + +inline PathFlags& operator|=(PathFlags& lhs, PathFlags rhs) +{ + lhs = static_cast( + static_cast::type>(lhs) | + static_cast::type>(rhs)); + + return lhs; +} + +inline PathFlags& operator&=(PathFlags& lhs, PathFlags rhs) +{ + lhs = static_cast( + static_cast::type>(lhs) & + static_cast::type>(rhs)); + + return lhs; +} + +inline PathFlags& operator^=(PathFlags& lhs, PathFlags rhs) +{ + lhs = static_cast( + static_cast::type>(lhs) ^ + static_cast::type>(rhs)); + + return lhs; +} +} // namespace rive + +#endif diff --git a/third_party/rive/include/rive/shapes/path_vertex.hpp b/third_party/rive/include/rive/shapes/path_vertex.hpp new file mode 100644 index 0000000..1df0872 --- /dev/null +++ b/third_party/rive/include/rive/shapes/path_vertex.hpp @@ -0,0 +1,17 @@ +#ifndef _RIVE_PATH_VERTEX_HPP_ +#define _RIVE_PATH_VERTEX_HPP_ +#include "rive/bones/weight.hpp" +#include "rive/generated/shapes/path_vertex_base.hpp" +#include "rive/math/mat2d.hpp" +namespace rive +{ +class PathVertex : public PathVertexBase +{ + +public: + StatusCode onAddedDirty(CoreContext* context) override; + void markGeometryDirty() override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/shapes/points_path.hpp b/third_party/rive/include/rive/shapes/points_path.hpp new file mode 100644 index 0000000..d57e0b2 --- /dev/null +++ b/third_party/rive/include/rive/shapes/points_path.hpp @@ -0,0 +1,21 @@ +#ifndef _RIVE_POINTS_PATH_HPP_ +#define _RIVE_POINTS_PATH_HPP_ +#include "rive/bones/skinnable.hpp" +#include "rive/generated/shapes/points_path_base.hpp" +namespace rive +{ +class PointsPath : public PointsPathBase, public Skinnable +{ +public: + bool isPathClosed() const override { return isClosed(); } + void buildDependencies() override; + void update(ComponentDirt value) override; + void markPathDirty(bool sendToLayout = true) override; + void markSkinDirty() override; + const Mat2D& pathTransform() const override; + + bool isClockwise() const; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/shapes/polygon.hpp b/third_party/rive/include/rive/shapes/polygon.hpp new file mode 100644 index 0000000..7d2ed4b --- /dev/null +++ b/third_party/rive/include/rive/shapes/polygon.hpp @@ -0,0 +1,27 @@ +#ifndef _RIVE_POLYGON_HPP_ +#define _RIVE_POLYGON_HPP_ +#include "rive/generated/shapes/polygon_base.hpp" +#include "rive/shapes/path_vertex.hpp" +#include "rive/shapes/straight_vertex.hpp" +#include +namespace rive +{ +class Polygon : public PolygonBase +{ +protected: + std::vector m_PolygonVertices; + +public: + Polygon(); + ~Polygon() override; + void update(ComponentDirt value) override; + +protected: + void cornerRadiusChanged() override; + void pointsChanged() override; + virtual std::size_t vertexCount(); + virtual void buildPolygon(); +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/shapes/rectangle.hpp b/third_party/rive/include/rive/shapes/rectangle.hpp new file mode 100644 index 0000000..26bcdc1 --- /dev/null +++ b/third_party/rive/include/rive/shapes/rectangle.hpp @@ -0,0 +1,24 @@ +#ifndef _RIVE_RECTANGLE_HPP_ +#define _RIVE_RECTANGLE_HPP_ +#include "rive/generated/shapes/rectangle_base.hpp" +#include "rive/shapes/straight_vertex.hpp" + +namespace rive +{ +class Rectangle : public RectangleBase +{ + StraightVertex m_Vertex1, m_Vertex2, m_Vertex3, m_Vertex4; + +public: + Rectangle(); + void update(ComponentDirt value) override; + +protected: + void cornerRadiusTLChanged() override; + void cornerRadiusTRChanged() override; + void cornerRadiusBLChanged() override; + void cornerRadiusBRChanged() override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/shapes/shape.hpp b/third_party/rive/include/rive/shapes/shape.hpp new file mode 100644 index 0000000..d28db0e --- /dev/null +++ b/third_party/rive/include/rive/shapes/shape.hpp @@ -0,0 +1,104 @@ +#ifndef _RIVE_SHAPE_HPP_ +#define _RIVE_SHAPE_HPP_ + +#include "rive/hit_info.hpp" +#include "rive/generated/shapes/shape_base.hpp" +#include "rive/animation/hittable.hpp" +#include "rive/shapes/path_composer.hpp" +#include "rive/shapes/shape_paint_container.hpp" +#include "rive/drawable_flag.hpp" +#include + +namespace rive +{ +class Path; +class PathComposer; +class HitTester; +class RenderPathDeformer; + +class Shape : public ShapeBase, public ShapePaintContainer, public Hittable +{ +private: + PathComposer m_PathComposer; + std::vector m_Paths; + AABB m_WorldBounds; + float m_WorldLength = -1; + + bool m_WantDifferencePath = false; + RenderPathDeformer* m_deformer = nullptr; + + Artboard* getArtboard() override { return artboard(); } + +public: + Shape(); + void buildDependencies() override; + bool collapse(bool value) override; + bool canDeferPathUpdate(); + void addPath(Path* path); + void addToRenderPath(RenderPath* commandPath, const Mat2D& transform); + std::vector& paths() { return m_Paths; } + + bool wantDifferencePath() const { return m_WantDifferencePath; } + + void update(ComponentDirt value) override; + void draw(Renderer* renderer) override; + Core* hitTest(HitInfo*, const Mat2D&) override; + + const PathComposer* pathComposer() const { return &m_PathComposer; } + PathComposer* pathComposer() { return &m_PathComposer; } + + RenderPathDeformer* deformer() const { return m_deformer; } + + void pathChanged(); + void addFlags(PathFlags flags); + bool isFlagged(PathFlags flags) const; + StatusCode onAddedDirty(CoreContext* context) override; + StatusCode onAddedClean(CoreContext* context) override; + bool isEmpty(); + void pathCollapseChanged(); + + float length() override; + void setLength(float value) override {} + + AABB worldBounds() + { + if ((static_cast(drawableFlags()) & + DrawableFlag::WorldBoundsClean) != DrawableFlag::WorldBoundsClean) + { + drawableFlags( + drawableFlags() | + static_cast(DrawableFlag::WorldBoundsClean)); + m_WorldBounds = computeWorldBounds(); + } + return m_WorldBounds; + } + void markBoundsDirty() + { + drawableFlags(drawableFlags() & ~static_cast( + DrawableFlag::WorldBoundsClean)); + m_WorldLength = -1; + } + + AABB computeWorldBounds(const Mat2D* xform = nullptr) const; + AABB computeLocalBounds() const; + Vec2D measureLayout(float width, + LayoutMeasureMode widthMode, + float height, + LayoutMeasureMode heightMode) override; + + bool hitTestAABB(const Vec2D& position) override; + bool hitTestHiFi(const Vec2D& position, float hitRadius) override; + // Implemented for ShapePaintContainer. + const Mat2D& shapeWorldTransform() const override + { + return worldTransform(); + } + + ShapePaintPath* worldPath() override; + ShapePaintPath* localPath() override; + ShapePaintPath* localClockwisePath() override; + Component* pathBuilder() override; +}; +} // namespace rive + +#endif diff --git a/third_party/rive/include/rive/shapes/shape_paint_container.hpp b/third_party/rive/include/rive/shapes/shape_paint_container.hpp new file mode 100644 index 0000000..6867bdf --- /dev/null +++ b/third_party/rive/include/rive/shapes/shape_paint_container.hpp @@ -0,0 +1,60 @@ +#ifndef _RIVE_SHAPE_PAINT_CONTAINER_HPP_ +#define _RIVE_SHAPE_PAINT_CONTAINER_HPP_ +#include "rive/refcnt.hpp" +#include "rive/shapes/path_flags.hpp" +#include "rive/shapes/shape_paint_path.hpp" +#include "rive/math/mat2d.hpp" +#include + +namespace rive +{ +class Artboard; +class ShapePaint; +class Component; + +class CommandPath; + +class ShapePaintContainer +{ + friend class ShapePaint; + +protected: + // Need this to access our artboard. We are treated as a mixin, either + // as a Shape or Artboard, so both of those will override this. + virtual Artboard* getArtboard() = 0; + + PathFlags m_pathFlags = PathFlags::none; + std::vector m_ShapePaints; + void addPaint(ShapePaint* paint); + +public: + static ShapePaintContainer* from(Component* component); + + /// The component that's responsible for path building, helpful for adding + /// dependencies after the paths are built. + virtual Component* pathBuilder() = 0; + + virtual ~ShapePaintContainer() {} + + PathFlags pathFlags() const; + + void invalidateStrokeEffects(); + + void propagateOpacity(float opacity); + + virtual const Mat2D& shapeWorldTransform() const = 0; + +#ifdef TESTING + const std::vector& shapePaints() const + { + return m_ShapePaints; + } +#endif + + virtual ShapePaintPath* worldPath() { return nullptr; } + virtual ShapePaintPath* localPath() { return nullptr; } + virtual ShapePaintPath* localClockwisePath() { return nullptr; } +}; +} // namespace rive + +#endif diff --git a/third_party/rive/include/rive/shapes/shape_paint_path.hpp b/third_party/rive/include/rive/shapes/shape_paint_path.hpp new file mode 100644 index 0000000..bcf6c26 --- /dev/null +++ b/third_party/rive/include/rive/shapes/shape_paint_path.hpp @@ -0,0 +1,86 @@ +#ifndef _RIVE_SHAPE_PAINT_PATH_HPP_ +#define _RIVE_SHAPE_PAINT_PATH_HPP_ + +#include "rive/math/raw_path.hpp" +#include "rive/renderer.hpp" + +namespace rive +{ +class Component; +class Factory; +class ShapePaintPath +{ +public: + ShapePaintPath(bool isLocal = true); + ShapePaintPath(bool isLocal, FillRule fillRule); + RenderPath* renderPath(const Component* component); + RenderPath* renderPath(Factory* factory); + const RawPath* rawPath() const { return &m_rawPath; } + RawPath* mutableRawPath() { return &m_rawPath; } + bool isLocal() const { return m_isLocal; } + FillRule fillRule() const { return m_fillRule; } + bool empty() const { return m_rawPath.empty(); } + + void rewind(); + void rewind(bool isLocal, FillRule fillRule) + { + m_isLocal = isLocal; + m_fillRule = fillRule; + rewind(); + } + void rewind(bool isLocal) + { + m_isLocal = isLocal; + rewind(); + } + void addPath(const RawPath& rawPath, const Mat2D* transform = nullptr); + void addPathBackwards(const RawPath& rawPath, + const Mat2D* transform = nullptr); + + // Determines winding of the rawPath and adds in the clockwise order. + void addPathClockwise(const RawPath& rawPath, + const Mat2D* transform = nullptr); + + void addPath(const ShapePaintPath* path, const Mat2D* transform = nullptr) + { + return addPath(*path->rawPath(), transform); + } + void addPathBackwards(const ShapePaintPath* path, + const Mat2D* transform = nullptr) + { + return addPathBackwards(*path->rawPath(), transform); + } + + void addRect(const AABB& aabb, PathDirection dir = PathDirection::cw) + { + m_rawPath.addRect(aabb, dir); + } + + const bool hasRenderPath() const + { + return m_renderPath != nullptr && !m_isRenderPathDirty; + } + +#ifdef TESTING + size_t numContours() + { + size_t contours = 0; + for (auto verb : m_rawPath.verbs()) + { + if (verb == PathVerb::move) + { + contours++; + } + } + return contours; + } +#endif +private: + bool m_isRenderPathDirty = true; + rcp m_renderPath; + RawPath m_rawPath; + bool m_isLocal; + FillRule m_fillRule = FillRule::clockwise; +}; +} // namespace rive +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/shapes/shape_path_flags.hpp b/third_party/rive/include/rive/shapes/shape_path_flags.hpp new file mode 100644 index 0000000..ba527ff --- /dev/null +++ b/third_party/rive/include/rive/shapes/shape_path_flags.hpp @@ -0,0 +1,18 @@ +#ifndef _RIVE_SHAPE_PATH_FLAGS_HPP_ +#define _RIVE_SHAPE_PATH_FLAGS_HPP_ + +#include "rive/rive_types.hpp" + +namespace rive +{ +enum class ShapePathFlags : uint8_t +{ + none = 0, + hidden = 1 << 0, // Unused at runtime + isCounterClockwise = 1 << 1, +}; + +RIVE_MAKE_ENUM_BITSET(ShapePathFlags) +} // namespace rive + +#endif diff --git a/third_party/rive/include/rive/shapes/slice_mesh.hpp b/third_party/rive/include/rive/shapes/slice_mesh.hpp new file mode 100644 index 0000000..3949675 --- /dev/null +++ b/third_party/rive/include/rive/shapes/slice_mesh.hpp @@ -0,0 +1,69 @@ +#ifndef _RIVE_SLICE_MESH_HPP_ +#define _RIVE_SLICE_MESH_HPP_ +#include "rive/shapes/mesh_drawable.hpp" +#include "rive/renderer.hpp" + +namespace rive +{ +class NSlicer; +enum class AxisType : int; + +struct SliceMeshVertex +{ + int id = -1; + Vec2D uv; + Vec2D vertex; +}; + +struct Corner +{ + int x; + int y; +}; + +// A temporary mesh that backs up an NSlicer. +class SliceMesh : public MeshDrawable +{ +private: + NSlicer* m_nslicer; + + // More readable representation of the render buffers. + std::vector m_uvs; + std::vector m_vertices; + std::vector m_indices; + + std::vector uvStops(AxisType forAxis); + std::vector vertexStops(const std::vector& normalizedStops, + AxisType forAxis); + + uint16_t tileRepeat(std::vector& vertices, + std::vector& indices, + const std::vector& box, + uint16_t start); + + // Update the member (non-render) buffers. + void calc(); + + // Copy the member (non-render) buffers into the render buffers. + void updateBuffers(); + + static const uint16_t triangulation[]; + static const Corner patchCorners[]; + bool isFixedSegment(int i) const; + +protected: +public: + SliceMesh(NSlicer* nslicer); + MeshType type() override { return MeshType::nslice; } + void draw(Renderer* renderer, + const RenderImage* image, + ImageSampler, + BlendMode blendMode, + float opacity) override; + void onAssetLoaded(RenderImage* renderImage) override; + + void update(); // not Component::update() as SliceMesh is not in core. +}; +} // namespace rive + +#endif diff --git a/third_party/rive/include/rive/shapes/star.hpp b/third_party/rive/include/rive/shapes/star.hpp new file mode 100644 index 0000000..903bd51 --- /dev/null +++ b/third_party/rive/include/rive/shapes/star.hpp @@ -0,0 +1,20 @@ +#ifndef _RIVE_STAR_HPP_ +#define _RIVE_STAR_HPP_ +#include "rive/generated/shapes/star_base.hpp" +#include +namespace rive +{ +class Star : public StarBase +{ +public: + Star(); + void update(ComponentDirt value) override; + +protected: + void innerRadiusChanged() override; + std::size_t vertexCount() override; + void buildPolygon() override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/shapes/straight_vertex.hpp b/third_party/rive/include/rive/shapes/straight_vertex.hpp new file mode 100644 index 0000000..ae0e4e3 --- /dev/null +++ b/third_party/rive/include/rive/shapes/straight_vertex.hpp @@ -0,0 +1,13 @@ +#ifndef _RIVE_STRAIGHT_VERTEX_HPP_ +#define _RIVE_STRAIGHT_VERTEX_HPP_ +#include "rive/generated/shapes/straight_vertex_base.hpp" +namespace rive +{ +class StraightVertex : public StraightVertexBase +{ +protected: + void radiusChanged() override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/shapes/triangle.hpp b/third_party/rive/include/rive/shapes/triangle.hpp new file mode 100644 index 0000000..ff44a5b --- /dev/null +++ b/third_party/rive/include/rive/shapes/triangle.hpp @@ -0,0 +1,19 @@ +#ifndef _RIVE_TRIANGLE_HPP_ +#define _RIVE_TRIANGLE_HPP_ +#include "rive/generated/shapes/triangle_base.hpp" +#include "rive/shapes/straight_vertex.hpp" + +namespace rive +{ +class Triangle : public TriangleBase +{ +private: + StraightVertex m_Vertex1, m_Vertex2, m_Vertex3; + +public: + Triangle(); + void update(ComponentDirt value) override; +}; +} // namespace rive + +#endif diff --git a/third_party/rive/include/rive/shapes/vertex.hpp b/third_party/rive/include/rive/shapes/vertex.hpp new file mode 100644 index 0000000..9550195 --- /dev/null +++ b/third_party/rive/include/rive/shapes/vertex.hpp @@ -0,0 +1,35 @@ +#ifndef _RIVE_VERTEX_HPP_ +#define _RIVE_VERTEX_HPP_ +#include "rive/bones/weight.hpp" +#include "rive/generated/shapes/vertex_base.hpp" +#include "rive/math/mat2d.hpp" +namespace rive +{ +class Vertex : public VertexBase +{ + friend class Weight; + +private: + Weight* m_Weight = nullptr; + void weight(Weight* value) { m_Weight = value; } + +public: + template T* weight() { return m_Weight->as(); } + virtual void deform(const Mat2D& worldTransform, + const float* boneTransforms); + bool hasWeight() { return m_Weight != nullptr; } + Vec2D renderTranslation(); + +protected: + virtual void markGeometryDirty() = 0; + void xChanged() override; + void yChanged() override; + +#ifdef TESTING +public: + Weight* weight() { return m_Weight; } +#endif +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/simple_array.hpp b/third_party/rive/include/rive/simple_array.hpp new file mode 100644 index 0000000..57a0506 --- /dev/null +++ b/third_party/rive/include/rive/simple_array.hpp @@ -0,0 +1,261 @@ +/* + * Copyright 2022 Rive + */ + +#ifndef _RIVE_SIMPLE_ARRAY_HPP_ +#define _RIVE_SIMPLE_ARRAY_HPP_ + +#include "rive/rive_types.hpp" + +#include +#include +#include +#include + +namespace rive +{ + +template class SimpleArrayBuilder; + +#ifdef TESTING +namespace SimpleArrayTesting +{ +extern int mallocCount; +extern int reallocCount; +extern int freeCount; +void resetCounters(); +} // namespace SimpleArrayTesting +#endif + +// Helper for constructing and destructing arrays of objects. +template ()> class SimpleArrayHelper +{ +public: + static_assert(!std::is_pod(), "This helper is for non-POD types."); + static void DefaultConstructArray(T* ptr, T* end) + { + for (; ptr < end; ++ptr) + new (ptr) T(); + } + static void CopyConstructArray(const T* first, const T* end, T* ptr) + { + for (; first < end; ++first, ++ptr) + new (ptr) T(*first); + } + static void DestructArray(T* ptr, T* end) + { + for (; ptr < end; ++ptr) + ptr->~T(); + } +}; + +// Specialized helper for constructing and destructing arrays of POD objects. +template class SimpleArrayHelper +{ +public: + static_assert(std::is_pod(), "This helper is only for POD types."); + static void DefaultConstructArray(T* ptr, T* end) {} + static void CopyConstructArray(const T* first, const T* end, T* ptr) + { + memcpy(ptr, + first, + reinterpret_cast(end) - + reinterpret_cast(first)); + } + static void DestructArray(T* ptr, T* end) {} +}; + +/// Lightweight heap array meant to be used when knowing the exact memory layout +/// of the simple array is necessary, like marshaling the data to Dart/C#/Wasm. +/// Note that it intentionally doesn't have push/add/resize functionality as +/// that's reserved for a special case builder that should be to build up the +/// array. This saves the structure from needing to store extra ptrs and keeps +/// it optimally sized for marshaling. See SimpleArrayBuilder below for push +/// functionality. + +template class SimpleArray +{ +public: + SimpleArray() : m_ptr(nullptr), m_size(0) {} + SimpleArray(size_t size) : + m_ptr(static_cast(malloc(size * sizeof(T)))), m_size(size) + { + SimpleArrayHelper::DefaultConstructArray(m_ptr, m_ptr + m_size); +#ifdef TESTING + SimpleArrayTesting::mallocCount++; +#endif + } + SimpleArray(const T* ptr, size_t size) : SimpleArray(size) + { + assert(ptr <= ptr + size); + SimpleArrayHelper::CopyConstructArray(ptr, ptr + size, m_ptr); + } + + constexpr SimpleArray(const SimpleArray& other) : + SimpleArray(other.m_ptr, other.m_size) + {} + + SimpleArray(SimpleArray&& other) : + m_ptr(other.m_ptr), m_size(other.m_size) + { + other.m_ptr = nullptr; + other.m_size = 0; + } + + SimpleArray(SimpleArrayBuilder&& other); + + SimpleArray& operator=(const SimpleArray& other) = delete; + + SimpleArray& operator=(SimpleArray&& other) + { + SimpleArrayHelper::DestructArray(m_ptr, m_ptr + m_size); + free(m_ptr); + m_ptr = other.m_ptr; + m_size = other.m_size; + other.m_ptr = nullptr; + other.m_size = 0; + return *this; + } + + SimpleArray& operator=(SimpleArrayBuilder&& other); + + template + constexpr SimpleArray(Container& c) : SimpleArray(c.data(), c.size()) + {} + constexpr SimpleArray(const std::initializer_list& il) : + SimpleArray(il.begin(), il.size()) + {} + ~SimpleArray() + { + SimpleArrayHelper::DestructArray(m_ptr, m_ptr + m_size); + free(m_ptr); +#ifdef TESTING + SimpleArrayTesting::freeCount++; +#endif + } + + T& operator[](size_t index) const { return m_ptr[index]; } + + constexpr T* data() const { return m_ptr; } + constexpr size_t size() const { return m_size; } + constexpr bool empty() const { return m_size == 0; } + + constexpr T* begin() const { return m_ptr; } + constexpr T* end() const { return m_ptr + m_size; } + + constexpr T& front() const { return (*this)[0]; } + constexpr T& back() const { return (*this)[m_size - 1]; } + + // returns byte-size of the entire simple array + constexpr size_t size_bytes() const { return m_size * sizeof(T); } + + // Makes rive::SimpleArray std::Container compatible + // https://en.cppreference.com/w/cpp/named_req/Container + typedef typename std::remove_cv::type value_type; + typedef T& reference; + typedef T const& const_reference; + typedef T* iterator; + typedef T const* const_iterator; + typedef std::ptrdiff_t difference_type; + typedef size_t size_type; + +protected: + T* m_ptr; + size_t m_size; +}; + +/// Extension of SimpleArray which can progressively expand as contents are +/// pushed/added/written to it. Can be released as a simple SimpleArray. +template class SimpleArrayBuilder : public SimpleArray +{ + friend class SimpleArray; + +public: + SimpleArrayBuilder(size_t reserve) : SimpleArray(reserve) + { + assert(this->m_ptr <= this->m_ptr + this->m_size); + m_write = this->m_ptr; + } + + SimpleArrayBuilder() : SimpleArrayBuilder(0) {} + + void add(const T& value) + { + growToFit(); + *m_write++ = value; + } + + void add(T&& value) + { + growToFit(); + *m_write++ = std::move(value); + } + + // Allows iterating just the written content. + constexpr size_t capacity() const { return this->m_size; } + constexpr size_t size() const { return m_write - this->m_ptr; } + constexpr bool empty() const { return size() == 0; } + constexpr T* begin() const { return this->m_ptr; } + constexpr T* end() const { return m_write; } + + constexpr T& front() const { return (*this)[0]; } + constexpr T& back() const { return *(m_write - 1); } + +private: + void growToFit() + { + if (m_write == this->m_ptr + this->m_size) + { + auto writeOffset = m_write - this->m_ptr; + this->resize(std::max((size_t)1, this->m_size * 2)); + m_write = this->m_ptr + writeOffset; + } + } + + void resize(size_t size) + { + if (size == this->m_size) + { + return; + } +#ifdef TESTING + SimpleArrayTesting::reallocCount++; +#endif + // Call destructor for elements when sizing down. + SimpleArrayHelper::DestructArray(this->m_ptr + size, + this->m_ptr + this->m_size); + this->m_ptr = static_cast(realloc(this->m_ptr, size * sizeof(T))); + // Call constructor for elements when sizing up. + SimpleArrayHelper::DefaultConstructArray(this->m_ptr + this->m_size, + this->m_ptr + size); + this->m_size = size; + } + + T* m_write; +}; + +template SimpleArray::SimpleArray(SimpleArrayBuilder&& other) +{ + // Bring the capacity down to the actual size (this should keep the same + // ptr, but that's not guaranteed, so we copy the ptr after the realloc). + other.resize(other.size()); + m_ptr = other.m_ptr; + m_size = other.m_size; + other.m_ptr = nullptr; + other.m_size = 0; +} + +template +SimpleArray& SimpleArray::operator=(SimpleArrayBuilder&& other) +{ + other.resize(other.size()); + this->m_ptr = other.m_ptr; + this->m_size = other.m_size; + other.m_ptr = nullptr; + other.m_size = 0; + return *this; +} + +} // namespace rive + +#endif diff --git a/third_party/rive/include/rive/solo.hpp b/third_party/rive/include/rive/solo.hpp new file mode 100644 index 0000000..8458d76 --- /dev/null +++ b/third_party/rive/include/rive/solo.hpp @@ -0,0 +1,18 @@ +#ifndef _RIVE_SOLO_HPP_ +#define _RIVE_SOLO_HPP_ +#include "rive/generated/solo_base.hpp" +namespace rive +{ +class Solo : public SoloBase +{ +public: + void activeComponentIdChanged() override; + StatusCode onAddedClean(CoreContext* context) override; + bool collapse(bool value) override; + +private: + void propagateCollapse(bool collapse); +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/span.hpp b/third_party/rive/include/rive/span.hpp new file mode 100644 index 0000000..b130277 --- /dev/null +++ b/third_party/rive/include/rive/span.hpp @@ -0,0 +1,104 @@ +/* + * Copyright 2022 Rive + */ + +#ifndef _RIVE_SPAN_HPP_ +#define _RIVE_SPAN_HPP_ + +#include "rive/rive_types.hpp" + +#include +#include +#include + +/* + * Span : cheap impl of std::span (which is C++20) + * + * Inspired by Skia's SkSpan + */ + +namespace rive +{ + +template class Span +{ + T* m_Ptr; + size_t m_Size; + +public: + Span() : m_Ptr(nullptr), m_Size(0) {} + Span(T* ptr, size_t size) : m_Ptr(ptr), m_Size(size) + { + assert(ptr <= ptr + size); + } + + // Handle Span --> Span + template ::value>::type> + constexpr Span(const Span& that) : Span(that.data(), that.size()) + {} + template + constexpr Span(Container& c) : Span(c.data(), c.size()) + {} + + T& operator[](size_t index) const + { + assert(index < m_Size); + return m_Ptr[index]; + } + + constexpr T* data() const { return m_Ptr; } + constexpr size_t size() const { return m_Size; } + constexpr bool empty() const { return m_Size == 0; } + + constexpr T* begin() const { return m_Ptr; } + constexpr T* end() const { return m_Ptr + m_Size; } + + constexpr T& front() const { return (*this)[0]; } + constexpr T& back() const { return (*this)[m_Size - 1]; } + + // returns byte-size of the entire span + constexpr size_t size_bytes() const { return m_Size * sizeof(T); } + + constexpr size_t count() const { return m_Size; } + + Span subset(size_t offset, size_t size) const + { + assert(offset <= m_Size); + assert(size <= m_Size - offset); + return {m_Ptr + offset, size}; + } + + // Makes rive::Span std::Container compatible + // https://en.cppreference.com/w/cpp/named_req/Container + typedef typename std::remove_cv::type value_type; + typedef T& reference; + typedef T const& const_reference; + typedef T* iterator; + typedef T const* const_iterator; + typedef std::ptrdiff_t difference_type; + typedef size_t size_type; + + bool operator!=(const Span& that) const + { + return m_Ptr != that.m_Ptr || m_Size != that.m_Size; + } + bool operator==(const Span& that) const + { + return m_Ptr == that.m_Ptr && m_Size == that.m_Size; + } +}; + +template Span make_span(T* ptr, size_t size) +{ + return Span(ptr, size); +} + +template Span make_span(T (&ptr)[N]) +{ + return Span(ptr, N); +} +} // namespace rive + +#endif diff --git a/third_party/rive/include/rive/static_scene.hpp b/third_party/rive/include/rive/static_scene.hpp new file mode 100644 index 0000000..63147f8 --- /dev/null +++ b/third_party/rive/include/rive/static_scene.hpp @@ -0,0 +1,26 @@ +#ifndef _RIVE_STATIC_SCENE_HPP_ +#define _RIVE_STATIC_SCENE_HPP_ + +#include "rive/artboard.hpp" +#include "rive/scene.hpp" + +namespace rive +{ +class StaticScene : public Scene +{ +public: + StaticScene(ArtboardInstance*); + ~StaticScene() override; + + bool isTranslucent() const override; + + std::string name() const override; + + Loop loop() const override; + + float durationSeconds() const override; + + bool advanceAndApply(float seconds) override; +}; +} // namespace rive +#endif diff --git a/third_party/rive/include/rive/status_code.hpp b/third_party/rive/include/rive/status_code.hpp new file mode 100644 index 0000000..a7967ea --- /dev/null +++ b/third_party/rive/include/rive/status_code.hpp @@ -0,0 +1,16 @@ +#ifndef _RIVE_STATUS_CODE_HPP_ +#define _RIVE_STATUS_CODE_HPP_ + +#include "rive/rive_types.hpp" + +namespace rive +{ +enum class StatusCode : unsigned char +{ + Ok, + MissingObject, + InvalidObject, + FailedInversion +}; +} +#endif diff --git a/third_party/rive/include/rive/text/cursor.hpp b/third_party/rive/include/rive/text/cursor.hpp new file mode 100644 index 0000000..24da500 --- /dev/null +++ b/third_party/rive/include/rive/text/cursor.hpp @@ -0,0 +1,209 @@ +#ifndef _RIVE_CURSOR_HPP_ +#define _RIVE_CURSOR_HPP_ + +#ifdef WITH_RIVE_TEXT +#include +#include "rive/text_engine.hpp" +#include "rive/text/glyph_lookup.hpp" +#include "rive/text/fully_shaped_text.hpp" + +#include + +namespace rive +{ +class ShapePaintPath; + +class CursorVisualPosition +{ +public: + static CursorVisualPosition missing() { return CursorVisualPosition(); } + + CursorVisualPosition(float x, float top, float bottom) : + m_found(true), m_x(x), m_top(top), m_bottom(bottom) + {} + + bool found() const { return m_found; } + float x() const { return m_x; } + float top() const { return m_top; } + float bottom() const { return m_bottom; } + +private: + CursorVisualPosition() : + m_found(false), m_x(0.0f), m_top(0.0f), m_bottom(0.0f) + {} + + bool m_found; + float m_x; + float m_top; + float m_bottom; +}; + +class CursorPosition +{ +public: + CursorPosition(uint32_t lineIndex, uint32_t codePointIndex) : + m_lineIndex(lineIndex), m_codePointIndex(codePointIndex) + {} + + CursorPosition(uint32_t codePointIndex) : + m_lineIndex(-1), m_codePointIndex(codePointIndex) + {} + + uint32_t lineIndex() const { return m_lineIndex; } + uint32_t lineIndex(int32_t inc) const; + uint32_t codePointIndex() const { return m_codePointIndex; } + uint32_t codePointIndex(int32_t inc) const; + + static CursorPosition zero() { return CursorPosition(0, 0); } + + CursorPosition& operator+=(uint32_t v) + { + m_codePointIndex += v; + return *this; + } + + CursorPosition& operator-=(uint32_t v) + { + if (m_codePointIndex >= v) + { + m_codePointIndex -= v; + } + else + { + m_codePointIndex = 0; + } + return *this; + } + + bool hasLineIndex() const { return m_lineIndex != -1; } + + // Find the closest lineIndex() for the codePointIndex(). + void resolveLine(const FullyShapedText& shape); + + CursorVisualPosition visualPosition(const FullyShapedText& shape) const; + + // Move this cursor to the given translation and return the visual position. + static CursorPosition fromTranslation(const Vec2D translation, + const FullyShapedText& shape); + + static CursorPosition fromLineX(uint32_t lineIndex, + float x, + const FullyShapedText& shape); + + static CursorPosition atIndex(uint32_t codePointIndex, + const FullyShapedText& shape); + + CursorPosition clamped(const FullyShapedText& shape) const; + +private: + static CursorPosition fromOrderedLine(const OrderedLine& orderedLine, + uint32_t lineIndex, + float translationX, + const FullyShapedText& shape); + uint32_t m_lineIndex; + uint32_t m_codePointIndex; +}; + +// Add an offset to the code point index of the cursor and return a cursor with +// undetermined line. +inline CursorPosition operator+(const CursorPosition& cursor, + const int32_t offset) +{ + return CursorPosition(cursor.codePointIndex(offset)); +} + +inline CursorPosition operator-(const CursorPosition& cursor, + const int32_t offset) +{ + return CursorPosition(cursor.codePointIndex(-offset)); +} + +inline bool operator==(const CursorPosition& a, const CursorPosition& b) +{ + return a.lineIndex() == b.lineIndex() && + a.codePointIndex() == b.codePointIndex(); +} + +inline bool operator!=(const CursorPosition& a, const CursorPosition& b) +{ + return a.lineIndex() != b.lineIndex() || + a.codePointIndex() != b.codePointIndex(); +} + +inline bool operator<(const CursorPosition& a, const CursorPosition& b) +{ + return a.codePointIndex() < b.codePointIndex(); +} + +inline bool operator>(const CursorPosition& a, const CursorPosition& b) +{ + return a.codePointIndex() > b.codePointIndex(); +} + +inline bool operator<=(const CursorPosition& a, const CursorPosition& b) +{ + return a.codePointIndex() <= b.codePointIndex(); +} + +inline bool operator>=(const CursorPosition& a, const CursorPosition& b) +{ + return a.codePointIndex() >= b.codePointIndex(); +} + +class Cursor +{ +public: + Cursor(CursorPosition start, CursorPosition end) : + m_start(start), m_end(end) + {} + + static Cursor collapsed(CursorPosition position) + { + return Cursor(position, position); + } + + static Cursor zero() { return Cursor::collapsed(CursorPosition::zero()); } + + static Cursor atStart() + { + return Cursor(CursorPosition::zero(), CursorPosition::zero()); + } + + CursorPosition start() const { return m_start; } + CursorPosition end() const { return m_end; } + + CursorPosition first() const { return m_start < m_end ? m_start : m_end; } + CursorPosition last() const { return m_start < m_end ? m_end : m_start; } + + bool isCollapsed() const { return m_start == m_end; } + bool hasSelection() const { return m_start != m_end; } + + void selectionRects(std::vector& rects, + const FullyShapedText& shape) const; + + void updateSelectionPath(ShapePaintPath& path, + const std::vector& rects, + const FullyShapedText& shape) const; + + bool resolveLinePositions(const FullyShapedText& shape); + + bool contains(uint32_t codePointIndex) const; + +private: + CursorPosition m_start; + CursorPosition m_end; +}; + +inline bool operator==(const Cursor& a, const Cursor& b) +{ + return a.start() == b.start() && a.end() == b.end(); +} + +inline bool operator!=(const Cursor& a, const Cursor& b) +{ + return a.start() != b.start() || a.end() != b.end(); +} +} // namespace rive + +#endif +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/text/font_hb.hpp b/third_party/rive/include/rive/text/font_hb.hpp new file mode 100644 index 0000000..a63d98b --- /dev/null +++ b/third_party/rive/include/rive/text/font_hb.hpp @@ -0,0 +1,76 @@ +#ifndef _RIVE_FONT_HB_HPP_ +#define _RIVE_FONT_HB_HPP_ + +#include "rive/factory.hpp" +#include "rive/text_engine.hpp" + +#include + +struct hb_font_t; +struct hb_draw_funcs_t; +struct hb_feature_t; + +class HBFont : public rive::Font +{ +public: + // We assume ownership of font! + HBFont(hb_font_t* font); + ~HBFont() override; + + Axis getAxis(uint16_t index) const override; + uint16_t getAxisCount() const override; + float getAxisValue(uint32_t axisTag) const override; + uint32_t getFeatureValue(uint32_t featureTag) const override; + uint16_t getWeight() const override; + bool isItalic() const override; + + rive::RawPath getPath(rive::GlyphID) const override; + rive::SimpleArray onShapeText( + rive::Span, + rive::Span, + int textDirectionFlag) const override; + rive::SimpleArray features() const override; + rive::rcp withOptions( + rive::Span variableAxes, + rive::Span features) const override; + + bool hasGlyph(const rive::Unichar) const override; + + static rive::rcp Decode(rive::Span); + static rive::rcp FromSystem(void* systemFont, + bool useSystemShaper, + uint16_t weight, + uint8_t width); + static float GetStyle(hb_font_t*, uint32_t); + hb_font_t* font() const { return m_font; } + +private: + HBFont(hb_font_t* font, + std::unordered_map axisValues, + std::unordered_map featureValues, + std::vector features); + +public: + hb_font_t* m_font; + virtual void shapeFallbackRun( + rive::SimpleArrayBuilder& gruns, + const rive::Unichar text[], + const unsigned textStart, + const rive::TextRun& textRun, + const rive::TextRun& originalTextRun, + const uint32_t fallbackIndex); + + // The features list to pass directly to Harfbuzz. + std::vector m_features; + +private: + hb_draw_funcs_t* m_drawFuncs; + + // Feature value lookup based on tag. + std::unordered_map m_featureValues; + + // Axis value lookup based on for the feature. + std::unordered_map m_axisValues; +}; + +#endif diff --git a/third_party/rive/include/rive/text/fully_shaped_text.hpp b/third_party/rive/include/rive/text/fully_shaped_text.hpp new file mode 100644 index 0000000..7a442f8 --- /dev/null +++ b/third_party/rive/include/rive/text/fully_shaped_text.hpp @@ -0,0 +1,61 @@ +#ifndef _RIVE_FULLY_SHAPED_TEXT_HPP_ +#define _RIVE_FULLY_SHAPED_TEXT_HPP_ + +#include "rive/span.hpp" +#include "rive/text/utf.hpp" +#include "rive/text_engine.hpp" +#include "rive/text/glyph_lookup.hpp" + +namespace rive +{ +// Structure containing all the necessary data to interact with (draw/edit) +// a block (multiple paragraphs) of text. +class FullyShapedText +{ +public: + // Paragraphs as returned by the shaper. + const SimpleArray& paragraphs() const { return m_paragraphs; } + + // Lines as computed by the line breaker. + const SimpleArray>& paragraphLines() const + { + return m_paragraphLines; + } + + // Lines with glyphs re-ordered into visual (bidi dictated) order. + const std::vector& orderedLines() const + { + return m_orderedLines; + } + + // Lookup table finding glyphs by text index. + const GlyphLookup& glyphLookup() const { return m_glyphLookup; } + + const AABB& bounds() const { return m_bounds; } + + bool hasValidBounds() const { return !m_bounds.isEmptyOrNaN(); } + + uint32_t lineCount() const { return (uint32_t)m_orderedLines.size(); } + + void shape(Span text, + Span runs, + TextSizing sizing, + float maxWidth, + float maxHeight, + TextAlign alignment, + TextWrap wrap, + TextOrigin origin, + TextOverflow overflow, + float paragraphSpacing); + +private: + SimpleArray m_paragraphs; + SimpleArray> m_paragraphLines; + std::vector m_orderedLines; + GlyphLookup m_glyphLookup; + GlyphRun m_ellipsisRun; + AABB m_bounds; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/text/glyph_lookup.hpp b/third_party/rive/include/rive/text/glyph_lookup.hpp new file mode 100644 index 0000000..9286619 --- /dev/null +++ b/third_party/rive/include/rive/text/glyph_lookup.hpp @@ -0,0 +1,47 @@ +#ifndef _RIVE_TEXT_GLYPH_LOOKUP_HPP_ +#define _RIVE_TEXT_GLYPH_LOOKUP_HPP_ +#include "rive/text_engine.hpp" +#include +#include + +namespace rive +{ + +/// Stores the glyphId/Index representing the unicode point at i. +class GlyphLookup +{ +public: + void compute(Span text, const SimpleArray& shape); + +private: + std::vector m_glyphIndices; + +public: + uint32_t count(uint32_t index) const; + size_t size() const { return m_glyphIndices.size(); } + + // Returns the glyph index from the computed shape given the codePointIndex + // in the original text. + uint32_t operator[](uint32_t codePointIndex) const + { + assert(codePointIndex >= 0 && + codePointIndex < (uint32_t)m_glyphIndices.size()); + return m_glyphIndices[codePointIndex]; + } + + uint32_t lastCodeUnitIndex() const + { + return m_glyphIndices.size() == 0 + ? 0 + : (uint32_t)(m_glyphIndices.size() - 1); + } + + bool empty() const { return m_glyphIndices.empty(); } + void clear() { m_glyphIndices.clear(); } + + // How far this codePoint index is within the glyph. + float advanceFactor(int32_t codePointIndex, bool inv) const; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/text/raw_text.hpp b/third_party/rive/include/rive/text/raw_text.hpp new file mode 100644 index 0000000..36b687e --- /dev/null +++ b/third_party/rive/include/rive/text/raw_text.hpp @@ -0,0 +1,98 @@ +#ifndef _RIVE_RENDER_TEXT_HPP_ +#define _RIVE_RENDER_TEXT_HPP_ + +#ifdef WITH_RIVE_TEXT + +#include "rive/text/text.hpp" + +namespace rive +{ +class Factory; + +class RawText +{ +public: + RawText(Factory* factory); + + /// Returns true if the text object contains no text. + bool empty() const; + + /// Appends a run to the text object. + void append(const std::string& text, + rcp paint, + rcp font, + float size = 16.0f, + float lineHeight = -1.0f, + float letterSpacing = 0.0f); + + /// Resets the text object to empty state (no text). + void clear(); + + /// Draw the text using renderer. Second argument is optional to override + /// all paints provided with run styles + void render(Renderer* renderer, rcp paint = nullptr); + + TextSizing sizing() const; + TextOverflow overflow() const; + TextAlign align() const; + float maxWidth() const; + float maxHeight() const; + float paragraphSpacing() const; + + void sizing(TextSizing value); + + /// How text that overflows when TextSizing::fixed is used. + void overflow(TextOverflow value); + + /// How text aligns within the bounds. + void align(TextAlign value); + + /// The width at which the text will wrap when using any sizing but + /// TextSizing::auto. + void maxWidth(float value); + + /// The height at which the text will overflow when using TextSizing::fixed. + void maxHeight(float value); + + /// The vertical space between paragraphs delineated by a return character. + void paragraphSpacing(float value); + + /// Returns the bounds of the text object (helpful for aligning multiple + /// text objects/procredurally drawn shapes). + AABB bounds(); + +private: + void update(); + struct RenderStyle + { + rcp paint; + bool isEmpty; + ShapePaintPath path; + }; + SimpleArray m_shape; + SimpleArray> m_lines; + + StyledText m_styled; + Factory* m_factory; + std::vector m_styles; + std::vector m_renderStyles; + bool m_dirty = false; + float m_paragraphSpacing = 0.0f; + + TextOrigin m_origin = TextOrigin::top; + TextSizing m_sizing = TextSizing::autoWidth; + TextOverflow m_overflow = TextOverflow::visible; + TextAlign m_align = TextAlign::left; + TextWrap m_wrap = TextWrap::wrap; + float m_maxWidth = 0.0f; + float m_maxHeight = 0.0f; + std::vector m_orderedLines; + GlyphRun m_ellipsisRun; + AABB m_bounds; + rcp m_clipRenderPath; +}; +} // namespace rive + +#endif // WITH_RIVE_TEXT + +#endif diff --git a/third_party/rive/include/rive/text/raw_text_input.hpp b/third_party/rive/include/rive/text/raw_text_input.hpp new file mode 100644 index 0000000..cf177eb --- /dev/null +++ b/third_party/rive/include/rive/text/raw_text_input.hpp @@ -0,0 +1,235 @@ +#ifndef _RIVE_RAW_TEXT_INPUT_HPP_ +#define _RIVE_RAW_TEXT_INPUT_HPP_ + +#ifdef WITH_RIVE_TEXT +#include "rive/text/cursor.hpp" +#include "rive/text/text.hpp" +#include "rive/text/fully_shaped_text.hpp" +#include "rive/text/text_selection_path.hpp" + +namespace rive +{ +class Factory; + +enum class CursorBoundary : uint8_t +{ + character, + word, + subWord, + line +}; + +class RawTextInput +{ +public: +#ifdef TESTING + uint32_t measureCount = 0; +#endif + RawTextInput(); + + void draw(Factory* factory, + Renderer* renderer, + const Mat2D& worldTransform, + RenderPaint* textPaint, + RenderPaint* selectionPaint, + RenderPaint* cursorPaint); + + float fontSize() const { return m_textRun.size; } + void fontSize(float value); + + float maxWidth() const { return m_maxWidth; } + void maxWidth(float value); + + float maxHeight() const { return m_maxHeight; } + void maxHeight(float value); + + TextSizing sizing() const { return m_sizing; } + void sizing(TextSizing value); + + TextOverflow overflow() const { return m_overflow; } + void overflow(TextOverflow value); + + rcp font() const { return m_textRun.font; } + void font(rcp value); + + float paragraphSpacing() const { return m_paragraphSpacing; } + void paragraphSpacing(float value); + + float selectionCornerRadius() const { return m_selectionCornerRadius; } + void selectionCornerRadius(float value); + + bool separateSelectionText() const; + void separateSelectionText(bool value); + + enum class Flags : uint8_t + { + none = 0, + shapeDirty = 1 << 0, + selectionDirty = 1 << 1, + separateSelectionText = 1 << 2, + measureDirty = 1 << 3 + }; + + Flags update(Factory* factory); + + ShapePaintPath* textPath() { return &m_textPath; } + ShapePaintPath* selectedTextPath() { return &m_selectedTextPath; } + ShapePaintPath* cursorPath() { return &m_cursorPath; } + ShapePaintPath* selectionPath() { return &m_selectionPath; } + rcp clipRenderPath() { return m_clipRenderPath; } + + /// Returns the bounds of the text object (helpful for aligning multiple + /// text objects/procredurally drawn shapes). + AABB bounds() const; + CursorVisualPosition cursorVisualPosition(CursorPosition position) + { + return position.visualPosition(m_shape); + } + + CursorVisualPosition cursorVisualPosition() const + { + return m_cursorVisualPosition; + } + + void insert(const std::string& text); + void insert(Unichar codePoint); + void erase(); + void backspace(int32_t direction); + + void cursorLeft(CursorBoundary boundary = CursorBoundary::character, + bool select = false); + void cursorRight(CursorBoundary boundary = CursorBoundary::character, + bool select = false); + void cursorUp(bool select = false); + void cursorDown(bool select = false); + + void moveCursorTo(Vec2D translation, bool select = false); + const FullyShapedText& shape() const { return m_shape; } + const Cursor cursor() const { return m_cursor; } + void cursor(Cursor value); + + // Selects the word at the cursor. + void selectWord(); + + std::string text() const; + void text(std::string value); + // Length of the input text. + size_t length() const; + + // Returns true if the input is empty. + bool empty() const; + + void undo(); + void redo(); + + AABB measure(float maxWidth, float maxHeight); + + enum class Delineator : uint8_t + { + unknown = 0, + lowercase = 1 << 0, + uppercase = 1 << 1, + symbol = 1 << 2, + underscore = 1 << 3, + whitespace = 1 << 4, + word = lowercase | uppercase | underscore, + any = + lowercase | uppercase | symbol | underscore | whitespace | lowercase + + }; + +private: + void captureJournalEntry(Cursor cursor); + void cursorHorizontal(int32_t offset, CursorBoundary boundary, bool select); + static Delineator classify(Unichar codepoint); + Delineator classify(CursorPosition position) const; + + // Hunt for a delineator bit maks from position in direction. Returns what + // was actually found. The position will be updated to the location where + // the Delineator was found. + Delineator find(uint8_t delineatorMask, + CursorPosition& position, + int32_t direction) const; + + CursorPosition findPosition(uint8_t delineatorMask, + const CursorPosition& position, + int32_t direction) const; + + const OrderedLine* orderedLine(CursorPosition position) const; + + void buildTextPaths(Factory* factory); + void computeVisualPositionFromCursor(); + void setTextPrivate(std::string value); + bool flagged(Flags mask) const; + bool unflag(Flags mask); + void flag(Flags mask); + + Cursor m_cursor; + TextRun m_textRun; + ShapePaintPath m_textPath; + ShapePaintPath m_selectedTextPath; + ShapePaintPath m_cursorPath; + TextSelectionPath m_selectionPath; + std::vector m_text; + + FullyShapedText m_shape; + std::unique_ptr m_measuringShape; + float m_lastMeasureMaxWidth = 0.0f; + float m_lastMeasureMaxHeight = 0.0f; + + Flags m_flags = Flags::none; + + float m_paragraphSpacing = 0.0f; + TextOrigin m_origin = TextOrigin::top; + TextSizing m_sizing = TextSizing::autoWidth; + TextOverflow m_overflow = TextOverflow::visible; + TextAlign m_align = TextAlign::left; + TextWrap m_wrap = TextWrap::wrap; + float m_maxWidth = 0.0f; + float m_maxHeight = 0.0f; + rcp m_clipRenderPath; + float m_idealCursorX = -1.0f; + + CursorVisualPosition m_cursorVisualPosition; + std::vector m_selectionRects; + + float m_selectionCornerRadius = 5.0f; + + struct JournalEntry + { + Cursor cursorFrom; + Cursor cursorTo; + std::string text; + }; + std::vector m_journal; + uint32_t m_journalIndex = 0; +}; + +// Helper for performing bitwise and with Delineator. +inline uint8_t operator&(const RawTextInput::Delineator& delineator, + const uint8_t mask) +{ + return (uint8_t)delineator & mask; +} + +inline uint8_t operator~(const RawTextInput::Delineator& delineator) +{ + return ~(uint8_t)delineator; +} + +inline RawTextInput::Delineator operator|(const RawTextInput::Delineator& a, + const RawTextInput::Delineator& b) +{ + return (RawTextInput::Delineator)((uint8_t)a | (uint8_t)b); +} + +inline RawTextInput::Delineator operator&(const RawTextInput::Delineator& a, + const RawTextInput::Delineator& b) +{ + return (RawTextInput::Delineator)((uint8_t)a & (uint8_t)b); +} +RIVE_MAKE_ENUM_BITSET(RawTextInput::Flags); +} // namespace rive + +#endif +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/text/text.hpp b/third_party/rive/include/rive/text/text.hpp new file mode 100644 index 0000000..91b3a38 --- /dev/null +++ b/third_party/rive/include/rive/text/text.hpp @@ -0,0 +1,194 @@ +#ifndef _RIVE_TEXT_CORE_HPP_ +#define _RIVE_TEXT_CORE_HPP_ +#include "rive/generated/text/text_base.hpp" +#include "rive/math/aabb.hpp" +#include "rive/text/text_value_run.hpp" +#include "rive/text_engine.hpp" +#include "rive/shapes/shape_paint_path.hpp" +#include "rive/simple_array.hpp" +#include "rive/text/glyph_lookup.hpp" +#include "rive/text/text_interface.hpp" + +#include +#include + +namespace rive +{ + +class TextModifierGroup; + +class StyledText +{ +private: + /// Represents the unicode characters making up the entire text string + /// displayed. Only valid after update. + std::vector m_value; + std::vector m_runs; + +public: + bool empty() const; + void clear(); + void append(rcp font, + float size, + float lineHeight, + float letterSpacing, + const std::string& text, + uint16_t styleId); + const std::vector& unichars() const { return m_value; } + const std::vector& runs() const { return m_runs; } + + void swapRuns(std::vector& otherRuns) { m_runs.swap(otherRuns); } +}; + +struct TextBoundsInfo +{ + float minY; + float maxWidth; + float totalHeight; + int ellipsisLine; + bool isEllipsisLineLast; +}; + +enum class LineIter : uint8_t +{ + drawLine, + skipThisLine, + yOutOfBounds +}; + +class TextStylePaint; +class Text : public TextBase, public TextInterface +{ +public: + // Implements TextInterface + void markShapeDirty() override; + void markPaintDirty() override; + + void draw(Renderer* renderer) override; + Core* hitTest(HitInfo*, const Mat2D&) override; + void addRun(TextValueRun* run); + void addModifierGroup(TextModifierGroup* group); + void markShapeDirty(bool sendToLayout); + void modifierShapeDirty(); + + void update(ComponentDirt value) override; + void onDirty(ComponentDirt value) override; + Mat2D m_transform; + Mat2D m_shapeWorldTransform; + + const Mat2D& shapeWorldTransform() const { return m_shapeWorldTransform; } + TextSizing sizing() const { return (TextSizing)sizingValue(); } + TextSizing effectiveSizing() const; + TextOverflow overflow() const { return (TextOverflow)overflowValue(); } + TextOrigin textOrigin() const { return (TextOrigin)originValue(); } + TextWrap wrap() const { return (TextWrap)wrapValue(); } + VerticalTextAlign verticalAlign() const + { + return (VerticalTextAlign)verticalAlignValue(); + } + TextAlign align() const; + void overflow(TextOverflow value) { return overflowValue((uint32_t)value); } + void buildRenderStyles(); + const TextStylePaint* styleFromShaperId(uint16_t id) const; + bool modifierRangesNeedShape() const; + AABB localBounds() const override; + void originXChanged() override; + void originYChanged() override; + + Vec2D measureLayout(float width, + LayoutMeasureMode widthMode, + float height, + LayoutMeasureMode heightMode) override; + void controlSize(Vec2D size, + LayoutScaleType widthScaleType, + LayoutScaleType heightScaleType, + LayoutDirection direction) override; + float effectiveWidth() + { + return std::isnan(m_layoutWidth) ? width() : m_layoutWidth; + } + float effectiveHeight() + { + return std::isnan(m_layoutHeight) ? height() : m_layoutHeight; + } + float computedWidth() override { return localBounds().width(); }; + float computedHeight() override { return localBounds().height(); }; +#ifdef WITH_RIVE_TEXT + const std::vector& runs() const { return m_runs; } + static SimpleArray> BreakLines( + const SimpleArray& paragraphs, + float width, + TextAlign align, + TextWrap wrap); +#endif + + bool haveModifiers() const + { +#ifdef WITH_RIVE_TEXT + return !m_modifierGroups.empty(); +#else + return false; +#endif + } +#ifdef TESTING + const std::vector& orderedLines() const + { + return m_orderedLines; + } + const std::vector& modifierGroups() const + { + return m_modifierGroups; + } + const SimpleArray& shape() const { return m_shape; } + const std::vector& unichars() const + { + return m_styledText.unichars(); + } +#endif + +protected: + void alignValueChanged() override; + void sizingValueChanged() override; + void overflowValueChanged() override; + void widthChanged() override; + void heightChanged() override; + void paragraphSpacingChanged() override; + bool makeStyled(StyledText& styledText, bool withModifiers = true) const; + void originValueChanged() override; + +private: +#ifdef WITH_RIVE_TEXT + void updateOriginWorldTransform(); + std::vector m_runs; + std::vector m_renderStyles; + SimpleArray m_shape; + SimpleArray m_modifierShape; + SimpleArray> m_lines; + SimpleArray> m_modifierLines; + // Runs ordered by paragraph line. + std::vector m_orderedLines; + GlyphRun m_ellipsisRun; + RawPath m_clipRect; + ShapePaintPath m_clipPath; + AABB m_bounds; + std::vector m_modifierGroups; + + StyledText m_styledText; + StyledText m_modifierStyledText; + GlyphLookup m_glyphLookup; + + void clearRenderStyles(); + TextBoundsInfo computeBoundsInfo(); + LineIter shouldDrawLine(float y, float totalHeight, const GlyphLine& line); + +#endif + float m_layoutWidth = NAN; + float m_layoutHeight = NAN; + uint8_t m_layoutWidthScaleType = std::numeric_limits::max(); + uint8_t m_layoutHeightScaleType = std::numeric_limits::max(); + LayoutDirection m_layoutDirection = LayoutDirection::inherit; + Vec2D measure(Vec2D maxSize); +}; +} // namespace rive + +#endif diff --git a/third_party/rive/include/rive/text/text_follow_path_modifier.hpp b/third_party/rive/include/rive/text/text_follow_path_modifier.hpp new file mode 100644 index 0000000..c1254c5 --- /dev/null +++ b/third_party/rive/include/rive/text/text_follow_path_modifier.hpp @@ -0,0 +1,37 @@ +#ifndef _RIVE_TEXT_FOLLOW_PATH_MODIFIER_HPP_ +#define _RIVE_TEXT_FOLLOW_PATH_MODIFIER_HPP_ +#include "rive/generated/text/text_follow_path_modifier_base.hpp" +#include "rive/math/path_measure.hpp" +#include "rive/math/transform_components.hpp" +namespace rive +{ +struct TransformGlyphArg; +class TextFollowPathModifier : public TextFollowPathModifierBase +{ +public: + void buildDependencies() override; + StatusCode onAddedClean(CoreContext* context) override; + void update(ComponentDirt value) override; + + void reset(const Mat2D* inverseText); + TransformComponents transformGlyph(const TransformComponents& cur, + const TransformGlyphArg& arg); + +protected: + void radialChanged() override; + void orientChanged() override; + void startChanged() override; + void endChanged() override; + void offsetChanged() override; + void strengthChanged() override; + +private: + RawPath m_worldPath; + RawPath m_localPath; + PathMeasure m_pathMeasure; + + void modifierShapeDirty(); +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/text/text_input.hpp b/third_party/rive/include/rive/text/text_input.hpp new file mode 100644 index 0000000..e550c52 --- /dev/null +++ b/third_party/rive/include/rive/text/text_input.hpp @@ -0,0 +1,50 @@ +#ifndef _RIVE_TEXT_INPUT_HPP_ +#define _RIVE_TEXT_INPUT_HPP_ + +#include "rive/generated/text/text_input_base.hpp" +#include "rive/text/raw_text_input.hpp" +#include "rive/text/text_interface.hpp" + +namespace rive +{ +class TextStyle; +class TextInput : public TextInputBase, public TextInterface +{ +public: + void draw(Renderer* renderer) override; + Core* hitTest(HitInfo*, const Mat2D&) override; + +#ifdef WITH_RIVE_TEXT + RawTextInput* rawTextInput() { return &m_rawTextInput; } +#endif + + void markPaintDirty() override; + void markShapeDirty() override; + StatusCode onAddedClean(CoreContext* context) override; + + AABB localBounds() const override; + void update(ComponentDirt value) override; + + Vec2D measureLayout(float width, + LayoutMeasureMode widthMode, + float height, + LayoutMeasureMode heightMode) override; + void controlSize(Vec2D size, + LayoutScaleType widthScaleType, + LayoutScaleType heightScaleType, + LayoutDirection direction) override; + +protected: + void textChanged() override; + void selectionRadiusChanged() override; + +private: + AABB m_worldBounds; + TextStyle* m_textStyle = nullptr; +#ifdef WITH_RIVE_TEXT + RawTextInput m_rawTextInput; +#endif +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/text/text_input_cursor.hpp b/third_party/rive/include/rive/text/text_input_cursor.hpp new file mode 100644 index 0000000..7527f52 --- /dev/null +++ b/third_party/rive/include/rive/text/text_input_cursor.hpp @@ -0,0 +1,15 @@ +#ifndef _RIVE_TEXT_INPUT_CURSOR_HPP_ +#define _RIVE_TEXT_INPUT_CURSOR_HPP_ +#include "rive/generated/text/text_input_cursor_base.hpp" +#include +namespace rive +{ +class TextInputCursor : public TextInputCursorBase +{ +public: + Core* hitTest(HitInfo*, const Mat2D&) override; + ShapePaintPath* localClockwisePath() override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/text/text_input_drawable.hpp b/third_party/rive/include/rive/text/text_input_drawable.hpp new file mode 100644 index 0000000..f0219fd --- /dev/null +++ b/third_party/rive/include/rive/text/text_input_drawable.hpp @@ -0,0 +1,27 @@ +#ifndef _RIVE_TEXT_INPUT_DRAWABLE_HPP_ +#define _RIVE_TEXT_INPUT_DRAWABLE_HPP_ + +#include "rive/generated/text/text_input_drawable_base.hpp" +#include "rive/shapes/shape_paint_container.hpp" + +namespace rive +{ +class TextInput; +class TextInputDrawable : public TextInputDrawableBase, + public ShapePaintContainer +{ +private: + Artboard* getArtboard() override { return artboard(); } + +public: + ShapePaintPath* worldPath() override; + const Mat2D& shapeWorldTransform() const override; + ShapePaintPath* localPath() override { return localClockwisePath(); } + StatusCode onAddedClean(CoreContext* context) override; + TextInput* textInput() const; + Component* pathBuilder() override { return parent(); } + void draw(Renderer* renderer) override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/text/text_input_selected_text.hpp b/third_party/rive/include/rive/text/text_input_selected_text.hpp new file mode 100644 index 0000000..05cfc2f --- /dev/null +++ b/third_party/rive/include/rive/text/text_input_selected_text.hpp @@ -0,0 +1,15 @@ +#ifndef _RIVE_TEXT_INPUT_SELECTED_TEXT_HPP_ +#define _RIVE_TEXT_INPUT_SELECTED_TEXT_HPP_ +#include "rive/generated/text/text_input_selected_text_base.hpp" +#include +namespace rive +{ +class TextInputSelectedText : public TextInputSelectedTextBase +{ +public: + Core* hitTest(HitInfo*, const Mat2D&) override; + ShapePaintPath* localClockwisePath() override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/text/text_input_selection.hpp b/third_party/rive/include/rive/text/text_input_selection.hpp new file mode 100644 index 0000000..e3abfb7 --- /dev/null +++ b/third_party/rive/include/rive/text/text_input_selection.hpp @@ -0,0 +1,15 @@ +#ifndef _RIVE_TEXT_INPUT_SELECTION_HPP_ +#define _RIVE_TEXT_INPUT_SELECTION_HPP_ +#include "rive/generated/text/text_input_selection_base.hpp" + +namespace rive +{ +class TextInputSelection : public TextInputSelectionBase +{ +public: + Core* hitTest(HitInfo*, const Mat2D&) override; + ShapePaintPath* localClockwisePath() override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/text/text_input_text.hpp b/third_party/rive/include/rive/text/text_input_text.hpp new file mode 100644 index 0000000..a04b2b4 --- /dev/null +++ b/third_party/rive/include/rive/text/text_input_text.hpp @@ -0,0 +1,15 @@ +#ifndef _RIVE_TEXT_INPUT_TEXT_HPP_ +#define _RIVE_TEXT_INPUT_TEXT_HPP_ +#include "rive/generated/text/text_input_text_base.hpp" +#include +namespace rive +{ +class TextInputText : public TextInputTextBase +{ +public: + Core* hitTest(HitInfo*, const Mat2D&) override; + ShapePaintPath* localClockwisePath() override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/text/text_interface.hpp b/third_party/rive/include/rive/text/text_interface.hpp new file mode 100644 index 0000000..b6e7360 --- /dev/null +++ b/third_party/rive/include/rive/text/text_interface.hpp @@ -0,0 +1,22 @@ +#ifndef _RIVE_TEXT_INTERFACE_HPP_ +#define _RIVE_TEXT_INTERFACE_HPP_ + +#include "rive/math/aabb.hpp" +#include "rive/math/vec2d.hpp" +#include "rive/math/mat2d.hpp" + +namespace rive +{ +class Core; + +class TextInterface +{ +public: + static TextInterface* from(Core* component); + virtual void markPaintDirty() = 0; + virtual void markShapeDirty() = 0; + virtual AABB localBounds() const = 0; +}; + +} // namespace rive +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/text/text_modifier.hpp b/third_party/rive/include/rive/text/text_modifier.hpp new file mode 100644 index 0000000..6d4b653 --- /dev/null +++ b/third_party/rive/include/rive/text/text_modifier.hpp @@ -0,0 +1,14 @@ +#ifndef _RIVE_TEXT_MODIFIER_HPP_ +#define _RIVE_TEXT_MODIFIER_HPP_ +#include "rive/generated/text/text_modifier_base.hpp" + +namespace rive +{ +class TextModifier : public TextModifierBase +{ +public: + StatusCode onAddedDirty(CoreContext* context) override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/text/text_modifier_flags.hpp b/third_party/rive/include/rive/text/text_modifier_flags.hpp new file mode 100644 index 0000000..9787f3c --- /dev/null +++ b/third_party/rive/include/rive/text/text_modifier_flags.hpp @@ -0,0 +1,79 @@ +#ifndef _RIVE_TEXT_MODIFIER_FLAGS_HPP_ +#define _RIVE_TEXT_MODIFIER_FLAGS_HPP_ + +#include + +namespace rive +{ + +enum class TextModifierFlags : uint8_t +{ + modifyOrigin = 1 << 0, + modifyTranslation = 1 << 2, + modifyRotation = 1 << 3, + modifyScale = 1 << 4, + modifyOpacity = 1 << 5, + invertOpacity = 1 << 6 +}; + +inline constexpr TextModifierFlags operator&(TextModifierFlags lhs, + TextModifierFlags rhs) +{ + return static_cast( + static_cast::type>(lhs) & + static_cast::type>(rhs)); +} + +inline constexpr TextModifierFlags operator^(TextModifierFlags lhs, + TextModifierFlags rhs) +{ + return static_cast( + static_cast::type>(lhs) ^ + static_cast::type>(rhs)); +} + +inline constexpr TextModifierFlags operator|(TextModifierFlags lhs, + TextModifierFlags rhs) +{ + return static_cast( + static_cast::type>(lhs) | + static_cast::type>(rhs)); +} + +inline constexpr TextModifierFlags operator~(TextModifierFlags rhs) +{ + return static_cast( + ~static_cast::type>(rhs)); +} + +inline TextModifierFlags& operator|=(TextModifierFlags& lhs, + TextModifierFlags rhs) +{ + lhs = static_cast( + static_cast::type>(lhs) | + static_cast::type>(rhs)); + + return lhs; +} + +inline TextModifierFlags& operator&=(TextModifierFlags& lhs, + TextModifierFlags rhs) +{ + lhs = static_cast( + static_cast::type>(lhs) & + static_cast::type>(rhs)); + + return lhs; +} + +inline TextModifierFlags& operator^=(TextModifierFlags& lhs, + TextModifierFlags rhs) +{ + lhs = static_cast( + static_cast::type>(lhs) ^ + static_cast::type>(rhs)); + + return lhs; +} +} // namespace rive +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/text/text_modifier_group.hpp b/third_party/rive/include/rive/text/text_modifier_group.hpp new file mode 100644 index 0000000..31d1ed1 --- /dev/null +++ b/third_party/rive/include/rive/text/text_modifier_group.hpp @@ -0,0 +1,141 @@ +#ifndef _RIVE_TEXT_MODIFIER_GROUP_HPP_ +#define _RIVE_TEXT_MODIFIER_GROUP_HPP_ +#include "rive/generated/text/text_modifier_group_base.hpp" +#include "rive/text/text_modifier_flags.hpp" +#include "rive/text_engine.hpp" + +#include + +namespace rive +{ +class TextModifierRange; +class TextModifier; +class TextFollowPathModifier; +class TextShapeModifier; +class GlyphLookup; +class Text; +class StyledText; + +struct TransformGlyphArg +{ + Vec2D position; + Vec2D originPosition; + Vec2D offset; + float centerX; + int lineIndexInParagraph; + const SimpleArray& paragraphLines; + + TransformGlyphArg(Vec2D position_, + float centerX_, + int lineIndexInParagraph_, + const SimpleArray& lines) : + position(position_), + originPosition(Vec2D(position_.x + centerX_, position_.y)), + centerX(centerX_), + lineIndexInParagraph(lineIndexInParagraph_), + paragraphLines(lines) + { + offset = {0, 0}; + } +}; + +class TextModifierGroup : public TextModifierGroupBase +{ +public: + StatusCode onAddedDirty(CoreContext* context) override; + + void addModifierRange(TextModifierRange* range); + void addModifier(TextModifier* modifier); + void rangeChanged(); + void rangeTypeChanged(); + void shapeModifierChanged(); + void clearRangeMaps(); + void computeRangeMap(Span text, + const rive::SimpleArray& shape, + const SimpleArray>& lines, + const GlyphLookup& glyphLookup); + void computeCoverage(uint32_t textSize); + Text* textComponent() const; + void resetTextFollowPath(); + float glyphCoverage(uint32_t textIndex, uint32_t codePointCount); + float coverage(uint32_t textIndex) + { + assert(textIndex < m_coverage.size()); + return m_coverage[textIndex]; + } + void transform(float amount, Mat2D& ctm, TransformGlyphArg& arg); + TextRun modifyShape(const Text& text, TextRun run, float strength); + void applyShapeModifiers(const Text& text, StyledText& styledText); + + bool modifiesTransform() const + { + return (modifierFlags() & + (uint32_t)(TextModifierFlags::modifyTranslation | + TextModifierFlags::modifyRotation | + TextModifierFlags::modifyScale | + TextModifierFlags::modifyOrigin)) != 0; + } + + bool modifiesOpacity() const + { + return (modifierFlags() & (uint32_t)TextModifierFlags::modifyOpacity) != + 0; + } + + bool modifiesRotation() const + { + return (modifierFlags() & + (uint32_t)TextModifierFlags::modifyRotation) != 0; + } + + bool modifiesTranslation() const + { + return (modifierFlags() & + (uint32_t)TextModifierFlags::modifyTranslation) != 0; + } + + bool modifiesScale() const + { + return (modifierFlags() & (uint32_t)TextModifierFlags::modifyScale) != + 0; + } + + bool modifiesOrigin() const + { + return (modifierFlags() & (uint32_t)TextModifierFlags::modifyOrigin) != + 0; + } + + float computeOpacity(float current, float t) const; + bool needsShape() const; + void onTextWorldTransformDirty(); + +#ifdef TESTING + const std::vector& ranges() const { return m_ranges; } + const std::vector& modifiers() const { return m_modifiers; } +#endif + +protected: + void modifierFlagsChanged() override; + void originXChanged() override; + void originYChanged() override; + void opacityChanged() override; + void xChanged() override; + void yChanged() override; + void rotationChanged() override; + void scaleXChanged() override; + void scaleYChanged() override; + +private: + std::vector m_ranges; + std::vector m_modifiers; + std::vector m_shapeModifiers; + std::vector m_followPathModifiers; + std::vector m_coverage; + rcp m_variableFont; + std::vector m_variationCoords; + std::vector m_nextTextRuns; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/text/text_modifier_range.hpp b/third_party/rive/include/rive/text/text_modifier_range.hpp new file mode 100644 index 0000000..b17acff --- /dev/null +++ b/third_party/rive/include/rive/text/text_modifier_range.hpp @@ -0,0 +1,162 @@ +#ifndef _RIVE_TEXT_MODIFIER_RANGE_HPP_ +#define _RIVE_TEXT_MODIFIER_RANGE_HPP_ +#include "rive/generated/text/text_modifier_range_base.hpp" +#include "rive/text_engine.hpp" +#include + +namespace rive +{ +enum class TextRangeUnits : uint8_t +{ + characters, + charactersExcludingSpaces, + words, + lines +}; + +enum class TextRangeMode : uint8_t +{ + add, + subtract, + multiply, + min, + max, + difference +}; + +enum class TextRangeType : uint8_t +{ + percentage, + unitIndex +}; + +enum class TextRangeInterpolator : uint8_t +{ + linear, + cubic +}; + +class GlyphLookup; +class TextValueRun; +class RangeMapper +{ +public: + uint32_t unitCount() { return (uint32_t)m_unitLengths.size(); } + uint32_t unitCharacterIndexCount() + { + return (uint32_t)m_unitCharacterIndices.size(); + } + + void clear(); + bool empty() { return m_unitLengths.empty(); } + + /// Compute ranges of words. + void fromWords(Span text, uint32_t start, uint32_t end); + + /// Compute ranges of characters in text. + void fromCharacters(Span text, + uint32_t start, + uint32_t end, + const GlyphLookup& glyphLookup, + bool withoutSpaces = false); + + /// Compute ranges of lines. + void fromLines(Span text, + uint32_t start, + uint32_t end, + const SimpleArray& shape, + const SimpleArray>& lines, + const GlyphLookup& glyphLookup); + + float unitToCharacterRange(float word) const; + + uint32_t unitCharacterIndex(uint32_t at) const + { + assert(at < m_unitCharacterIndices.size()); + return m_unitCharacterIndices[at]; + } + + uint32_t unitLength(uint32_t at) const + { + assert(at < m_unitLengths.size()); + return m_unitLengths[at]; + } + + // Add (some of) unit at indexFrom to indexTo where it falls within the + // start/end offset. + void addRange(uint32_t indexFrom, + uint32_t indexTo, + uint32_t startOffset, + uint32_t endOffset); + +private: + /// Each item in this list represents the index (in unicode codepoints) of + /// the selectable element. Always has length 1+unitLengths.length as it's + /// expected to always include the final index with 0 length. + std::vector m_unitCharacterIndices; + + /// Each item in this list represents the length of the matching element at + /// the same index in the _unitIndices list. + std::vector m_unitLengths; +}; + +class CubicInterpolatorComponent; +class TextModifierRange : public TextModifierRangeBase +{ +public: + StatusCode onAddedDirty(CoreContext* context) override; + + void clearRangeMap(); + void computeRange(Span text, + const SimpleArray& shape, + const SimpleArray>& lines, + const GlyphLookup& glyphLookup); + void computeCoverage(Span coverage); + + TextRangeUnits units() const { return (TextRangeUnits)unitsValue(); } + TextRangeType type() const { return (TextRangeType)typeValue(); } + TextRangeMode mode() const { return (TextRangeMode)modeValue(); } + void addChild(Component* component) override; + bool needsShape() const; + +#ifdef TESTING + CubicInterpolatorComponent* interpolator() const { return m_interpolator; } +#endif + +protected: + void modifyFromChanged() override; + void modifyToChanged() override; + void strengthChanged() override; + void unitsValueChanged() override; + void typeValueChanged() override; + void modeValueChanged() override; + void clampChanged() override; + void falloffFromChanged() override; + void falloffToChanged() override; + void offsetChanged() override; + +private: + RangeMapper m_rangeMapper; + // Cache indices. + float m_indexFrom = 0.0f; + float m_indexTo = 0.0f; + float m_indexFalloffFrom = 0.0f; + float m_indexFalloffTo = 0.0f; + CubicInterpolatorComponent* m_interpolator = nullptr; + TextValueRun* m_run = nullptr; + + float offsetModifyFrom() const { return modifyFrom() + offset(); } + float offsetModifyTo() const { return modifyTo() + offset(); } + float offsetFalloffFrom() const { return falloffFrom() + offset(); } + float offsetFalloffTo() const { return falloffTo() + offset(); } + + float coverageAt(float t); + +public: +#ifdef TESTING + TextValueRun* run() const { return m_run; } +#endif +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/text/text_selection_path.hpp b/third_party/rive/include/rive/text/text_selection_path.hpp new file mode 100644 index 0000000..3cbe886 --- /dev/null +++ b/third_party/rive/include/rive/text/text_selection_path.hpp @@ -0,0 +1,22 @@ +#ifndef _RIVE_TEXT_SELECTION_PATH_HPP_ +#define _RIVE_TEXT_SELECTION_PATH_HPP_ +#ifdef WITH_RIVE_TEXT + +#include "rive/math/rectangles_to_contour.hpp" +#include "rive/shapes/shape_paint_path.hpp" + +namespace rive +{ +class TextSelectionPath : public ShapePaintPath +{ +public: + void update(Span rects, float cornerRadius); + +private: + RectanglesToContour m_rectanglesToContour; + + void addRoundedPath(const Contour& contour, float radius, RawPath& rawPath); +}; +}; // namespace rive +#endif +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/text/text_shape_modifier.hpp b/third_party/rive/include/rive/text/text_shape_modifier.hpp new file mode 100644 index 0000000..d8b14de --- /dev/null +++ b/third_party/rive/include/rive/text/text_shape_modifier.hpp @@ -0,0 +1,19 @@ +#ifndef _RIVE_TEXT_SHAPE_MODIFIER_HPP_ +#define _RIVE_TEXT_SHAPE_MODIFIER_HPP_ +#include "rive/generated/text/text_shape_modifier_base.hpp" +#include + +namespace rive +{ +class Font; +class TextShapeModifier : public TextShapeModifierBase +{ +public: + virtual float modify(Font* font, + std::unordered_map& variations, + float fontSize, + float strength) const = 0; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/text/text_style.hpp b/third_party/rive/include/rive/text/text_style.hpp new file mode 100644 index 0000000..5a92e8a --- /dev/null +++ b/third_party/rive/include/rive/text/text_style.hpp @@ -0,0 +1,60 @@ +#ifndef _RIVE_TEXT_STYLE_HPP_ +#define _RIVE_TEXT_STYLE_HPP_ +#include "rive/generated/text/text_style_base.hpp" +#include "rive/assets/file_asset_referencer.hpp" +#include "rive/assets/file_asset.hpp" +#include "rive/assets/font_asset.hpp" +#include "rive/text/text_interface.hpp" + +namespace rive +{ +class FontAsset; +class Font; +class FileAsset; +class Renderer; +class RenderPath; +class RenderPaint; + +class TextVariationHelper; +class TextStyleAxis; +class TextStyleFeature; +class TextInterface; + +class TextStyle : public TextStyleBase, public FileAssetReferencer +{ +public: + TextStyle(); + void buildDependencies() override; + const rcp font() const; + void setAsset(FileAsset*) override; + uint32_t assetId() override; + StatusCode import(ImportStack& importStack) override; + + FontAsset* fontAsset() const { return (FontAsset*)m_fileAsset; } + + Core* clone() const override; + void addVariation(TextStyleAxis* axis); + void addFeature(TextStyleFeature* feature); + void updateVariableFont(); + StatusCode onAddedClean(CoreContext* context) override; + void onDirty(ComponentDirt dirt) override; + bool validate(CoreContext* context) override; + +protected: + void fontSizeChanged() override; + void lineHeightChanged() override; + void letterSpacingChanged() override; + +private: + std::unique_ptr m_variationHelper; + rcp m_variableFont; + + std::vector m_coords; + std::vector m_variations; + std::vector m_styleFeatures; + std::vector m_features; + TextInterface* m_text; +}; +} // namespace rive + +#endif diff --git a/third_party/rive/include/rive/text/text_style_axis.hpp b/third_party/rive/include/rive/text/text_style_axis.hpp new file mode 100644 index 0000000..695df58 --- /dev/null +++ b/third_party/rive/include/rive/text/text_style_axis.hpp @@ -0,0 +1,16 @@ +#ifndef _RIVE_TEXT_STYLE_AXIS_HPP_ +#define _RIVE_TEXT_STYLE_AXIS_HPP_ +#include "rive/generated/text/text_style_axis_base.hpp" +#include +namespace rive +{ +class TextStyleAxis : public TextStyleAxisBase +{ +public: + StatusCode onAddedDirty(CoreContext* context) override; + void tagChanged() override; + void axisValueChanged() override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/text/text_style_feature.hpp b/third_party/rive/include/rive/text/text_style_feature.hpp new file mode 100644 index 0000000..fd0bb75 --- /dev/null +++ b/third_party/rive/include/rive/text/text_style_feature.hpp @@ -0,0 +1,14 @@ +#ifndef _RIVE_TEXT_STYLE_FEATURE_HPP_ +#define _RIVE_TEXT_STYLE_FEATURE_HPP_ +#include "rive/generated/text/text_style_feature_base.hpp" +#include +namespace rive +{ +class TextStyleFeature : public TextStyleFeatureBase +{ +public: + StatusCode onAddedDirty(CoreContext* context) override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/text/text_style_paint.hpp b/third_party/rive/include/rive/text/text_style_paint.hpp new file mode 100644 index 0000000..2ec96e1 --- /dev/null +++ b/third_party/rive/include/rive/text/text_style_paint.hpp @@ -0,0 +1,34 @@ +#ifndef _RIVE_TEXT_STYLE_PAINT_HPP_ +#define _RIVE_TEXT_STYLE_PAINT_HPP_ +#include "rive/generated/text/text_style_paint_base.hpp" +#include "rive/shapes/shape_paint_container.hpp" +#include "rive/shapes/shape_paint_path.hpp" +#include + +namespace rive +{ +class TextStylePaint : public TextStylePaintBase, public ShapePaintContainer +{ +public: + TextStylePaint(); + bool addPath(const RawPath& rawPath, float opacity); + void rewindPath(); + void draw(Renderer* renderer, const Mat2D& worldTransform); + + // Implemented for ShapePaintContainer. + const Mat2D& shapeWorldTransform() const override; + Component* pathBuilder() override; + ShapePaintPath* localPath() override { return &m_path; } + ShapePaintPath* localClockwisePath() override { return &m_path; } + Core* clone() const override; + +private: + Artboard* getArtboard() override { return artboard(); } + std::unordered_map m_opacityPaths; + std::vector> m_paintPool; + ShapePaintPath m_path; + bool m_hasContents = false; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/text/text_target_modifier.hpp b/third_party/rive/include/rive/text/text_target_modifier.hpp new file mode 100644 index 0000000..a3c262f --- /dev/null +++ b/third_party/rive/include/rive/text/text_target_modifier.hpp @@ -0,0 +1,20 @@ +#ifndef _RIVE_TEXT_TARGET_MODIFIER_HPP_ +#define _RIVE_TEXT_TARGET_MODIFIER_HPP_ +#include "rive/generated/text/text_target_modifier_base.hpp" +#include +namespace rive +{ +class Text; +class TransformComponent; +class TextTargetModifier : public TextTargetModifierBase +{ +protected: + TransformComponent* m_Target = nullptr; + +public: + StatusCode onAddedDirty(CoreContext* context) override; + Text* textComponent() const; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/text/text_value_run.hpp b/third_party/rive/include/rive/text/text_value_run.hpp new file mode 100644 index 0000000..9404991 --- /dev/null +++ b/third_party/rive/include/rive/text/text_value_run.hpp @@ -0,0 +1,71 @@ +#ifndef _RIVE_TEXT_VALUE_RUN_HPP_ +#define _RIVE_TEXT_VALUE_RUN_HPP_ +#include "rive/generated/text/text_value_run_base.hpp" +#include "rive/animation/hittable.hpp" +#include "rive/text/utf.hpp" +#include "rive/math/rectangles_to_contour.hpp" + +namespace rive +{ +class TextStylePaint; +class Text; +class TextValueRun : public TextValueRunBase, public Hittable +{ + friend class HitTextRun; + +public: + StatusCode onAddedClean(CoreContext* context) override; + StatusCode onAddedDirty(CoreContext* context) override; + TextStylePaint* style() { return m_style; } + Text* textComponent() const; + uint32_t length() + { + if (m_length == -1) + { + + const uint8_t* ptr = (const uint8_t*)text().c_str(); + uint32_t n = 0; + while (*ptr) + { + UTF::NextUTF8(&ptr); + n += 1; + } + m_length = n; + } + return m_length; + } + uint32_t offset() const; + + // Reset stored data for hit testing the run. + void resetHitTest(); + + // Add a rectangle (usually bounding a glyph) as a hit rect that will be + // used to compute contours when computeHitContours is called. + void addHitRect(const AABB& rect); + + // Compute the contours used for hit testing, call resetHitTest to start + // adding hit rects (via addHitRect) again. + void computeHitContours(); + + bool hitTestAABB(const Vec2D& position) override; + bool hitTestHiFi(const Vec2D& position, float hitRadius) override; + + bool isHitTarget() const { return m_isHitTarget; } + void isHitTarget(bool value); + +protected: + void textChanged() override; + void styleIdChanged() override; + +private: + std::unique_ptr m_rectanglesToContour; + AABB m_localBounds; + bool m_isHitTarget = false; + std::vector m_glyphHitRects; + TextStylePaint* m_style = nullptr; + uint32_t m_length = -1; + bool canHitTest() const; +}; +} // namespace rive + +#endif diff --git a/third_party/rive/include/rive/text/text_variation_helper.hpp b/third_party/rive/include/rive/text/text_variation_helper.hpp new file mode 100644 index 0000000..d35e56c --- /dev/null +++ b/third_party/rive/include/rive/text/text_variation_helper.hpp @@ -0,0 +1,21 @@ +#ifndef _RIVE_TEXT_VARIATION_HELPER_HPP_ +#define _RIVE_TEXT_VARIATION_HELPER_HPP_ + +#include "rive/component.hpp" +namespace rive +{ +class TextStyle; +class TextVariationHelper : public Component +{ +public: + TextVariationHelper(TextStyle* style) : m_textStyle(style) {} + TextStyle* style() const { return m_textStyle; } + void buildDependencies() override; + void update(ComponentDirt value) override; + +private: + TextStyle* m_textStyle; +}; +} // namespace rive + +#endif diff --git a/third_party/rive/include/rive/text/text_variation_modifier.hpp b/third_party/rive/include/rive/text/text_variation_modifier.hpp new file mode 100644 index 0000000..f5bab27 --- /dev/null +++ b/third_party/rive/include/rive/text/text_variation_modifier.hpp @@ -0,0 +1,18 @@ +#ifndef _RIVE_TEXT_VARIATION_MODIFIER_HPP_ +#define _RIVE_TEXT_VARIATION_MODIFIER_HPP_ +#include "rive/generated/text/text_variation_modifier_base.hpp" + +namespace rive +{ +class TextVariationModifier : public TextVariationModifierBase +{ +public: + float modify(Font* font, + std::unordered_map& variations, + float fontSize, + float strength) const override; + void axisValueChanged() override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/text/utf.hpp b/third_party/rive/include/rive/text/utf.hpp new file mode 100644 index 0000000..a48b8e9 --- /dev/null +++ b/third_party/rive/include/rive/text/utf.hpp @@ -0,0 +1,33 @@ +#ifndef _RIVE_UTF_HPP_ +#define _RIVE_UTF_HPP_ + +#include "rive/text_engine.hpp" + +namespace rive +{ + +class UTF +{ +public: + // returns the number of bytes needed in this sequence + // For ascii, this will return 1 + static int CountUTF8Length(const uint8_t utf8[]); + + // Return the unichar pointed to by the utf8 pointer, and then + // update the pointer to point to the next sequence. + static Unichar NextUTF8(const uint8_t** utf8Ptr); + + // Convert the unichar into (1 or 2) utf16 values, and return + // the number of values. + static int ToUTF16(Unichar uni, uint16_t utf16[]); + + // Count the number of bytes needed to encode the codepoints to utf8. + static uint32_t CountCodePointLength(Span codepoints); + + // Encode a utf8 codepoint into a byte buffer. + static uint32_t Encode(uint8_t* output, Unichar codepoint); +}; + +} // namespace rive + +#endif diff --git a/third_party/rive/include/rive/text_engine.hpp b/third_party/rive/include/rive/text_engine.hpp new file mode 100644 index 0000000..e9d5e85 --- /dev/null +++ b/third_party/rive/include/rive/text_engine.hpp @@ -0,0 +1,478 @@ +/* + * Copyright 2022 Rive + */ + +#ifndef _RIVE_TEXT_ENGINE_HPP_ +#define _RIVE_TEXT_ENGINE_HPP_ + +#include "rive/math/raw_path.hpp" +#include "rive/refcnt.hpp" +#include "rive/span.hpp" +#include "rive/simple_array.hpp" + +namespace rive +{ + +enum class TextSizing : uint8_t +{ + autoWidth, + autoHeight, + fixed +}; + +enum class TextOverflow : uint8_t +{ + visible, + hidden, + clipped, + ellipsis, + fit, +}; + +enum class TextOrigin : uint8_t +{ + top, + baseline +}; + +// Representation of a single unicode codepoint. +using Unichar = uint32_t; +// Id for a glyph within a font. +using GlyphID = uint16_t; + +struct TextRun; +struct GlyphRun; + +bool isWhiteSpace(Unichar c); + +// Direction a paragraph or run flows in. +enum class TextDirection : uint8_t +{ + ltr = 0, + rtl = 1 +}; + +// The alignment of each word wrapped line in a paragraph. +enum class TextAlign : uint8_t +{ + left = 0, + right = 1, + center = 2 +}; + +// The wrap mode. +enum class TextWrap : uint8_t +{ + wrap = 0, + noWrap = 1 +}; + +// The alignment of each word wrapped line in a paragraph. +enum class VerticalTextAlign : uint8_t +{ + top = 0, + bottom = 1, + middle = 2 +}; + +// A horizontal line of text within a paragraph, after line-breaking. +struct GlyphLine +{ + uint32_t startRunIndex; + uint32_t startGlyphIndex; + uint32_t endRunIndex; + uint32_t endGlyphIndex; + float startX; + float top = 0, baseline = 0, bottom = 0; + + bool operator==(const GlyphLine& o) const + { + return startRunIndex == o.startRunIndex && + startGlyphIndex == o.startGlyphIndex && + endRunIndex == o.endRunIndex && endGlyphIndex == o.endGlyphIndex; + } + + GlyphLine() : + startRunIndex(0), + startGlyphIndex(0), + endRunIndex(0), + endGlyphIndex(0), + startX(0.0f) + {} + GlyphLine(uint32_t run, uint32_t index) : + startRunIndex(run), + startGlyphIndex(index), + endRunIndex(run), + endGlyphIndex(index), + startX(0.0f) + {} + + bool empty() const + { + return startRunIndex == endRunIndex && startGlyphIndex == endGlyphIndex; + } + + static SimpleArray BreakLines(Span runs, + float width); + + // Compute values for top/baseline/bottom per line + static void ComputeLineSpacing(bool isFirstLine, + Span, + Span, + float width, + TextAlign align); + + static float ComputeMaxWidth(Span lines, + Span runs); +}; + +// A paragraph represents of set of runs that flow in a specific direction. The +// runs are always provided in LTR and must be drawn in reverse when the +// baseDirection is RTL. These are built by the system during shaping where the +// user provided string and text styling is converted to shaped paragraphs. +struct Paragraph +{ + SimpleArray runs; + uint8_t level; + TextDirection baseDirection() const + { + return level & 1 ? TextDirection::rtl : TextDirection::ltr; + } +}; + +// An abstraction for interfacing with an individual font. +class Font : public RefCnt +{ +public: + virtual ~Font() {} + + struct LineMetrics + { + float ascent, descent; + }; + + const LineMetrics& lineMetrics() const { return m_lineMetrics; } + + float ascent(float size) const { return m_lineMetrics.ascent * size; } + + float descent(float size) const { return m_lineMetrics.descent * size; } + + // Variable axis available for the font. + struct Axis + { + uint32_t tag; + float min; + float def; // default value + float max; + }; + + // Variable axis setting. + struct Coord + { + uint32_t axis; + float value; + }; + + // Returns the count of variable axes available for this font. + virtual uint16_t getAxisCount() const = 0; + + // Returns the definition of the Axis at the provided index. + virtual Axis getAxis(uint16_t index) const = 0; + + // Value for the axis, if a Coord has been provided the value from the Coord + // will be used. Otherwise the default value for the axis will be returned. + virtual float getAxisValue(uint32_t axisTag) const = 0; + + // Returns the current font value as a numeric value [1, 1000] + virtual uint16_t getWeight() const = 0; + + // Whether this font is italic or not. + virtual bool isItalic() const = 0; + + // Font feature. + struct Feature + { + uint32_t tag; + uint32_t value; + }; + + // Returns the features available for this font. + virtual SimpleArray features() const = 0; + + virtual bool hasGlyph(const rive::Unichar) const = 0; + + // Value for the feature, if no value has been provided a (uint32_t)-1 is + // returned to signal that the text engine will pick the best feature value + // for the content. + virtual uint32_t getFeatureValue(uint32_t featureTag) const = 0; + + rcp makeAtCoords(Span coords) const + { + return withOptions(coords, Span(nullptr, 0)); + } + + rcp makeAtCoord(Coord c) + { + return this->makeAtCoords(Span(&c, 1)); + } + + virtual rcp withOptions(Span variableAxes, + Span features) const = 0; + + // Returns a 1-point path for this glyph. It will be positioned + // relative to (0,0) with the typographic baseline at y = 0. + // + virtual RawPath getPath(GlyphID) const = 0; + + SimpleArray shapeText(Span text, + Span runs, + int textDirectionFlag = -1) const; + + // If the platform can supply fallback font(s), set this function pointer. + // It will be called with a span of unichars, and the platform attempts to + // return a font that can draw (at least some of) them. If no font is + // available just return nullptr. + + using FallbackProc = rive::rcp (*)(const rive::Unichar missing, + const uint32_t fallbackIndex, + const rive::Font*); + static FallbackProc gFallbackProc; + static bool gFallbackProcEnabled; + static constexpr unsigned kRegularWeight = 400; + +protected: + Font(const LineMetrics& lm) : m_lineMetrics(lm) {} + + virtual SimpleArray onShapeText(Span text, + Span runs, + int textDirectionFlag) const = 0; + +private: + /// The font specified line metrics (automatic line metrics). + const LineMetrics m_lineMetrics; +}; + +// A user defined styling guide for a set of unicode codepoints within a larger +// text string. +struct TextRun +{ + rcp font; + float size; + float lineHeight; + float letterSpacing; + uint32_t unicharCount; + uint32_t script; + uint16_t styleId; + uint8_t level; +}; + +// The corresponding system generated run for the user provided TextRuns. +// GlyphRuns may not match TextRuns if the system needs to split the run (for +// fallback fonts) or if codepoints get ligated/shaped to a single glyph. +struct GlyphRun +{ + GlyphRun(size_t glyphCount = 0) : + glyphs(glyphCount), + textIndices(glyphCount), + advances(glyphCount), + xpos(glyphCount + 1), + offsets(glyphCount) + {} + + GlyphRun(SimpleArray glyphIds, + SimpleArray offsets, + SimpleArray ws, + SimpleArray xs, + SimpleArray offs) : + glyphs(glyphIds), + textIndices(offsets), + advances(ws), + xpos(xs), + offsets(offs) + {} + + rcp font; + float size; + float lineHeight; + float letterSpacing; + + // List of glyphs, represented by font specific glyph ids. Length is equal + // to number of glyphs in the run. + SimpleArray glyphs; + + // Index in the unicode text array representing the text displayed in this + // run. Because each glyph can be composed of multiple unicode values, this + // index points to the first index in the unicode text. Length is equal to + // number of glyphs in the run. + SimpleArray textIndices; + + // X position of each glyph in visual order (xpos is in logical/memory + // order). + SimpleArray advances; + + // X position of each glyph, with an extra value at the end for the right + // most extent of the last glyph. + SimpleArray xpos; + + // X and Y offset each glyphs draws at relative to its baseline and advance + // position. + SimpleArray offsets; + + // List of possible indices to line break at. Has a stride of 2 uint32_ts + // where each pair marks the start and end of a word, with the exception of + // a return character (forced linebreak) which is represented as a 0 length + // word (where start/end index is the same). + SimpleArray breaks; + + // The unique identifier for the styling (fill/stroke colors, anything not + // determined by the font or font size) applied to this run. + uint16_t styleId; + + // Bidi level (even is LTR, odd is RTL) + uint8_t level; + + TextDirection dir() const + { + return level & 1 ? TextDirection::rtl : TextDirection::ltr; + } +}; + +class OrderedLine; + +// STL-style iterator for individual glyphs in a line, simplfies call sites from +// needing to iterate both runs and glyphs within those runs per line. A single +// iterator allows iterating all the glyphs in the line and provides the correct +// run they belong to (this also takes into account bidi which can put the runs +// in different order from how they were provided by the line breaker). +// +// for (auto [run, glyphIndex] : orderedLine) { ... } +// +class GlyphItr +{ +public: + GlyphItr() = default; + GlyphItr(const OrderedLine* line, + const rive::GlyphRun* const* run, + uint32_t glyphIndex) : + m_line(line), m_run(run), m_glyphIndex(glyphIndex) + {} + + void tryAdvanceRun(); + + bool operator!=(const GlyphItr& that) const + { + return m_run != that.m_run || m_glyphIndex != that.m_glyphIndex; + } + bool operator==(const GlyphItr& that) const + { + return m_run == that.m_run && m_glyphIndex == that.m_glyphIndex; + } + + GlyphItr& operator++(); + + std::tuple operator*() const + { + return {*m_run, m_glyphIndex}; + } + + const rive::GlyphRun* run() const { return *m_run; } + uint32_t glyphIndex() const { return m_glyphIndex; } + +private: + const OrderedLine* m_line; + const rive::GlyphRun* const* m_run; + uint32_t m_glyphIndex; +}; + +class GlyphLookup; +// Represents a line of text with runs ordered visually. Also tracks logical +// start/end which will differ when using bidi. +class OrderedLine +{ +public: + OrderedLine(const Paragraph& paragraph, + const GlyphLine& line, + float lineWidth, // for ellipsis + bool wantEllipsis, + bool isEllipsisLineLast, + GlyphRun* ellipsisRun, + float y); + + bool buildEllipsisRuns(std::vector& logicalRuns, + const Paragraph& paragraph, + const GlyphLine& line, + float lineWidth, + bool isEllipsisLineLast, + GlyphRun* ellipsisRun); + const GlyphRun* startLogical() const { return m_startLogical; } + const GlyphRun* endLogical() const { return m_endLogical; } + const std::vector& runs() const { return m_runs; } + + GlyphItr begin() const + { + auto runItr = m_runs.data(); + auto itr = GlyphItr(this, runItr, startGlyphIndex(*runItr)); + itr.tryAdvanceRun(); + return itr; + } + + GlyphItr end() const + { + auto runItr = + m_runs.data() + (m_runs.size() == 0 ? 0 : m_runs.size() - 1); + return GlyphItr(this, runItr, endGlyphIndex(*runItr)); + } + + const GlyphLine& glyphLine() const { return *m_glyphLine; } + float y() const { return m_y; } + float bottom() const; + + uint32_t firstCodePointIndex(const GlyphLookup& glyphLookup) const; + uint32_t lastCodePointIndex(const GlyphLookup& glyphLookup) const; + bool containsCodePointIndex(const GlyphLookup& glyphLookup, + uint32_t codePointIndex) const; + +private: + const GlyphRun* m_startLogical = nullptr; + const GlyphRun* m_endLogical = nullptr; + uint32_t m_startGlyphIndex; + uint32_t m_endGlyphIndex; + std::vector m_runs; + const GlyphLine* m_glyphLine; + float m_y; + +public: + const GlyphRun* lastRun() const { return m_runs.back(); } + uint32_t startGlyphIndex(const GlyphRun* run) const + { + TextDirection dir = + run->level & 1 ? TextDirection::rtl : TextDirection::ltr; + switch (dir) + { + case TextDirection::ltr: + return m_startLogical == run ? m_startGlyphIndex : 0; + case TextDirection::rtl: + return (m_endLogical == run ? m_endGlyphIndex + : (uint32_t)run->glyphs.size()) - + 1; + } + RIVE_UNREACHABLE(); + } + uint32_t endGlyphIndex(const GlyphRun* run) const + { + TextDirection dir = + run->level & 1 ? TextDirection::rtl : TextDirection::ltr; + switch (dir) + { + case TextDirection::ltr: + return m_endLogical == run ? m_endGlyphIndex + : (uint32_t)run->glyphs.size(); + case TextDirection::rtl: + return (m_startLogical == run ? m_startGlyphIndex : 0) - 1; + } + RIVE_UNREACHABLE(); + } +}; + +} // namespace rive +#endif diff --git a/third_party/rive/include/rive/transform_component.hpp b/third_party/rive/include/rive/transform_component.hpp new file mode 100644 index 0000000..e9bfa99 --- /dev/null +++ b/third_party/rive/include/rive/transform_component.hpp @@ -0,0 +1,63 @@ +#ifndef _RIVE_TRANSFORM_COMPONENT_HPP_ +#define _RIVE_TRANSFORM_COMPONENT_HPP_ +#include "rive/generated/transform_component_base.hpp" +#include "rive/intrinsically_sizeable.hpp" +#include "rive/math/aabb.hpp" +#include "rive/math/mat2d.hpp" +#include "rive/layout/layout_measure_mode.hpp" + +namespace rive +{ +class Constraint; +class WorldTransformComponent; +class AABB; +class TransformComponent : public TransformComponentBase, + public IntrinsicallySizeable +{ +protected: + Mat2D m_Transform; + float m_RenderOpacity = 0.0f; + WorldTransformComponent* m_ParentTransformComponent = nullptr; + std::vector m_Constraints; + +protected: + virtual void updateConstraints(); + +public: + bool collapse(bool value) override; + const std::vector& constraints() const + { + return m_Constraints; + } + StatusCode onAddedClean(CoreContext* context) override; + void buildDependencies() override; + void update(ComponentDirt value) override; + virtual void updateTransform(); + virtual void updateWorldTransform(); + void markTransformDirty(); + + /// Opacity inherited by any child of this transform component. This'll + /// later get overridden by effect layers. + float childOpacity() override { return m_RenderOpacity; } + float renderOpacity() const { return m_RenderOpacity; } + + const Mat2D& transform() const; + + /// Explicitly dangerous. Use transform/worldTransform when you don't + /// need to transform things outside of their hierarchy. + Mat2D& mutableTransform(); + + virtual float x() const = 0; + virtual float y() const = 0; + + void rotationChanged() override; + void scaleXChanged() override; + void scaleYChanged() override; + + void addConstraint(Constraint* constraint); + virtual AABB localBounds() const; + void markDirtyIfConstrained(); +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/transform_space.hpp b/third_party/rive/include/rive/transform_space.hpp new file mode 100644 index 0000000..3e9c3c9 --- /dev/null +++ b/third_party/rive/include/rive/transform_space.hpp @@ -0,0 +1,11 @@ +#ifndef _RIVE_TRANSFORM_SPACE_HPP_ +#define _RIVE_TRANSFORM_SPACE_HPP_ +namespace rive +{ +enum class TransformSpace : unsigned int +{ + world = 0, + local = 1 +}; +} +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/trim_type.hpp b/third_party/rive/include/rive/trim_type.hpp new file mode 100644 index 0000000..ad9a068 --- /dev/null +++ b/third_party/rive/include/rive/trim_type.hpp @@ -0,0 +1,13 @@ +#ifndef _RIVE_TRIM_TYPE_HPP_ +#define _RIVE_TRIM_TYPE_HPP_ +namespace rive +{ +enum class TrimType : int +{ + none = 0, + start = 1, + end = 2, + all = 3, +}; +} +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/typed_children.hpp b/third_party/rive/include/rive/typed_children.hpp new file mode 100644 index 0000000..fbb2efb --- /dev/null +++ b/third_party/rive/include/rive/typed_children.hpp @@ -0,0 +1,84 @@ +#ifndef _RIVE_TYPED_CHILDREN_HPP_ +#define _RIVE_TYPED_CHILDREN_HPP_ + +#include "rive/core.hpp" +#include "rive/span.hpp" + +namespace rive +{ +class Core; +template class TypedChild +{ +public: + TypedChild(Core** child, Core** end) : m_child(child), m_end(end) {} + + T* operator*() const { return (*m_child)->template as(); } + TypedChild& operator++() + { + m_child++; + while (m_child != m_end && (*m_child) != nullptr && + !(*m_child)->template is()) + { + m_child++; + } + return *this; + } + + bool operator==(const TypedChild& o) const { return m_child == o.m_child; } + + bool operator!=(const TypedChild& o) const { return m_child != o.m_child; } + +private: + Core** m_child; + Core** m_end; +}; + +template class TypedChildren +{ +public: + TypedChildren(Span children) : m_children(children) {} + + TypedChild begin() const + { + size_t size = m_children.size(); + size_t index = 0; + while (index < size && !m_children[index]->template is()) + { + index++; + } + return TypedChild(m_children.data() + index, + m_children.data() + size); + } + + TypedChild end() const + { + auto ptr = m_children.data() + m_children.size(); + return TypedChild(ptr, ptr); + } + + T* first() const + { + auto start = begin(); + if (start == end()) + { + return nullptr; + } + return *start; + } + + size_t size() const + { + size_t count = 0; + auto last = end(); + for (auto itr = begin(); itr != last; ++itr) + { + count++; + } + return count; + } + +private: + Span m_children; +}; +} // namespace rive +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/viewmodel/data_enum.hpp b/third_party/rive/include/rive/viewmodel/data_enum.hpp new file mode 100644 index 0000000..6e925e4 --- /dev/null +++ b/third_party/rive/include/rive/viewmodel/data_enum.hpp @@ -0,0 +1,29 @@ +#ifndef _RIVE_DATA_ENUM_HPP_ +#define _RIVE_DATA_ENUM_HPP_ +#include "rive/generated/viewmodel/data_enum_base.hpp" +#include "rive/viewmodel/data_enum_value.hpp" +#include "rive/refcnt.hpp" +#include +namespace rive +{ +class DataEnum : public DataEnumBase, public RefCnt +{ +private: + std::vector m_Values; + const std::string m_name = ""; + +public: + ~DataEnum(); + void addValue(DataEnumValue* value); + std::vector& values() { return m_Values; }; + std::string value(std::string name); + std::string value(uint32_t index); + bool value(std::string name, std::string value); + bool value(uint32_t index, std::string value); + int valueIndex(std::string name); + int valueIndex(uint32_t index); + virtual const std::string& enumName() const { return m_name; }; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/viewmodel/data_enum_custom.hpp b/third_party/rive/include/rive/viewmodel/data_enum_custom.hpp new file mode 100644 index 0000000..572f828 --- /dev/null +++ b/third_party/rive/include/rive/viewmodel/data_enum_custom.hpp @@ -0,0 +1,14 @@ +#ifndef _RIVE_DATA_ENUM_CUSTOM_HPP_ +#define _RIVE_DATA_ENUM_CUSTOM_HPP_ +#include "rive/generated/viewmodel/data_enum_custom_base.hpp" +#include +namespace rive +{ +class DataEnumCustom : public DataEnumCustomBase +{ +public: + const std::string& enumName() const override { return name(); } +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/viewmodel/data_enum_system.hpp b/third_party/rive/include/rive/viewmodel/data_enum_system.hpp new file mode 100644 index 0000000..e522d5e --- /dev/null +++ b/third_party/rive/include/rive/viewmodel/data_enum_system.hpp @@ -0,0 +1,13 @@ +#ifndef _RIVE_DATA_ENUM_SYSTEM_HPP_ +#define _RIVE_DATA_ENUM_SYSTEM_HPP_ +#include "rive/generated/viewmodel/data_enum_system_base.hpp" +#include +namespace rive +{ +class DataEnumSystem : public DataEnumSystemBase +{ +public: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/viewmodel/data_enum_value.hpp b/third_party/rive/include/rive/viewmodel/data_enum_value.hpp new file mode 100644 index 0000000..de64216 --- /dev/null +++ b/third_party/rive/include/rive/viewmodel/data_enum_value.hpp @@ -0,0 +1,14 @@ +#ifndef _RIVE_DATA_ENUM_VALUE_HPP_ +#define _RIVE_DATA_ENUM_VALUE_HPP_ +#include "rive/generated/viewmodel/data_enum_value_base.hpp" +#include +namespace rive +{ +class DataEnumValue : public DataEnumValueBase +{ +public: + StatusCode import(ImportStack& importStack) override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/viewmodel/runtime/viewmodel_instance_asset_image_runtime.hpp b/third_party/rive/include/rive/viewmodel/runtime/viewmodel_instance_asset_image_runtime.hpp new file mode 100644 index 0000000..9db0a8c --- /dev/null +++ b/third_party/rive/include/rive/viewmodel/runtime/viewmodel_instance_asset_image_runtime.hpp @@ -0,0 +1,23 @@ +#ifndef _RIVE_VIEW_MODEL_INSTANCE_ASSET_IMAGE_RUNTIME_HPP_ +#define _RIVE_VIEW_MODEL_INSTANCE_ASSET_IMAGE_RUNTIME_HPP_ + +#include +#include +#include "rive/viewmodel/runtime/viewmodel_instance_value_runtime.hpp" +#include "rive/viewmodel/viewmodel_instance_asset_image.hpp" + +namespace rive +{ + +class ViewModelInstanceAssetImageRuntime : public ViewModelInstanceValueRuntime +{ + +public: + ViewModelInstanceAssetImageRuntime( + ViewModelInstanceAssetImage* viewModelInstance) : + ViewModelInstanceValueRuntime(viewModelInstance) + {} + void value(RenderImage* renderImage); +}; +} // namespace rive +#endif diff --git a/third_party/rive/include/rive/viewmodel/runtime/viewmodel_instance_boolean_runtime.hpp b/third_party/rive/include/rive/viewmodel/runtime/viewmodel_instance_boolean_runtime.hpp new file mode 100644 index 0000000..4673dc1 --- /dev/null +++ b/third_party/rive/include/rive/viewmodel/runtime/viewmodel_instance_boolean_runtime.hpp @@ -0,0 +1,24 @@ +#ifndef _RIVE_VIEW_MODEL_INSTANCE_BOOLEAN_RUNTIME_HPP_ +#define _RIVE_VIEW_MODEL_INSTANCE_BOOLEAN_RUNTIME_HPP_ + +#include +#include +#include "rive/viewmodel/runtime/viewmodel_instance_value_runtime.hpp" +#include "rive/viewmodel/viewmodel_instance_boolean.hpp" + +namespace rive +{ + +class ViewModelInstanceBooleanRuntime : public ViewModelInstanceValueRuntime +{ + +public: + ViewModelInstanceBooleanRuntime( + ViewModelInstanceBoolean* viewModelInstance) : + ViewModelInstanceValueRuntime(viewModelInstance) + {} + bool value() const; + void value(bool); +}; +} // namespace rive +#endif diff --git a/third_party/rive/include/rive/viewmodel/runtime/viewmodel_instance_color_runtime.hpp b/third_party/rive/include/rive/viewmodel/runtime/viewmodel_instance_color_runtime.hpp new file mode 100644 index 0000000..22f9a15 --- /dev/null +++ b/third_party/rive/include/rive/viewmodel/runtime/viewmodel_instance_color_runtime.hpp @@ -0,0 +1,26 @@ +#ifndef _RIVE_VIEW_MODEL_INSTANCE_COLOR_RUNTIME_HPP_ +#define _RIVE_VIEW_MODEL_INSTANCE_COLOR_RUNTIME_HPP_ + +#include +#include +#include "rive/viewmodel/runtime/viewmodel_instance_value_runtime.hpp" +#include "rive/viewmodel/viewmodel_instance_color.hpp" + +namespace rive +{ + +class ViewModelInstanceColorRuntime : public ViewModelInstanceValueRuntime +{ + +public: + ViewModelInstanceColorRuntime(ViewModelInstanceColor* viewModelInstance) : + ViewModelInstanceValueRuntime(viewModelInstance) + {} + int value() const; + void value(int); + void rgb(int, int, int); + void argb(int, int, int, int); + void alpha(int); +}; +} // namespace rive +#endif diff --git a/third_party/rive/include/rive/viewmodel/runtime/viewmodel_instance_enum_runtime.hpp b/third_party/rive/include/rive/viewmodel/runtime/viewmodel_instance_enum_runtime.hpp new file mode 100644 index 0000000..e520183 --- /dev/null +++ b/third_party/rive/include/rive/viewmodel/runtime/viewmodel_instance_enum_runtime.hpp @@ -0,0 +1,31 @@ +#ifndef _RIVE_VIEW_MODEL_INSTANCE_ENUM_RUNTIME_HPP_ +#define _RIVE_VIEW_MODEL_INSTANCE_ENUM_RUNTIME_HPP_ + +#include +#include +#include "rive/viewmodel/runtime/viewmodel_instance_value_runtime.hpp" +#include "rive/viewmodel/viewmodel_instance_enum.hpp" +#include "rive/viewmodel/data_enum.hpp" +#include "rive/viewmodel/data_enum_value.hpp" + +namespace rive +{ + +class ViewModelInstanceEnumRuntime : public ViewModelInstanceValueRuntime +{ + +public: + ViewModelInstanceEnumRuntime(ViewModelInstanceEnum* viewModelInstance) : + ViewModelInstanceValueRuntime(viewModelInstance) + {} + std::string value() const; + void value(std::string); + uint32_t valueIndex() const; + void valueIndex(uint32_t); + std::vector values() const; + +private: + std::vector dataValues() const; +}; +} // namespace rive +#endif diff --git a/third_party/rive/include/rive/viewmodel/runtime/viewmodel_instance_list_runtime.hpp b/third_party/rive/include/rive/viewmodel/runtime/viewmodel_instance_list_runtime.hpp new file mode 100644 index 0000000..4d41af1 --- /dev/null +++ b/third_party/rive/include/rive/viewmodel/runtime/viewmodel_instance_list_runtime.hpp @@ -0,0 +1,35 @@ +#ifndef _RIVE_VIEW_MODEL_INSTANCE_LIST_RUNTIME_HPP_ +#define _RIVE_VIEW_MODEL_INSTANCE_LIST_RUNTIME_HPP_ + +#include +#include +#include +#include "rive/viewmodel/runtime/viewmodel_instance_value_runtime.hpp" +#include "rive/viewmodel/viewmodel_instance_list.hpp" +#include "rive/viewmodel/viewmodel_instance_list_item.hpp" + +namespace rive +{ +class ViewModelInstanceRuntime; + +class ViewModelInstanceListRuntime : public ViewModelInstanceValueRuntime +{ + +public: + ~ViewModelInstanceListRuntime(); + ViewModelInstanceListRuntime(ViewModelInstanceList* viewModelInstance) : + ViewModelInstanceValueRuntime(viewModelInstance) + {} + ViewModelInstanceRuntime* instanceAt(int index); + void addInstance(ViewModelInstanceRuntime*); + void removeInstance(ViewModelInstanceRuntime*); + void removeInstanceAt(int); + void swap(uint32_t, uint32_t); + size_t size() const; + +private: + std::unordered_map + m_itemsMap; +}; +} // namespace rive +#endif diff --git a/third_party/rive/include/rive/viewmodel/runtime/viewmodel_instance_number_runtime.hpp b/third_party/rive/include/rive/viewmodel/runtime/viewmodel_instance_number_runtime.hpp new file mode 100644 index 0000000..06e864b --- /dev/null +++ b/third_party/rive/include/rive/viewmodel/runtime/viewmodel_instance_number_runtime.hpp @@ -0,0 +1,23 @@ +#ifndef _RIVE_VIEW_MODEL_INSTANCE_NUMBER_RUNTIME_HPP_ +#define _RIVE_VIEW_MODEL_INSTANCE_NUMBER_RUNTIME_HPP_ + +#include +#include +#include "rive/viewmodel/runtime/viewmodel_instance_value_runtime.hpp" +#include "rive/viewmodel/viewmodel_instance_number.hpp" + +namespace rive +{ + +class ViewModelInstanceNumberRuntime : public ViewModelInstanceValueRuntime +{ + +public: + ViewModelInstanceNumberRuntime(ViewModelInstanceNumber* viewModelInstance) : + ViewModelInstanceValueRuntime(viewModelInstance) + {} + float value() const; + void value(float); +}; +} // namespace rive +#endif diff --git a/third_party/rive/include/rive/viewmodel/runtime/viewmodel_instance_runtime.hpp b/third_party/rive/include/rive/viewmodel/runtime/viewmodel_instance_runtime.hpp new file mode 100644 index 0000000..c3cf87e --- /dev/null +++ b/third_party/rive/include/rive/viewmodel/runtime/viewmodel_instance_runtime.hpp @@ -0,0 +1,94 @@ +#ifndef _RIVE_VIEW_MODEL_INSTANCE_RUNTIME_HPP_ +#define _RIVE_VIEW_MODEL_INSTANCE_RUNTIME_HPP_ + +#include +#include +#include +#include "rive/viewmodel/viewmodel_instance.hpp" +#include "rive/viewmodel/viewmodel.hpp" +#include "rive/viewmodel/runtime/viewmodel_instance_value_runtime.hpp" +#include "rive/viewmodel/runtime/viewmodel_instance_boolean_runtime.hpp" +#include "rive/viewmodel/runtime/viewmodel_instance_color_runtime.hpp" +#include "rive/viewmodel/runtime/viewmodel_instance_number_runtime.hpp" +#include "rive/viewmodel/runtime/viewmodel_instance_string_runtime.hpp" +#include "rive/viewmodel/runtime/viewmodel_instance_enum_runtime.hpp" +#include "rive/viewmodel/runtime/viewmodel_instance_trigger_runtime.hpp" +#include "rive/viewmodel/runtime/viewmodel_instance_list_runtime.hpp" +#include "rive/viewmodel/runtime/viewmodel_instance_asset_image_runtime.hpp" +#include "rive/refcnt.hpp" + +namespace rive +{ +class ViewModel; +struct PropertyData; + +class ViewModelInstanceRuntime : public RefCnt +{ + +public: + ViewModelInstanceRuntime(rcp instance); + ~ViewModelInstanceRuntime(); + + const std::string& name() const; + size_t propertyCount() const; + ViewModelInstanceNumberRuntime* propertyNumber( + const std::string& path) const; + ViewModelInstanceStringRuntime* propertyString( + const std::string& path) const; + ViewModelInstanceBooleanRuntime* propertyBoolean( + const std::string& path) const; + ViewModelInstanceColorRuntime* propertyColor(const std::string& path) const; + ViewModelInstanceEnumRuntime* propertyEnum(const std::string& path) const; + ViewModelInstanceTriggerRuntime* propertyTrigger( + const std::string& path) const; + ViewModelInstanceListRuntime* propertyList(const std::string& path) const; + ViewModelInstanceRuntime* propertyViewModel(const std::string& path) const; + ViewModelInstanceAssetImageRuntime* propertyImage( + const std::string& path) const; + bool replaceViewModel(const std::string& path, + ViewModelInstanceRuntime* value) const; + bool replaceViewModelByName(const std::string& name, + ViewModelInstanceRuntime* value) const; + ViewModelInstanceValueRuntime* property(const std::string& path) const; + rcp instance() { return m_viewModelInstance; }; + std::vector properties() const; + +private: + rcp m_viewModelInstance = nullptr; + + std::string getPropertyNameFromPath(const std::string& path) const; + const ViewModelInstanceRuntime* viewModelInstanceFromFullPath( + const std::string& path) const; + + mutable std::unordered_map + m_properties; + mutable std::unordered_map> + m_viewModelInstances; + rcp viewModelInstanceProperty( + const std::string& name) const; + rcp instanceRuntime( + const std::string& name) const; + ViewModelInstanceRuntime* viewModelInstanceAtPath( + const std::string& path) const; + template + U* getPropertyInstance(const std::string name) const + { + auto itr = m_properties.find(name); + if (itr != m_properties.end()) + { + return static_cast(itr->second); + } + auto viewModelInstanceValue = m_viewModelInstance->propertyValue(name); + if (viewModelInstanceValue != nullptr && + viewModelInstanceValue->is()) + { + auto runtimeInstance = new U(viewModelInstanceValue->as()); + m_properties[name] = runtimeInstance; + return runtimeInstance; + } + return nullptr; + }; +}; +} // namespace rive +#endif diff --git a/third_party/rive/include/rive/viewmodel/runtime/viewmodel_instance_string_runtime.hpp b/third_party/rive/include/rive/viewmodel/runtime/viewmodel_instance_string_runtime.hpp new file mode 100644 index 0000000..dc2e481 --- /dev/null +++ b/third_party/rive/include/rive/viewmodel/runtime/viewmodel_instance_string_runtime.hpp @@ -0,0 +1,23 @@ +#ifndef _RIVE_VIEW_MODEL_INSTANCE_STRING_RUNTIME_HPP_ +#define _RIVE_VIEW_MODEL_INSTANCE_STRING_RUNTIME_HPP_ + +#include +#include +#include "rive/viewmodel/runtime/viewmodel_instance_value_runtime.hpp" +#include "rive/viewmodel/viewmodel_instance_string.hpp" + +namespace rive +{ + +class ViewModelInstanceStringRuntime : public ViewModelInstanceValueRuntime +{ + +public: + ViewModelInstanceStringRuntime(ViewModelInstanceString* viewModelInstance) : + ViewModelInstanceValueRuntime(viewModelInstance) + {} + const std::string& value() const; + void value(std::string); +}; +} // namespace rive +#endif diff --git a/third_party/rive/include/rive/viewmodel/runtime/viewmodel_instance_trigger_runtime.hpp b/third_party/rive/include/rive/viewmodel/runtime/viewmodel_instance_trigger_runtime.hpp new file mode 100644 index 0000000..73d346b --- /dev/null +++ b/third_party/rive/include/rive/viewmodel/runtime/viewmodel_instance_trigger_runtime.hpp @@ -0,0 +1,23 @@ +#ifndef _RIVE_VIEW_MODEL_INSTANCE_TRIGGER_RUNTIME_HPP_ +#define _RIVE_VIEW_MODEL_INSTANCE_TRIGGER_RUNTIME_HPP_ + +#include +#include +#include "rive/viewmodel/runtime/viewmodel_instance_value_runtime.hpp" +#include "rive/viewmodel/viewmodel_instance_trigger.hpp" + +namespace rive +{ + +class ViewModelInstanceTriggerRuntime : public ViewModelInstanceValueRuntime +{ + +public: + ViewModelInstanceTriggerRuntime( + ViewModelInstanceTrigger* viewModelInstance) : + ViewModelInstanceValueRuntime(viewModelInstance) + {} + void trigger(); +}; +} // namespace rive +#endif diff --git a/third_party/rive/include/rive/viewmodel/runtime/viewmodel_instance_value_runtime.hpp b/third_party/rive/include/rive/viewmodel/runtime/viewmodel_instance_value_runtime.hpp new file mode 100644 index 0000000..306d826 --- /dev/null +++ b/third_party/rive/include/rive/viewmodel/runtime/viewmodel_instance_value_runtime.hpp @@ -0,0 +1,31 @@ +#ifndef _RIVE_VIEW_MODEL_INSTANCE_VALUE_RUNTIME_HPP_ +#define _RIVE_VIEW_MODEL_INSTANCE_VALUE_RUNTIME_HPP_ + +#include +#include +#include "rive/viewmodel/viewmodel_instance_value.hpp" +#include "rive/dirtyable.hpp" + +namespace rive +{ + +class ViewModelInstanceValueRuntime : public Dirtyable +{ + +public: + ViewModelInstanceValueRuntime(ViewModelInstanceValue* instanceValue); + virtual ~ViewModelInstanceValueRuntime(); + void addDirt(ComponentDirt dirt, bool recurse) override; + void clearChanges(); + bool hasChanged() const { return m_hasChanged; } + bool flushChanges(); + const std::string& name() const; + +protected: + ViewModelInstanceValue* m_viewModelInstanceValue = nullptr; + +private: + bool m_hasChanged = false; +}; +} // namespace rive +#endif diff --git a/third_party/rive/include/rive/viewmodel/runtime/viewmodel_runtime.hpp b/third_party/rive/include/rive/viewmodel/runtime/viewmodel_runtime.hpp new file mode 100644 index 0000000..a249f25 --- /dev/null +++ b/third_party/rive/include/rive/viewmodel/runtime/viewmodel_runtime.hpp @@ -0,0 +1,49 @@ +#ifndef _RIVE_VIEW_MODEL_RUNTIME_HPP_ +#define _RIVE_VIEW_MODEL_RUNTIME_HPP_ + +#include +#include +#include "rive/file.hpp" +#include "rive/viewmodel/viewmodel_instance.hpp" +#include "rive/viewmodel/runtime/viewmodel_instance_runtime.hpp" +#include "rive/data_bind/data_values/data_type.hpp" + +namespace rive +{ +class ViewModel; + +struct PropertyData +{ + DataType type; + std::string name; +}; + +class ViewModelRuntime +{ + +public: + ViewModelRuntime(ViewModel* viewModel, const File* file); + + const std::string& name() const; + size_t instanceCount() const; + size_t propertyCount() const; + ViewModelInstanceRuntime* createInstanceFromIndex(size_t index) const; + ViewModelInstanceRuntime* createInstanceFromName( + const std::string& name) const; + ViewModelInstanceRuntime* createDefaultInstance() const; + ViewModelInstanceRuntime* createInstance() const; + std::vector properties(); + static std::vector buildPropertiesData( + std::vector& properties); + std::vector instanceNames() const; + +private: + ViewModel* m_viewModel; + const File* m_file; + mutable std::vector> + m_viewModelInstanceRuntimes; + ViewModelInstanceRuntime* createRuntimeInstance( + rcp instance) const; +}; +} // namespace rive +#endif diff --git a/third_party/rive/include/rive/viewmodel/viewmodel.hpp b/third_party/rive/include/rive/viewmodel/viewmodel.hpp new file mode 100644 index 0000000..1d1d3e8 --- /dev/null +++ b/third_party/rive/include/rive/viewmodel/viewmodel.hpp @@ -0,0 +1,31 @@ +#ifndef _RIVE_VIEW_MODEL_HPP_ +#define _RIVE_VIEW_MODEL_HPP_ +#include "rive/generated/viewmodel/viewmodel_base.hpp" +#include "rive/viewmodel/viewmodel_property.hpp" +#include "rive/viewmodel/viewmodel_instance.hpp" +#include "rive/refcnt.hpp" +#include +namespace rive +{ +class ViewModel : public ViewModelBase, public RefCnt +{ +private: + std::vector m_Properties; + std::vector m_Instances; + +public: + ~ViewModel(); + void addProperty(ViewModelProperty* property); + ViewModelProperty* property(const std::string& name); + ViewModelProperty* property(size_t index); + void addInstance(ViewModelInstance* value); + ViewModelInstance* instance(size_t index); + ViewModelInstance* instance(const std::string& name); + ViewModelInstance* defaultInstance(); + size_t instanceCount() const; + std::vector properties() { return m_Properties; } + std::vector instances() { return m_Instances; } +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/viewmodel/viewmodel_component.hpp b/third_party/rive/include/rive/viewmodel/viewmodel_component.hpp new file mode 100644 index 0000000..28354b4 --- /dev/null +++ b/third_party/rive/include/rive/viewmodel/viewmodel_component.hpp @@ -0,0 +1,13 @@ +#ifndef _RIVE_VIEW_MODEL_COMPONENT_HPP_ +#define _RIVE_VIEW_MODEL_COMPONENT_HPP_ +#include "rive/generated/viewmodel/viewmodel_component_base.hpp" +#include +namespace rive +{ +class ViewModelComponent : public ViewModelComponentBase +{ +public: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/viewmodel/viewmodel_instance.hpp b/third_party/rive/include/rive/viewmodel/viewmodel_instance.hpp new file mode 100644 index 0000000..4abea31 --- /dev/null +++ b/third_party/rive/include/rive/viewmodel/viewmodel_instance.hpp @@ -0,0 +1,40 @@ +#ifndef _RIVE_VIEW_MODEL_INSTANCE_HPP_ +#define _RIVE_VIEW_MODEL_INSTANCE_HPP_ +#include "rive/generated/viewmodel/viewmodel_instance_base.hpp" +#include "rive/viewmodel/viewmodel_instance_value.hpp" +#include "rive/component.hpp" +#include "rive/refcnt.hpp" +#include +namespace rive +{ +class ViewModel; +class ViewModelInstance : public ViewModelInstanceBase, + public RefCnt +{ +private: + std::vector m_PropertyValues; + ViewModel* m_ViewModel; + +public: + ~ViewModelInstance(); + void addValue(ViewModelInstanceValue* value); + ViewModelInstanceValue* propertyValue(const uint32_t id); + ViewModelInstanceValue* propertyValue(const std::string& name); + bool replaceViewModelByName(const std::string& name, + rcp value); + std::vector propertyValues(); + ViewModelInstanceValue* propertyFromPath(std::vector* path, + size_t index); + ViewModelInstanceValue* symbol(int coreType); + void viewModel(ViewModel* value); + ViewModel* viewModel() const; + void onComponentDirty(Component* component); + void setAsRoot(rcp instance); + void setRoot(rcp value); + Core* clone() const override; + StatusCode import(ImportStack& importStack) override; + void advanced(); +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/viewmodel/viewmodel_instance_asset.hpp b/third_party/rive/include/rive/viewmodel/viewmodel_instance_asset.hpp new file mode 100644 index 0000000..181f635 --- /dev/null +++ b/third_party/rive/include/rive/viewmodel/viewmodel_instance_asset.hpp @@ -0,0 +1,35 @@ +#ifndef _RIVE_VIEW_MODEL_INSTANCE_ASSET_HPP_ +#define _RIVE_VIEW_MODEL_INSTANCE_ASSET_HPP_ +#include "rive/generated/viewmodel/viewmodel_instance_asset_base.hpp" +#include "rive/assets/file_asset.hpp" +#include +namespace rive +{ +#ifdef WITH_RIVE_TOOLS +class ViewModelInstanceAsset; +typedef void (*ViewModelAssetChanged)(ViewModelInstanceAsset* vmi, + uint32_t value); +#endif +class ViewModelInstanceAsset : public ViewModelInstanceAssetBase +{ +public: + StatusCode import(ImportStack& importStack) override; + void addAsset(FileAsset* asset) { m_assets.push_back(asset); } + +protected: + const std::vector& assets() const { return m_assets; } + +private: + std::vector m_assets; +#ifdef WITH_RIVE_TOOLS +public: + void onChanged(ViewModelAssetChanged callback) + { + m_changedCallback = callback; + } + ViewModelAssetChanged m_changedCallback = nullptr; +#endif +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/viewmodel/viewmodel_instance_asset_image.hpp b/third_party/rive/include/rive/viewmodel/viewmodel_instance_asset_image.hpp new file mode 100644 index 0000000..9a523ee --- /dev/null +++ b/third_party/rive/include/rive/viewmodel/viewmodel_instance_asset_image.hpp @@ -0,0 +1,24 @@ +#ifndef _RIVE_VIEW_MODEL_INSTANCE_ASSET_IMAGE_HPP_ +#define _RIVE_VIEW_MODEL_INSTANCE_ASSET_IMAGE_HPP_ +#include "rive/generated/viewmodel/viewmodel_instance_asset_image_base.hpp" +#include "rive/renderer.hpp" +#include "rive/assets/image_asset.hpp" +#include +namespace rive +{ +class ViewModelInstanceAssetImage : public ViewModelInstanceAssetImageBase +{ +protected: + void propertyValueChanged() override; + +public: + void value(RenderImage* image); + ImageAsset* asset() { return &m_imageAsset; } + Core* clone() const override; + +private: + ImageAsset m_imageAsset; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/viewmodel/viewmodel_instance_boolean.hpp b/third_party/rive/include/rive/viewmodel/viewmodel_instance_boolean.hpp new file mode 100644 index 0000000..26ec4ee --- /dev/null +++ b/third_party/rive/include/rive/viewmodel/viewmodel_instance_boolean.hpp @@ -0,0 +1,27 @@ +#ifndef _RIVE_VIEW_MODEL_INSTANCE_BOOLEAN_HPP_ +#define _RIVE_VIEW_MODEL_INSTANCE_BOOLEAN_HPP_ +#include "rive/generated/viewmodel/viewmodel_instance_boolean_base.hpp" +#include +namespace rive +{ +#ifdef WITH_RIVE_TOOLS +class ViewModelInstanceBoolean; +typedef void (*ViewModelBooleanChanged)(ViewModelInstanceBoolean* vmi, + bool value); +#endif +class ViewModelInstanceBoolean : public ViewModelInstanceBooleanBase +{ +protected: + void propertyValueChanged() override; +#ifdef WITH_RIVE_TOOLS +public: + void onChanged(ViewModelBooleanChanged callback) + { + m_changedCallback = callback; + } + ViewModelBooleanChanged m_changedCallback = nullptr; +#endif +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/viewmodel/viewmodel_instance_color.hpp b/third_party/rive/include/rive/viewmodel/viewmodel_instance_color.hpp new file mode 100644 index 0000000..045dd61 --- /dev/null +++ b/third_party/rive/include/rive/viewmodel/viewmodel_instance_color.hpp @@ -0,0 +1,26 @@ +#ifndef _RIVE_VIEW_MODEL_INSTANCE_COLOR_HPP_ +#define _RIVE_VIEW_MODEL_INSTANCE_COLOR_HPP_ +#include "rive/generated/viewmodel/viewmodel_instance_color_base.hpp" +#include +namespace rive +{ +#ifdef WITH_RIVE_TOOLS +class ViewModelInstanceColor; +typedef void (*ViewModelColorChanged)(ViewModelInstanceColor* vmi, int value); +#endif +class ViewModelInstanceColor : public ViewModelInstanceColorBase +{ +public: + void propertyValueChanged() override; +#ifdef WITH_RIVE_TOOLS +public: + void onChanged(ViewModelColorChanged callback) + { + m_changedCallback = callback; + } + ViewModelColorChanged m_changedCallback = nullptr; +#endif +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/viewmodel/viewmodel_instance_enum.hpp b/third_party/rive/include/rive/viewmodel/viewmodel_instance_enum.hpp new file mode 100644 index 0000000..65db727 --- /dev/null +++ b/third_party/rive/include/rive/viewmodel/viewmodel_instance_enum.hpp @@ -0,0 +1,31 @@ +#ifndef _RIVE_VIEW_MODEL_INSTANCE_ENUM_HPP_ +#define _RIVE_VIEW_MODEL_INSTANCE_ENUM_HPP_ +#include "rive/generated/viewmodel/viewmodel_instance_enum_base.hpp" +#include +namespace rive +{ +#ifdef WITH_RIVE_TOOLS +class ViewModelInstanceEnum; +typedef void (*ViewModelEnumChanged)(ViewModelInstanceEnum* vmi, + uint32_t value); +#endif +class ViewModelInstanceEnum : public ViewModelInstanceEnumBase +{ +public: + bool value(std::string name); + bool value(uint32_t index); + +protected: + void propertyValueChanged() override; +#ifdef WITH_RIVE_TOOLS +public: + void onChanged(ViewModelEnumChanged callback) + { + m_changedCallback = callback; + } + ViewModelEnumChanged m_changedCallback = nullptr; +#endif +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/viewmodel/viewmodel_instance_list.hpp b/third_party/rive/include/rive/viewmodel/viewmodel_instance_list.hpp new file mode 100644 index 0000000..63277ad --- /dev/null +++ b/third_party/rive/include/rive/viewmodel/viewmodel_instance_list.hpp @@ -0,0 +1,28 @@ +#ifndef _RIVE_VIEW_MODEL_INSTANCE_LIST_HPP_ +#define _RIVE_VIEW_MODEL_INSTANCE_LIST_HPP_ +#include "rive/generated/viewmodel/viewmodel_instance_list_base.hpp" +#include "rive/viewmodel/viewmodel_instance_list_item.hpp" +#include +namespace rive +{ +class ViewModelInstanceList : public ViewModelInstanceListBase +{ +public: + ~ViewModelInstanceList(); + void addItem(ViewModelInstanceListItem* listItem); + void internalAddItem(ViewModelInstanceListItem* listItem); + void insertItem(int index, ViewModelInstanceListItem* listItem); + void removeItem(int index); + void removeItem(ViewModelInstanceListItem* listItem); + std::vector listItems() { return m_ListItems; }; + ViewModelInstanceListItem* item(uint32_t index); + void swap(uint32_t index1, uint32_t index2); + Core* clone() const override; + +protected: + std::vector m_ListItems; + void propertyValueChanged(); +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/viewmodel/viewmodel_instance_list_item.hpp b/third_party/rive/include/rive/viewmodel/viewmodel_instance_list_item.hpp new file mode 100644 index 0000000..7a36877 --- /dev/null +++ b/third_party/rive/include/rive/viewmodel/viewmodel_instance_list_item.hpp @@ -0,0 +1,28 @@ +#ifndef _RIVE_VIEW_MODEL_INSTANCE_LIST_ITEM_HPP_ +#define _RIVE_VIEW_MODEL_INSTANCE_LIST_ITEM_HPP_ +#include "rive/generated/viewmodel/viewmodel_instance_list_item_base.hpp" +#include "rive/viewmodel/viewmodel_instance.hpp" +#include "rive/refcnt.hpp" +#include +namespace rive +{ +class ViewModelInstanceListItem : public ViewModelInstanceListItemBase, + public RefCnt +{ +private: + rcp m_viewModelInstance; + Artboard* m_artboard; + +public: + void viewModelInstance(rcp value) + { + m_viewModelInstance = value; + }; + rcp viewModelInstance() { return m_viewModelInstance; } + void artboard(Artboard* value) { m_artboard = value; }; + Artboard* artboard() { return m_artboard; } + StatusCode import(ImportStack& importStack) override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/viewmodel/viewmodel_instance_number.hpp b/third_party/rive/include/rive/viewmodel/viewmodel_instance_number.hpp new file mode 100644 index 0000000..7e85b52 --- /dev/null +++ b/third_party/rive/include/rive/viewmodel/viewmodel_instance_number.hpp @@ -0,0 +1,27 @@ +#ifndef _RIVE_VIEW_MODEL_INSTANCE_NUMBER_HPP_ +#define _RIVE_VIEW_MODEL_INSTANCE_NUMBER_HPP_ +#include "rive/generated/viewmodel/viewmodel_instance_number_base.hpp" +#include +namespace rive +{ +#ifdef WITH_RIVE_TOOLS +class ViewModelInstanceNumber; +typedef void (*ViewModelNumberChanged)(ViewModelInstanceNumber* vmi, + float value); +#endif +class ViewModelInstanceNumber : public ViewModelInstanceNumberBase +{ +protected: + void propertyValueChanged() override; +#ifdef WITH_RIVE_TOOLS +public: + void onChanged(ViewModelNumberChanged callback) + { + m_changedCallback = callback; + } + ViewModelNumberChanged m_changedCallback = nullptr; +#endif +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/viewmodel/viewmodel_instance_string.hpp b/third_party/rive/include/rive/viewmodel/viewmodel_instance_string.hpp new file mode 100644 index 0000000..a579298 --- /dev/null +++ b/third_party/rive/include/rive/viewmodel/viewmodel_instance_string.hpp @@ -0,0 +1,27 @@ +#ifndef _RIVE_VIEW_MODEL_INSTANCE_STRING_HPP_ +#define _RIVE_VIEW_MODEL_INSTANCE_STRING_HPP_ +#include "rive/generated/viewmodel/viewmodel_instance_string_base.hpp" +#include +namespace rive +{ +#ifdef WITH_RIVE_TOOLS +class ViewModelInstanceString; +typedef void (*ViewModelStringChanged)(ViewModelInstanceString* vmi, + const char* value); +#endif +class ViewModelInstanceString : public ViewModelInstanceStringBase +{ +public: + void propertyValueChanged() override; +#ifdef WITH_RIVE_TOOLS +public: + void onChanged(ViewModelStringChanged callback) + { + m_changedCallback = callback; + } + ViewModelStringChanged m_changedCallback = nullptr; +#endif +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/viewmodel/viewmodel_instance_symbol.hpp b/third_party/rive/include/rive/viewmodel/viewmodel_instance_symbol.hpp new file mode 100644 index 0000000..babb69c --- /dev/null +++ b/third_party/rive/include/rive/viewmodel/viewmodel_instance_symbol.hpp @@ -0,0 +1,13 @@ +#ifndef _RIVE_VIEW_MODEL_INSTANCE_SYMBOL_HPP_ +#define _RIVE_VIEW_MODEL_INSTANCE_SYMBOL_HPP_ +#include "rive/generated/viewmodel/viewmodel_instance_symbol_base.hpp" +#include +namespace rive +{ +class ViewModelInstanceSymbol : public ViewModelInstanceSymbolBase +{ +public: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/viewmodel/viewmodel_instance_symbol_list_index.hpp b/third_party/rive/include/rive/viewmodel/viewmodel_instance_symbol_list_index.hpp new file mode 100644 index 0000000..23d7151 --- /dev/null +++ b/third_party/rive/include/rive/viewmodel/viewmodel_instance_symbol_list_index.hpp @@ -0,0 +1,29 @@ +#ifndef _RIVE_VIEW_MODEL_INSTANCE_SYMBOL_LIST_INDEX_HPP_ +#define _RIVE_VIEW_MODEL_INSTANCE_SYMBOL_LIST_INDEX_HPP_ +#include "rive/generated/viewmodel/viewmodel_instance_symbol_list_index_base.hpp" +#include +namespace rive +{ +#ifdef WITH_RIVE_TOOLS +class ViewModelInstanceSymbolListIndex; +typedef void (*ViewModelSymbolListIndexChanged)( + ViewModelInstanceSymbolListIndex* vmi, + uint32_t value); +#endif +class ViewModelInstanceSymbolListIndex + : public ViewModelInstanceSymbolListIndexBase +{ +protected: + void propertyValueChanged() override; +#ifdef WITH_RIVE_TOOLS +public: + void onChanged(ViewModelSymbolListIndexChanged callback) + { + m_changedCallback = callback; + } + ViewModelSymbolListIndexChanged m_changedCallback = nullptr; +#endif +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/viewmodel/viewmodel_instance_trigger.hpp b/third_party/rive/include/rive/viewmodel/viewmodel_instance_trigger.hpp new file mode 100644 index 0000000..618a5b6 --- /dev/null +++ b/third_party/rive/include/rive/viewmodel/viewmodel_instance_trigger.hpp @@ -0,0 +1,33 @@ +#ifndef _RIVE_VIEW_MODEL_INSTANCE_TRIGGER_HPP_ +#define _RIVE_VIEW_MODEL_INSTANCE_TRIGGER_HPP_ +#include "rive/generated/viewmodel/viewmodel_instance_trigger_base.hpp" +#include "rive/animation/state_machine_input_instance.hpp" +#include +namespace rive +{ +#ifdef WITH_RIVE_TOOLS +class ViewModelInstanceTrigger; +typedef void (*ViewModelTriggerChanged)(ViewModelInstanceTrigger* vmi, + uint32_t value); +#endif +class ViewModelInstanceTrigger : public ViewModelInstanceTriggerBase, + public Triggerable +{ +protected: + void propertyValueChanged() override; + +public: + void advanced() override; +#ifdef WITH_RIVE_TOOLS + void onChanged(ViewModelTriggerChanged callback) + { + m_changedCallback = callback; + } + ViewModelTriggerChanged m_changedCallback = nullptr; +#endif + + void trigger() { propertyValue(propertyValue() + 1); } +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/viewmodel/viewmodel_instance_value.hpp b/third_party/rive/include/rive/viewmodel/viewmodel_instance_value.hpp new file mode 100644 index 0000000..292c7ac --- /dev/null +++ b/third_party/rive/include/rive/viewmodel/viewmodel_instance_value.hpp @@ -0,0 +1,37 @@ +#ifndef _RIVE_VIEW_MODEL_INSTANCE_VALUE_HPP_ +#define _RIVE_VIEW_MODEL_INSTANCE_VALUE_HPP_ +#include "rive/generated/viewmodel/viewmodel_instance_value_base.hpp" +#include "rive/viewmodel/viewmodel_property.hpp" +#include "rive/dependency_helper.hpp" +#include "rive/dirtyable.hpp" +#include "rive/component.hpp" +#include "rive/component_dirt.hpp" +#include "rive/refcnt.hpp" +#include +namespace rive +{ +class ViewModelInstance; +class ViewModelInstanceValue : public ViewModelInstanceValueBase, + public RefCnt +{ +private: + ViewModelProperty* m_ViewModelProperty; + static std::string defaultName; + +protected: + DependencyHelper, Dirtyable> m_DependencyHelper; + void addDirt(ComponentDirt value); + +public: + StatusCode import(ImportStack& importStack) override; + void viewModelProperty(ViewModelProperty* value); + ViewModelProperty* viewModelProperty(); + void addDependent(Dirtyable* value); + void removeDependent(Dirtyable* value); + virtual void setRoot(rcp value); + virtual void advanced(){}; + const std::string& name() const; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/viewmodel/viewmodel_instance_viewmodel.hpp b/third_party/rive/include/rive/viewmodel/viewmodel_instance_viewmodel.hpp new file mode 100644 index 0000000..e1407ca --- /dev/null +++ b/third_party/rive/include/rive/viewmodel/viewmodel_instance_viewmodel.hpp @@ -0,0 +1,29 @@ +#ifndef _RIVE_VIEW_MODEL_INSTANCE_VIEW_MODEL_HPP_ +#define _RIVE_VIEW_MODEL_INSTANCE_VIEW_MODEL_HPP_ +#include "rive/generated/viewmodel/viewmodel_instance_viewmodel_base.hpp" +#include "rive/viewmodel/viewmodel_instance.hpp" +#include "rive/refcnt.hpp" +#include +namespace rive +{ +class ViewModelInstanceViewModel : public ViewModelInstanceViewModelBase +{ +private: + rcp m_referenceViewModelInstance; + +public: + ~ViewModelInstanceViewModel(); + void referenceViewModelInstance(rcp value) + { + m_referenceViewModelInstance = value; + }; + rcp referenceViewModelInstance() + { + return m_referenceViewModelInstance; + } + void setRoot(rcp value) override; + void advanced() override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/viewmodel/viewmodel_property.hpp b/third_party/rive/include/rive/viewmodel/viewmodel_property.hpp new file mode 100644 index 0000000..9c60f2b --- /dev/null +++ b/third_party/rive/include/rive/viewmodel/viewmodel_property.hpp @@ -0,0 +1,15 @@ +#ifndef _RIVE_VIEW_MODEL_PROPERTY_HPP_ +#define _RIVE_VIEW_MODEL_PROPERTY_HPP_ +#include "rive/generated/viewmodel/viewmodel_property_base.hpp" +#include +namespace rive +{ +class ViewModelProperty : public ViewModelPropertyBase +{ +public: + StatusCode import(ImportStack& importStack) override; + inline const std::string& constName() const { return m_Name; } +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/viewmodel/viewmodel_property_asset.hpp b/third_party/rive/include/rive/viewmodel/viewmodel_property_asset.hpp new file mode 100644 index 0000000..a00a4fb --- /dev/null +++ b/third_party/rive/include/rive/viewmodel/viewmodel_property_asset.hpp @@ -0,0 +1,13 @@ +#ifndef _RIVE_VIEW_MODEL_PROPERTY_ASSET_HPP_ +#define _RIVE_VIEW_MODEL_PROPERTY_ASSET_HPP_ +#include "rive/generated/viewmodel/viewmodel_property_asset_base.hpp" +#include +namespace rive +{ +class ViewModelPropertyAsset : public ViewModelPropertyAssetBase +{ +public: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/viewmodel/viewmodel_property_asset_image.hpp b/third_party/rive/include/rive/viewmodel/viewmodel_property_asset_image.hpp new file mode 100644 index 0000000..74a44ce --- /dev/null +++ b/third_party/rive/include/rive/viewmodel/viewmodel_property_asset_image.hpp @@ -0,0 +1,13 @@ +#ifndef _RIVE_VIEW_MODEL_PROPERTY_ASSET_IMAGE_HPP_ +#define _RIVE_VIEW_MODEL_PROPERTY_ASSET_IMAGE_HPP_ +#include "rive/generated/viewmodel/viewmodel_property_asset_image_base.hpp" +#include +namespace rive +{ +class ViewModelPropertyAssetImage : public ViewModelPropertyAssetImageBase +{ +public: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/viewmodel/viewmodel_property_boolean.hpp b/third_party/rive/include/rive/viewmodel/viewmodel_property_boolean.hpp new file mode 100644 index 0000000..c86fb61 --- /dev/null +++ b/third_party/rive/include/rive/viewmodel/viewmodel_property_boolean.hpp @@ -0,0 +1,13 @@ +#ifndef _RIVE_VIEW_MODEL_PROPERTY_BOOLEAN_HPP_ +#define _RIVE_VIEW_MODEL_PROPERTY_BOOLEAN_HPP_ +#include "rive/generated/viewmodel/viewmodel_property_boolean_base.hpp" +#include +namespace rive +{ +class ViewModelPropertyBoolean : public ViewModelPropertyBooleanBase +{ +public: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/viewmodel/viewmodel_property_color.hpp b/third_party/rive/include/rive/viewmodel/viewmodel_property_color.hpp new file mode 100644 index 0000000..ffc1191 --- /dev/null +++ b/third_party/rive/include/rive/viewmodel/viewmodel_property_color.hpp @@ -0,0 +1,13 @@ +#ifndef _RIVE_VIEW_MODEL_PROPERTY_COLOR_HPP_ +#define _RIVE_VIEW_MODEL_PROPERTY_COLOR_HPP_ +#include "rive/generated/viewmodel/viewmodel_property_color_base.hpp" +#include +namespace rive +{ +class ViewModelPropertyColor : public ViewModelPropertyColorBase +{ +public: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/viewmodel/viewmodel_property_enum.hpp b/third_party/rive/include/rive/viewmodel/viewmodel_property_enum.hpp new file mode 100644 index 0000000..433a207 --- /dev/null +++ b/third_party/rive/include/rive/viewmodel/viewmodel_property_enum.hpp @@ -0,0 +1,28 @@ +#ifndef _RIVE_VIEW_MODEL_PROPERTY_ENUM_HPP_ +#define _RIVE_VIEW_MODEL_PROPERTY_ENUM_HPP_ +#include "rive/generated/viewmodel/viewmodel_property_enum_base.hpp" +#include "rive/viewmodel/data_enum.hpp" +#include "rive/refcnt.hpp" +#include +namespace rive +{ +class ViewModelPropertyEnum : public ViewModelPropertyEnumBase +{ + +public: + std::string value(std::string name); + std::string value(uint32_t index); + bool value(std::string name, std::string value); + bool value(uint32_t index, std::string value); + int valueIndex(std::string name); + int valueIndex(uint32_t index); + void dataEnum(DataEnum* value); + virtual DataEnum* dataEnum(); + +private: + rcp m_DataEnum; +}; + +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/viewmodel/viewmodel_property_enum_custom.hpp b/third_party/rive/include/rive/viewmodel/viewmodel_property_enum_custom.hpp new file mode 100644 index 0000000..efaf976 --- /dev/null +++ b/third_party/rive/include/rive/viewmodel/viewmodel_property_enum_custom.hpp @@ -0,0 +1,13 @@ +#ifndef _RIVE_VIEW_MODEL_PROPERTY_ENUM_CUSTOM_HPP_ +#define _RIVE_VIEW_MODEL_PROPERTY_ENUM_CUSTOM_HPP_ +#include "rive/generated/viewmodel/viewmodel_property_enum_custom_base.hpp" +#include +namespace rive +{ +class ViewModelPropertyEnumCustom : public ViewModelPropertyEnumCustomBase +{ +public: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/viewmodel/viewmodel_property_enum_system.hpp b/third_party/rive/include/rive/viewmodel/viewmodel_property_enum_system.hpp new file mode 100644 index 0000000..aac38da --- /dev/null +++ b/third_party/rive/include/rive/viewmodel/viewmodel_property_enum_system.hpp @@ -0,0 +1,17 @@ +#ifndef _RIVE_VIEW_MODEL_PROPERTY_ENUM_SYSTEM_HPP_ +#define _RIVE_VIEW_MODEL_PROPERTY_ENUM_SYSTEM_HPP_ +#include "rive/generated/viewmodel/viewmodel_property_enum_system_base.hpp" +#include +namespace rive +{ +class ViewModelPropertyEnumSystem : public ViewModelPropertyEnumSystemBase +{ +public: + DataEnum* dataEnum() override { return &m_systemDataEnum; } + +private: + static DataEnum m_systemDataEnum; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/viewmodel/viewmodel_property_list.hpp b/third_party/rive/include/rive/viewmodel/viewmodel_property_list.hpp new file mode 100644 index 0000000..a4fa054 --- /dev/null +++ b/third_party/rive/include/rive/viewmodel/viewmodel_property_list.hpp @@ -0,0 +1,13 @@ +#ifndef _RIVE_VIEW_MODEL_PROPERTY_LIST_HPP_ +#define _RIVE_VIEW_MODEL_PROPERTY_LIST_HPP_ +#include "rive/generated/viewmodel/viewmodel_property_list_base.hpp" +#include +namespace rive +{ +class ViewModelPropertyList : public ViewModelPropertyListBase +{ +public: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/viewmodel/viewmodel_property_number.hpp b/third_party/rive/include/rive/viewmodel/viewmodel_property_number.hpp new file mode 100644 index 0000000..0ba2468 --- /dev/null +++ b/third_party/rive/include/rive/viewmodel/viewmodel_property_number.hpp @@ -0,0 +1,13 @@ +#ifndef _RIVE_VIEW_MODEL_PROPERTY_NUMBER_HPP_ +#define _RIVE_VIEW_MODEL_PROPERTY_NUMBER_HPP_ +#include "rive/generated/viewmodel/viewmodel_property_number_base.hpp" +#include +namespace rive +{ +class ViewModelPropertyNumber : public ViewModelPropertyNumberBase +{ +public: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/viewmodel/viewmodel_property_string.hpp b/third_party/rive/include/rive/viewmodel/viewmodel_property_string.hpp new file mode 100644 index 0000000..0ff3745 --- /dev/null +++ b/third_party/rive/include/rive/viewmodel/viewmodel_property_string.hpp @@ -0,0 +1,13 @@ +#ifndef _RIVE_VIEW_MODEL_PROPERTY_STRING_HPP_ +#define _RIVE_VIEW_MODEL_PROPERTY_STRING_HPP_ +#include "rive/generated/viewmodel/viewmodel_property_string_base.hpp" +#include +namespace rive +{ +class ViewModelPropertyString : public ViewModelPropertyStringBase +{ +public: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/viewmodel/viewmodel_property_symbol.hpp b/third_party/rive/include/rive/viewmodel/viewmodel_property_symbol.hpp new file mode 100644 index 0000000..c6632ce --- /dev/null +++ b/third_party/rive/include/rive/viewmodel/viewmodel_property_symbol.hpp @@ -0,0 +1,13 @@ +#ifndef _RIVE_VIEW_MODEL_PROPERTY_SYMBOL_HPP_ +#define _RIVE_VIEW_MODEL_PROPERTY_SYMBOL_HPP_ +#include "rive/generated/viewmodel/viewmodel_property_symbol_base.hpp" +#include +namespace rive +{ +class ViewModelPropertySymbol : public ViewModelPropertySymbolBase +{ +public: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/viewmodel/viewmodel_property_symbol_list_index.hpp b/third_party/rive/include/rive/viewmodel/viewmodel_property_symbol_list_index.hpp new file mode 100644 index 0000000..6af14fc --- /dev/null +++ b/third_party/rive/include/rive/viewmodel/viewmodel_property_symbol_list_index.hpp @@ -0,0 +1,14 @@ +#ifndef _RIVE_VIEW_MODEL_PROPERTY_SYMBOL_LIST_INDEX_HPP_ +#define _RIVE_VIEW_MODEL_PROPERTY_SYMBOL_LIST_INDEX_HPP_ +#include "rive/generated/viewmodel/viewmodel_property_symbol_list_index_base.hpp" +#include +namespace rive +{ +class ViewModelPropertySymbolListIndex + : public ViewModelPropertySymbolListIndexBase +{ +public: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/viewmodel/viewmodel_property_trigger.hpp b/third_party/rive/include/rive/viewmodel/viewmodel_property_trigger.hpp new file mode 100644 index 0000000..794618d --- /dev/null +++ b/third_party/rive/include/rive/viewmodel/viewmodel_property_trigger.hpp @@ -0,0 +1,13 @@ +#ifndef _RIVE_VIEW_MODEL_PROPERTY_TRIGGER_HPP_ +#define _RIVE_VIEW_MODEL_PROPERTY_TRIGGER_HPP_ +#include "rive/generated/viewmodel/viewmodel_property_trigger_base.hpp" +#include +namespace rive +{ +class ViewModelPropertyTrigger : public ViewModelPropertyTriggerBase +{ +public: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/viewmodel/viewmodel_property_viewmodel.hpp b/third_party/rive/include/rive/viewmodel/viewmodel_property_viewmodel.hpp new file mode 100644 index 0000000..32ae213 --- /dev/null +++ b/third_party/rive/include/rive/viewmodel/viewmodel_property_viewmodel.hpp @@ -0,0 +1,13 @@ +#ifndef _RIVE_VIEW_MODEL_PROPERTY_VIEW_MODEL_HPP_ +#define _RIVE_VIEW_MODEL_PROPERTY_VIEW_MODEL_HPP_ +#include "rive/generated/viewmodel/viewmodel_property_viewmodel_base.hpp" +#include +namespace rive +{ +class ViewModelPropertyViewModel : public ViewModelPropertyViewModelBase +{ +public: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/rive/world_transform_component.hpp b/third_party/rive/include/rive/world_transform_component.hpp new file mode 100644 index 0000000..f5c97b2 --- /dev/null +++ b/third_party/rive/include/rive/world_transform_component.hpp @@ -0,0 +1,26 @@ +#ifndef _RIVE_WORLD_TRANSFORM_COMPONENT_HPP_ +#define _RIVE_WORLD_TRANSFORM_COMPONENT_HPP_ +#include "rive/generated/world_transform_component_base.hpp" +#include "rive/math/mat2d.hpp" + +namespace rive +{ +class TransformComponent; +class WorldTransformComponent : public WorldTransformComponentBase +{ + friend class TransformComponent; + +protected: + Mat2D m_WorldTransform; + +public: + void markWorldTransformDirty(); + virtual float childOpacity(); + Mat2D& mutableWorldTransform(); + const Mat2D& worldTransform() const; + Vec2D worldTranslation() const { return m_WorldTransform.translation(); } + void opacityChanged() override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/include/utils/auto_cf.hpp b/third_party/rive/include/utils/auto_cf.hpp new file mode 100644 index 0000000..5512a0b --- /dev/null +++ b/third_party/rive/include/utils/auto_cf.hpp @@ -0,0 +1,74 @@ +#pragma once + +#include "rive/rive_types.hpp" + +#ifdef RIVE_BUILD_FOR_APPLE + +#if defined(RIVE_BUILD_FOR_OSX) +#include +#elif defined(RIVE_BUILD_FOR_IOS) +#include +#endif + +template class AutoCF +{ + T m_obj; + +public: + AutoCF(T obj = nullptr) : m_obj(obj) {} + AutoCF(const AutoCF& other) + { + if (other.m_obj) + { + CFRetain(other.m_obj); + } + m_obj = other.m_obj; + } + AutoCF(AutoCF&& other) + { + m_obj = other.m_obj; + other.m_obj = nullptr; + } + ~AutoCF() + { + if (m_obj) + { + CFRelease(m_obj); + } + } + + AutoCF& operator=(const AutoCF& other) + { + if (m_obj != other.m_obj) + { + if (other.m_obj) + { + CFRetain(other.m_obj); + } + if (m_obj) + { + CFRelease(m_obj); + } + m_obj = other.m_obj; + } + return *this; + } + + void reset(T obj) + { + if (obj != m_obj) + { + if (m_obj) + { + CFRelease(m_obj); + } + m_obj = obj; + } + } + + operator T() const { return m_obj; } + operator bool() const { return m_obj != nullptr; } + T get() const { return m_obj; } +}; + +#endif // RIVE_BUILD_FOR_APPLE diff --git a/third_party/rive/include/utils/compile_time_string_hash.hpp b/third_party/rive/include/utils/compile_time_string_hash.hpp new file mode 100644 index 0000000..e0203a0 --- /dev/null +++ b/third_party/rive/include/utils/compile_time_string_hash.hpp @@ -0,0 +1,78 @@ +#include +#include + +// taken and modified from +// https://stackoverflow.com/questions/2111667/compile-time-string-hashing +namespace detail +{ +static constexpr unsigned int crc_table[256] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, + 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, + 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, + 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, + 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, + 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, + 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, + 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, + 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, + 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, + 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, + 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, + 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, + 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, + 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, + 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, + 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, + 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d}; + +template +constexpr uint32_t combine_crc32(const char* str, uint32_t part) +{ + return (part >> 8) ^ crc_table[(part ^ str[IDX]) & 0x000000FF]; +} + +template constexpr uint32_t crc32(const char* str) +{ + return combine_crc32(str, crc32(str)); +} + +// This is the stop-recursion function +template <> constexpr uint32_t crc32(const char* str) +{ + return 0xFFFFFFFF; +} + +} // namespace detail + +template constexpr uint32_t ctcrc32(const char (&str)[LEN]) +{ + // LEN-1 is to remove the null terminator at the end of the string const. + return detail::crc32(str) ^ 0xFFFFFFFF; +} + +#define CONST_ID(VALUE) ctcrc32(#VALUE) \ No newline at end of file diff --git a/third_party/rive/include/utils/factory_utils.hpp b/third_party/rive/include/utils/factory_utils.hpp new file mode 100644 index 0000000..8959da9 --- /dev/null +++ b/third_party/rive/include/utils/factory_utils.hpp @@ -0,0 +1,51 @@ +/* + * Copyright 2022 Rive + */ + +#ifndef _RIVE_FACTORY_UTILS_HPP_ +#define _RIVE_FACTORY_UTILS_HPP_ + +#include "rive/factory.hpp" + +namespace rive +{ + +// Generic subclass of RenderBuffer that just stores the data on the cpu. +// +class DataRenderBuffer + : public LITE_RTTI_OVERRIDE(RenderBuffer, DataRenderBuffer) +{ +public: + DataRenderBuffer(RenderBufferType type, + RenderBufferFlags flags, + size_t sizeInBytes) : + lite_rtti_override(type, flags, sizeInBytes) + { + m_storage = malloc(sizeInBytes); + } + + ~DataRenderBuffer() { free(m_storage); } + + const float* f32s() const + { + return reinterpret_cast(m_storage); + } + + const uint16_t* u16s() const + { + return reinterpret_cast(m_storage); + } + + const Vec2D* vecs() const { return reinterpret_cast(f32s()); } + +protected: + void* onMap() override { return m_storage; } + void onUnmap() override {} + +private: + void* m_storage; +}; + +} // namespace rive + +#endif diff --git a/third_party/rive/include/utils/lite_rtti.hpp b/third_party/rive/include/utils/lite_rtti.hpp new file mode 100644 index 0000000..6879ef8 --- /dev/null +++ b/third_party/rive/include/utils/lite_rtti.hpp @@ -0,0 +1,93 @@ +/* + * Copyright 2023 Rive + */ + +// "lite_rtti_cast()" is a very basic polyfill for "dynamic_cast()" that +// can only cast a pointer to its most-derived type. To use it, the base class +// must derive from enable_lite_rtti, and the subclass must inherit from +// lite_rtti_override: +// +// class Root : public enable_lite_rtti {}; +// class Derived : public lite_rtti_override {}; +// Root* derived = new Derived(); +// lite_rtti_cast(derived); +// + +#pragma once + +#include "utils/compile_time_string_hash.hpp" +#include "rive/refcnt.hpp" +#include +#include + +namespace rive +{ + +// Enable lite rtti on the root of a class hierarchy. +template class enable_lite_rtti +{ +public: + unsigned int liteTypeID() const { return m_liteTypeId; } + +protected: + unsigned int m_liteTypeId = ID; +}; + +// Override the lite rtti type ID on subsequent classes of a class hierarchy. +template +class lite_rtti_override : public Base +{ +public: + constexpr static uint32_t LITE_RTTI_TYPE_ID = ID; + lite_rtti_override() { Base::m_liteTypeId = ID; } + + template + lite_rtti_override(Args&&... args) : Base(std::forward(args)...) + { + Base::m_liteTypeId = ID; + } +}; + +// Like dynamic_cast<>, but can only cast a pointer to its most-derived type. +template U lite_rtti_cast(T* t) +{ + if (t != nullptr && + t->liteTypeID() == std::remove_pointer::type::LITE_RTTI_TYPE_ID) + { + return static_cast(t); + } + return nullptr; +} + +template rcp lite_rtti_rcp_cast(rcp t) +{ + if (t != nullptr && + t->liteTypeID() == std::remove_pointer::type::LITE_RTTI_TYPE_ID) + { + return static_rcp_cast(t); + } + return nullptr; +} + +// Different versions of clang-format disagree on how to formate these. +// clang-format off + +#define ENABLE_LITE_RTTI(ROOT) enable_lite_rtti +#define LITE_RTTI_OVERRIDE(BASE, DERRIVED) lite_rtti_override + +#define LITE_RTTI_CAST_OR_RETURN(NAME, TYPE, POINTER) \ + auto NAME = rive::lite_rtti_cast(POINTER); \ + if (NAME == nullptr) \ + return + +#define LITE_RTTI_CAST_OR_BREAK(NAME, TYPE, POINTER) \ + auto NAME = rive::lite_rtti_cast(POINTER); \ + if (NAME == nullptr) \ + break + +#define LITE_RTTI_CAST_OR_CONTINUE(NAME, TYPE, POINTER) \ + auto NAME = rive::lite_rtti_cast(POINTER); \ + if (NAME == nullptr) \ + continue +// clang-format on +} // namespace rive diff --git a/third_party/rive/include/utils/no_op_factory.hpp b/third_party/rive/include/utils/no_op_factory.hpp new file mode 100644 index 0000000..ba6bb62 --- /dev/null +++ b/third_party/rive/include/utils/no_op_factory.hpp @@ -0,0 +1,43 @@ +/* + * Copyright 2022 Rive + */ + +#ifndef _RIVE_NOOP_FACTORY_HPP_ +#define _RIVE_NOOP_FACTORY_HPP_ + +#include "rive/factory.hpp" + +namespace rive +{ + +class NoOpFactory : public Factory +{ + rcp makeRenderBuffer(RenderBufferType, + RenderBufferFlags, + size_t) override; + + rcp makeLinearGradient(float sx, + float sy, + float ex, + float ey, + const ColorInt colors[], // [count] + const float stops[], // [count] + size_t count) override; + + rcp makeRadialGradient(float cx, + float cy, + float radius, + const ColorInt colors[], // [count] + const float stops[], // [count] + size_t count) override; + + rcp makeRenderPath(RawPath&, FillRule) override; + + rcp makeEmptyRenderPath() override; + + rcp makeRenderPaint() override; + + rcp decodeImage(Span) override; +}; +} // namespace rive +#endif diff --git a/third_party/rive/include/utils/no_op_renderer.hpp b/third_party/rive/include/utils/no_op_renderer.hpp new file mode 100644 index 0000000..9c39b1f --- /dev/null +++ b/third_party/rive/include/utils/no_op_renderer.hpp @@ -0,0 +1,37 @@ +/* + * Copyright 2022 Rive + */ + +#ifndef _RIVE_NOOP_RENDERER_HPP_ +#define _RIVE_NOOP_RENDERER_HPP_ + +#include "rive/renderer.hpp" + +namespace rive +{ + +class NoOpRenderer : public Renderer +{ +public: + void save() override {} + void restore() override {} + void transform(const Mat2D&) override {} + void drawPath(RenderPath* path, RenderPaint* paint) override {} + void clipPath(RenderPath* path) override {} + void drawImage(const RenderImage*, ImageSampler, BlendMode, float) override + {} + void drawImageMesh(const RenderImage*, + ImageSampler, + rcp, + rcp, + rcp, + uint32_t vertexCount, + uint32_t indexCount, + BlendMode, + float) override + {} +}; + +} // namespace rive + +#endif diff --git a/third_party/rive/include/utils/serializing_factory.hpp b/third_party/rive/include/utils/serializing_factory.hpp new file mode 100644 index 0000000..e180427 --- /dev/null +++ b/third_party/rive/include/utils/serializing_factory.hpp @@ -0,0 +1,70 @@ +/* + * Copyright 2022 Rive + */ + +#ifndef _RIVE_SERIALIZING_FACTORY_HPP_ +#define _RIVE_SERIALIZING_FACTORY_HPP_ + +#include "rive/factory.hpp" +#include "rive/core/vector_binary_writer.hpp" +#include + +namespace rive +{ +// A factory that generates render objects which serialize their rendering +// commands into one buffer that can then be used to replay the commands in a +// viewer app or compare them to ensure that subsequent runs generate the same +// commands. +class SerializingFactory : public Factory +{ +public: + SerializingFactory(); + rcp makeRenderBuffer(RenderBufferType, + RenderBufferFlags, + size_t) override; + + rcp makeLinearGradient(float sx, + float sy, + float ex, + float ey, + const ColorInt colors[], // [count] + const float stops[], // [count] + size_t count) override; + + rcp makeRadialGradient(float cx, + float cy, + float radius, + const ColorInt colors[], // [count] + const float stops[], // [count] + size_t count) override; + + rcp makeRenderPath(RawPath&, FillRule) override; + + rcp makeEmptyRenderPath() override; + + rcp makeRenderPaint() override; + + rcp decodeImage(Span) override; + + std::unique_ptr makeRenderer(); + + void addFrame(); + void frameSize(uint32_t width, uint32_t height); + + void save(const char* filename); + bool matches(const char* filename); + +private: + void saveTarnished(const char* filename); + + std::vector m_buffer; + VectorBinaryWriter m_writer; + + uint64_t m_renderImageId = 0; + uint64_t m_renderPaintId = 0; + uint64_t m_renderPathId = 0; + uint64_t m_renderBufferId = 0; + uint64_t m_renderShaderId = 0; +}; +} // namespace rive +#endif diff --git a/third_party/rive/rive.cpp b/third_party/rive/rive.cpp new file mode 100644 index 0000000..dcb1c66 --- /dev/null +++ b/third_party/rive/rive.cpp @@ -0,0 +1,590 @@ +/* + ============================================================================== + + This file is part of the YUP library. + Copyright (c) 2024 - kunitoki@gmail.com + + YUP is an open source library subject to open-source licensing. + + The code included in this file is provided under the terms of the ISC license + http://www.isc.org/downloads/software-support-policy/isc-license. Permission + to use, copy, modify, and/or distribute this software for any purpose with or + without fee is hereby granted provided that the above copyright notice and + this permission notice appear in all copies. + + YUP IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +#include "rive.h" + +#if __clang__ + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wshorten-64-to-32" +#elif __GNUC__ + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#elif _MSC_VER + #pragma warning (push) + #pragma warning (disable : 4244) +#endif + +#if !defined(_RIVE_INTERNAL_) +#define _RIVE_INTERNAL_ 1 +#endif + +#include "source/generated/nested_artboard_layout_base.cpp" +#include "source/generated/viewmodel/viewmodel_instance_list_base.cpp" +#include "source/generated/viewmodel/viewmodel_instance_enum_base.cpp" +#include "source/generated/viewmodel/viewmodel_property_color_base.cpp" +#include "source/generated/viewmodel/viewmodel_property_number_base.cpp" +#include "source/generated/viewmodel/viewmodel_property_enum_base.cpp" +#include "source/generated/viewmodel/data_enum_value_base.cpp" +#include "source/generated/viewmodel/viewmodel_property_symbol_list_index_base.cpp" +#include "source/generated/viewmodel/data_enum_custom_base.cpp" +#include "source/generated/viewmodel/viewmodel_instance_boolean_base.cpp" +#include "source/generated/viewmodel/viewmodel_property_list_base.cpp" +#include "source/generated/viewmodel/viewmodel_property_asset_base.cpp" +#include "source/generated/viewmodel/viewmodel_instance_base.cpp" +#include "source/generated/viewmodel/viewmodel_property_enum_system_base.cpp" +#include "source/generated/viewmodel/viewmodel_instance_symbol_list_index_base.cpp" +#include "source/generated/viewmodel/viewmodel_property_base.cpp" +#include "source/generated/viewmodel/viewmodel_property_boolean_base.cpp" +#include "source/generated/viewmodel/viewmodel_property_string_base.cpp" +#include "source/generated/viewmodel/viewmodel_instance_list_item_base.cpp" +#include "source/generated/viewmodel/viewmodel_instance_color_base.cpp" +#include "source/generated/viewmodel/viewmodel_property_asset_image_base.cpp" +#include "source/generated/viewmodel/viewmodel_instance_trigger_base.cpp" +#include "source/generated/viewmodel/viewmodel_property_enum_custom_base.cpp" +#include "source/generated/viewmodel/viewmodel_instance_number_base.cpp" +#include "source/generated/viewmodel/viewmodel_instance_asset_base.cpp" +#include "source/generated/viewmodel/viewmodel_property_trigger_base.cpp" +#include "source/generated/viewmodel/viewmodel_property_viewmodel_base.cpp" +#include "source/generated/viewmodel/viewmodel_base.cpp" +#include "source/generated/viewmodel/data_enum_base.cpp" +#include "source/generated/viewmodel/viewmodel_instance_viewmodel_base.cpp" +#include "source/generated/viewmodel/viewmodel_instance_asset_image_base.cpp" +#include "source/generated/viewmodel/viewmodel_component_base.cpp" +#include "source/generated/viewmodel/viewmodel_instance_string_base.cpp" +#include "source/generated/viewmodel/data_enum_system_base.cpp" +#include "source/generated/draw_target_base.cpp" +#include "source/generated/backboard_base.cpp" +#include "source/generated/custom_property_group_base.cpp" +#include "source/generated/foreground_layout_drawable_base.cpp" +#include "source/generated/constraints/follow_path_constraint_base.cpp" +#include "source/generated/constraints/distance_constraint_base.cpp" +#include "source/generated/constraints/translation_constraint_base.cpp" +#include "source/generated/constraints/ik_constraint_base.cpp" +#include "source/generated/constraints/scale_constraint_base.cpp" +#include "source/generated/constraints/transform_constraint_base.cpp" +#include "source/generated/constraints/scrolling/clamped_scroll_physics_base.cpp" +#include "source/generated/constraints/scrolling/elastic_scroll_physics_base.cpp" +#include "source/generated/constraints/scrolling/scroll_bar_constraint_base.cpp" +#include "source/generated/constraints/scrolling/scroll_constraint_base.cpp" +#include "source/generated/constraints/rotation_constraint_base.cpp" +#include "source/generated/layout/n_slicer_base.cpp" +#include "source/generated/layout/axis_y_base.cpp" +#include "source/generated/layout/axis_x_base.cpp" +#include "source/generated/layout/n_sliced_node_base.cpp" +#include "source/generated/layout/layout_component_style_base.cpp" +#include "source/generated/layout/n_slicer_tile_mode_base.cpp" +#include "source/generated/audio_event_base.cpp" +#include "source/generated/nested_artboard_leaf_base.cpp" +#include "source/generated/layout_component_base.cpp" +#include "source/generated/animation/any_state_base.cpp" +#include "source/generated/animation/nested_state_machine_base.cpp" +#include "source/generated/animation/elastic_interpolator_base.cpp" +#include "source/generated/animation/state_machine_fire_event_base.cpp" +#include "source/generated/animation/transition_value_enum_comparator_base.cpp" +#include "source/generated/animation/transition_property_artboard_comparator_base.cpp" +#include "source/generated/animation/transition_value_boolean_comparator_base.cpp" +#include "source/generated/animation/state_machine_trigger_base.cpp" +#include "source/generated/animation/state_machine_base.cpp" +#include "source/generated/animation/listener_trigger_change_base.cpp" +#include "source/generated/animation/exit_state_base.cpp" +#include "source/generated/animation/listener_bool_change_base.cpp" +#include "source/generated/animation/listener_viewmodel_change_base.cpp" +#include "source/generated/animation/transition_value_string_comparator_base.cpp" +#include "source/generated/animation/listener_number_change_base.cpp" +#include "source/generated/animation/state_machine_fire_event.cpp" +#include "source/generated/animation/state_machine_number_base.cpp" +#include "source/generated/animation/state_transition_base.cpp" +#include "source/generated/animation/keyframe_double_base.cpp" +#include "source/generated/animation/transition_value_color_comparator_base.cpp" +#include "source/generated/animation/state_machine_bool_base.cpp" +#include "source/generated/animation/blend_state_1d_viewmodel_base.cpp" +#include "source/generated/animation/blend_state_transition_base.cpp" +#include "source/generated/animation/blend_animation_direct_base.cpp" +#include "source/generated/animation/transition_viewmodel_condition_base.cpp" +#include "source/generated/animation/transition_bool_condition_base.cpp" +#include "source/generated/animation/listener_align_target_base.cpp" +#include "source/generated/animation/nested_number_base.cpp" +#include "source/generated/animation/keyframe_string_base.cpp" +#include "source/generated/animation/transition_trigger_condition_base.cpp" +#include "source/generated/animation/transition_number_condition_base.cpp" +#include "source/generated/animation/keyframe_uint_base.cpp" +#include "source/generated/animation/keyframe_callback_base.cpp" +#include "source/generated/animation/nested_simple_animation_base.cpp" +#include "source/generated/animation/transition_value_trigger_comparator_base.cpp" +#include "source/generated/animation/nested_trigger_base.cpp" +#include "source/generated/animation/listener_fire_event_base.cpp" +#include "source/generated/animation/linear_animation_base.cpp" +#include "source/generated/animation/transition_value_number_comparator_base.cpp" +#include "source/generated/animation/entry_state_base.cpp" +#include "source/generated/animation/transition_artboard_condition_base.cpp" +#include "source/generated/animation/blend_state_direct_base.cpp" +#include "source/generated/animation/state_machine_layer_base.cpp" +#include "source/generated/animation/cubic_interpolator_component_base.cpp" +#include "source/generated/animation/blend_animation_1d_base.cpp" +#include "source/generated/animation/keyed_object_base.cpp" +#include "source/generated/animation/transition_property_viewmodel_comparator_base.cpp" +#include "source/generated/animation/keyframe_id_base.cpp" +#include "source/generated/animation/state_machine_listener_base.cpp" +#include "source/generated/animation/cubic_value_interpolator_base.cpp" +#include "source/generated/animation/nested_bool_base.cpp" +#include "source/generated/animation/keyframe_color_base.cpp" +#include "source/generated/animation/keyframe_bool_base.cpp" +#include "source/generated/animation/keyed_property_base.cpp" +#include "source/generated/animation/blend_state_1d_input_base.cpp" +#include "source/generated/animation/cubic_ease_interpolator_base.cpp" +#include "source/generated/animation/nested_remap_animation_base.cpp" +#include "source/generated/animation/animation_base.cpp" +#include "source/generated/animation/animation_state_base.cpp" +#include "source/generated/shapes/straight_vertex_base.cpp" +#include "source/generated/shapes/paint/radial_gradient_base.cpp" +#include "source/generated/shapes/paint/gradient_stop_base.cpp" +#include "source/generated/shapes/paint/dash_path_base.cpp" +#include "source/generated/shapes/paint/solid_color_base.cpp" +#include "source/generated/shapes/paint/trim_path_base.cpp" +#include "source/generated/shapes/paint/feather_base.cpp" +#include "source/generated/shapes/paint/dash_base.cpp" +#include "source/generated/shapes/paint/linear_gradient_base.cpp" +#include "source/generated/shapes/paint/stroke_base.cpp" +#include "source/generated/shapes/paint/fill_base.cpp" +#include "source/generated/shapes/polygon_base.cpp" +#include "source/generated/shapes/cubic_detached_vertex_base.cpp" +#include "source/generated/shapes/clipping_shape_base.cpp" +#include "source/generated/shapes/mesh_base.cpp" +#include "source/generated/shapes/rectangle_base.cpp" +#include "source/generated/shapes/cubic_mirrored_vertex_base.cpp" +#include "source/generated/shapes/star_base.cpp" +#include "source/generated/shapes/mesh_vertex_base.cpp" +#include "source/generated/shapes/ellipse_base.cpp" +#include "source/generated/shapes/points_path_base.cpp" +#include "source/generated/shapes/triangle_base.cpp" +#include "source/generated/shapes/shape_base.cpp" +#include "source/generated/shapes/cubic_asymmetric_vertex_base.cpp" +#include "source/generated/shapes/contour_mesh_vertex_base.cpp" +#include "source/generated/shapes/image_base.cpp" +#include "source/generated/custom_property_number_base.cpp" +#include "source/generated/nested_artboard_base.cpp" +#include "source/generated/custom_property_boolean_base.cpp" +#include "source/generated/artboard_base.cpp" +#include "source/generated/draw_rules_base.cpp" +#include "source/generated/data_bind/bindable_property_enum_base.cpp" +#include "source/generated/data_bind/data_bind_base.cpp" +#include "source/generated/data_bind/bindable_property_integer_base.cpp" +#include "source/generated/data_bind/bindable_property_boolean_base.cpp" +#include "source/generated/data_bind/converters/data_converter_range_mapper_base.cpp" +#include "source/generated/data_bind/converters/data_converter_interpolator_base.cpp" +#include "source/generated/data_bind/converters/data_converter_operation_value_base.cpp" +#include "source/generated/data_bind/converters/data_converter_string_pad_base.cpp" +#include "source/generated/data_bind/converters/data_converter_formula_base.cpp" +#include "source/generated/data_bind/converters/data_converter_string_remove_zeros_base.cpp" +#include "source/generated/data_bind/converters/data_converter_system_degs_to_rads_base.cpp" +#include "source/generated/data_bind/converters/data_converter_rounder_base.cpp" +#include "source/generated/data_bind/converters/data_converter_system_normalizer_base.cpp" +#include "source/generated/data_bind/converters/data_converter_boolean_negate_base.cpp" +#include "source/generated/data_bind/converters/data_converter_operation_viewmodel_base.cpp" +#include "source/generated/data_bind/converters/data_converter_number_to_list_base.cpp" +#include "source/generated/data_bind/converters/data_converter_group_base.cpp" +#include "source/generated/data_bind/converters/data_converter_operation_base.cpp" +#include "source/generated/data_bind/converters/formula/formula_token_parenthesis_open_base.cpp" +#include "source/generated/data_bind/converters/formula/formula_token_value_base.cpp" +#include "source/generated/data_bind/converters/formula/formula_token_function_base.cpp" +#include "source/generated/data_bind/converters/formula/formula_token_operation_base.cpp" +#include "source/generated/data_bind/converters/formula/formula_token_input_base.cpp" +#include "source/generated/data_bind/converters/formula/formula_token_parenthesis_close_base.cpp" +#include "source/generated/data_bind/converters/formula/formula_token_parenthesis_base.cpp" +#include "source/generated/data_bind/converters/formula/formula_token_argument_separator_base.cpp" +#include "source/generated/data_bind/converters/formula/formula_token_base.cpp" +#include "source/generated/data_bind/converters/data_converter_group_item_base.cpp" +#include "source/generated/data_bind/converters/data_converter_trigger_base.cpp" +#include "source/generated/data_bind/converters/data_converter_string_trim_base.cpp" +#include "source/generated/data_bind/converters/data_converter_to_string_base.cpp" +#include "source/generated/data_bind/data_bind_context_base.cpp" +#include "source/generated/data_bind/bindable_property_color_base.cpp" +#include "source/generated/data_bind/bindable_property_trigger_base.cpp" +#include "source/generated/data_bind/bindable_property_asset_base.cpp" +#include "source/generated/data_bind/bindable_property_string_base.cpp" +#include "source/generated/data_bind/bindable_property_number_base.cpp" +#include "source/generated/custom_property_string_base.cpp" +#include "source/generated/bones/tendon_base.cpp" +#include "source/generated/bones/skin_base.cpp" +#include "source/generated/bones/bone_base.cpp" +#include "source/generated/bones/weight_base.cpp" +#include "source/generated/bones/root_bone_base.cpp" +#include "source/generated/bones/cubic_weight_base.cpp" +#include "source/generated/text/text_modifier_group_base.cpp" +#include "source/generated/text/text_style_axis_base.cpp" +#include "source/generated/text/text_style_base.cpp" +#include "source/generated/text/text_input_selection_base.cpp" +#include "source/generated/text/text_style_paint_base.cpp" +#include "source/generated/text/text_input_base.cpp" +#include "source/generated/text/text_modifier_range_base.cpp" +#include "source/generated/text/text_input_cursor_base.cpp" +#include "source/generated/text/text_base.cpp" +#include "source/generated/text/text_variation_modifier_base.cpp" +#include "source/generated/text/text_follow_path_modifier_base.cpp" +#include "source/generated/text/text_style_feature_base.cpp" +#include "source/generated/text/text_input_selected_text_base.cpp" +#include "source/generated/text/text_input_text_base.cpp" +#include "source/generated/text/text_value_run_base.cpp" +#include "source/generated/open_url_event_base.cpp" +#include "source/generated/node_base.cpp" +#include "source/generated/assets/file_asset_contents_base.cpp" +#include "source/generated/assets/folder_base.cpp" +#include "source/generated/assets/audio_asset_base.cpp" +#include "source/generated/assets/font_asset_base.cpp" +#include "source/generated/assets/image_asset_base.cpp" +#include "source/generated/event_base.cpp" +#include "source/generated/artboard_component_list_base.cpp" +#include "source/generated/solo_base.cpp" +#include "source/generated/joystick_base.cpp" +#include "source/viewmodel/viewmodel_instance_color.cpp" +#include "source/viewmodel/viewmodel_instance_trigger.cpp" +#include "source/viewmodel/viewmodel_instance_list_item.cpp" +#include "source/viewmodel/viewmodel_instance_asset_image.cpp" +#include "source/viewmodel/viewmodel_instance_asset.cpp" +#include "source/viewmodel/viewmodel.cpp" +#include "source/viewmodel/runtime/viewmodel_instance_value_runtime.cpp" +#include "source/viewmodel/runtime/viewmodel_instance_number_runtime.cpp" +#include "source/viewmodel/runtime/viewmodel_instance_enum_runtime.cpp" +#include "source/viewmodel/runtime/viewmodel_instance_asset_image_runtime.cpp" +#include "source/viewmodel/runtime/viewmodel_instance_list_runtime.cpp" +#include "source/viewmodel/runtime/viewmodel_instance_color_runtime.cpp" +#include "source/viewmodel/runtime/viewmodel_instance_runtime.cpp" +#include "source/viewmodel/runtime/viewmodel_runtime.cpp" +#include "source/viewmodel/runtime/viewmodel_instance_boolean_runtime.cpp" +#include "source/viewmodel/runtime/viewmodel_instance_string_runtime.cpp" +#include "source/viewmodel/runtime/viewmodel_instance_trigger_runtime.cpp" +#include "source/viewmodel/viewmodel_instance_boolean.cpp" +#include "source/viewmodel/viewmodel_instance_string.cpp" +#include "source/viewmodel/viewmodel_property.cpp" +#include "source/viewmodel/data_enum.cpp" +#include "source/viewmodel/viewmodel_instance_list.cpp" +#include "source/viewmodel/viewmodel_instance_enum.cpp" +#include "source/viewmodel/viewmodel_instance_symbol_list_index.cpp" +#include "source/viewmodel/viewmodel_property_enum.cpp" +#include "source/viewmodel/viewmodel_instance_value.cpp" +#include "source/viewmodel/viewmodel_instance.cpp" +#include "source/viewmodel/viewmodel_instance_viewmodel.cpp" +#include "source/viewmodel/viewmodel_instance_number.cpp" +#include "source/viewmodel/data_enum_value.cpp" +#include "source/viewmodel/viewmodel_property_enum_system.cpp" +#include "source/draw_rules.cpp" +#include "source/core/field_types/core_bool_type.cpp" +#include "source/core/field_types/core_bytes_type.cpp" +#include "source/core/field_types/core_uint_type.cpp" +#include "source/core/field_types/core_double_type.cpp" +#include "source/core/field_types/core_string_type.cpp" +#include "source/core/field_types/core_color_type.cpp" +#include "source/core/binary_data_reader.cpp" +#include "source/core/binary_reader.cpp" +#include "source/core/binary_writer.cpp" +#include "source/scene.cpp" +#include "source/simple_array.cpp" +#include "source/nested_artboard.cpp" +#include "source/constraints/transform_constraint.cpp" +#include "source/constraints/distance_constraint.cpp" +#include "source/constraints/follow_path_constraint.cpp" +#include "source/constraints/constraint.cpp" +#include "source/constraints/rotation_constraint.cpp" +#include "source/constraints/ik_constraint.cpp" +#include "source/constraints/scale_constraint.cpp" +#include "source/constraints/targeted_constraint.cpp" +#include "source/constraints/scrolling/scroll_constraint.cpp" +#include "source/constraints/scrolling/scroll_constraint_proxy.cpp" +#include "source/constraints/scrolling/elastic_scroll_physics.cpp" +#include "source/constraints/scrolling/scroll_bar_constraint.cpp" +#include "source/constraints/scrolling/scroll_physics.cpp" +#include "source/constraints/scrolling/scroll_bar_constraint_proxy.cpp" +#include "source/constraints/scrolling/clamped_scroll_physics.cpp" +#include "source/constraints/translation_constraint.cpp" +#include "source/hittest_command_path.cpp" +#include "source/transform_component.cpp" +#include "source/importers/transition_viewmodel_condition_importer.cpp" +#include "source/importers/artboard_importer.cpp" +#include "source/importers/state_machine_importer.cpp" +#include "source/importers/linear_animation_importer.cpp" +#include "source/importers/data_converter_formula_importer.cpp" +#include "source/importers/layer_state_importer.cpp" +#include "source/importers/viewmodel_instance_importer.cpp" +#include "source/importers/enum_importer.cpp" +#include "source/importers/keyed_object_importer.cpp" +#include "source/importers/backboard_importer.cpp" +#include "source/importers/bindable_property_importer.cpp" +#include "source/importers/file_asset_importer.cpp" +#include "source/importers/state_machine_layer_component_importer.cpp" +#include "source/importers/data_converter_group_importer.cpp" +#include "source/importers/viewmodel_instance_list_importer.cpp" +#include "source/importers/state_transition_importer.cpp" +#include "source/importers/state_machine_layer_importer.cpp" +#include "source/importers/state_machine_listener_importer.cpp" +#include "source/importers/viewmodel_importer.cpp" +#include "source/importers/keyed_property_importer.cpp" +#include "source/nested_artboard_layout.cpp" +#include "source/foreground_layout_drawable.cpp" +#include "source/component.cpp" +#include "source/artboard_component_list.cpp" +#include "source/layout/layout_component_style.cpp" +#include "source/layout/n_slicer_tile_mode.cpp" +#include "source/layout/n_slicer_details.cpp" +#include "source/layout/axis.cpp" +#include "source/layout/axis_y.cpp" +#include "source/layout/axis_x.cpp" +#include "source/layout/n_slicer.cpp" +#include "source/layout/n_sliced_node.cpp" +#include "source/layout/layout_node_provider.cpp" +#include "source/node.cpp" +#include "source/layout.cpp" +#include "source/layout_component.cpp" +#include "source/animation/blend_state_1d_input.cpp" +#include "source/animation/transition_value_string_comparator.cpp" +#include "source/animation/cubic_interpolator_solver.cpp" +#include "source/animation/nested_trigger.cpp" +#include "source/animation/keyframe_color.cpp" +#include "source/animation/blend_state_1d_viewmodel.cpp" +#include "source/animation/keyframe_callback.cpp" +#include "source/animation/blend_animation.cpp" +#include "source/animation/listener_number_change.cpp" +#include "source/animation/state_machine_instance.cpp" +#include "source/animation/keyframe_interpolator.cpp" +#include "source/animation/transition_input_condition.cpp" +#include "source/animation/nested_bool.cpp" +#include "source/animation/blend_state_direct.cpp" +#include "source/animation/animation_state.cpp" +#include "source/animation/nested_animation.cpp" +#include "source/animation/keyframe_uint.cpp" +#include "source/animation/transition_trigger_condition.cpp" +#include "source/animation/state_machine_listener.cpp" +#include "source/animation/keyed_object.cpp" +#include "source/animation/nested_state_machine.cpp" +#include "source/animation/animation_reset_factory.cpp" +#include "source/animation/interpolating_keyframe.cpp" +#include "source/animation/state_machine.cpp" +#include "source/animation/nested_linear_animation.cpp" +#include "source/animation/blend_state_1d_instance.cpp" +#include "source/animation/state_machine_input_instance.cpp" +#include "source/animation/transition_viewmodel_condition.cpp" +#include "source/animation/keyframe_bool.cpp" +#include "source/animation/animation_state_instance.cpp" +#include "source/animation/nested_simple_animation.cpp" +#include "source/animation/transition_condition.cpp" +#include "source/animation/elastic_interpolator.cpp" +#include "source/animation/linear_animation.cpp" +#include "source/animation/transition_comparator.cpp" +#include "source/animation/blend_state_direct_instance.cpp" +#include "source/animation/elastic_ease.cpp" +#include "source/animation/linear_animation_instance.cpp" +#include "source/animation/keyframe_double.cpp" +#include "source/animation/listener_input_change.cpp" +#include "source/animation/hittable.cpp" +#include "source/animation/blend_animation_direct.cpp" +#include "source/animation/transition_property_comparator.cpp" +#include "source/animation/cubic_ease_interpolator.cpp" +#include "source/animation/blend_state_transition.cpp" +#include "source/animation/nested_number.cpp" +#include "source/animation/transition_property_artboard_comparator.cpp" +#include "source/animation/transition_number_condition.cpp" +#include "source/animation/listener_bool_change.cpp" +#include "source/animation/keyframe.cpp" +#include "source/animation/listener_action.cpp" +#include "source/animation/blend_state.cpp" +#include "source/animation/listener_fire_event.cpp" +#include "source/animation/state_machine_layer.cpp" +#include "source/animation/listener_align_target.cpp" +#include "source/animation/blend_animation_1d.cpp" +#include "source/animation/transition_value_enum_comparator.cpp" +#include "source/animation/blend_state_1d.cpp" +#include "source/animation/cubic_value_interpolator.cpp" +#include "source/animation/cubic_interpolator_component.cpp" +#include "source/animation/state_instance.cpp" +#include "source/animation/transition_value_color_comparator.cpp" +#include "source/animation/listener_trigger_change.cpp" +#include "source/animation/transition_value_boolean_comparator.cpp" +#include "source/animation/cubic_interpolator.cpp" +#include "source/animation/keyed_property.cpp" +#include "source/animation/transition_bool_condition.cpp" +#include "source/animation/state_machine_input.cpp" +#include "source/animation/animation_reset.cpp" +#include "source/animation/nested_remap_animation.cpp" +#include "source/animation/layer_state.cpp" +#include "source/animation/transition_value_number_comparator.cpp" +#include "source/animation/system_state_instance.cpp" +#include "source/animation/state_transition.cpp" +#include "source/animation/listener_viewmodel_change.cpp" +#include "source/animation/transition_property_viewmodel_comparator.cpp" +#include "source/animation/keyframe_string.cpp" +#include "source/animation/keyframe_id.cpp" +#include "source/drawable.cpp" +#include "source/shapes/paint/solid_color.cpp" +#include "source/shapes/paint/feather.cpp" +#include "source/shapes/paint/linear_gradient.cpp" +#include "source/shapes/paint/shape_paint.cpp" +#include "source/shapes/paint/fill.cpp" +#include "source/shapes/paint/shape_paint_path.cpp" +#include "source/shapes/paint/dash_path.cpp" +#include "source/shapes/paint/radial_gradient.cpp" +#include "source/shapes/paint/color.cpp" +#include "source/shapes/paint/trim_path.cpp" +#include "source/shapes/paint/shape_paint_mutator.cpp" +#include "source/shapes/paint/gradient_stop.cpp" +#include "source/shapes/paint/dash.cpp" +#include "source/shapes/paint/stroke.cpp" +#include "source/shapes/points_path.cpp" +#include "source/shapes/star.cpp" +#include "source/shapes/mesh.cpp" +#include "source/shapes/cubic_asymmetric_vertex.cpp" +#include "source/shapes/image.cpp" +#include "source/shapes/cubic_detached_vertex.cpp" +#include "source/shapes/mesh_vertex.cpp" +#include "source/shapes/slice_mesh.cpp" +#include "source/shapes/cubic_vertex.cpp" +#include "source/shapes/deformer.cpp" +#include "source/shapes/shape.cpp" +#include "source/shapes/triangle.cpp" +#include "source/shapes/polygon.cpp" +#include "source/shapes/path.cpp" +#include "source/shapes/parametric_path.cpp" +#include "source/shapes/path_vertex.cpp" +#include "source/shapes/rectangle.cpp" +#include "source/shapes/straight_vertex.cpp" +#include "source/shapes/path_composer.cpp" +#include "source/shapes/shape_paint_container.cpp" +#include "source/shapes/cubic_mirrored_vertex.cpp" +#include "source/shapes/vertex.cpp" +#include "source/shapes/ellipse.cpp" +#include "source/shapes/clipping_shape.cpp" +#include "source/math/contour_measure.cpp" +#include "source/math/raw_path.cpp" +#include "source/math/bezier_utils.cpp" +#include "source/math/bit_field_loc.cpp" +#include "source/math/aabb.cpp" +#include "source/math/mat2d_find_max_scale.cpp" +#include "source/math/path_measure.cpp" +#include "source/math/hit_test.cpp" +#include "source/math/raw_path_utils.cpp" +#include "source/math/rectangles_to_contour.cpp" +#include "source/math/vec2d.cpp" +#include "source/math/mat2d.cpp" +#include "source/math/n_slicer_helpers.cpp" +#include "source/dependency_sorter.cpp" +#include "source/artboard.cpp" +#include "source/world_transform_component.cpp" +#include "source/draw_target.cpp" +#include "source/audio/audio_reader.cpp" +#include "source/audio/audio_engine.cpp" +#include "source/audio/audio_source.cpp" +#include "source/audio/audio_sound.cpp" +#include "source/container_component.cpp" +#include "source/file.cpp" +#include "source/data_bind/data_bind_context.cpp" +#include "source/data_bind/context/context_value_list.cpp" +#include "source/data_bind/context/context_value_number.cpp" +#include "source/data_bind/context/context_value_enum.cpp" +#include "source/data_bind/context/context_value_asset_image.cpp" +#include "source/data_bind/context/context_value_string.cpp" +#include "source/data_bind/context/context_value_trigger.cpp" +#include "source/data_bind/context/context_value_color.cpp" +#include "source/data_bind/context/context_value.cpp" +#include "source/data_bind/context/context_value_symbol_list_index.cpp" +#include "source/data_bind/context/context_value_boolean.cpp" +#include "source/data_bind/data_bind.cpp" +#include "source/data_bind/data_bind_list_item_consumer.cpp" +#include "source/data_bind/converters/data_converter_boolean_negate.cpp" +#include "source/data_bind/converters/data_converter_system_normalizer.cpp" +#include "source/data_bind/converters/data_converter_string_remove_zeros.cpp" +#include "source/data_bind/converters/data_converter_number_to_list.cpp" +#include "source/data_bind/converters/data_converter_operation_value.cpp" +#include "source/data_bind/converters/data_converter.cpp" +#include "source/data_bind/converters/data_converter_operation_viewmodel.cpp" +#include "source/data_bind/converters/data_converter_to_string.cpp" +#include "source/data_bind/converters/data_converter_operation.cpp" +#include "source/data_bind/converters/data_converter_system_degs_to_rads.cpp" +#include "source/data_bind/converters/data_converter_interpolator.cpp" +#include "source/data_bind/converters/data_converter_trigger.cpp" +#include "source/data_bind/converters/data_converter_group_item.cpp" +#include "source/data_bind/converters/data_converter_rounder.cpp" +#include "source/data_bind/converters/formula/formula_token.cpp" +#include "source/data_bind/converters/data_converter_formula.cpp" +#include "source/data_bind/converters/data_converter_group.cpp" +#include "source/data_bind/converters/data_converter_string_pad.cpp" +#include "source/data_bind/converters/data_converter_range_mapper.cpp" +#include "source/data_bind/converters/data_converter_string_trim.cpp" +#include "source/data_bind/data_context.cpp" +#include "source/intrinsically_sizeable.cpp" +#include "source/bones/root_bone.cpp" +#include "source/bones/bone.cpp" +#include "source/bones/skinnable.cpp" +#include "source/bones/weight.cpp" +#include "source/bones/skin.cpp" +#include "source/bones/tendon.cpp" +#include "source/advancing_component.cpp" +#include "source/text/text_interface.cpp" +#include "source/text/text.cpp" +#include "source/text/text_engine.cpp" +#include "source/text/text_style_axis.cpp" +#include "source/text/text_modifier_group.cpp" +#include "source/text/text_variation_modifier.cpp" +#include "source/text/glyph_lookup.cpp" +#include "source/text/font_hb.cpp" +#include "source/text/text_input_selected_text.cpp" +#include "source/text/text_variation_helper.cpp" +#include "source/text/text_input.cpp" +#include "source/text/text_input_drawable.cpp" +#include "source/text/text_modifier.cpp" +#include "source/text/line_breaker.cpp" +#include "source/text/text_style.cpp" +#include "source/text/text_target_modifier.cpp" +#include "source/text/text_style_feature.cpp" +#include "source/text/text_follow_path_modifier.cpp" +#include "source/text/text_input_cursor.cpp" +#include "source/text/text_value_run.cpp" +#include "source/text/text_selection_path.cpp" +#include "source/text/cursor.cpp" +#include "source/text/text_input_text.cpp" +#include "source/text/utf.cpp" +#include "source/text/raw_text.cpp" +#include "source/text/text_input_selection.cpp" +#include "source/text/text_modifier_range.cpp" +#include "source/text/raw_text_input.cpp" +#include "source/text/text_style_paint.cpp" +#include "source/text/fully_shaped_text.cpp" +#include "source/event.cpp" +#include "source/factory.cpp" +#include "source/command_queue.cpp" +#include "source/assets/audio_asset.cpp" +#include "source/assets/image_asset.cpp" +#include "source/assets/font_asset.cpp" +#include "source/assets/file_asset_contents.cpp" +#include "source/assets/file_asset_referencer.cpp" +#include "source/assets/file_asset.cpp" +#include "source/joystick.cpp" +#include "source/command_server.cpp" +#include "source/solo.cpp" +#include "source/static_scene.cpp" +#include "source/renderer.cpp" +#include "source/audio_event.cpp" +#include "source/nested_artboard_leaf.cpp" + +#if __clang__ + #pragma clang diagnostic pop +#elif __GNUC__ + #pragma GCC diagnostic pop +#elif _MSC_VER + #pragma warning (pop) +#endif diff --git a/third_party/rive/rive.h b/third_party/rive/rive.h new file mode 100644 index 0000000..d060c91 --- /dev/null +++ b/third_party/rive/rive.h @@ -0,0 +1,56 @@ +/* + ============================================================================== + + This file is part of the YUP library. + Copyright (c) 2024 - kunitoki@gmail.com + + YUP is an open source library subject to open-source licensing. + + The code included in this file is provided under the terms of the ISC license + http://www.isc.org/downloads/software-support-policy/isc-license. Permission + to use, copy, modify, and/or distribute this software for any purpose with or + without fee is hereby granted provided that the above copyright notice and + this permission notice appear in all copies. + + YUP IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +/* + ============================================================================== + + BEGIN_YUP_MODULE_DECLARATION + + ID: rive + vendor: rive + version: 1.0 + name: Rive C++ is a runtime library for Rive. + description: Rive C++ is a runtime library for Rive, a real-time interactive design and animation tool. + website: https://github.com/rive-app/rive-runtime + license: MIT + + dependencies: harfbuzz sheenbidi yoga_library + defines: WITH_RIVE_TEXT=1 WITH_RIVE_YOGA=1 WITH_RIVE_LAYOUT=1 + appleFrameworks: CoreText + searchpaths: include + + END_YUP_MODULE_DECLARATION + + ============================================================================== +*/ + +#pragma once + +#include "include/rive/text/utf.hpp" +#include "include/rive/artboard.hpp" +#include "include/rive/file.hpp" +#include "include/rive/static_scene.hpp" +#include "include/rive/layout.hpp" +#include "include/rive/custom_property_number.hpp" +#include "include/rive/custom_property_boolean.hpp" +#include "include/rive/custom_property_string.hpp" +#include "include/rive/animation/state_machine_instance.hpp" +#include "include/rive/animation/state_machine_input_instance.hpp" diff --git a/third_party/rive/rive.mm b/third_party/rive/rive.mm new file mode 100644 index 0000000..95a98d4 --- /dev/null +++ b/third_party/rive/rive.mm @@ -0,0 +1,22 @@ +/* + ============================================================================== + + This file is part of the YUP library. + Copyright (c) 2025 - kunitoki@gmail.com + + YUP is an open source library subject to open-source licensing. + + The code included in this file is provided under the terms of the ISC license + http://www.isc.org/downloads/software-support-policy/isc-license. Permission + to use, copy, modify, and/or distribute this software for any purpose with or + without fee is hereby granted provided that the above copyright notice and + this permission notice appear in all copies. + + YUP IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +#include "rive.cpp" diff --git a/third_party/rive/rive_apple.mm b/third_party/rive/rive_apple.mm new file mode 100644 index 0000000..b0f1aab --- /dev/null +++ b/third_party/rive/rive_apple.mm @@ -0,0 +1,35 @@ +/* + ============================================================================== + + This file is part of the YUP library. + Copyright (c) 2025 - kunitoki@gmail.com + + YUP is an open source library subject to open-source licensing. + + The code included in this file is provided under the terms of the ISC license + http://www.isc.org/downloads/software-support-policy/isc-license. Permission + to use, copy, modify, and/or distribute this software for any purpose with or + without fee is hereby granted provided that the above copyright notice and + this permission notice appear in all copies. + + YUP IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +#if __clang__ + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wshorten-64-to-32" +#endif + +#if !defined(_RIVE_INTERNAL_) +#define _RIVE_INTERNAL_ 1 +#endif + +#include "source/text/font_hb_apple.mm" + +#if __clang__ + #pragma clang diagnostic pop +#endif diff --git a/third_party/rive/source/advancing_component.cpp b/third_party/rive/source/advancing_component.cpp new file mode 100644 index 0000000..c364015 --- /dev/null +++ b/third_party/rive/source/advancing_component.cpp @@ -0,0 +1,30 @@ +#include "rive/component.hpp" +#include "rive/constraints/scrolling/scroll_constraint.hpp" +#include "rive/artboard.hpp" +#include "rive/artboard_component_list.hpp" +#include "rive/layout_component.hpp" +#include "rive/nested_artboard.hpp" +#include "rive/nested_artboard_layout.hpp" +#include "rive/nested_artboard_leaf.hpp" + +using namespace rive; + +AdvancingComponent* AdvancingComponent::from(Component* component) +{ + switch (component->coreType()) + { + case NestedArtboardLeaf::typeKey: + case NestedArtboardLayout::typeKey: + case NestedArtboard::typeKey: + return component->as(); + case LayoutComponent::typeKey: + return component->as(); + case Artboard::typeKey: + return component->as(); + case ArtboardComponentListBase::typeKey: + return component->as(); + case ScrollConstraint::typeKey: + return component->as(); + } + return nullptr; +} \ No newline at end of file diff --git a/third_party/rive/source/animation/animation_reset.cpp b/third_party/rive/source/animation/animation_reset.cpp new file mode 100644 index 0000000..60f9c75 --- /dev/null +++ b/third_party/rive/source/animation/animation_reset.cpp @@ -0,0 +1,63 @@ +#include "rive/animation/animation_reset.hpp" +#include "rive/core/vector_binary_writer.hpp" +#include "rive/generated/core_registry.hpp" + +using namespace rive; + +AnimationReset::AnimationReset() : + m_binaryWriter(&m_WriteBuffer), m_binaryReader(nullptr, 0) +{} + +void AnimationReset::writeObjectId(uint32_t objectId) +{ + m_binaryWriter.writeVarUint(objectId); +} + +void AnimationReset::writeTotalProperties(uint32_t value) +{ + m_binaryWriter.writeVarUint(value); +} + +void AnimationReset::writePropertyKey(uint32_t value) +{ + m_binaryWriter.writeVarUint(value); +} + +void AnimationReset::writePropertyValue(float value) +{ + m_binaryWriter.writeFloat(value); +} + +void AnimationReset::clear() { m_binaryWriter.clear(); } + +void AnimationReset::complete() +{ + m_binaryReader.complete(&m_WriteBuffer.front(), m_binaryWriter.size()); +} + +void AnimationReset::apply(Artboard* artboard) +{ + m_binaryReader.reset(&m_WriteBuffer.front()); + while (!m_binaryReader.isEOF()) + { + auto objectId = m_binaryReader.readVarUint32(); + auto object = artboard->resolve(objectId); + auto totalProperties = m_binaryReader.readVarUint32(); + uint32_t currentPropertyIndex = 0; + while (currentPropertyIndex < totalProperties) + { + auto propertyKey = m_binaryReader.readVarUint32(); + auto propertyValue = m_binaryReader.readFloat32(); + switch (CoreRegistry::propertyFieldId(propertyKey)) + { + case CoreDoubleType::id: + CoreRegistry::setDouble(object, propertyKey, propertyValue); + break; + case CoreColorType::id: + CoreRegistry::setColor(object, propertyKey, propertyValue); + break; + } + currentPropertyIndex++; + } + } +} diff --git a/third_party/rive/source/animation/animation_reset_factory.cpp b/third_party/rive/source/animation/animation_reset_factory.cpp new file mode 100644 index 0000000..ace9919 --- /dev/null +++ b/third_party/rive/source/animation/animation_reset_factory.cpp @@ -0,0 +1,235 @@ +#include "rive/animation/animation_reset_factory.hpp" +#include "rive/animation/linear_animation.hpp" +#include "rive/animation/animation_state.hpp" +#include "rive/animation/keyed_object.hpp" +#include "rive/animation/keyed_property.hpp" +#include "rive/generated/core_registry.hpp" +#include +#include + +using namespace rive; + +class KeyedPropertyData +{ +public: + const KeyedProperty* keyedProperty; + bool isBaseline; + KeyedPropertyData(const KeyedProperty* value, bool baselineValue) : + keyedProperty(value), isBaseline(baselineValue) + {} +}; + +class KeyedObjectData +{ +public: + std::vector keyedPropertiesData; + std::set keyedPropertiesSet; + uint32_t objectId; + KeyedObjectData(const uint32_t value) { objectId = value; } + void addProperties(const KeyedObject* keyedObject, bool isBaseline) + { + size_t index = 0; + while (index < keyedObject->numKeyedProperties()) + { + auto keyedProperty = keyedObject->getProperty(index); + auto pos = keyedPropertiesSet.find(keyedProperty->propertyKey()); + if (pos == keyedPropertiesSet.end()) + { + switch ( + CoreRegistry::propertyFieldId(keyedProperty->propertyKey())) + { + case CoreDoubleType::id: + case CoreColorType::id: + keyedPropertiesSet.insert(keyedProperty->propertyKey()); + keyedPropertiesData.push_back( + KeyedPropertyData(keyedProperty, isBaseline)); + break; + } + } + index++; + } + } +}; + +class AnimationsData +{ + +private: + std::vector> keyedObjectsData; + KeyedObjectData* getKeyedObjectData(const KeyedObject* keyedObject) + { + for (auto& keyedObjectData : keyedObjectsData) + { + if (keyedObjectData->objectId == keyedObject->objectId()) + { + return keyedObjectData.get(); + } + } + + auto keyedObjectData = + rivestd::make_unique(keyedObject->objectId()); + auto ref = keyedObjectData.get(); + keyedObjectsData.push_back(std::move(keyedObjectData)); + return ref; + } + + void findKeyedObjects(const LinearAnimation* animation, + bool isFirstAnimation) + { + size_t index = 0; + while (index < animation->numKeyedObjects()) + { + auto keyedObject = animation->getObject(index); + auto keyedObjectData = getKeyedObjectData(keyedObject); + + keyedObjectData->addProperties(keyedObject, isFirstAnimation); + index++; + } + } + +public: + AnimationsData(std::vector& animations, + bool useFirstAsBaseline) + { + bool isFirstAnimation = useFirstAsBaseline; + for (auto animation : animations) + { + findKeyedObjects(animation, isFirstAnimation); + isFirstAnimation = false; + } + } + + void writeObjects(AnimationReset* animationReset, + ArtboardInstance* artboard) + { + for (auto& keyedObjectData : keyedObjectsData) + { + auto object = artboard->resolve(keyedObjectData->objectId); + if (object == nullptr) + { + continue; + } + auto component = object->as(); + auto propertiesData = keyedObjectData->keyedPropertiesData; + if (propertiesData.size() > 0) + { + animationReset->writeObjectId(keyedObjectData->objectId); + animationReset->writeTotalProperties( + (uint32_t)propertiesData.size()); + for (auto keyedPropertyData : propertiesData) + { + auto keyedProperty = keyedPropertyData.keyedProperty; + auto propertyKey = keyedProperty->propertyKey(); + switch (CoreRegistry::propertyFieldId(propertyKey)) + { + case CoreDoubleType::id: + animationReset->writePropertyKey(propertyKey); + if (keyedPropertyData.isBaseline) + { + auto firstKeyframe = keyedProperty->first(); + if (firstKeyframe != nullptr) + { + auto value = keyedProperty->first() + ->as() + ->value(); + animationReset->writePropertyValue(value); + } + } + else + { + animationReset->writePropertyValue( + CoreRegistry::getDouble(component, + propertyKey)); + } + break; + case CoreColorType::id: + + animationReset->writePropertyKey(propertyKey); + if (keyedPropertyData.isBaseline) + { + auto firstKeyframe = keyedProperty->first(); + if (firstKeyframe != nullptr) + { + auto value = keyedProperty->first() + ->as() + ->value(); + animationReset->writePropertyValue( + (float)value); + } + } + else + { + animationReset->writePropertyValue( + (float)CoreRegistry::getColor(component, + propertyKey)); + } + break; + } + } + } + } + animationReset->complete(); + } +}; + +std::unique_ptr AnimationResetFactory::getInstance() +{ + std::unique_lock lock(m_mutex); + if (m_resources.size() > 0) + { + auto instance = std::move(m_resources.back()); + m_resources.pop_back(); + return instance; + } + auto instance = rivestd::make_unique(); + return instance; +} + +void AnimationResetFactory::fromState( + StateInstance* stateInstance, + std::vector& animations) +{ + if (stateInstance != nullptr) + { + auto state = stateInstance->state(); + if (state->is() && + state->as()->animation() != nullptr) + { + animations.push_back(state->as()->animation()); + } + } +} + +std::unique_ptr AnimationResetFactory::fromStates( + StateInstance* stateFrom, + StateInstance* currentState, + ArtboardInstance* artboard) +{ + std::vector animations; + fromState(stateFrom, animations); + fromState(currentState, animations); + return fromAnimations(animations, artboard, false); +} + +std::unique_ptr AnimationResetFactory::fromAnimations( + std::vector& animations, + ArtboardInstance* artboard, + bool useFirstAsBaseline) +{ + auto animationsData = new AnimationsData(animations, useFirstAsBaseline); + auto animationReset = AnimationResetFactory::getInstance(); + animationsData->writeObjects(animationReset.get(), artboard); + delete animationsData; + return animationReset; +} + +std::vector> AnimationResetFactory::m_resources; + +std::mutex AnimationResetFactory::m_mutex; + +void AnimationResetFactory::release(std::unique_ptr value) +{ + std::unique_lock lock(m_mutex); + value->clear(); + m_resources.push_back(std::move(value)); +} diff --git a/third_party/rive/source/animation/animation_state.cpp b/third_party/rive/source/animation/animation_state.cpp new file mode 100644 index 0000000..c037ca0 --- /dev/null +++ b/third_party/rive/source/animation/animation_state.cpp @@ -0,0 +1,20 @@ +#include "rive/animation/animation_state.hpp" +#include "rive/animation/linear_animation.hpp" +#include "rive/animation/animation_state_instance.hpp" +#include "rive/core_context.hpp" +#include "rive/artboard.hpp" + +using namespace rive; + +std::unique_ptr AnimationState::makeInstance( + ArtboardInstance* instance) const +{ + return rivestd::make_unique(this, instance); +} + +#ifdef TESTING +void AnimationState::animation(LinearAnimation* animation) +{ + m_Animation = animation; +} +#endif diff --git a/third_party/rive/source/animation/animation_state_instance.cpp b/third_party/rive/source/animation/animation_state_instance.cpp new file mode 100644 index 0000000..d610ac4 --- /dev/null +++ b/third_party/rive/source/animation/animation_state_instance.cpp @@ -0,0 +1,45 @@ +#include "rive/animation/animation_state_instance.hpp" +#include "rive/animation/animation_state.hpp" +#include "rive/animation/state_machine_instance.hpp" + +using namespace rive; + +static LinearAnimation emptyAnimation; + +AnimationStateInstance::AnimationStateInstance(const AnimationState* state, + ArtboardInstance* instance) : + StateInstance(state), + // We're careful to always instance a valid animation here as the + // StateMachine makes assumptions about AnimationState's producing valid + // AnimationStateInstances with backing animations. This was discovered when + // using Clang address sanitizer. We previously returned a + // SystemStateInstance (basically a no-op StateMachine state) which would + // cause bad casts in parts of the code where we assumed AnimationStates + // would have create AnimationStateInstances. + m_AnimationInstance(state->animation() ? state->animation() + : &emptyAnimation, + instance, + state->speed()), + m_KeepGoing(true) +{} + +// NOTE:: should we return bool here? we are not currently using the output of +// this, we are instead using m_keepGoing directly. +void AnimationStateInstance::advance(float seconds, + StateMachineInstance* stateMachineInstance) +{ + m_KeepGoing = m_AnimationInstance.advance( + seconds * state()->as()->speed(), + stateMachineInstance); +} + +void AnimationStateInstance::apply(ArtboardInstance* instance, float mix) +{ + m_AnimationInstance.apply(mix); +} + +bool AnimationStateInstance::keepGoing() const { return m_KeepGoing; } +void AnimationStateInstance::clearSpilledTime() +{ + m_AnimationInstance.clearSpilledTime(); +} \ No newline at end of file diff --git a/third_party/rive/source/animation/blend_animation.cpp b/third_party/rive/source/animation/blend_animation.cpp new file mode 100644 index 0000000..c379e68 --- /dev/null +++ b/third_party/rive/source/animation/blend_animation.cpp @@ -0,0 +1,39 @@ +#include "rive/artboard.hpp" +#include "rive/animation/blend_animation.hpp" +#include "rive/animation/layer_state.hpp" +#include "rive/importers/layer_state_importer.hpp" +#include "rive/importers/artboard_importer.hpp" + +using namespace rive; + +LinearAnimation BlendAnimation::m_EmptyAnimation; + +StatusCode BlendAnimation::import(ImportStack& importStack) +{ + auto importer = + importStack.latest(LayerStateBase::typeKey); + if (importer == nullptr) + { + return StatusCode::MissingObject; + } + else if (!importer->addBlendAnimation(this)) + { + return StatusCode::InvalidObject; + } + + auto artboardImporter = + importStack.latest(ArtboardBase::typeKey); + if (artboardImporter == nullptr) + { + return StatusCode::MissingObject; + } + + auto artboard = artboardImporter->artboard(); + size_t animationCount = artboard->animationCount(); + if ((size_t)animationId() < animationCount) + { + m_Animation = artboardImporter->artboard()->animation(animationId()); + } + + return Super::import(importStack); +} diff --git a/third_party/rive/source/animation/blend_animation_1d.cpp b/third_party/rive/source/animation/blend_animation_1d.cpp new file mode 100644 index 0000000..286c537 --- /dev/null +++ b/third_party/rive/source/animation/blend_animation_1d.cpp @@ -0,0 +1,13 @@ +#include "rive/animation/blend_animation_1d.hpp" + +using namespace rive; + +StatusCode BlendAnimation1D::onAddedDirty(CoreContext* context) +{ + return StatusCode::Ok; +} + +StatusCode BlendAnimation1D::onAddedClean(CoreContext* context) +{ + return StatusCode::Ok; +} \ No newline at end of file diff --git a/third_party/rive/source/animation/blend_animation_direct.cpp b/third_party/rive/source/animation/blend_animation_direct.cpp new file mode 100644 index 0000000..334fed8 --- /dev/null +++ b/third_party/rive/source/animation/blend_animation_direct.cpp @@ -0,0 +1,56 @@ +#include "rive/animation/blend_animation_direct.hpp" +#include "rive/animation/state_machine.hpp" +#include "rive/animation/state_machine_number.hpp" +#include "rive/importers/state_machine_importer.hpp" +#include "rive/importers/bindable_property_importer.hpp" +#include "rive/data_bind/bindable_property.hpp" + +using namespace rive; + +StatusCode BlendAnimationDirect::onAddedDirty(CoreContext* context) +{ + return StatusCode::Ok; +} + +StatusCode BlendAnimationDirect::onAddedClean(CoreContext* context) +{ + return StatusCode::Ok; +} + +StatusCode BlendAnimationDirect::import(ImportStack& importStack) +{ + auto stateMachineImporter = + importStack.latest(StateMachine::typeKey); + if (stateMachineImporter == nullptr) + { + return StatusCode::MissingObject; + } + + // Make sure the inputId doesn't overflow the input buffer. + if (blendSource() == static_cast(DirectBlendSource::inputId)) + { + if ((size_t)inputId() >= + stateMachineImporter->stateMachine()->inputCount()) + { + return StatusCode::InvalidObject; + } + auto input = + stateMachineImporter->stateMachine()->input((size_t)inputId()); + if (input == nullptr || !input->is()) + { + return StatusCode::InvalidObject; + } + } + else if (blendSource() == static_cast(DirectBlendSource::dataBindId)) + { + auto bindablePropertyImporter = + importStack.latest( + BindablePropertyBase::typeKey); + if (bindablePropertyImporter == nullptr) + { + return StatusCode::MissingObject; + } + m_bindableProperty = bindablePropertyImporter->bindableProperty(); + } + return Super::import(importStack); +} diff --git a/third_party/rive/source/animation/blend_state.cpp b/third_party/rive/source/animation/blend_state.cpp new file mode 100644 index 0000000..ed83d63 --- /dev/null +++ b/third_party/rive/source/animation/blend_state.cpp @@ -0,0 +1,20 @@ +#include "rive/animation/blend_state.hpp" +#include "rive/animation/blend_animation.hpp" + +using namespace rive; + +BlendState::~BlendState() +{ + for (auto anim : m_Animations) + { + delete anim; + } +} + +void BlendState::addAnimation(BlendAnimation* animation) +{ + // Assert it's not already contained. + assert(std::find(m_Animations.begin(), m_Animations.end(), animation) == + m_Animations.end()); + m_Animations.push_back(animation); +} \ No newline at end of file diff --git a/third_party/rive/source/animation/blend_state_1d.cpp b/third_party/rive/source/animation/blend_state_1d.cpp new file mode 100644 index 0000000..ddfab5d --- /dev/null +++ b/third_party/rive/source/animation/blend_state_1d.cpp @@ -0,0 +1,10 @@ +#include "rive/animation/blend_state_1d.hpp" +#include "rive/animation/blend_state_1d_instance.hpp" + +using namespace rive; + +std::unique_ptr BlendState1D::makeInstance( + ArtboardInstance* instance) const +{ + return rivestd::make_unique(this, instance); +} diff --git a/third_party/rive/source/animation/blend_state_1d_input.cpp b/third_party/rive/source/animation/blend_state_1d_input.cpp new file mode 100644 index 0000000..93027fb --- /dev/null +++ b/third_party/rive/source/animation/blend_state_1d_input.cpp @@ -0,0 +1,34 @@ +#include "rive/animation/blend_state_1d_input.hpp" +#include "rive/animation/state_machine.hpp" +#include "rive/animation/state_machine_number.hpp" +#include "rive/animation/blend_state_1d_instance.hpp" +#include "rive/importers/state_machine_importer.hpp" + +using namespace rive; + +StatusCode BlendState1DInput::import(ImportStack& importStack) +{ + auto stateMachineImporter = + importStack.latest(StateMachine::typeKey); + if (stateMachineImporter == nullptr) + { + return StatusCode::MissingObject; + } + + if (hasValidInputId()) + { + // Make sure the inputId doesn't overflow the input buffer. + if ((size_t)inputId() >= + stateMachineImporter->stateMachine()->inputCount()) + { + return StatusCode::InvalidObject; + } + auto input = + stateMachineImporter->stateMachine()->input((size_t)inputId()); + if (input == nullptr || !input->is()) + { + return StatusCode::InvalidObject; + } + } + return Super::import(importStack); +} diff --git a/third_party/rive/source/animation/blend_state_1d_instance.cpp b/third_party/rive/source/animation/blend_state_1d_instance.cpp new file mode 100644 index 0000000..bc8cc0b --- /dev/null +++ b/third_party/rive/source/animation/blend_state_1d_instance.cpp @@ -0,0 +1,148 @@ +#include "rive/animation/blend_state_1d_input.hpp" +#include "rive/animation/blend_state_1d_instance.hpp" +#include "rive/animation/blend_state_1d_viewmodel.hpp" +#include "rive/animation/state_machine_input_instance.hpp" +#include "rive/data_bind/bindable_property_number.hpp" +#include "rive/animation/layer_state_flags.hpp" + +using namespace rive; + +BlendState1DInstance::BlendState1DInstance(const BlendState1D* blendState, + ArtboardInstance* instance) : + BlendStateInstance(blendState, instance) +{ + + if ((static_cast(blendState->flags()) & + LayerStateFlags::Reset) == LayerStateFlags::Reset) + { + auto animations = std::vector(); + for (auto blendAnimation : blendState->animations()) + { + animations.push_back(blendAnimation->animation()); + } + m_AnimationReset = + AnimationResetFactory::fromAnimations(animations, instance, true); + } +} + +BlendState1DInstance::~BlendState1DInstance() +{ + if (m_AnimationReset != nullptr) + { + AnimationResetFactory::release(std::move(m_AnimationReset)); + } +} + +int BlendState1DInstance::animationIndex(float value) +{ + int idx = 0; + int mid = 0; + float closestValue = 0; + int start = 0; + int end = static_cast(m_AnimationInstances.size()) - 1; + + while (start <= end) + { + mid = (start + end) >> 1; + closestValue = m_AnimationInstances[mid].blendAnimation()->value(); + if (closestValue < value) + { + start = mid + 1; + } + else if (closestValue > value) + { + end = mid - 1; + } + else + { + idx = start = mid; + break; + } + + idx = start; + } + return idx; +} + +void BlendState1DInstance::apply(ArtboardInstance* instance, float mix) +{ + if (m_AnimationReset != nullptr) + { + m_AnimationReset->apply(instance); + } + BlendStateInstance::apply(instance, mix); +} + +void BlendState1DInstance::advance(float seconds, + StateMachineInstance* stateMachineInstance) +{ + BlendStateInstance::advance( + seconds, + stateMachineInstance); + + float value = 0.0f; + if (state()->is()) + { + auto blendState = state()->as(); + + if (blendState->hasValidInputId()) + { + // TODO: https://github.com/rive-app/rive-cpp/issues/229 + auto inputInstance = + stateMachineInstance->input(blendState->inputId()); + auto numberInput = static_cast(inputInstance); + value = numberInput->value(); + } + } + else if (state()->is()) + { + auto blendState = state()->as(); + auto bindablePropertyInstance = + stateMachineInstance->bindablePropertyInstance( + blendState->bindableProperty()); + if (bindablePropertyInstance->is()) + { + value = bindablePropertyInstance->as() + ->propertyValue(); + } + } + int index = animationIndex(value); + auto animationsCount = static_cast(m_AnimationInstances.size()); + m_To = index >= 0 && index < animationsCount ? &m_AnimationInstances[index] + : nullptr; + m_From = index - 1 >= 0 && index - 1 < animationsCount + ? &m_AnimationInstances[index - 1] + : nullptr; + + float mix, mixFrom; + auto toValue = m_To == nullptr ? 0.0f : m_To->blendAnimation()->value(); + auto fromValue = + m_From == nullptr ? 0.0f : m_From->blendAnimation()->value(); + + if (m_To == nullptr || m_From == nullptr || toValue == fromValue) + { + mix = mixFrom = 1.0f; + } + else + { + mix = (value - fromValue) / (toValue - fromValue); + mixFrom = 1.0f - mix; + } + + for (auto& animation : m_AnimationInstances) + { + auto animationValue = animation.blendAnimation()->value(); + if (m_To != nullptr && animationValue == toValue) + { + animation.mix(mix); + } + else if (m_From != nullptr && animationValue == fromValue) + { + animation.mix(mixFrom); + } + else + { + animation.mix(0.0f); + } + } +} diff --git a/third_party/rive/source/animation/blend_state_1d_viewmodel.cpp b/third_party/rive/source/animation/blend_state_1d_viewmodel.cpp new file mode 100644 index 0000000..a370a78 --- /dev/null +++ b/third_party/rive/source/animation/blend_state_1d_viewmodel.cpp @@ -0,0 +1,35 @@ +#include "rive/animation/blend_state_1d_viewmodel.hpp" +#include "rive/animation/state_machine.hpp" +#include "rive/animation/state_machine_number.hpp" +#include "rive/importers/state_machine_importer.hpp" +#include "rive/importers/bindable_property_importer.hpp" + +using namespace rive; + +BlendState1DViewModel::~BlendState1DViewModel() +{ + if (m_bindableProperty != nullptr) + { + delete m_bindableProperty; + m_bindableProperty = nullptr; + } +} + +StatusCode BlendState1DViewModel::import(ImportStack& importStack) +{ + auto stateMachineImporter = + importStack.latest(StateMachine::typeKey); + if (stateMachineImporter == nullptr) + { + return StatusCode::MissingObject; + } + auto bindablePropertyImporter = + importStack.latest( + BindablePropertyBase::typeKey); + if (bindablePropertyImporter == nullptr) + { + return StatusCode::MissingObject; + } + m_bindableProperty = bindablePropertyImporter->bindableProperty(); + return Super::import(importStack); +} \ No newline at end of file diff --git a/third_party/rive/source/animation/blend_state_direct.cpp b/third_party/rive/source/animation/blend_state_direct.cpp new file mode 100644 index 0000000..82db10b --- /dev/null +++ b/third_party/rive/source/animation/blend_state_direct.cpp @@ -0,0 +1,12 @@ +#include "rive/animation/blend_state_direct.hpp" +#include "rive/animation/state_machine.hpp" +#include "rive/animation/state_machine_number.hpp" +#include "rive/animation/blend_state_direct_instance.hpp" + +using namespace rive; + +std::unique_ptr BlendStateDirect::makeInstance( + ArtboardInstance* instance) const +{ + return rivestd::make_unique(this, instance); +} \ No newline at end of file diff --git a/third_party/rive/source/animation/blend_state_direct_instance.cpp b/third_party/rive/source/animation/blend_state_direct_instance.cpp new file mode 100644 index 0000000..c7dad63 --- /dev/null +++ b/third_party/rive/source/animation/blend_state_direct_instance.cpp @@ -0,0 +1,58 @@ + +#include "rive/animation/blend_animation_direct.hpp" +#include "rive/animation/blend_state_direct_instance.hpp" +#include "rive/animation/state_machine_input_instance.hpp" +#include "rive/data_bind/bindable_property_number.hpp" +#include + +using namespace rive; + +BlendStateDirectInstance::BlendStateDirectInstance( + const BlendStateDirect* blendState, + ArtboardInstance* instance) : + BlendStateInstance(blendState, + instance) +{} + +void BlendStateDirectInstance::advance( + float seconds, + StateMachineInstance* stateMachineInstance) +{ + BlendStateInstance::advance( + seconds, + stateMachineInstance); + + for (auto& animation : m_AnimationInstances) + { + if (animation.blendAnimation()->blendSource() == + static_cast(DirectBlendSource::mixValue)) + { + auto value = animation.blendAnimation()->mixValue(); + animation.mix(std::min(1.0f, std::max(0.0f, value / 100.0f))); + } + else if (animation.blendAnimation()->blendSource() == + static_cast(DirectBlendSource::dataBindId)) + { + auto bindableProperty = + animation.blendAnimation()->bindableProperty(); + auto bindableInstance = + stateMachineInstance->bindablePropertyInstance( + bindableProperty); + if (bindableInstance->is()) + { + auto bindableNumber = + bindableInstance->as(); + auto value = bindableNumber->propertyValue(); + animation.mix(std::min(1.0f, std::max(0.0f, value / 100.0f))); + } + } + else + { + auto inputInstance = stateMachineInstance->input( + animation.blendAnimation()->inputId()); + auto numberInput = static_cast(inputInstance); + auto value = numberInput->value(); + animation.mix(std::min(1.0f, std::max(0.0f, value / 100.0f))); + } + } +} diff --git a/third_party/rive/source/animation/blend_state_transition.cpp b/third_party/rive/source/animation/blend_state_transition.cpp new file mode 100644 index 0000000..86e5c1d --- /dev/null +++ b/third_party/rive/source/animation/blend_state_transition.cpp @@ -0,0 +1,43 @@ +#include "rive/artboard.hpp" +#include "rive/animation/blend_state_transition.hpp" +#include "rive/animation/blend_state_instance.hpp" +#include "rive/animation/blend_state_1d_input.hpp" +#include "rive/animation/blend_state_1d_viewmodel.hpp" +#include "rive/animation/blend_state_direct.hpp" +#include "rive/animation/blend_state_1d_instance.hpp" +#include "rive/animation/blend_state_direct_instance.hpp" + +using namespace rive; + +const LinearAnimationInstance* BlendStateTransition::exitTimeAnimationInstance( + const StateInstance* from) const +{ + if (from != nullptr) + { + switch (from->state()->coreType()) + { + case BlendState1DInput::typeKey: + case BlendState1DViewModel::typeKey: + + return static_cast(from) + ->animationInstance(m_ExitBlendAnimation); + + case BlendStateDirect::typeKey: + + return static_cast(from) + ->animationInstance(m_ExitBlendAnimation); + } + } + + return nullptr; +} + +const LinearAnimation* BlendStateTransition::exitTimeAnimation( + const LayerState* from) const +{ + if (m_ExitBlendAnimation != nullptr) + { + return m_ExitBlendAnimation->animation(); + } + return nullptr; +} \ No newline at end of file diff --git a/third_party/rive/source/animation/cubic_ease_interpolator.cpp b/third_party/rive/source/animation/cubic_ease_interpolator.cpp new file mode 100644 index 0000000..6f62797 --- /dev/null +++ b/third_party/rive/source/animation/cubic_ease_interpolator.cpp @@ -0,0 +1,17 @@ +#include "rive/animation/cubic_ease_interpolator.hpp" + +using namespace rive; + +float CubicEaseInterpolator::transformValue(float valueFrom, + float valueTo, + float factor) +{ + return valueFrom + (valueTo - valueFrom) * transform(factor); +} + +float CubicEaseInterpolator::transform(float factor) const +{ + return CubicInterpolatorSolver::calcBezier(m_solver.getT(factor), + y1(), + y2()); +} \ No newline at end of file diff --git a/third_party/rive/source/animation/cubic_interpolator.cpp b/third_party/rive/source/animation/cubic_interpolator.cpp new file mode 100644 index 0000000..d6e5526 --- /dev/null +++ b/third_party/rive/source/animation/cubic_interpolator.cpp @@ -0,0 +1,11 @@ +#include "rive/animation/cubic_interpolator.hpp" + +using namespace rive; + +StatusCode CubicInterpolator::onAddedDirty(CoreContext* context) +{ + m_solver.build(x1(), x2()); + return StatusCode::Ok; +} + +void CubicInterpolator::initialize() { m_solver.build(x1(), x2()); } \ No newline at end of file diff --git a/third_party/rive/source/animation/cubic_interpolator_component.cpp b/third_party/rive/source/animation/cubic_interpolator_component.cpp new file mode 100644 index 0000000..d568649 --- /dev/null +++ b/third_party/rive/source/animation/cubic_interpolator_component.cpp @@ -0,0 +1,21 @@ +#include "rive/animation/cubic_interpolator_component.hpp" + +using namespace rive; + +StatusCode CubicInterpolatorComponent::onAddedDirty(CoreContext* context) +{ + StatusCode code = Super::onAddedDirty(context); + if (code != StatusCode::Ok) + { + return code; + } + m_solver.build(x1(), x2()); + return StatusCode::Ok; +} + +float CubicInterpolatorComponent::transform(float factor) const +{ + return CubicInterpolatorSolver::calcBezier(m_solver.getT(factor), + y1(), + y2()); +} \ No newline at end of file diff --git a/third_party/rive/source/animation/cubic_interpolator_solver.cpp b/third_party/rive/source/animation/cubic_interpolator_solver.cpp new file mode 100644 index 0000000..d6904c3 --- /dev/null +++ b/third_party/rive/source/animation/cubic_interpolator_solver.cpp @@ -0,0 +1,96 @@ +#include "rive/animation/cubic_interpolator_solver.hpp" +#include + +using namespace rive; + +const int NewtonIterations = 4; +const float NewtonMinSlope = 0.001f; +const float SubdivisionPrecision = 0.0000001f; +const int SubdivisionMaxIterations = 10; + +// Returns x(t) given t, x1, and x2, or y(t) given t, y1, and y2. +float CubicInterpolatorSolver::calcBezier(float aT, float aA1, float aA2) +{ + return (((1.0f - 3.0f * aA2 + 3.0f * aA1) * aT + + (3.0f * aA2 - 6.0f * aA1)) * + aT + + (3.0f * aA1)) * + aT; +} + +// Returns dx/dt given t, x1, and x2, or dy/dt given t, y1, and y2. +static float getSlope(float aT, float aA1, float aA2) +{ + return 3.0f * (1.0f - 3.0f * aA2 + 3.0f * aA1) * aT * aT + + 2.0f * (3.0f * aA2 - 6.0f * aA1) * aT + (3.0f * aA1); +} + +void CubicInterpolatorSolver::build(float x1, float x2) +{ + m_x1 = x1; + m_x2 = x2; + for (int i = 0; i < SplineTableSize; ++i) + { + m_values[i] = calcBezier(i * SampleStepSize, x1, x2); + } +} + +float CubicInterpolatorSolver::getT(float x) const +{ + float intervalStart = 0.0f; + int currentSample = 1; + int lastSample = SplineTableSize - 1; + + for (; currentSample != lastSample && m_values[currentSample] <= x; + ++currentSample) + { + intervalStart += SampleStepSize; + } + --currentSample; + + // Interpolate to provide an initial guess for t + float dist = (x - m_values[currentSample]) / + (m_values[currentSample + 1] - m_values[currentSample]); + float guessForT = intervalStart + dist * SampleStepSize; + + float initialSlope = getSlope(guessForT, m_x1, m_x2); + if (initialSlope >= NewtonMinSlope) + { + for (int i = 0; i < NewtonIterations; ++i) + { + float currentSlope = getSlope(guessForT, m_x1, m_x2); + if (currentSlope == 0.0f) + { + return guessForT; + } + float currentX = calcBezier(guessForT, m_x1, m_x2) - x; + guessForT -= currentX / currentSlope; + } + return guessForT; + } + else if (initialSlope == 0.0f) + { + return guessForT; + } + else + { + float aB = intervalStart + SampleStepSize; + float currentX, currentT; + int i = 0; + do + { + currentT = intervalStart + (aB - intervalStart) / 2.0f; + currentX = calcBezier(currentT, m_x1, m_x2) - x; + if (currentX > 0.0f) + { + aB = currentT; + } + else + { + intervalStart = currentT; + } + } while (std::abs(currentX) > SubdivisionPrecision && + ++i < SubdivisionMaxIterations); + return currentT; + } +} \ No newline at end of file diff --git a/third_party/rive/source/animation/cubic_value_interpolator.cpp b/third_party/rive/source/animation/cubic_value_interpolator.cpp new file mode 100644 index 0000000..6e5825c --- /dev/null +++ b/third_party/rive/source/animation/cubic_value_interpolator.cpp @@ -0,0 +1,46 @@ +#include "rive/animation/cubic_value_interpolator.hpp" + +using namespace rive; + +CubicValueInterpolator::CubicValueInterpolator() : m_D(0.0f), m_ValueTo(0.0f) +{ + computeParameters(); +} +void CubicValueInterpolator::computeParameters() +{ + float y1 = m_D; + float y2 = CubicValueInterpolator::y1(); + float y3 = CubicValueInterpolator::y2(); + float y4 = m_ValueTo; + + m_A = y4 + 3 * (y2 - y3) - y1; + m_B = 3 * (y3 - y2 * 2 + y1); + m_C = 3 * (y2 - y1); + // m_D = y1; +} + +float CubicValueInterpolator::transformValue(float valueFrom, + float valueTo, + float factor) +{ + if (m_D != valueFrom || m_ValueTo != valueTo) + { + m_D = valueFrom; + m_ValueTo = valueTo; + computeParameters(); + } + float t = m_solver.getT(factor); + return ((m_A * t + m_B) * t + m_C) * t + m_D; +} + +float CubicValueInterpolator::transform(float factor) const +{ + assert(false); + return factor; +} + +StatusCode CubicValueInterpolator::onAddedDirty(CoreContext* context) +{ + computeParameters(); + return Super::onAddedDirty(context); +} \ No newline at end of file diff --git a/third_party/rive/source/animation/elastic_ease.cpp b/third_party/rive/source/animation/elastic_ease.cpp new file mode 100644 index 0000000..e754809 --- /dev/null +++ b/third_party/rive/source/animation/elastic_ease.cpp @@ -0,0 +1,69 @@ +#include "rive/animation/elastic_ease.hpp" +#include "rive/math/math_types.hpp" +#include "math.h" + +using namespace rive; + +ElasticEase::ElasticEase(float amplitude, float period) : + m_amplitude(amplitude), + m_period(period), + m_s(amplitude < 1.0f ? period / 4.0f + : period / (2.0f * math::PI) * asinf(1.0f / amplitude)) +{} + +float ElasticEase::computeActualAmplitude(float time) const +{ + if (m_amplitude < 1.0f) + { + /// We use this when the amplitude is less than 1.0 (amplitude is + /// described as factor of change in value). We also precompute s which + /// is the effective starting period we use to align the decaying sin + /// with our keyframe. + float t = abs(m_s); + float absTime = abs(time); + if (absTime < t) + { + float l = absTime / t; + return (m_amplitude * l) + (1.0f - l); + } + } + + return m_amplitude; +} + +float ElasticEase::easeOut(float factor) const +{ + float time = factor; + float actualAmplitude = computeActualAmplitude(time); + + return (actualAmplitude * pow(2.0f, 10.0f * -time) * + sinf((time - m_s) * (2.0f * math::PI) / m_period)) + + 1.0f; +} + +float ElasticEase::easeIn(float factor) const +{ + float time = factor - 1.0f; + + float actualAmplitude = computeActualAmplitude(time); + + return -(actualAmplitude * pow(2.0f, 10.0f * time) * + sinf((-time - m_s) * (2.0f * math::PI) / m_period)); +} + +float ElasticEase::easeInOut(float factor) const +{ + float time = factor * 2.0f - 1.0f; + float actualAmplitude = computeActualAmplitude(time); + if (time < 0.0f) + { + return -0.5f * actualAmplitude * pow(2.0f, 10.0f * time) * + sinf((-time - m_s) * (2.0f * math::PI) / m_period); + } + else + { + return 0.5f * (actualAmplitude * pow(2.0f, 10.0f * -time) * + sinf((time - m_s) * (2.0f * math::PI) / m_period)) + + 1.0f; + } +} diff --git a/third_party/rive/source/animation/elastic_interpolator.cpp b/third_party/rive/source/animation/elastic_interpolator.cpp new file mode 100644 index 0000000..b953d57 --- /dev/null +++ b/third_party/rive/source/animation/elastic_interpolator.cpp @@ -0,0 +1,37 @@ +#include "rive/animation/elastic_interpolator.hpp" + +using namespace rive; + +ElasticInterpolator::ElasticInterpolator() : m_elastic(1.0f, 0.5f) {} + +void ElasticInterpolator::initialize() +{ + m_elastic = ElasticEase(amplitude(), period() == 0.0f ? 0.5f : period()); +} + +StatusCode ElasticInterpolator::onAddedDirty(CoreContext* context) +{ + initialize(); + return StatusCode::Ok; +} + +float ElasticInterpolator::transformValue(float valueFrom, + float valueTo, + float factor) +{ + return valueFrom + (valueTo - valueFrom) * transform(factor); +} + +float ElasticInterpolator::transform(float factor) const +{ + switch (easing()) + { + case Easing::easeIn: + return m_elastic.easeIn(factor); + case Easing::easeOut: + return m_elastic.easeOut(factor); + case Easing::easeInOut: + return m_elastic.easeInOut(factor); + } + return factor; +} \ No newline at end of file diff --git a/third_party/rive/source/animation/hittable.cpp b/third_party/rive/source/animation/hittable.cpp new file mode 100644 index 0000000..9566586 --- /dev/null +++ b/third_party/rive/source/animation/hittable.cpp @@ -0,0 +1,18 @@ +#include "rive/animation/hittable.hpp" +#include "rive/component.hpp" +#include "rive/shapes/shape.hpp" +#include "rive/text/text_value_run.hpp" + +using namespace rive; + +Hittable* Hittable::from(Component* component) +{ + switch (component->coreType()) + { + case Shape::typeKey: + return component->as(); + case TextValueRun::typeKey: + return component->as(); + } + return nullptr; +} diff --git a/third_party/rive/source/animation/interpolating_keyframe.cpp b/third_party/rive/source/animation/interpolating_keyframe.cpp new file mode 100644 index 0000000..7f7a0da --- /dev/null +++ b/third_party/rive/source/animation/interpolating_keyframe.cpp @@ -0,0 +1,20 @@ +#include "rive/animation/interpolating_keyframe.hpp" +#include "rive/animation/keyframe_interpolator.hpp" +#include "rive/core_context.hpp" + +using namespace rive; + +StatusCode InterpolatingKeyFrame::onAddedDirty(CoreContext* context) +{ + if (interpolatorId() != -1) + { + auto coreObject = context->resolve(interpolatorId()); + if (coreObject == nullptr || !coreObject->is()) + { + return StatusCode::MissingObject; + } + m_interpolator = coreObject->as(); + } + + return StatusCode::Ok; +} \ No newline at end of file diff --git a/third_party/rive/source/animation/keyed_object.cpp b/third_party/rive/source/animation/keyed_object.cpp new file mode 100644 index 0000000..5db97ad --- /dev/null +++ b/third_party/rive/source/animation/keyed_object.cpp @@ -0,0 +1,104 @@ +#include "rive/animation/keyed_object.hpp" +#include "rive/animation/keyed_property.hpp" +#include "rive/animation/linear_animation.hpp" +#include "rive/artboard.hpp" +#include "rive/importers/linear_animation_importer.hpp" +#include "rive/generated/core_registry.hpp" + +using namespace rive; + +KeyedObject::KeyedObject() {} +KeyedObject::~KeyedObject() {} + +void KeyedObject::addKeyedProperty(std::unique_ptr property) +{ + m_keyedProperties.push_back(std::move(property)); +} + +StatusCode KeyedObject::onAddedDirty(CoreContext* context) +{ + // Make sure we're keying a valid object. + Core* coreObject = context->resolve(objectId()); + if (coreObject == nullptr) + { + return StatusCode::MissingObject; + } + + for (auto itr = m_keyedProperties.begin(); itr != m_keyedProperties.end();) + { + auto& property = *itr; + // Validate coreObject supports propertyKey, if not remove it from the + // property keys. + if (!CoreRegistry::objectSupportsProperty(coreObject, + property->propertyKey())) + { + itr = m_keyedProperties.erase(itr); + continue; + } + StatusCode code; + if ((code = property->onAddedDirty(context)) != StatusCode::Ok) + { + return code; + } + itr++; + } + return StatusCode::Ok; +} + +StatusCode KeyedObject::onAddedClean(CoreContext* context) +{ + for (auto& property : m_keyedProperties) + { + property->onAddedClean(context); + } + return StatusCode::Ok; +} + +void KeyedObject::reportKeyedCallbacks(KeyedCallbackReporter* reporter, + float secondsFrom, + float secondsTo, + bool isAtStartFrame) const +{ + for (const std::unique_ptr& property : m_keyedProperties) + { + if (!CoreRegistry::isCallback(property->propertyKey())) + { + continue; + } + property->reportKeyedCallbacks(reporter, + objectId(), + secondsFrom, + secondsTo, + isAtStartFrame); + } +} + +void KeyedObject::apply(Artboard* artboard, float time, float mix) +{ + Core* object = artboard->resolve(objectId()); + if (object == nullptr) + { + return; + } + for (std::unique_ptr& property : m_keyedProperties) + { + if (CoreRegistry::isCallback(property->propertyKey())) + { + continue; + } + property->apply(object, time, mix); + } +} + +StatusCode KeyedObject::import(ImportStack& importStack) +{ + auto importer = importStack.latest( + LinearAnimationBase::typeKey); + if (importer == nullptr) + { + return StatusCode::MissingObject; + } + // we transfer ownership of ourself to the importer! + importer->addKeyedObject(std::unique_ptr(this)); + return Super::import(importStack); +} \ No newline at end of file diff --git a/third_party/rive/source/animation/keyed_property.cpp b/third_party/rive/source/animation/keyed_property.cpp new file mode 100644 index 0000000..2f35ef5 --- /dev/null +++ b/third_party/rive/source/animation/keyed_property.cpp @@ -0,0 +1,192 @@ +#include "rive/animation/keyed_property.hpp" +#include "rive/animation/keyed_object.hpp" +#include "rive/animation/keyframe.hpp" +#include "rive/animation/keyframe_interpolator.hpp" +#include "rive/animation/interpolating_keyframe.hpp" +#include "rive/animation/keyed_callback_reporter.hpp" +#include "rive/importers/import_stack.hpp" +#include "rive/importers/keyed_object_importer.hpp" + +using namespace rive; + +KeyedProperty::KeyedProperty() {} +KeyedProperty::~KeyedProperty() {} + +void KeyedProperty::addKeyFrame(std::unique_ptr keyframe) +{ + m_keyFrames.push_back(std::move(keyframe)); +} + +int KeyedProperty::closestFrameIndex(float seconds, int exactOffset) const +{ + int mid = 0; + float closestSeconds = 0; + int start = 0; + auto numKeyFrames = static_cast(m_keyFrames.size()); + int end = numKeyFrames - 1; + + // If it's the last keyframe, we skip the binary search + if (seconds > m_keyFrames[end]->seconds()) + { + return end + 1; + } + + while (start <= end) + { + mid = (start + end) >> 1; + closestSeconds = m_keyFrames[mid]->seconds(); + if (closestSeconds < seconds) + { + start = mid + 1; + } + else if (closestSeconds > seconds) + { + end = mid - 1; + } + else + { + return mid + exactOffset; + } + } + return start; +} + +void KeyedProperty::reportKeyedCallbacks(KeyedCallbackReporter* reporter, + uint32_t objectId, + float secondsFrom, + float secondsTo, + bool isAtStartFrame) const +{ + if (secondsFrom == secondsTo) + { + return; + } + bool isForward = secondsFrom <= secondsTo; + int fromExactOffset = 0; + int toExactOffset = isForward ? 1 : 0; + if (isForward) + { + if (!isAtStartFrame) + { + fromExactOffset = 1; + } + } + else + { + if (isAtStartFrame) + { + fromExactOffset = 1; + } + } + int idx = closestFrameIndex(secondsFrom, fromExactOffset); + int idxTo = closestFrameIndex(secondsTo, toExactOffset); + + if (idxTo < idx) + { + auto swap = idx; + idx = idxTo; + idxTo = swap; + } + while (idxTo > idx) + { + const std::unique_ptr& frame = m_keyFrames[idx]; + reporter->reportKeyedCallback(objectId, + propertyKey(), + secondsTo - frame->seconds()); + idx++; + } +} + +void KeyedProperty::apply(Core* object, float seconds, float mix) +{ + assert(!m_keyFrames.empty()); + + auto interpolatorHost = InterpolatorHost::from(object); + auto actualMix = mix; + if (interpolatorHost != nullptr && + interpolatorHost->overridesKeyedInterpolation(propertyKey())) + { + actualMix = 1.0f; + } + + int idx = closestFrameIndex(seconds); + int pk = propertyKey(); + + if (idx == 0) + { + static_cast(m_keyFrames[0].get()) + ->apply(object, pk, actualMix); + } + else + { + if (idx < static_cast(m_keyFrames.size())) + { + InterpolatingKeyFrame* fromFrame = + static_cast(m_keyFrames[idx - 1].get()); + InterpolatingKeyFrame* toFrame = + static_cast(m_keyFrames[idx].get()); + if (seconds == toFrame->seconds()) + { + toFrame->apply(object, pk, actualMix); + } + else + { + if (fromFrame->interpolationType() == 0) + { + fromFrame->apply(object, pk, actualMix); + } + else + { + fromFrame->applyInterpolation(object, + pk, + seconds, + toFrame, + actualMix); + } + } + } + else + { + static_cast(m_keyFrames[idx - 1].get()) + ->apply(object, pk, actualMix); + } + } +} + +StatusCode KeyedProperty::onAddedDirty(CoreContext* context) +{ + StatusCode code; + for (auto& keyframe : m_keyFrames) + { + if ((code = keyframe->onAddedDirty(context)) != StatusCode::Ok) + { + return code; + } + } + return StatusCode::Ok; +} + +StatusCode KeyedProperty::onAddedClean(CoreContext* context) +{ + StatusCode code; + for (auto& keyframe : m_keyFrames) + { + if ((code = keyframe->onAddedClean(context)) != StatusCode::Ok) + { + return code; + } + } + return StatusCode::Ok; +} + +StatusCode KeyedProperty::import(ImportStack& importStack) +{ + auto importer = + importStack.latest(KeyedObjectBase::typeKey); + if (importer == nullptr) + { + return StatusCode::MissingObject; + } + importer->addKeyedProperty(std::unique_ptr(this)); + return Super::import(importStack); +} diff --git a/third_party/rive/source/animation/keyframe.cpp b/third_party/rive/source/animation/keyframe.cpp new file mode 100644 index 0000000..14adf60 --- /dev/null +++ b/third_party/rive/source/animation/keyframe.cpp @@ -0,0 +1,22 @@ +#include "rive/animation/keyframe.hpp" +#include "rive/animation/cubic_interpolator.hpp" +#include "rive/animation/keyed_property.hpp" +#include "rive/core_context.hpp" +#include "rive/importers/import_stack.hpp" +#include "rive/importers/keyed_property_importer.hpp" + +using namespace rive; + +void KeyFrame::computeSeconds(int fps) { m_seconds = frame() / (float)fps; } + +StatusCode KeyFrame::import(ImportStack& importStack) +{ + auto importer = + importStack.latest(KeyedProperty::typeKey); + if (importer == nullptr) + { + return StatusCode::MissingObject; + } + importer->addKeyFrame(std::unique_ptr(this)); + return Super::import(importStack); +} \ No newline at end of file diff --git a/third_party/rive/source/animation/keyframe_bool.cpp b/third_party/rive/source/animation/keyframe_bool.cpp new file mode 100644 index 0000000..2d89d8d --- /dev/null +++ b/third_party/rive/source/animation/keyframe_bool.cpp @@ -0,0 +1,18 @@ +#include "rive/animation/keyframe_bool.hpp" +#include "rive/generated/core_registry.hpp" + +using namespace rive; + +void KeyFrameBool::apply(Core* object, int propertyKey, float mix) +{ + CoreRegistry::setBool(object, propertyKey, value()); +} + +void KeyFrameBool::applyInterpolation(Core* object, + int propertyKey, + float currentTime, + const KeyFrame* nextFrame, + float mix) +{ + CoreRegistry::setBool(object, propertyKey, value()); +} \ No newline at end of file diff --git a/third_party/rive/source/animation/keyframe_callback.cpp b/third_party/rive/source/animation/keyframe_callback.cpp new file mode 100644 index 0000000..4989039 --- /dev/null +++ b/third_party/rive/source/animation/keyframe_callback.cpp @@ -0,0 +1,2 @@ +#include "rive/animation/keyframe_callback.hpp" +#include "rive/core_context.hpp" diff --git a/third_party/rive/source/animation/keyframe_color.cpp b/third_party/rive/source/animation/keyframe_color.cpp new file mode 100644 index 0000000..01ad723 --- /dev/null +++ b/third_party/rive/source/animation/keyframe_color.cpp @@ -0,0 +1,45 @@ +#include "rive/animation/keyframe_color.hpp" +#include "rive/generated/core_registry.hpp" +#include "rive/shapes/paint/color.hpp" + +using namespace rive; + +static void applyColor(Core* object, int propertyKey, float mix, int value) +{ + if (mix == 1.0f) + { + CoreRegistry::setColor(object, propertyKey, value); + } + else + { + auto mixedColor = + colorLerp(CoreRegistry::getColor(object, propertyKey), value, mix); + CoreRegistry::setColor(object, propertyKey, mixedColor); + } +} + +void KeyFrameColor::apply(Core* object, int propertyKey, float mix) +{ + applyColor(object, propertyKey, mix, value()); +} + +void KeyFrameColor::applyInterpolation(Core* object, + int propertyKey, + float currentTime, + const KeyFrame* nextFrame, + float mix) +{ + auto kfc = nextFrame->as(); + const KeyFrameColor& nextColor = *kfc; + float f = (currentTime - seconds()) / (nextColor.seconds() - seconds()); + + if (KeyFrameInterpolator* keyframeInterpolator = interpolator()) + { + f = keyframeInterpolator->transform(f); + } + + applyColor(object, + propertyKey, + mix, + colorLerp(value(), nextColor.value(), f)); +} \ No newline at end of file diff --git a/third_party/rive/source/animation/keyframe_double.cpp b/third_party/rive/source/animation/keyframe_double.cpp new file mode 100644 index 0000000..d2feb76 --- /dev/null +++ b/third_party/rive/source/animation/keyframe_double.cpp @@ -0,0 +1,55 @@ +#include "rive/animation/keyframe_double.hpp" +#include "rive/generated/core_registry.hpp" + +using namespace rive; + +// This whole class is intentionally misnamed to match our editor code. The +// editor uses doubles (float64) for numeric values but at runtime 32 bit +// floating point numbers suffice. So even though this is a "double keyframe" to +// match editor names, the actual values are stored and applied in 32 bits. + +static void applyDouble(Core* object, int propertyKey, float mix, float value) +{ + if (mix == 1.0f) + { + CoreRegistry::setDouble(object, propertyKey, value); + } + else + { + float mixi = 1.0f - mix; + CoreRegistry::setDouble( + object, + propertyKey, + CoreRegistry::getDouble(object, propertyKey) * mixi + value * mix); + } +} + +void KeyFrameDouble::apply(Core* object, int propertyKey, float mix) +{ + applyDouble(object, propertyKey, mix, value()); +} + +void KeyFrameDouble::applyInterpolation(Core* object, + int propertyKey, + float currentTime, + const KeyFrame* nextFrame, + float mix) +{ + auto kfd = nextFrame->as(); + const KeyFrameDouble& nextDouble = *kfd; + float f = (currentTime - seconds()) / (nextDouble.seconds() - seconds()); + + float frameValue; + if (KeyFrameInterpolator* keyframeInterpolator = interpolator()) + { + frameValue = keyframeInterpolator->transformValue(value(), + nextDouble.value(), + f); + } + else + { + frameValue = value() + (nextDouble.value() - value()) * f; + } + + applyDouble(object, propertyKey, mix, frameValue); +} \ No newline at end of file diff --git a/third_party/rive/source/animation/keyframe_id.cpp b/third_party/rive/source/animation/keyframe_id.cpp new file mode 100644 index 0000000..dfa8fcc --- /dev/null +++ b/third_party/rive/source/animation/keyframe_id.cpp @@ -0,0 +1,18 @@ +#include "rive/animation/keyframe_id.hpp" +#include "rive/generated/core_registry.hpp" + +using namespace rive; + +void KeyFrameId::apply(Core* object, int propertyKey, float mix) +{ + CoreRegistry::setUint(object, propertyKey, value()); +} + +void KeyFrameId::applyInterpolation(Core* object, + int propertyKey, + float currentTime, + const KeyFrame* nextFrame, + float mix) +{ + CoreRegistry::setUint(object, propertyKey, value()); +} \ No newline at end of file diff --git a/third_party/rive/source/animation/keyframe_interpolator.cpp b/third_party/rive/source/animation/keyframe_interpolator.cpp new file mode 100644 index 0000000..cc76378 --- /dev/null +++ b/third_party/rive/source/animation/keyframe_interpolator.cpp @@ -0,0 +1,46 @@ +#include "rive/animation/keyframe_interpolator.hpp" +#include "rive/artboard.hpp" +#include "rive/backboard.hpp" +#include "rive/core.hpp" +#include "rive/importers/artboard_importer.hpp" +#include "rive/importers/backboard_importer.hpp" +#include "rive/importers/import_stack.hpp" +#include "rive/layout_component.hpp" + +using namespace rive; + +InterpolatorHost* InterpolatorHost::from(Core* component) +{ + switch (component->coreType()) + { + case LayoutComponent::typeKey: + return component->as(); + default: + return nullptr; + } + return nullptr; +} + +StatusCode KeyFrameInterpolator::import(ImportStack& importStack) +{ + auto artboardImporter = + importStack.latest(ArtboardBase::typeKey); + if (artboardImporter != nullptr) + { + artboardImporter->addComponent(this); + } + else + { + auto backboardImporter = + importStack.latest(BackboardBase::typeKey); + if (backboardImporter != nullptr) + { + backboardImporter->addInterpolator(this); + } + else + { + return StatusCode::MissingObject; + } + } + return Super::import(importStack); +} \ No newline at end of file diff --git a/third_party/rive/source/animation/keyframe_string.cpp b/third_party/rive/source/animation/keyframe_string.cpp new file mode 100644 index 0000000..7968dda --- /dev/null +++ b/third_party/rive/source/animation/keyframe_string.cpp @@ -0,0 +1,18 @@ +#include "rive/animation/keyframe_string.hpp" +#include "rive/generated/core_registry.hpp" + +using namespace rive; + +void KeyFrameString::apply(Core* object, int propertyKey, float mix) +{ + CoreRegistry::setString(object, propertyKey, value()); +} + +void KeyFrameString::applyInterpolation(Core* object, + int propertyKey, + float currentTime, + const KeyFrame* nextFrame, + float mix) +{ + CoreRegistry::setString(object, propertyKey, value()); +} \ No newline at end of file diff --git a/third_party/rive/source/animation/keyframe_uint.cpp b/third_party/rive/source/animation/keyframe_uint.cpp new file mode 100644 index 0000000..398abe3 --- /dev/null +++ b/third_party/rive/source/animation/keyframe_uint.cpp @@ -0,0 +1,18 @@ +#include "rive/animation/keyframe_uint.hpp" +#include "rive/generated/core_registry.hpp" + +using namespace rive; + +void KeyFrameUint::apply(Core* object, int propertyKey, float mix) +{ + CoreRegistry::setUint(object, propertyKey, value()); +} + +void KeyFrameUint::applyInterpolation(Core* object, + int propertyKey, + float currentTime, + const KeyFrame* nextFrame, + float mix) +{ + CoreRegistry::setUint(object, propertyKey, value()); +} \ No newline at end of file diff --git a/third_party/rive/source/animation/layer_state.cpp b/third_party/rive/source/animation/layer_state.cpp new file mode 100644 index 0000000..2d6d034 --- /dev/null +++ b/third_party/rive/source/animation/layer_state.cpp @@ -0,0 +1,66 @@ +#include "rive/animation/layer_state.hpp" +#include "rive/animation/transition_bool_condition.hpp" +#include "rive/importers/import_stack.hpp" +#include "rive/importers/state_machine_layer_importer.hpp" +#include "rive/generated/animation/state_machine_layer_base.hpp" +#include "rive/animation/state_transition.hpp" +#include "rive/animation/system_state_instance.hpp" + +using namespace rive; + +LayerState::~LayerState() +{ + for (auto transition : m_Transitions) + { + delete transition; + } +} + +StatusCode LayerState::onAddedDirty(CoreContext* context) +{ + StatusCode code; + for (auto transition : m_Transitions) + { + if ((code = transition->onAddedDirty(context)) != StatusCode::Ok) + { + return code; + } + } + return StatusCode::Ok; +} + +StatusCode LayerState::onAddedClean(CoreContext* context) +{ + StatusCode code; + for (auto transition : m_Transitions) + { + if ((code = transition->onAddedClean(context)) != StatusCode::Ok) + { + return code; + } + } + return StatusCode::Ok; +} + +StatusCode LayerState::import(ImportStack& importStack) +{ + auto layerImporter = importStack.latest( + StateMachineLayerBase::typeKey); + if (layerImporter == nullptr) + { + return StatusCode::MissingObject; + } + layerImporter->addState(this); + return Super::import(importStack); +} + +void LayerState::addTransition(StateTransition* transition) +{ + m_Transitions.push_back(transition); +} + +std::unique_ptr LayerState::makeInstance( + ArtboardInstance* instance) const +{ + return rivestd::make_unique(this, instance); +} \ No newline at end of file diff --git a/third_party/rive/source/animation/linear_animation.cpp b/third_party/rive/source/animation/linear_animation.cpp new file mode 100644 index 0000000..25dd73b --- /dev/null +++ b/third_party/rive/source/animation/linear_animation.cpp @@ -0,0 +1,151 @@ +#include "rive/animation/linear_animation.hpp" +#include "rive/animation/keyed_object.hpp" +#include "rive/animation/keyed_callback_reporter.hpp" +#include "rive/artboard.hpp" +#include "rive/importers/artboard_importer.hpp" +#include "rive/importers/import_stack.hpp" +#include "rive/math/math_types.hpp" +#include + +using namespace rive; + +#ifdef TESTING +int LinearAnimation::deleteCount = 0; +#endif + +LinearAnimation::LinearAnimation() {} + +LinearAnimation::~LinearAnimation() +{ +#ifdef TESTING + deleteCount++; +#endif +} + +StatusCode LinearAnimation::onAddedDirty(CoreContext* context) +{ + StatusCode code; + for (const auto& object : m_KeyedObjects) + { + if ((code = object->onAddedDirty(context)) != StatusCode::Ok) + { + return code; + } + } + return StatusCode::Ok; +} + +StatusCode LinearAnimation::onAddedClean(CoreContext* context) +{ + StatusCode code; + for (const auto& object : m_KeyedObjects) + { + if ((code = object->onAddedClean(context)) != StatusCode::Ok) + { + return code; + } + } + return StatusCode::Ok; +} + +void LinearAnimation::addKeyedObject(std::unique_ptr object) +{ + m_KeyedObjects.push_back(std::move(object)); +} + +void LinearAnimation::apply(Artboard* artboard, float time, float mix) const +{ + if (quantize()) + { + float ffps = (float)fps(); + time = std::floor(time * ffps) / ffps; + } + for (const auto& object : m_KeyedObjects) + { + object->apply(artboard, time, mix); + } +} + +StatusCode LinearAnimation::import(ImportStack& importStack) +{ + auto artboardImporter = + importStack.latest(ArtboardBase::typeKey); + if (artboardImporter == nullptr) + { + return StatusCode::MissingObject; + } + artboardImporter->addAnimation(this); + return Super::import(importStack); +} + +float LinearAnimation::startSeconds() const +{ + return (enableWorkArea() ? (float)workStart() : 0.0f) / (float)fps(); +} +float LinearAnimation::endSeconds() const +{ + return (float)(enableWorkArea() ? workEnd() : duration()) / (float)fps(); +} + +float LinearAnimation::startTime() const +{ + return (speed() >= 0) ? startSeconds() : endSeconds(); +} +float LinearAnimation::startTime(float multiplier) const +{ + return ((speed() * multiplier) >= 0) ? startSeconds() : endSeconds(); +} +float LinearAnimation::endTime() const +{ + return (speed() >= 0) ? endSeconds() : startSeconds(); +} +float LinearAnimation::durationSeconds() const +{ + return std::abs(endSeconds() - startSeconds()); +} + +// Matches Dart modulus: +// https://api.dart.dev/stable/2.19.0/dart-core/double/operator_modulo.html +static float positiveMod(float value, float range) +{ + assert(range > 0.0f); + return math::positive_mod(value, range); +} + +float LinearAnimation::globalToLocalSeconds(float seconds) const +{ + switch (loop()) + { + case Loop::oneShot: + return seconds + startTime(); + case Loop::loop: + return positiveMod(seconds, (durationSeconds())) + startTime(); + case Loop::pingPong: + float localTime = positiveMod(seconds, (durationSeconds())); + int direction = ((int)(seconds / (durationSeconds()))) % 2; + return direction == 0 ? localTime + startTime() + : endTime() - localTime; + } + RIVE_UNREACHABLE(); +} + +void LinearAnimation::reportKeyedCallbacks(KeyedCallbackReporter* reporter, + float secondsFrom, + float secondsTo, + float speedDirection, + bool fromPong) const +{ + float startingTime = startTime(speedDirection); + bool isAtStartFrame = startingTime == secondsFrom; + + if (!isAtStartFrame || !fromPong) + { + for (const auto& object : m_KeyedObjects) + { + object->reportKeyedCallbacks(reporter, + secondsFrom, + secondsTo, + isAtStartFrame); + } + } +} \ No newline at end of file diff --git a/third_party/rive/source/animation/linear_animation_instance.cpp b/third_party/rive/source/animation/linear_animation_instance.cpp new file mode 100644 index 0000000..f7887ba --- /dev/null +++ b/third_party/rive/source/animation/linear_animation_instance.cpp @@ -0,0 +1,311 @@ +#include "rive/animation/linear_animation_instance.hpp" +#include "rive/animation/linear_animation.hpp" +#include "rive/animation/loop.hpp" +#include "rive/animation/keyed_callback_reporter.hpp" +#include +#include + +using namespace rive; + +LinearAnimationInstance::LinearAnimationInstance( + const LinearAnimation* animation, + ArtboardInstance* instance, + float speedMultiplier) : + Scene(instance), + m_animation((assert(animation != nullptr), animation)), + m_time((speedMultiplier >= 0) ? animation->startTime() + : animation->endTime()), + m_speedDirection((speedMultiplier >= 0) ? 1 : -1), + m_totalTime(0.0f), + m_lastTotalTime(0.0f), + m_spilledTime(0.0f), + m_direction(1) +{} + +LinearAnimationInstance::LinearAnimationInstance( + LinearAnimationInstance const& lhs) : + Scene(lhs), + m_animation(lhs.m_animation), + m_time(lhs.m_time), + m_speedDirection(lhs.m_speedDirection), + m_totalTime(lhs.m_totalTime), + m_lastTotalTime(lhs.m_lastTotalTime), + m_spilledTime(lhs.m_spilledTime), + m_direction(lhs.m_direction), + m_didLoop(lhs.m_didLoop), + m_loopValue(lhs.m_loopValue) +{} + +LinearAnimationInstance::~LinearAnimationInstance() {} + +bool LinearAnimationInstance::advanceAndApply(float seconds) +{ + bool more = this->advance(seconds, this); + this->apply(); + if (m_artboardInstance->advance(seconds)) + { + more = true; + } + return more || keepGoing(); +} + +bool LinearAnimationInstance::advance(float elapsedSeconds, + KeyedCallbackReporter* reporter) +{ + const LinearAnimation& animation = *m_animation; + float deltaSeconds = elapsedSeconds * animation.speed() * m_direction; + + m_spilledTime = 0.0f; + if (deltaSeconds == 0) + { + m_didLoop = false; + return false; + } + + m_lastTotalTime = m_totalTime; + m_totalTime += std::abs(deltaSeconds); + + // NOTE: + // do not track spilled time, if our one shot loop is already completed. + // stop gap before we move spilled tracking into state machine logic. + bool killSpilledTime = !this->keepGoing(elapsedSeconds); + + float lastTime = m_time; + m_time += deltaSeconds; + if (reporter != nullptr) + { + animation.reportKeyedCallbacks(reporter, + lastTime, + m_time, + m_speedDirection, + false); + } + + float fps = (float)animation.fps(); + float frames = m_time * fps; + float start = + animation.enableWorkArea() ? (float)animation.workStart() : 0.0f; + float end = animation.enableWorkArea() ? (float)animation.workEnd() + : (float)animation.duration(); + float range = end - start; + + bool didLoop = false; + + // this has some issues when deltaSeconds is 0, + // right now we basically assume we default to going forwards in that case + // + int direction = deltaSeconds < 0 ? -1 : 1; + switch (loop()) + { + case Loop::oneShot: + if (direction == 1 && frames > end) + { + // Account for the time dilation or contraction applied in the + // animation local time by its speed to calculate spilled time. + // Calculate the ratio of the time excess by the total elapsed + // time in local time (deltaFrames) and multiply the elapsed + // time by it. + auto deltaFrames = deltaSeconds * fps; + auto spilledFramesRatio = (frames - end) / deltaFrames; + m_spilledTime = spilledFramesRatio * elapsedSeconds; + frames = (float)end; + m_time = frames / fps; + didLoop = true; + } + else if (direction == -1 && frames < start) + { + auto deltaFrames = std::abs(deltaSeconds * fps); + auto spilledFramesRatio = (start - frames) / deltaFrames; + m_spilledTime = spilledFramesRatio * elapsedSeconds; + frames = (float)start; + m_time = frames / fps; + didLoop = true; + } + break; + case Loop::loop: + if (direction == 1 && frames >= end) + { + // How spilled time has to be calculated, given that local time + // can be scaled to a factor of the regular time: + // - for convenience, calculate the local elapsed time in frames + // (deltaFrames) + // - get the remainder of current frame position (frames) by + // duration (range) + // - use that remainder as the ratio of the original time that + // was not consumed by the loop (spilledFramesRatio) + // - multiply the original elapsedTime by the ratio to set the + // spilled time + auto deltaFrames = deltaSeconds * fps; + auto remainder = std::fmod(frames - start, (float)range); + auto spilledFramesRatio = remainder / deltaFrames; + m_spilledTime = spilledFramesRatio * elapsedSeconds; + frames = start + remainder; + m_time = frames / fps; + didLoop = true; + if (reporter != nullptr) + { + animation.reportKeyedCallbacks(reporter, + 0.0f, + m_time, + m_speedDirection, + false); + } + } + else if (direction == -1 && frames <= start) + { + auto deltaFrames = deltaSeconds * fps; + auto remainder = + std::abs(std::fmod(start - frames, (float)range)); + auto spilledFramesRatio = std::abs(remainder / deltaFrames); + m_spilledTime = spilledFramesRatio * elapsedSeconds; + frames = end - remainder; + m_time = frames / fps; + didLoop = true; + if (reporter != nullptr) + { + animation.reportKeyedCallbacks(reporter, + end / (float)fps, + m_time, + m_speedDirection, + false); + } + } + break; + case Loop::pingPong: + bool fromPong = true; + while (true) + { + if (direction == 1 && frames >= end) + { + m_spilledTime = (frames - end) / fps; + frames = end + (end - frames); + lastTime = end / (float)fps; + } + else if (direction == -1 && frames < start) + { + m_spilledTime = (start - frames) / fps; + frames = start + (start - frames); + lastTime = start / (float)fps; + } + else + { + // we're within the range, we can stop fixing. We do this in + // a loop to fix conditions when time has advanced so far + // that we've ping-ponged back and forth a few times in a + // single frame. We want to accomodate for this in cases + // where animations are not advanced on regular intervals. + break; + } + m_time = frames / fps; + m_direction *= -1; + direction *= -1; + didLoop = true; + if (reporter != nullptr) + { + animation.reportKeyedCallbacks(reporter, + lastTime, + m_time, + m_speedDirection, + fromPong); + } + fromPong = !fromPong; + } + break; + } + + if (killSpilledTime) + { + m_spilledTime = 0; + } + + m_didLoop = didLoop; + return this->keepGoing(elapsedSeconds); +} + +void LinearAnimationInstance::time(float value) +{ + if (m_time == value) + { + return; + } + m_time = value; + // Make sure to keep last and total in relative lockstep so state machines + // can track change even when setting time. + auto diff = m_totalTime - m_lastTotalTime; + + float start = + (m_animation->enableWorkArea() ? (float)m_animation->workStart() + : 0.0f) * + (float)m_animation->fps(); + m_totalTime = value - start; + m_lastTotalTime = m_totalTime - diff; + + // leaving this RIGHT now. but is this required? it kinda messes up + // playing things backwards and seeking. what purpose does it solve? + m_direction = 1; +} + +void LinearAnimationInstance::reset(float speedMultiplier = 1.0) +{ + m_time = (speedMultiplier >= 0) ? m_animation->startTime() + : m_animation->endTime(); +} + +uint32_t LinearAnimationInstance::fps() const { return m_animation->fps(); } + +uint32_t LinearAnimationInstance::duration() const +{ + return m_animation->duration(); +} + +float LinearAnimationInstance::speed() const { return m_animation->speed(); } + +float LinearAnimationInstance::startTime() const +{ + return m_animation->startTime(); +} + +std::string LinearAnimationInstance::name() const +{ + return m_animation->name(); +} + +bool LinearAnimationInstance::isTranslucent() const +{ + return m_artboardInstance->isTranslucent(this); +} + +// Returns either the animation's default or overridden loop values +int LinearAnimationInstance::loopValue() const +{ + if (m_loopValue != -1) + { + return m_loopValue; + } + return m_animation->loopValue(); +} + +// Override the animation's loop value +void LinearAnimationInstance::loopValue(int value) +{ + if (m_loopValue == value) + { + return; + } + if (m_loopValue == -1 && m_animation->loopValue() == value) + { + return; + } + m_loopValue = value; +} + +float LinearAnimationInstance::durationSeconds() const +{ + return m_animation->durationSeconds(); +} + +void LinearAnimationInstance::reportEvent(Event* event, float secondsDelay) +{ + const std::vector events{event}; + notifyListeners(events); +} \ No newline at end of file diff --git a/third_party/rive/source/animation/listener_action.cpp b/third_party/rive/source/animation/listener_action.cpp new file mode 100644 index 0000000..0b1f34f --- /dev/null +++ b/third_party/rive/source/animation/listener_action.cpp @@ -0,0 +1,23 @@ +#include "rive/animation/state_machine_listener.hpp" +#include "rive/importers/import_stack.hpp" +#include "rive/importers/state_machine_listener_importer.hpp" +#include "rive/importers/state_machine_importer.hpp" +#include "rive/animation/listener_input_change.hpp" +#include "rive/animation/state_machine.hpp" + +using namespace rive; + +StatusCode ListenerAction::import(ImportStack& importStack) +{ + auto stateMachineListenerImporter = + importStack.latest( + StateMachineListenerBase::typeKey); + if (stateMachineListenerImporter == nullptr) + { + return StatusCode::MissingObject; + } + + stateMachineListenerImporter->addAction( + std::unique_ptr(this)); + return Super::import(importStack); +} diff --git a/third_party/rive/source/animation/listener_align_target.cpp b/third_party/rive/source/animation/listener_align_target.cpp new file mode 100644 index 0000000..415321e --- /dev/null +++ b/third_party/rive/source/animation/listener_align_target.cpp @@ -0,0 +1,38 @@ +#include "rive/animation/listener_align_target.hpp" +#include "rive/animation/state_machine_instance.hpp" +#include "rive/node.hpp" +#include "rive/constraints/constraint.hpp" + +using namespace rive; + +void ListenerAlignTarget::perform(StateMachineInstance* stateMachineInstance, + Vec2D position, + Vec2D previousPosition) const +{ + auto coreTarget = stateMachineInstance->artboard()->resolve(targetId()); + if (coreTarget == nullptr || !coreTarget->is()) + { + return; + } + auto target = coreTarget->as(); + Mat2D targetParentWorld = getParentWorld(*target); + Mat2D inverse; + if (!targetParentWorld.invert(&inverse)) + { + return; + } + if (preserveOffset()) + { + + auto localPosition = inverse * position; + auto prevLocalPosition = inverse * previousPosition; + target->x(target->x() + localPosition.x - prevLocalPosition.x); + target->y(target->y() + localPosition.y - prevLocalPosition.y); + } + else + { + auto localPosition = inverse * position; + target->x(localPosition.x); + target->y(localPosition.y); + } +} diff --git a/third_party/rive/source/animation/listener_bool_change.cpp b/third_party/rive/source/animation/listener_bool_change.cpp new file mode 100644 index 0000000..20bdf0e --- /dev/null +++ b/third_party/rive/source/animation/listener_bool_change.cpp @@ -0,0 +1,83 @@ +#include "rive/animation/listener_bool_change.hpp" +#include "rive/animation/nested_bool.hpp" +#include "rive/animation/nested_input.hpp" +#include "rive/animation/nested_state_machine.hpp" +#include "rive/animation/state_machine_instance.hpp" +#include "rive/animation/state_machine_bool.hpp" +#include "rive/animation/state_machine_input_instance.hpp" +using namespace rive; + +bool ListenerBoolChange::validateInputType(const StateMachineInput* input) const +{ + // A null input is valid as the StateMachine can attempt to limp along if we + // introduce new input types that old conditions are expected to handle in + // newer runtimes. The older runtimes will just evaluate them to true. + return input == nullptr || input->is(); +} + +bool ListenerBoolChange::validateNestedInputType(const NestedInput* input) const +{ + // A null nested input is valid as the StateMachine can attempt to limp + // along if we introduce new input types that old conditions are expected to + // handle in newer runtimes. The older runtimes will just evaluate them to + // true. + return input == nullptr || input->is(); +} + +void ListenerBoolChange::perform(StateMachineInstance* stateMachineInstance, + Vec2D position, + Vec2D previousPosition) const +{ + if (nestedInputId() != Core::emptyId) + { + auto nestedInputInstance = + stateMachineInstance->artboard()->resolve(nestedInputId()); + if (nestedInputInstance == nullptr) + { + return; + } + auto nestedBoolInput = static_cast(nestedInputInstance); + if (nestedBoolInput != nullptr) + { + switch (value()) + { + case 0: + nestedBoolInput->nestedValue(false); + break; + case 1: + nestedBoolInput->nestedValue(true); + break; + default: + nestedBoolInput->nestedValue( + !nestedBoolInput->nestedValue()); + break; + } + } + } + else + { + auto inputInstance = stateMachineInstance->input(inputId()); + if (inputInstance == nullptr) + { + return; + } + // If it's not null, it must be our correct type (why we validate at + // load time). + auto boolInput = static_cast(inputInstance); + if (boolInput != nullptr) + { + switch (value()) + { + case 0: + boolInput->value(false); + break; + case 1: + boolInput->value(true); + break; + default: + boolInput->value(!boolInput->value()); + break; + } + } + } +} diff --git a/third_party/rive/source/animation/listener_fire_event.cpp b/third_party/rive/source/animation/listener_fire_event.cpp new file mode 100644 index 0000000..bd6d074 --- /dev/null +++ b/third_party/rive/source/animation/listener_fire_event.cpp @@ -0,0 +1,17 @@ +#include "rive/animation/listener_fire_event.hpp" +#include "rive/animation/state_machine_instance.hpp" +#include "rive/event.hpp" + +using namespace rive; + +void ListenerFireEvent::perform(StateMachineInstance* stateMachineInstance, + Vec2D position, + Vec2D previousPosition) const +{ + auto coreEvent = stateMachineInstance->artboard()->resolve(eventId()); + if (coreEvent == nullptr || !coreEvent->is()) + { + return; + } + stateMachineInstance->reportEvent(coreEvent->as()); +} \ No newline at end of file diff --git a/third_party/rive/source/animation/listener_input_change.cpp b/third_party/rive/source/animation/listener_input_change.cpp new file mode 100644 index 0000000..c4e150a --- /dev/null +++ b/third_party/rive/source/animation/listener_input_change.cpp @@ -0,0 +1,49 @@ +#include "rive/animation/listener_input_change.hpp" +#include "rive/animation/nested_input.hpp" +#include "rive/animation/state_machine.hpp" +#include "rive/animation/state_machine_listener.hpp" +#include "rive/artboard.hpp" +#include "rive/importers/artboard_importer.hpp" +#include "rive/importers/import_stack.hpp" +#include "rive/importers/state_machine_listener_importer.hpp" +#include "rive/importers/state_machine_importer.hpp" + +using namespace rive; + +StatusCode ListenerInputChange::import(ImportStack& importStack) +{ + auto stateMachineImporter = + importStack.latest(StateMachine::typeKey); + if (stateMachineImporter == nullptr) + { + return StatusCode::MissingObject; + } + + auto artboardImporter = + importStack.latest(ArtboardBase::typeKey); + if (artboardImporter == nullptr) + { + return StatusCode::MissingObject; + } + // First validate if this input change applies to a nested input + auto nested = artboardImporter->artboard()->resolve(nestedInputId()); + auto nestedInput = nested != nullptr ? nested->as() : nullptr; + if (nestedInput != nullptr) + { + if (!validateNestedInputType(nestedInput)) + { + return StatusCode::InvalidObject; + } + } + // Only if it doesn't apply to a nested input, check against an input + else + { + auto input = + stateMachineImporter->stateMachine()->input((size_t)inputId()); + if (!validateInputType(input)) + { + return StatusCode::InvalidObject; + } + } + return Super::import(importStack); +} diff --git a/third_party/rive/source/animation/listener_number_change.cpp b/third_party/rive/source/animation/listener_number_change.cpp new file mode 100644 index 0000000..a57d0df --- /dev/null +++ b/third_party/rive/source/animation/listener_number_change.cpp @@ -0,0 +1,64 @@ +#include "rive/animation/listener_number_change.hpp" +#include "rive/animation/nested_input.hpp" +#include "rive/animation/nested_number.hpp" +#include "rive/animation/nested_state_machine.hpp" +#include "rive/animation/state_machine_instance.hpp" +#include "rive/animation/state_machine_number.hpp" +#include "rive/animation/state_machine_input_instance.hpp" + +using namespace rive; + +bool ListenerNumberChange::validateInputType( + const StateMachineInput* input) const +{ + // A null input is valid as the StateMachine can attempt to limp along if we + // introduce new input types that old conditions are expected to handle in + // newer runtimes. The older runtimes will just evaluate them to true. + return input == nullptr || input->is(); +} + +bool ListenerNumberChange::validateNestedInputType( + const NestedInput* input) const +{ + // A null nested input is valid as the StateMachine can attempt to limp + // along if we introduce new input types that old conditions are expected to + // handle in newer runtimes. The older runtimes will just evaluate them to + // true. + return input == nullptr || input->is(); +} + +void ListenerNumberChange::perform(StateMachineInstance* stateMachineInstance, + Vec2D position, + Vec2D previousPosition) const +{ + if (nestedInputId() != Core::emptyId) + { + auto nestedInputInstance = + stateMachineInstance->artboard()->resolve(nestedInputId()); + if (nestedInputInstance == nullptr) + { + return; + } + auto nestedNumberInput = + static_cast(nestedInputInstance); + if (nestedNumberInput != nullptr) + { + nestedNumberInput->nestedValue(value()); + } + } + else + { + auto inputInstance = stateMachineInstance->input(inputId()); + if (inputInstance == nullptr) + { + return; + } + // If it's not null, it must be our correct type (why we validate at + // load time). + auto numberInput = static_cast(inputInstance); + if (numberInput != nullptr) + { + numberInput->value(value()); + } + } +} diff --git a/third_party/rive/source/animation/listener_trigger_change.cpp b/third_party/rive/source/animation/listener_trigger_change.cpp new file mode 100644 index 0000000..f8d8584 --- /dev/null +++ b/third_party/rive/source/animation/listener_trigger_change.cpp @@ -0,0 +1,65 @@ +#include "rive/animation/listener_trigger_change.hpp" +#include "rive/animation/nested_input.hpp" +#include "rive/animation/nested_trigger.hpp" +#include "rive/animation/nested_state_machine.hpp" +#include "rive/animation/state_machine_instance.hpp" +#include "rive/animation/state_machine_trigger.hpp" +#include "rive/animation/state_machine_input_instance.hpp" +#include "rive/core/field_types/core_callback_type.hpp" + +using namespace rive; + +bool ListenerTriggerChange::validateInputType( + const StateMachineInput* input) const +{ + // A null input is valid as the StateMachine can attempt to limp along if we + // introduce new input types that old conditions are expected to handle in + // newer runtimes. The older runtimes will just evaluate them to true. + return input == nullptr || input->is(); +} + +bool ListenerTriggerChange::validateNestedInputType( + const NestedInput* input) const +{ + // A null nested input is valid as the StateMachine can attempt to limp + // along if we introduce new input types that old conditions are expected to + // handle in newer runtimes. The older runtimes will just evaluate them to + // true. + return input == nullptr || input->is(); +} + +void ListenerTriggerChange::perform(StateMachineInstance* stateMachineInstance, + Vec2D position, + Vec2D previousPosition) const +{ + if (nestedInputId() != Core::emptyId) + { + auto nestedInputInstance = + stateMachineInstance->artboard()->resolve(nestedInputId()); + if (nestedInputInstance == nullptr) + { + return; + } + auto nestedTriggerInput = + static_cast(nestedInputInstance); + if (nestedTriggerInput != nullptr) + { + nestedTriggerInput->fire(CallbackData(stateMachineInstance, 0)); + } + } + else + { + auto inputInstance = stateMachineInstance->input(inputId()); + if (inputInstance == nullptr) + { + return; + } + // If it's not null, it must be our correct type (why we validate at + // load time). + auto triggerInput = static_cast(inputInstance); + if (triggerInput != nullptr) + { + triggerInput->fire(); + } + } +} diff --git a/third_party/rive/source/animation/listener_viewmodel_change.cpp b/third_party/rive/source/animation/listener_viewmodel_change.cpp new file mode 100644 index 0000000..2c63b00 --- /dev/null +++ b/third_party/rive/source/animation/listener_viewmodel_change.cpp @@ -0,0 +1,53 @@ +#include "rive/animation/listener_viewmodel_change.hpp" +#include "rive/animation/state_machine_instance.hpp" +#include "rive/data_bind/bindable_property.hpp" +#include "rive/importers/bindable_property_importer.hpp" + +using namespace rive; + +ListenerViewModelChange::~ListenerViewModelChange() +{ + if (m_bindableProperty != nullptr) + { + delete m_bindableProperty; + m_bindableProperty = nullptr; + } +} + +StatusCode ListenerViewModelChange::import(ImportStack& importStack) +{ + + auto bindablePropertyImporter = + importStack.latest( + BindablePropertyBase::typeKey); + if (bindablePropertyImporter == nullptr) + { + return StatusCode::MissingObject; + } + m_bindableProperty = bindablePropertyImporter->bindableProperty(); + + return Super::import(importStack); +} + +// Note: perform works the same way whether the value comes from a direct value +// assignment or from another view model. In the case of coming from another +// view model, the state machine instance method "updataDataBinds" will handle +// updating the value of the bound object. That's the benefit of binding the +// same bindable property with two data binding objects. +void ListenerViewModelChange::perform( + StateMachineInstance* stateMachineInstance, + Vec2D position, + Vec2D previousPosition) const +{ + // Get the bindable property instance from the state machine instance + // context + auto bindableInstance = + stateMachineInstance->bindablePropertyInstance(m_bindableProperty); + // Get the data bound object (that goes from target to source) from this + // bindable instance + auto dataBind = + stateMachineInstance->bindableDataBindToSource(bindableInstance); + // Apply the change that will assign the value of the bindable property to + // the view model property instance + dataBind->updateSourceBinding(true); +} \ No newline at end of file diff --git a/third_party/rive/source/animation/nested_animation.cpp b/third_party/rive/source/animation/nested_animation.cpp new file mode 100644 index 0000000..815f414 --- /dev/null +++ b/third_party/rive/source/animation/nested_animation.cpp @@ -0,0 +1,29 @@ +#include "rive/nested_animation.hpp" +#include "rive/container_component.hpp" +#include "rive/nested_artboard.hpp" +#include "rive/core_context.hpp" + +using namespace rive; + +bool NestedAnimation::validate(CoreContext* context) +{ + if (!Super::validate(context)) + { + return false; + } + + auto parentObject = context->resolve(parentId()); + // We know parentObject is not null from Super::validate(). + return parentObject->is(); +} + +StatusCode NestedAnimation::onAddedDirty(CoreContext* context) +{ + StatusCode code = Super::onAddedDirty(context); + if (code == StatusCode::Ok) + { + auto nestedArtboard = parent()->as(); + nestedArtboard->addNestedAnimation(this); + } + return code; +} \ No newline at end of file diff --git a/third_party/rive/source/animation/nested_bool.cpp b/third_party/rive/source/animation/nested_bool.cpp new file mode 100644 index 0000000..3a5de15 --- /dev/null +++ b/third_party/rive/source/animation/nested_bool.cpp @@ -0,0 +1,48 @@ +#include "rive/animation/nested_bool.hpp" +#include "rive/animation/nested_state_machine.hpp" +#include "rive/animation/state_machine_input_instance.hpp" +#include "rive/container_component.hpp" + +using namespace rive; + +// Use the NestedBoolBase m_NestedValue on initialization but then it won't +// be used anymore and interface directly with the nested input value. +void NestedBool::applyValue() +{ + auto inputInstance = input(); + if (inputInstance != nullptr) + { + auto boolInput = static_cast(inputInstance); + if (boolInput != nullptr) + { + boolInput->value(NestedBoolBase::nestedValue()); + } + } +} + +void NestedBool::nestedValue(bool value) +{ + auto inputInstance = input(); + if (inputInstance != nullptr) + { + auto boolInput = static_cast(inputInstance); + if (boolInput != nullptr && boolInput->value() != value) + { + boolInput->value(value); + } + } +} + +bool NestedBool::nestedValue() const +{ + auto inputInstance = input(); + if (inputInstance != nullptr) + { + auto boolInput = static_cast(inputInstance); + if (boolInput != nullptr) + { + return boolInput->value(); + } + } + return false; +} diff --git a/third_party/rive/source/animation/nested_linear_animation.cpp b/third_party/rive/source/animation/nested_linear_animation.cpp new file mode 100644 index 0000000..42d904d --- /dev/null +++ b/third_party/rive/source/animation/nested_linear_animation.cpp @@ -0,0 +1,14 @@ +#include "rive/animation/nested_linear_animation.hpp" +#include "rive/animation/linear_animation_instance.hpp" + +using namespace rive; + +NestedLinearAnimation::NestedLinearAnimation() {} +NestedLinearAnimation::~NestedLinearAnimation() {} + +void NestedLinearAnimation::initializeAnimation(ArtboardInstance* artboard) +{ + m_AnimationInstance = rivestd::make_unique( + artboard->animation(animationId()), + artboard); +} \ No newline at end of file diff --git a/third_party/rive/source/animation/nested_number.cpp b/third_party/rive/source/animation/nested_number.cpp new file mode 100644 index 0000000..16a6a8d --- /dev/null +++ b/third_party/rive/source/animation/nested_number.cpp @@ -0,0 +1,48 @@ +#include "rive/animation/nested_number.hpp" +#include "rive/animation/nested_state_machine.hpp" +#include "rive/animation/state_machine_input_instance.hpp" +#include "rive/container_component.hpp" + +using namespace rive; + +// Use the NestedNumberBase m_NestedValue on initialization but then it won't +// be used anymore and interface directly with the nested input value. +void NestedNumber::applyValue() +{ + auto inputInstance = input(); + if (inputInstance != nullptr) + { + auto numInput = static_cast(inputInstance); + if (numInput != nullptr) + { + numInput->value(NestedNumberBase::nestedValue()); + } + } +} + +void NestedNumber::nestedValue(float value) +{ + auto inputInstance = input(); + if (inputInstance != nullptr) + { + auto numInput = static_cast(inputInstance); + if (numInput != nullptr && numInput->value() != value) + { + numInput->value(value); + } + } +} + +float NestedNumber::nestedValue() const +{ + auto inputInstance = input(); + if (inputInstance != nullptr) + { + auto numInput = static_cast(inputInstance); + if (numInput != nullptr) + { + return numInput->value(); + } + } + return 0.0; +} diff --git a/third_party/rive/source/animation/nested_remap_animation.cpp b/third_party/rive/source/animation/nested_remap_animation.cpp new file mode 100644 index 0000000..75d7922 --- /dev/null +++ b/third_party/rive/source/animation/nested_remap_animation.cpp @@ -0,0 +1,29 @@ +#include "rive/animation/nested_remap_animation.hpp" +#include "rive/animation/linear_animation_instance.hpp" + +using namespace rive; + +void NestedRemapAnimation::timeChanged() +{ + if (m_AnimationInstance != nullptr) + { + m_AnimationInstance->time( + m_AnimationInstance->animation()->globalToLocalSeconds( + m_AnimationInstance->durationSeconds() * time())); + } +} + +void NestedRemapAnimation::initializeAnimation(ArtboardInstance* artboard) +{ + Super::initializeAnimation(artboard); + timeChanged(); +} + +bool NestedRemapAnimation::advance(float elapsedSeconds, bool newFrame) +{ + if (m_AnimationInstance != nullptr && mix() != 0.0f) + { + m_AnimationInstance->apply(mix()); + } + return false; +} \ No newline at end of file diff --git a/third_party/rive/source/animation/nested_simple_animation.cpp b/third_party/rive/source/animation/nested_simple_animation.cpp new file mode 100644 index 0000000..e7ca119 --- /dev/null +++ b/third_party/rive/source/animation/nested_simple_animation.cpp @@ -0,0 +1,22 @@ +#include "rive/animation/nested_simple_animation.hpp" +#include "rive/animation/linear_animation_instance.hpp" + +using namespace rive; + +bool NestedSimpleAnimation::advance(float elapsedSeconds, bool newFrame) +{ + bool keepGoing = false; + if (m_AnimationInstance != nullptr) + { + if (isPlaying()) + { + keepGoing = m_AnimationInstance->advance(elapsedSeconds * speed(), + m_AnimationInstance.get()); + } + if (mix() != 0.0f) + { + m_AnimationInstance->apply(mix()); + } + } + return keepGoing; +} \ No newline at end of file diff --git a/third_party/rive/source/animation/nested_state_machine.cpp b/third_party/rive/source/animation/nested_state_machine.cpp new file mode 100644 index 0000000..d6737a7 --- /dev/null +++ b/third_party/rive/source/animation/nested_state_machine.cpp @@ -0,0 +1,137 @@ +#include "rive/animation/nested_bool.hpp" +#include "rive/animation/nested_input.hpp" +#include "rive/animation/nested_number.hpp" +#include "rive/animation/nested_state_machine.hpp" +#include "rive/animation/state_machine_instance.hpp" +#include "rive/hit_result.hpp" + +using namespace rive; + +NestedStateMachine::NestedStateMachine() {} +NestedStateMachine::~NestedStateMachine() {} + +bool NestedStateMachine::advance(float elapsedSeconds, bool newFrame) +{ + bool keepGoing = false; + if (m_StateMachineInstance != nullptr) + { + keepGoing = m_StateMachineInstance->advance(elapsedSeconds, newFrame); + } + return keepGoing; +} + +void NestedStateMachine::initializeAnimation(ArtboardInstance* artboard) +{ + m_StateMachineInstance = artboard->stateMachineAt(animationId()); + auto count = m_nestedInputs.size(); + for (size_t i = 0; i < count; i++) + { + auto nestedInput = m_nestedInputs[i]; + if (nestedInput->is() || nestedInput->is()) + { + nestedInput->applyValue(); + } + } +} + +StateMachineInstance* NestedStateMachine::stateMachineInstance() +{ + return m_StateMachineInstance.get(); +} + +bool NestedStateMachine::hitTest(Vec2D position) const +{ + if (m_StateMachineInstance != nullptr) + { + return m_StateMachineInstance->hitTest(position); + } + return false; +} + +HitResult NestedStateMachine::pointerMove(Vec2D position) +{ + if (m_StateMachineInstance != nullptr) + { + return m_StateMachineInstance->pointerMove(position); + } + return HitResult::none; +} + +HitResult NestedStateMachine::pointerDown(Vec2D position) +{ + if (m_StateMachineInstance != nullptr) + { + return m_StateMachineInstance->pointerDown(position); + } + return HitResult::none; +} + +HitResult NestedStateMachine::pointerUp(Vec2D position) +{ + if (m_StateMachineInstance != nullptr) + { + return m_StateMachineInstance->pointerUp(position); + } + return HitResult::none; +} + +HitResult NestedStateMachine::pointerExit(Vec2D position) +{ + if (m_StateMachineInstance != nullptr) + { + return m_StateMachineInstance->pointerExit(position); + } + return HitResult::none; +} + +NestedInput* NestedStateMachine::input(size_t index) +{ + if (index < m_nestedInputs.size()) + { + return m_nestedInputs[index]; + } + return nullptr; +} + +NestedInput* NestedStateMachine::input(std::string name) +{ + for (auto input : m_nestedInputs) + { + if (input->name() == name) + { + return input; + } + } + return nullptr; +} + +void NestedStateMachine::addNestedInput(NestedInput* input) +{ + m_nestedInputs.push_back(input); +} + +void NestedStateMachine::bindViewModelInstance( + rcp viewModelInstance) +{ + if (m_StateMachineInstance != nullptr) + { + m_StateMachineInstance->bindViewModelInstance(viewModelInstance); + } +} + +void NestedStateMachine::dataContext(DataContext* dataContext) +{ + if (m_StateMachineInstance != nullptr) + { + m_StateMachineInstance->dataContext(dataContext); + } +} + +bool NestedStateMachine::tryChangeState() +{ + if (m_StateMachineInstance != nullptr) + { + return m_StateMachineInstance->tryChangeState(); + } + return false; +} \ No newline at end of file diff --git a/third_party/rive/source/animation/nested_trigger.cpp b/third_party/rive/source/animation/nested_trigger.cpp new file mode 100644 index 0000000..be07004 --- /dev/null +++ b/third_party/rive/source/animation/nested_trigger.cpp @@ -0,0 +1,21 @@ +#include "rive/animation/nested_trigger.hpp" +#include "rive/animation/nested_state_machine.hpp" +#include "rive/animation/state_machine_input_instance.hpp" +#include "rive/container_component.hpp" + +using namespace rive; + +void NestedTrigger::fire(const CallbackData& value) { this->applyValue(); } + +void NestedTrigger::applyValue() +{ + auto inputInstance = input(); + if (inputInstance != nullptr) + { + auto numInput = static_cast(inputInstance); + if (numInput != nullptr) + { + numInput->fire(); + } + } +} diff --git a/third_party/rive/source/animation/state_instance.cpp b/third_party/rive/source/animation/state_instance.cpp new file mode 100644 index 0000000..230e48f --- /dev/null +++ b/third_party/rive/source/animation/state_instance.cpp @@ -0,0 +1,10 @@ +#include "rive/animation/state_instance.hpp" +using namespace rive; + +StateInstance::StateInstance(const LayerState* layerState) : + m_LayerState(layerState) +{} + +StateInstance::~StateInstance() {} + +const LayerState* StateInstance::state() const { return m_LayerState; } \ No newline at end of file diff --git a/third_party/rive/source/animation/state_machine.cpp b/third_party/rive/source/animation/state_machine.cpp new file mode 100644 index 0000000..d2c822b --- /dev/null +++ b/third_party/rive/source/animation/state_machine.cpp @@ -0,0 +1,158 @@ +#include "rive/animation/state_machine.hpp" +#include "rive/artboard.hpp" +#include "rive/importers/artboard_importer.hpp" +#include "rive/animation/state_machine_layer.hpp" +#include "rive/animation/state_machine_input.hpp" +#include "rive/animation/state_machine_listener.hpp" + +using namespace rive; + +StateMachine::StateMachine() {} + +StateMachine::~StateMachine() {} + +StatusCode StateMachine::onAddedDirty(CoreContext* context) +{ + StatusCode code; + for (auto& object : m_Inputs) + { + if ((code = object->onAddedDirty(context)) != StatusCode::Ok) + { + return code; + } + } + for (auto& object : m_Layers) + { + if ((code = object->onAddedDirty(context)) != StatusCode::Ok) + { + return code; + } + } + for (auto& object : m_Listeners) + { + if ((code = object->onAddedDirty(context)) != StatusCode::Ok) + { + return code; + } + } + return StatusCode::Ok; +} + +StatusCode StateMachine::onAddedClean(CoreContext* context) +{ + StatusCode code; + for (auto& object : m_Inputs) + { + if ((code = object->onAddedClean(context)) != StatusCode::Ok) + { + return code; + } + } + for (auto& object : m_Layers) + { + if ((code = object->onAddedClean(context)) != StatusCode::Ok) + { + return code; + } + } + for (auto& object : m_Listeners) + { + if ((code = object->onAddedClean(context)) != StatusCode::Ok) + { + return code; + } + } + return StatusCode::Ok; +} + +StatusCode StateMachine::import(ImportStack& importStack) +{ + auto artboardImporter = + importStack.latest(ArtboardBase::typeKey); + if (artboardImporter == nullptr) + { + return StatusCode::MissingObject; + } + artboardImporter->addStateMachine(this); + return Super::import(importStack); +} + +void StateMachine::addLayer(std::unique_ptr layer) +{ + m_Layers.push_back(std::move(layer)); +} + +void StateMachine::addInput(std::unique_ptr input) +{ + m_Inputs.push_back(std::move(input)); +} + +void StateMachine::addListener(std::unique_ptr listener) +{ + m_Listeners.push_back(std::move(listener)); +} + +void StateMachine::addDataBind(std::unique_ptr dataBind) +{ + m_dataBinds.push_back(std::move(dataBind)); +} + +const StateMachineInput* StateMachine::input(std::string name) const +{ + for (auto& input : m_Inputs) + { + if (input->name() == name) + { + return input.get(); + } + } + return nullptr; +} + +const StateMachineInput* StateMachine::input(size_t index) const +{ + if (index < m_Inputs.size()) + { + return m_Inputs[index].get(); + } + return nullptr; +} + +const StateMachineLayer* StateMachine::layer(std::string name) const +{ + for (auto& layer : m_Layers) + { + if (layer->name() == name) + { + return layer.get(); + } + } + return nullptr; +} + +const StateMachineLayer* StateMachine::layer(size_t index) const +{ + if (index < m_Layers.size()) + { + return m_Layers[index].get(); + } + return nullptr; +} + +const StateMachineListener* StateMachine::listener(size_t index) const +{ + if (index < m_Listeners.size()) + { + return m_Listeners[index].get(); + } + return nullptr; +} + +const DataBind* StateMachine::dataBind(size_t index) const +{ + if (index < m_dataBinds.size()) + { + return m_dataBinds[index].get(); + } + return nullptr; +} \ No newline at end of file diff --git a/third_party/rive/source/animation/state_machine_input.cpp b/third_party/rive/source/animation/state_machine_input.cpp new file mode 100644 index 0000000..8a3c272 --- /dev/null +++ b/third_party/rive/source/animation/state_machine_input.cpp @@ -0,0 +1,29 @@ +#include "rive/animation/state_machine_input.hpp" +#include "rive/importers/import_stack.hpp" +#include "rive/importers/state_machine_importer.hpp" +#include "rive/generated/animation/state_machine_base.hpp" + +using namespace rive; + +StatusCode StateMachineInput::onAddedDirty(CoreContext* context) +{ + return StatusCode::Ok; +} + +StatusCode StateMachineInput::onAddedClean(CoreContext* context) +{ + return StatusCode::Ok; +} + +StatusCode StateMachineInput::import(ImportStack& importStack) +{ + auto stateMachineImporter = + importStack.latest(StateMachineBase::typeKey); + if (stateMachineImporter == nullptr) + { + return StatusCode::MissingObject; + } + // WOW -- we're handing off ownership of this! + stateMachineImporter->addInput(std::unique_ptr(this)); + return Super::import(importStack); +} \ No newline at end of file diff --git a/third_party/rive/source/animation/state_machine_input_instance.cpp b/third_party/rive/source/animation/state_machine_input_instance.cpp new file mode 100644 index 0000000..02ebaf7 --- /dev/null +++ b/third_party/rive/source/animation/state_machine_input_instance.cpp @@ -0,0 +1,77 @@ +#include "rive/animation/state_machine_input_instance.hpp" +#include "rive/animation/state_machine_bool.hpp" +#include "rive/animation/state_machine_number.hpp" +#include "rive/animation/state_machine_trigger.hpp" +#include "rive/animation/state_machine_instance.hpp" + +using namespace rive; + +SMIInput::SMIInput(const StateMachineInput* input, + StateMachineInstance* machineInstance) : + m_machineInstance(machineInstance), m_input(input) +{} + +uint16_t SMIInput::inputCoreType() const { return m_input->coreType(); } + +const std::string& SMIInput::name() const { return m_input->name(); } + +void SMIInput::valueChanged() +{ + m_machineInstance->markNeedsAdvance(); +#ifdef WITH_RIVE_TOOLS + auto callback = m_machineInstance->m_inputChangedCallback; + if (callback != nullptr) + { + callback(m_machineInstance, m_index); + } +#endif +} + +// bool + +SMIBool::SMIBool(const StateMachineBool* input, + StateMachineInstance* machineInstance) : + SMIInput(input, machineInstance), m_Value(input->value()) +{} + +void SMIBool::value(bool newValue) +{ + if (m_Value == newValue) + { + return; + } + m_Value = newValue; + valueChanged(); +} + +// number +SMINumber::SMINumber(const StateMachineNumber* input, + StateMachineInstance* machineInstance) : + SMIInput(input, machineInstance), m_Value(input->value()) +{} + +void SMINumber::value(float newValue) +{ + if (m_Value == newValue) + { + return; + } + m_Value = newValue; + valueChanged(); +} + +// trigger +SMITrigger::SMITrigger(const StateMachineTrigger* input, + StateMachineInstance* machineInstance) : + SMIInput(input, machineInstance) +{} + +void SMITrigger::fire() +{ + if (m_fired) + { + return; + } + m_fired = true; + valueChanged(); +} diff --git a/third_party/rive/source/animation/state_machine_instance.cpp b/third_party/rive/source/animation/state_machine_instance.cpp new file mode 100644 index 0000000..ce95b5a --- /dev/null +++ b/third_party/rive/source/animation/state_machine_instance.cpp @@ -0,0 +1,2068 @@ +#include "rive/animation/animation_reset.hpp" +#include "rive/animation/animation_reset_factory.hpp" +#include "rive/animation/animation_state_instance.hpp" +#include "rive/animation/animation_state.hpp" +#include "rive/animation/any_state.hpp" +#include "rive/animation/keyframe_interpolator.hpp" +#include "rive/animation/entry_state.hpp" +#include "rive/animation/layer_state_flags.hpp" +#include "rive/animation/nested_linear_animation.hpp" +#include "rive/animation/nested_state_machine.hpp" +#include "rive/animation/state_instance.hpp" +#include "rive/animation/state_machine_bool.hpp" +#include "rive/animation/state_machine_input_instance.hpp" +#include "rive/animation/state_machine_input.hpp" +#include "rive/animation/state_machine_instance.hpp" +#include "rive/animation/state_machine_layer.hpp" +#include "rive/animation/state_machine_listener.hpp" +#include "rive/animation/state_machine_number.hpp" +#include "rive/animation/state_machine_trigger.hpp" +#include "rive/animation/state_machine.hpp" +#include "rive/animation/state_transition.hpp" +#include "rive/animation/transition_condition.hpp" +#include "rive/animation/transition_comparator.hpp" +#include "rive/animation/transition_property_viewmodel_comparator.hpp" +#include "rive/animation/transition_viewmodel_condition.hpp" +#include "rive/animation/state_machine_fire_event.hpp" +#include "rive/artboard_component_list.hpp" +#include "rive/constraints/draggable_constraint.hpp" +#include "rive/data_bind_flags.hpp" +#include "rive/event_report.hpp" +#include "rive/gesture_click_phase.hpp" +#include "rive/hit_result.hpp" +#include "rive/process_event_result.hpp" +#include "rive/math/aabb.hpp" +#include "rive/math/hit_test.hpp" +#include "rive/nested_animation.hpp" +#include "rive/nested_artboard.hpp" +#include "rive/shapes/shape.hpp" +#include "rive/text/text.hpp" +#include "rive/math/math_types.hpp" +#include "rive/audio_event.hpp" +#include +#include + +using namespace rive; +namespace rive +{ +class StateMachineLayerInstance +{ +public: + ~StateMachineLayerInstance() + { + delete m_anyStateInstance; + delete m_currentState; + delete m_stateFrom; + } + + void init(StateMachineInstance* stateMachineInstance, + const StateMachineLayer* layer, + ArtboardInstance* instance) + { + m_stateMachineInstance = stateMachineInstance; + m_artboardInstance = instance; + assert(m_layer == nullptr); + m_anyStateInstance = + layer->anyState()->makeInstance(instance).release(); + m_layer = layer; + changeState(m_layer->entryState()); + +#ifdef TESTING + srand((unsigned int)1); +#else + auto now = std::chrono::high_resolution_clock::now(); + auto nanos = std::chrono::duration_cast( + now.time_since_epoch()) + .count(); + srand((unsigned int)nanos); +#endif + } + + void updateMix(float seconds) + { + if (m_transition != nullptr && m_stateFrom != nullptr && + m_transition->duration() != 0) + { + m_mix = std::min( + 1.0f, + std::max(0.0f, + (m_mix + seconds / m_transition->mixTime( + m_stateFrom->state())))); + if (m_mix == 1.0f && !m_transitionCompleted) + { + m_transitionCompleted = true; + clearAnimationReset(); + fireEvents(StateMachineFireOccurance::atEnd, + m_transition->events()); + } + } + else + { + m_mix = 1.0f; + } + } + + bool advance(float seconds, bool newFrame) + { + if (newFrame) + { + m_stateMachineChangedOnAdvance = false; + } + m_currentState->advance(seconds, m_stateMachineInstance); + updateMix(seconds); + + if (m_stateFrom != nullptr && m_mix < 1.0f && !m_holdAnimationFrom) + { + // This didn't advance during our updateState, but it should now + // that we realize we need to mix it in. + m_stateFrom->advance(seconds, m_stateMachineInstance); + } + + apply(); + + bool changedState = false; + + for (int i = 0; updateState(); i++) + { + changedState = true; + apply(); + + if (i == maxIterations) + { + fprintf(stderr, "StateMachine exceeded max iterations.\n"); + return false; + } + } + + m_currentState->clearSpilledTime(); + + return changedState || m_mix != 1.0f || m_waitingForExit || + (m_currentState != nullptr && m_currentState->keepGoing()); + } + + bool isTransitioning() + { + return m_transition != nullptr && m_stateFrom != nullptr && + m_transition->duration() != 0 && m_mix < 1.0f; + } + + bool updateState() + { + // Don't allow changing state while a transition is taking place + // (we're mixing one state onto another) if enableEarlyExit is not true. + if (isTransitioning() && !m_transition->enableEarlyExit()) + { + return false; + } + + m_waitingForExit = false; + + if (tryChangeState(m_anyStateInstance)) + { + return true; + } + + return tryChangeState(m_currentState); + } + + void fireEvents(StateMachineFireOccurance occurs, + const std::vector& fireEvents) + { + for (auto event : fireEvents) + { + if (event->occurs() == occurs) + { + event->perform(m_stateMachineInstance); + } + } + } + + bool canChangeState(const LayerState* stateTo) + { + return !( + (m_currentState == nullptr ? nullptr : m_currentState->state()) == + stateTo); + } + + double randomValue() + { +#ifdef TESTING + return 0; +#else + return ((double)rand() / (RAND_MAX)); +#endif + } + + bool changeState(const LayerState* stateTo) + { + if ((m_currentState == nullptr ? nullptr : m_currentState->state()) == + stateTo) + { + return false; + } + + // Fire end events for the state we're changing from. + if (m_currentState != nullptr) + { + fireEvents(StateMachineFireOccurance::atEnd, + m_currentState->state()->events()); + } + + m_currentState = + stateTo == nullptr + ? nullptr + : stateTo->makeInstance(m_artboardInstance).release(); + + // Fire start events for the state we're changing to. + if (m_currentState != nullptr) + { + fireEvents(StateMachineFireOccurance::atStart, + m_currentState->state()->events()); + } + return true; + } + + StateTransition* findRandomTransition(StateInstance* stateFromInstance) + { + uint32_t totalWeight = 0; + auto stateFrom = stateFromInstance->state(); + for (size_t i = 0, length = stateFrom->transitionCount(); i < length; + i++) + { + auto transition = stateFrom->transition(i); + if (canChangeState(transition->stateTo())) + { + + auto allowed = transition->allowed(stateFromInstance, + m_stateMachineInstance, + this); + if (allowed == AllowTransition::yes) + { + transition->evaluatedRandomWeight( + transition->randomWeight()); + totalWeight += transition->randomWeight(); + } + else + { + transition->evaluatedRandomWeight(0); + if (allowed == AllowTransition::waitingForExit) + { + m_waitingForExit = true; + } + } + } + else + { + transition->evaluatedRandomWeight(0); + } + } + if (totalWeight > 0) + { + double randomWeight = randomValue() * totalWeight * 1.0; + double currentWeight = 0; + size_t index = 0; + StateTransition* transition; + while (index < stateFrom->transitionCount()) + { + transition = stateFrom->transition(index); + double transitionWeight = + (double)transition->evaluatedRandomWeight(); + if (currentWeight + transitionWeight > randomWeight) + { + transition->useLayerInConditions(m_stateMachineInstance, + this); + return transition; + } + currentWeight += transitionWeight; + index++; + } + } + return nullptr; + } + + StateTransition* findAllowedTransition(StateInstance* stateFromInstance) + { + auto stateFrom = stateFromInstance->state(); + // If it should randomize + if ((static_cast(stateFrom->flags()) & + LayerStateFlags::Random) == LayerStateFlags::Random) + { + return findRandomTransition(stateFromInstance); + } + // Else search the first valid transition + for (size_t i = 0, length = stateFrom->transitionCount(); i < length; + i++) + { + auto transition = stateFrom->transition(i); + if (canChangeState(transition->stateTo())) + { + + auto allowed = transition->allowed(stateFromInstance, + m_stateMachineInstance, + this); + if (allowed == AllowTransition::yes) + { + transition->evaluatedRandomWeight( + transition->randomWeight()); + transition->useLayerInConditions(m_stateMachineInstance, + this); + return transition; + } + else + { + transition->evaluatedRandomWeight(0); + if (allowed == AllowTransition::waitingForExit) + { + m_waitingForExit = true; + } + } + } + } + return nullptr; + } + + void buildAnimationResetForTransition() + { + m_animationReset = + AnimationResetFactory::fromStates(m_stateFrom, + m_currentState, + m_artboardInstance); + } + + void clearAnimationReset() + { + if (m_animationReset != nullptr) + { + AnimationResetFactory::release(std::move(m_animationReset)); + m_animationReset = nullptr; + } + } + + bool tryChangeState(StateInstance* stateFromInstance) + { + if (stateFromInstance == nullptr) + { + return false; + } + auto outState = m_currentState; + auto transition = findAllowedTransition(stateFromInstance); + if (transition != nullptr) + { + clearAnimationReset(); + changeState(transition->stateTo()); + m_stateMachineChangedOnAdvance = true; + // state actually has changed + m_transition = transition; + fireEvents(StateMachineFireOccurance::atStart, + transition->events()); + if (transition->duration() == 0) + { + m_transitionCompleted = true; + fireEvents(StateMachineFireOccurance::atEnd, + transition->events()); + } + else + { + m_transitionCompleted = false; + } + + if (m_stateFrom != m_anyStateInstance) + { + // Old state from is done. + delete m_stateFrom; + } + m_stateFrom = outState; + + if (!m_transitionCompleted) + { + buildAnimationResetForTransition(); + } + + // If we had an exit time and wanted to pause on exit, make + // sure to hold the exit time. Delegate this to the + // transition by telling it that it was completed. + if (outState != nullptr && transition->applyExitCondition(outState)) + { + // Make sure we apply this state. This only returns true + // when it's an animation state instance. + auto instance = + static_cast(m_stateFrom) + ->animationInstance(); + + m_holdAnimation = instance->animation(); + m_holdTime = instance->time(); + } + m_mixFrom = m_mix; + + // Keep mixing last animation that was mixed in. + if (m_mix != 0.0f) + { + m_holdAnimationFrom = transition->pauseOnExit(); + } + if (m_stateFrom != nullptr && + m_stateFrom->state()->is() && + m_currentState != nullptr) + { + auto instance = + static_cast(m_stateFrom) + ->animationInstance(); + + auto spilledTime = instance->spilledTime(); + m_currentState->advance(spilledTime, m_stateMachineInstance); + } + m_mix = 0.0f; + updateMix(0.0f); + m_waitingForExit = false; + return true; + } + return false; + } + + void apply(/*Artboard* artboard*/) + { + if (m_animationReset != nullptr) + { + m_animationReset->apply(m_artboardInstance); + } + if (m_holdAnimation != nullptr) + { + m_holdAnimation->apply(m_artboardInstance, m_holdTime, m_mixFrom); + m_holdAnimation = nullptr; + } + + KeyFrameInterpolator* interpolator = nullptr; + if (m_transition != nullptr && m_transition->interpolator() != nullptr) + { + interpolator = m_transition->interpolator(); + } + + if (m_stateFrom != nullptr && m_mix < 1.0f) + { + auto fromMix = interpolator != nullptr + ? interpolator->transform(m_mixFrom) + : m_mixFrom; + m_stateFrom->apply(m_artboardInstance, fromMix); + } + if (m_currentState != nullptr) + { + auto mix = interpolator != nullptr ? interpolator->transform(m_mix) + : m_mix; + m_currentState->apply(m_artboardInstance, mix); + } + } + + bool stateChangedOnAdvance() const + { + return m_stateMachineChangedOnAdvance; + } + + const LayerState* currentState() + { + return m_currentState == nullptr ? nullptr : m_currentState->state(); + } + + const LinearAnimationInstance* currentAnimation() const + { + if (m_currentState == nullptr || + !m_currentState->state()->is()) + { + return nullptr; + } + return static_cast(m_currentState) + ->animationInstance(); + } + +private: + static const int maxIterations = 100; + StateMachineInstance* m_stateMachineInstance = nullptr; + const StateMachineLayer* m_layer = nullptr; + ArtboardInstance* m_artboardInstance = nullptr; + + StateInstance* m_anyStateInstance = nullptr; + StateInstance* m_currentState = nullptr; + StateInstance* m_stateFrom = nullptr; + + const StateTransition* m_transition = nullptr; + std::unique_ptr m_animationReset = nullptr; + bool m_transitionCompleted = false; + + bool m_holdAnimationFrom = false; + + float m_mix = 1.0f; + float m_mixFrom = 1.0f; + bool m_stateMachineChangedOnAdvance = false; + + bool m_waitingForExit = false; + /// Used to ensure a specific animation is applied on the next apply. + const LinearAnimation* m_holdAnimation = nullptr; + float m_holdTime = 0.0f; +}; + +class ListenerGroup +{ +public: + ListenerGroup(const StateMachineListener* listener) : m_listener(listener) + {} + virtual ~ListenerGroup() {} + void consume() { m_isConsumed = true; } + // + void hover() { m_isHovered = true; } + void unhover() { m_isHovered = false; } + void reset() + { + m_isConsumed = false; + m_prevIsHovered = m_isHovered; + m_isHovered = false; + if (m_clickPhase == GestureClickPhase::clicked) + { + m_clickPhase = GestureClickPhase::out; + } + } + bool isConsumed() { return m_isConsumed; } + bool isHovered() { return m_isHovered; } + bool prevHovered() { return m_prevIsHovered; } + + virtual bool canEarlyOut(Component* drawable) + { + auto listenerType = m_listener->listenerType(); + return !(listenerType == ListenerType::enter || + listenerType == ListenerType::exit || + listenerType == ListenerType::move); + } + + virtual bool needsDownListener(Component* drawable) + { + auto listenerType = m_listener->listenerType(); + return listenerType == ListenerType::down || + listenerType == ListenerType::click; + } + + virtual bool needsUpListener(Component* drawable) + { + auto listenerType = m_listener->listenerType(); + return listenerType == ListenerType::up || + listenerType == ListenerType::click; + } + // Vec2D position, ListenerType hitType, bool canHit + virtual ProcessEventResult processEvent( + Component* component, + Vec2D position, + ListenerType hitEvent, + bool canHit, + StateMachineInstance* stateMachineInstance) + { + // Because each group is tested individually for its hover state, a + // group could be marked "incorrectly" as hovered at this point. But + // once we iterate each element in the drawing order, that group can be + // occluded by an opaque target on top of it. So although it is hovered + // in isolation, it shouldn't be considered as hovered in the full + // context. In this case, we unhover the group so it is not marked as + // previously hovered. + if (!canHit && isHovered()) + { + unhover(); + } + + bool isGroupHovered = canHit ? isHovered() : false; + bool hoverChange = prevHovered() != isGroupHovered; + // If hover has changes, it means that the element is hovered for the + // first time. Previous positions need to be reset to avoid jumps. + if (hoverChange && isGroupHovered) + { + previousPosition.x = position.x; + previousPosition.y = position.y; + } + + // Handle click gesture phases. A click gesture has two phases. + // First one attached to a pointer down actions, second one attached to + // a pointer up action. Both need to act on a shape of the listener + // group. + if (isGroupHovered) + { + if (hitEvent == ListenerType::down) + { + clickPhase(GestureClickPhase::down); + } + else if (hitEvent == ListenerType::up && + clickPhase() == GestureClickPhase::down) + { + clickPhase(GestureClickPhase::clicked); + } + } + else + { + if (hitEvent == ListenerType::down || hitEvent == ListenerType::up) + { + clickPhase(GestureClickPhase::out); + } + } + auto _listener = listener(); + // Always update hover states regardless of which specific listener type + // we're trying to trigger. + // If hover has changed and: + // - it's hovering and the listener is of type enter + // - it's not hovering and the listener is of type exit + if (hoverChange && ((isGroupHovered && _listener->listenerType() == + ListenerType::enter) || + (!isGroupHovered && + _listener->listenerType() == ListenerType::exit))) + { + _listener->performChanges(stateMachineInstance, + position, + previousPosition); + stateMachineInstance->markNeedsAdvance(); + consume(); + } + // Perform changes if: + // - the click gesture is complete and the listener is of type click + // - the event type matches the listener type and it is hovering the + // group + if ((clickPhase() == GestureClickPhase::clicked && + _listener->listenerType() == ListenerType::click) || + (isGroupHovered && hitEvent == _listener->listenerType())) + { + _listener->performChanges(stateMachineInstance, + position, + previousPosition); + stateMachineInstance->markNeedsAdvance(); + consume(); + } + previousPosition.x = position.x; + previousPosition.y = position.y; + return ProcessEventResult::pointer; + } + void clickPhase(GestureClickPhase value) { m_clickPhase = value; } + GestureClickPhase clickPhase() { return m_clickPhase; } + const StateMachineListener* listener() const { return m_listener; }; + // A vector storing the previous position for this specific listener gorup + Vec2D previousPosition; + +private: + // Consumed listeners aren't processed again in the current frame + bool m_isConsumed = false; + // This variable holds the hover status of the the listener itself so it can + // be shared between all shapes that target it + bool m_isHovered = false; + // Variable storing the previous hovered state to check for hover changes + bool m_prevIsHovered = false; + // A click gesture is composed of three phases and is shared between all + // shapes + GestureClickPhase m_clickPhase = GestureClickPhase::out; + const StateMachineListener* m_listener; +}; + +class DraggableConstraintListenerGroup : public ListenerGroup +{ +public: + DraggableConstraintListenerGroup(const StateMachineListener* listener, + DraggableConstraint* constraint, + DraggableProxy* draggable) : + ListenerGroup(listener), + m_constraint(constraint), + m_draggable(draggable) + {} + ~DraggableConstraintListenerGroup() + { + delete listener(); + delete m_draggable; + } + + DraggableConstraint* constraint() { return m_constraint; } + + bool canEarlyOut(Component* drawable) override { return false; } + + bool needsDownListener(Component* drawable) override { return true; } + + bool needsUpListener(Component* drawable) override { return true; } + // Vec2D position, ListenerType hitType, bool canHit + ProcessEventResult processEvent( + Component* component, + Vec2D position, + ListenerType hitEvent, + bool canHit, + StateMachineInstance* stateMachineInstance) override + { + auto prevPhase = clickPhase(); + ListenerGroup::processEvent(component, + position, + hitEvent, + canHit, + stateMachineInstance); + if (prevPhase == GestureClickPhase::down && + (clickPhase() == GestureClickPhase::clicked || + clickPhase() == GestureClickPhase::out)) + { + m_draggable->endDrag(position); + if (hasScrolled) + { + return ProcessEventResult::scroll; + hasScrolled = false; + } + } + else if (prevPhase != GestureClickPhase::down && + clickPhase() == GestureClickPhase::down) + { + m_draggable->startDrag(position); + hasScrolled = false; + } + else if (hitEvent == ListenerType::move && + clickPhase() == GestureClickPhase::down) + { + m_draggable->drag(position); + hasScrolled = true; + return ProcessEventResult::scroll; + } + return ProcessEventResult::none; + } + +private: + DraggableConstraint* m_constraint; + DraggableProxy* m_draggable; + bool hasScrolled = false; +}; + +/// Representation of a Component from the Artboard Instance and all the +/// listeners it triggers. Allows tracking hover and performing hit detection +/// only once on components that trigger multiple listeners. +class HitDrawable : public HitComponent +{ +public: + HitDrawable(Drawable* drawable, + Component* component, + StateMachineInstance* stateMachineInstance, + bool isOpaque) : + HitComponent(component, stateMachineInstance) + { + this->m_drawable = drawable; + this->isOpaque = isOpaque; + if (drawable->isTargetOpaque()) + { + canEarlyOut = false; + } + } + float hitRadius = 2; + bool isHovered = false; + bool canEarlyOut = true; + bool hasDownListener = false; + bool hasUpListener = false; + bool isOpaque = false; + Drawable* m_drawable; + std::vector listeners; + + virtual bool hitTestHelper(Vec2D position) const { return false; } + + bool hitTest(Vec2D position) const override + { + return hitTestHelper(position); + } + + virtual bool testBounds(Component* component, + Vec2D position, + bool skipOnUnclipped) const + { + if (component == nullptr) + { + return true; + } + + if (component->is()) + { + component = component->as()->hittableComponent(); + if (component == nullptr) + { + return true; + } + } + + if (component->is()) + { + Mat2D inverseWorld; + auto layout = component->as(); + + if (layout->worldTransform().invert(&inverseWorld)) + { + // If the layout is not clipped and skipOnUnclipped is true, we + // don't care about whether it contains the position + auto canSkip = skipOnUnclipped && !layout->clip(); + if (!canSkip) + { + auto localWorld = inverseWorld * position; + if (layout->is()) + { + auto artboard = layout->as(); + if (artboard->originX() != 0 || + artboard->originY() != 0) + { + localWorld += Vec2D( + artboard->originX() * artboard->layoutWidth(), + artboard->originY() * artboard->layoutHeight()); + } + } + if (!layout->localBounds().contains(localWorld)) + { + return false; + } + } + return testBounds(layout->parent(), position, true); + } + return false; + } + + // Keep going + return testBounds(component->parent(), position, skipOnUnclipped); + } + + void prepareEvent(Vec2D position, ListenerType hitType) override + { + if (canEarlyOut && + (hitType != ListenerType::down || !hasDownListener) && + (hitType != ListenerType::up || !hasUpListener)) + { +#ifdef TESTING + earlyOutCount++; +#endif + return; + } + isHovered = hitTest(position); + + // // iterate all listeners associated with this hit shape + if (isHovered) + { + for (auto listenerGroup : listeners) + { + + listenerGroup->hover(); + } + } + } + + HitResult processEvent(Vec2D position, + ListenerType hitType, + bool canHit) override + { + // If the shape doesn't have any ListenerType::move / enter / exit and + // the event being processed is not of the type it needs to handle. + // There is no need to perform a hitTest (which is relatively expensive + // and would be happening on every pointer move) so we early out. + if (canEarlyOut && + (hitType != ListenerType::down || !hasDownListener) && + (hitType != ListenerType::up || !hasUpListener)) + { + return HitResult::none; + } + bool isBlockingEvent = false; + // // iterate all listeners associated with this hit shape + for (auto listenerGroup : listeners) + { + if (listenerGroup->isConsumed()) + { + continue; + } + if (listenerGroup->processEvent(m_component, + position, + hitType, + canHit, + m_stateMachineInstance) == + ProcessEventResult::scroll) + { + isBlockingEvent = true; + } + } + return (isHovered && canHit) + ? (isOpaque || m_drawable->isTargetOpaque() || + isBlockingEvent) + ? HitResult::hitOpaque + : HitResult::hit + : HitResult::none; + } + + void addListener(ListenerGroup* listenerGroup) + { + if (!listenerGroup->canEarlyOut(m_component)) + { + canEarlyOut = false; + } + else + { + if (listenerGroup->needsDownListener(m_component)) + { + hasDownListener = true; + } + if (listenerGroup->needsUpListener(m_component)) + { + hasUpListener = true; + } + } + listeners.push_back(listenerGroup); + } +}; + +/// Representation of a HitDrawable with a Hittable component +class HitExpandable : public HitDrawable +{ +public: + bool testBounds(Component* component, + Vec2D position, + bool skipOnUnclipped) const override + { + Hittable* hittable = component ? Hittable::from(component) : nullptr; + if (hittable != nullptr) + { + if (hittable->hitTestAABB(position) && + HitDrawable::testBounds(component->parent(), position, true)) + { + return hittable->hitTestHiFi(position, hitRadius); + } + return false; + } + return HitDrawable::testBounds(component, position, true); + } + + HitExpandable(Drawable* drawable, + Component* component, + StateMachineInstance* stateMachineInstance, + bool isOpaque = false) : + HitDrawable(drawable, component, stateMachineInstance, isOpaque) + {} + + bool hitTestHelper(Vec2D position) const override + { + return testBounds(m_component, position, true); + } +}; + +// Wrapper around HitExpandable to garbage collect text run contours. +class HitTextRun : public HitExpandable +{ +public: + TextValueRun* m_textValueRun; + + HitTextRun(Drawable* drawable, + TextValueRun* component, + StateMachineInstance* stateMachineInstance, + bool isOpaque = false) : + HitExpandable(drawable, component, stateMachineInstance, isOpaque) + { + m_textValueRun = component; + if (m_textValueRun) + { + m_textValueRun->isHitTarget(true); + } + } + + ~HitTextRun() + { + if (m_textValueRun != nullptr) + { + m_textValueRun->isHitTarget(false); + m_textValueRun->resetHitTest(); + } + } +}; + +class HitLayout : public HitDrawable +{ +public: + HitLayout(Drawable* layout, + StateMachineInstance* stateMachineInstance, + bool isOpaque = false) : + HitDrawable(layout, layout, stateMachineInstance, isOpaque) + {} + + bool hitTestHelper(Vec2D position) const override + { + return testBounds(m_component, position, false); + } +}; + +class HitNestedArtboard : public HitComponent +{ +public: + HitNestedArtboard(Component* nestedArtboard, + StateMachineInstance* stateMachineInstance) : + HitComponent(nestedArtboard, stateMachineInstance) + {} + ~HitNestedArtboard() override {} + + bool hitTest(Vec2D position) const override + { + auto nestedArtboard = m_component->as(); + if (nestedArtboard->isCollapsed()) + { + return false; + } + Vec2D nestedPosition; + if (!nestedArtboard->worldToLocal(position, &nestedPosition)) + { + // Mounted artboard isn't ready or has a 0 scale transform. + return false; + } + + for (auto nestedAnimation : nestedArtboard->nestedAnimations()) + { + if (nestedAnimation->is()) + { + auto nestedStateMachine = + nestedAnimation->as(); + if (nestedStateMachine->hitTest(nestedPosition)) + { + return true; + } + } + } + return false; + } + HitResult processEvent(Vec2D position, + ListenerType hitType, + bool canHit) override + { + auto nestedArtboard = m_component->as(); + HitResult hitResult = HitResult::none; + if (nestedArtboard->isCollapsed()) + { + return hitResult; + } + Vec2D nestedPosition; + if (!nestedArtboard->worldToLocal(position, &nestedPosition)) + { + // Mounted artboard isn't ready or has a 0 scale transform. + return hitResult; + } + + for (auto nestedAnimation : nestedArtboard->nestedAnimations()) + { + if (nestedAnimation->is()) + { + auto nestedStateMachine = + nestedAnimation->as(); + if (canHit) + { + switch (hitType) + { + case ListenerType::down: + hitResult = + nestedStateMachine->pointerDown(nestedPosition); + break; + case ListenerType::up: + hitResult = + nestedStateMachine->pointerUp(nestedPosition); + break; + case ListenerType::move: + hitResult = + nestedStateMachine->pointerMove(nestedPosition); + break; + case ListenerType::enter: + case ListenerType::exit: + case ListenerType::event: + case ListenerType::click: + case ListenerType::draggableConstraint: + break; + } + } + else + { + switch (hitType) + { + case ListenerType::down: + case ListenerType::up: + case ListenerType::move: + nestedStateMachine->pointerExit(nestedPosition); + break; + case ListenerType::enter: + case ListenerType::exit: + case ListenerType::event: + case ListenerType::click: + case ListenerType::draggableConstraint: + break; + } + } + } + } + return hitResult; + } + void prepareEvent(Vec2D position, ListenerType hitType) override {} +}; + +class HitComponentList : public HitComponent +{ +public: + HitComponentList(Component* componentList, + StateMachineInstance* stateMachineInstance) : + HitComponent(componentList, stateMachineInstance) + {} + ~HitComponentList() override {} + + bool hitTest(Vec2D position) const override + { + auto componentList = m_component->as(); + if (componentList->isCollapsed()) + { + return false; + } + for (int i = 0; i < componentList->artboardCount(); i++) + { + Vec2D listPosition; + if (!componentList->worldToLocal(position, &listPosition, i)) + { + // Mounted artboard isn't ready or has a 0 scale transform. + continue; + } + auto stateMachine = componentList->stateMachineInstance(i); + if (stateMachine != nullptr && stateMachine->hitTest(listPosition)) + { + return true; + } + } + return false; + } + HitResult processEvent(Vec2D position, + ListenerType hitType, + bool canHit) override + { + auto componentList = m_component->as(); + HitResult hitResult = HitResult::none; + bool runningCanHit = canHit; + if (componentList->isCollapsed()) + { + return hitResult; + } + for (int i = 0; i < componentList->artboardCount(); i++) + { + Vec2D listPosition; + bool hit = componentList->worldToLocal(position, &listPosition, i); + if (!hit) + { + continue; + } + auto stateMachine = componentList->stateMachineInstance(i); + if (stateMachine != nullptr) + { + HitResult itemHitResult = HitResult::none; + if (runningCanHit) + { + switch (hitType) + { + case ListenerType::down: + itemHitResult = + stateMachine->pointerDown(listPosition); + break; + case ListenerType::up: + itemHitResult = + stateMachine->pointerUp(listPosition); + break; + case ListenerType::move: + itemHitResult = + stateMachine->pointerMove(listPosition); + break; + case ListenerType::enter: + case ListenerType::exit: + case ListenerType::event: + case ListenerType::click: + case ListenerType::draggableConstraint: + break; + } + } + else + { + switch (hitType) + { + case ListenerType::down: + case ListenerType::up: + case ListenerType::move: + stateMachine->pointerExit(listPosition); + break; + case ListenerType::enter: + case ListenerType::exit: + case ListenerType::event: + case ListenerType::click: + case ListenerType::draggableConstraint: + break; + } + } + if ((hitResult == HitResult::none && + (itemHitResult == HitResult::hit || + itemHitResult == HitResult::hitOpaque)) || + (hitResult == HitResult::hit && + itemHitResult == HitResult::hitOpaque)) + { + hitResult = itemHitResult; + } + if (hitResult == HitResult::hitOpaque) + { + runningCanHit = false; + } + } + } + return hitResult; + } + void prepareEvent(Vec2D position, ListenerType hitType) override {} +}; + +} // namespace rive + +HitResult StateMachineInstance::updateListeners(Vec2D position, + ListenerType hitType) +{ + if (m_artboardInstance->frameOrigin()) + { + position -= Vec2D( + m_artboardInstance->originX() * m_artboardInstance->layoutWidth(), + m_artboardInstance->originY() * m_artboardInstance->layoutHeight()); + } + // First reset all listener groups before processing the events + for (const auto& listenerGroup : m_listenerGroups) + { + listenerGroup.get()->reset(); + } + // Next prepare the event to set the common hover status for each group + for (const auto& hitShape : m_hitComponents) + { + hitShape->prepareEvent(position, hitType); + } + bool hitSomething = false; + bool hitOpaque = false; + // Finally process the events + for (const auto& hitShape : m_hitComponents) + { + // TODO: quick reject. + + HitResult hitResult = + hitShape->processEvent(position, hitType, !hitOpaque); + if (hitResult != HitResult::none) + { + hitSomething = true; + if (hitResult == HitResult::hitOpaque) + { + hitOpaque = true; + } + } + } + return hitSomething ? hitOpaque ? HitResult::hitOpaque : HitResult::hit + : HitResult::none; +} + +bool StateMachineInstance::hitTest(Vec2D position) const +{ + if (m_artboardInstance->frameOrigin()) + { + position -= Vec2D( + m_artboardInstance->originX() * m_artboardInstance->layoutWidth(), + m_artboardInstance->originY() * m_artboardInstance->layoutHeight()); + } + + for (const auto& hitShape : m_hitComponents) + { + // TODO: quick reject. + + if (hitShape->hitTest(position)) + { + return true; + } + } + return false; +} + +HitResult StateMachineInstance::pointerMove(Vec2D position) +{ + return updateListeners(position, ListenerType::move); +} +HitResult StateMachineInstance::pointerDown(Vec2D position) +{ + return updateListeners(position, ListenerType::down); +} +HitResult StateMachineInstance::pointerUp(Vec2D position) +{ + return updateListeners(position, ListenerType::up); +} +HitResult StateMachineInstance::pointerExit(Vec2D position) +{ + return updateListeners(position, ListenerType::exit); +} + +#ifdef TESTING +const LayerState* StateMachineInstance::layerState(size_t index) +{ + if (index < m_machine->layerCount()) + { + return m_layers[index].currentState(); + } + return nullptr; +} +#endif + +void StateMachineInstance::addToHitLookup( + Component* target, + bool isLayoutComponent, + std::unordered_map& hitLookup, + ListenerGroup* listenerGroup, + bool isOpaque) +{ + // target could either be a LayoutComponent or a DrawableProxy + if (isLayoutComponent) + { + HitLayout* hitLayout; + auto itr = hitLookup.find(target); + if (itr == hitLookup.end()) + { + auto hs = rivestd::make_unique(target->as(), + this, + isOpaque); + hitLookup[target] = hitLayout = hs.get(); + m_hitComponents.push_back(std::move(hs)); + } + else + { + hitLayout = static_cast(itr->second); + } + hitLayout->addListener(listenerGroup); + if (isOpaque) + { + hitLayout->isOpaque = true; + } + return; + } + + if (target->is()) + { + HitExpandable* hitShape; + auto itr = hitLookup.find(target); + if (itr == hitLookup.end()) + { + Shape* shape = target->as(); + shape->addFlags(PathFlags::neverDeferUpdate); + shape->addDirt(ComponentDirt::Path, true); + auto hs = rivestd::make_unique(shape, shape, this); + hitLookup[target] = hitShape = hs.get(); + m_hitComponents.push_back(std::move(hs)); + } + else + { + hitShape = static_cast(itr->second); + } + hitShape->addListener(listenerGroup); + return; + } + + if (target->is()) + { + HitTextRun* hitTextRun; + auto itr = hitLookup.find(target); + if (itr == hitLookup.end()) + { + TextValueRun* run = target->as(); + run->textComponent()->addDirt(ComponentDirt::Path, true); + auto hs = rivestd::make_unique(run->textComponent(), + run, + this); + hitLookup[target] = hitTextRun = hs.get(); + m_hitComponents.push_back(std::move(hs)); + } + else + { + hitTextRun = static_cast(itr->second); + } + hitTextRun->addListener(listenerGroup); + return; + } + + if (target->is()) + { + target->as()->forEachChild([&](Component* child) { + addToHitLookup(child, + child->is(), + hitLookup, + listenerGroup, + isOpaque); + return false; + }); + return; + } +} + +StateMachineInstance::StateMachineInstance(const StateMachine* machine, + ArtboardInstance* instance) : + Scene(instance), m_machine(machine) +{ + const auto count = machine->inputCount(); + m_inputInstances.resize(count); + for (size_t i = 0; i < count; i++) + { + auto input = machine->input(i); + if (input == nullptr) + { + continue; + } + switch (input->coreType()) + { + case StateMachineBool::typeKey: + m_inputInstances[i] = + new SMIBool(input->as(), this); + break; + case StateMachineNumber::typeKey: + m_inputInstances[i] = + new SMINumber(input->as(), this); + break; + case StateMachineTrigger::typeKey: + m_inputInstances[i] = + new SMITrigger(input->as(), this); + break; + default: + // Sanity check. + break; + } +#ifdef WITH_RIVE_TOOLS + auto instance = m_inputInstances[i]; + if (instance != nullptr) + { + instance->m_index = i; + } +#endif + } + + m_layerCount = machine->layerCount(); + m_layers = new StateMachineLayerInstance[m_layerCount]; + for (size_t i = 0; i < m_layerCount; i++) + { + m_layers[i].init(this, machine->layer(i), m_artboardInstance); + } + + // Initialize dataBinds. All databinds are cloned for the state machine + // instance. That enables binding each instance to its own context without + // polluting the rest. + auto dataBindCount = machine->dataBindCount(); + for (size_t i = 0; i < dataBindCount; i++) + { + auto dataBind = machine->dataBind(i); + auto dataBindClone = static_cast(dataBind->clone()); + dataBindClone->file(dataBind->file()); + if (dataBind->converter() != nullptr) + { + dataBindClone->converter( + dataBind->converter()->clone()->as()); + } + m_dataBinds.push_back(dataBindClone); + if (dataBind->target()->is()) + { + auto bindableProperty = dataBind->target()->as(); + auto bindablePropertyInstance = + m_bindablePropertyInstances.find(bindableProperty); + BindableProperty* bindablePropertyClone; + if (bindablePropertyInstance == m_bindablePropertyInstances.end()) + { + bindablePropertyClone = + bindableProperty->clone()->as(); + m_bindablePropertyInstances[bindableProperty] = + bindablePropertyClone; + } + else + { + bindablePropertyClone = bindablePropertyInstance->second; + } + dataBindClone->target(bindablePropertyClone); + // We are only storing in this unordered map data binds that are + // targetting the source. For now, this is only the case for + // listener actions. + if (static_cast(dataBindClone->flags()) == + DataBindFlags::ToSource) + { + m_bindableDataBindsToSource[bindablePropertyClone] = + dataBindClone; + } + else + { + m_bindableDataBindsToTarget[bindablePropertyClone] = + dataBindClone; + } + } + else + { + dataBindClone->target(dataBind->target()); + } + } + + // Initialize listeners. Store a lookup table of shape id to hit shape + // representation (an object that stores all the listeners triggered by the + // shape producing a listener). + std::unordered_map hitLookup; + for (std::size_t i = 0; i < machine->listenerCount(); i++) + { + auto listener = machine->listener(i); + if (listener->listenerType() == ListenerType::event) + { + continue; + } + auto listenerGroup = rivestd::make_unique(listener); + auto target = m_artboardInstance->resolve(listener->targetId()); + if (target != nullptr && target->is()) + { + bool isLayoutComponent = false; + if (target->is()) + { + isLayoutComponent = true; + target = target->as()->proxy(); + } + addToHitLookup(target->as(), + isLayoutComponent, + hitLookup, + listenerGroup.get(), + false); + } + m_listenerGroups.push_back(std::move(listenerGroup)); + } + + std::vector draggableConstraints; + for (auto core : m_artboardInstance->objects()) + { + if (core == nullptr) + { + continue; + } + if (core->is()) + { + draggableConstraints.push_back(core->as()); + } + } + for (auto constraint : draggableConstraints) + { + auto draggables = constraint->draggables(); + for (auto dragProxy : draggables) + { + auto listener = new StateMachineListener(); + listener->listenerTypeValue( + static_cast(ListenerType::draggableConstraint)); + auto listenerGroup = + rivestd::make_unique( + listener, + constraint, + dragProxy); + auto hittable = dragProxy->hittable(); + if (hittable != nullptr && hittable->is()) + { + addToHitLookup(hittable->as(), + hittable->is() || + hittable->isProxy(), + hitLookup, + listenerGroup.get(), + dragProxy->isOpaque()); + } + m_listenerGroups.push_back(std::move(listenerGroup)); + } + } + + for (auto nestedArtboard : instance->nestedArtboards()) + { + if (nestedArtboard->hasNestedStateMachines()) + { + auto hn = rivestd::make_unique( + nestedArtboard->as(), + this); + m_hitComponents.push_back(std::move(hn)); + } + for (auto animation : nestedArtboard->nestedAnimations()) + { + if (animation->is()) + { + if (auto notifier = animation->as() + ->stateMachineInstance()) + { + notifier->setNestedArtboard(nestedArtboard); + notifier->addNestedEventListener(this); + } + } + else if (animation->is()) + { + if (auto notifier = animation->as() + ->animationInstance()) + { + notifier->setNestedArtboard(nestedArtboard); + notifier->addNestedEventListener(this); + } + } + } + } + for (auto componentList : instance->artboardComponentLists()) + { + auto hc = rivestd::make_unique( + componentList->as(), + this); + m_hitComponents.push_back(std::move(hc)); + } + sortHitComponents(); +} + +StateMachineInstance::~StateMachineInstance() +{ + clearDataContext(); + for (auto inst : m_inputInstances) + { + delete inst; + } + for (auto& listenerGroup : m_listenerGroups) + { + listenerGroup.reset(); + } + for (auto databind : m_dataBinds) + { + delete databind; + } + delete[] m_layers; + for (auto pair : m_bindablePropertyInstances) + { + delete pair.second; + pair.second = nullptr; + } + if (m_ownsDataContext) + { + delete m_DataContext; + } + m_bindablePropertyInstances.clear(); +} + +#ifdef WITH_RIVE_TOOLS +void StateMachineInstance::onDataBindChanged(DataBindChanged callback) +{ + for (auto databind : m_dataBinds) + { + databind->onChanged(callback); + } +} +#endif + +void StateMachineInstance::sortHitComponents() +{ + auto hitShapesCount = m_hitComponents.size(); + auto currentSortedIndex = 0; + auto count = 0; + // Since the Artboard is not a drawable, we move all hit components + // pointing to the artboard to the front of the list + for (auto& comp : m_hitComponents) + { + if (comp->component() != nullptr && comp->component()->is()) + { + if (currentSortedIndex != count) + { + + std::iter_swap(m_hitComponents.begin() + currentSortedIndex, + m_hitComponents.begin() + count); + } + currentSortedIndex++; + } + count++; + } + Drawable* last = m_artboardInstance->firstDrawable(); + if (last) + { + // walk to the end, so we can visit in reverse-order + while (last->prev) + { + last = last->prev; + } + } + for (auto drawable = last; drawable; drawable = drawable->next) + { + for (size_t i = currentSortedIndex; i < hitShapesCount; i++) + { + if (m_hitComponents[i]->component() == drawable) + { + if (currentSortedIndex != i) + { + std::iter_swap(m_hitComponents.begin() + currentSortedIndex, + m_hitComponents.begin() + i); + } + currentSortedIndex++; + } + } + if (currentSortedIndex == hitShapesCount) + { + break; + } + } +} + +void StateMachineInstance::updateDataBinds() +{ + for (auto dataBind : m_dataBinds) + { + auto d = dataBind->dirt(); + if (d != ComponentDirt::None) + { + dataBind->dirt(ComponentDirt::None); + dataBind->update(d); + } + } +} + +bool StateMachineInstance::tryChangeState() +{ + bool hasChangedState = false; + for (size_t i = 0; i < m_layerCount; i++) + { + if (m_layers[i].updateState()) + { + hasChangedState = true; + } + } + return hasChangedState; +} + +bool StateMachineInstance::advance(float seconds, bool newFrame) +{ + if (m_drawOrderChangeCounter != + m_artboardInstance->drawOrderChangeCounter()) + { + m_drawOrderChangeCounter = m_artboardInstance->drawOrderChangeCounter(); + sortHitComponents(); + } + if (newFrame) + { + this->notifyEventListeners(m_reportedEvents, nullptr); + m_reportedEvents.clear(); + m_needsAdvance = false; + } + updateDataBinds(); + for (size_t i = 0; i < m_layerCount; i++) + { + if (m_layers[i].advance(seconds, newFrame)) + { + m_needsAdvance = true; + } + } + + for (auto& dataBind : m_dataBinds) + { + if (dataBind->advance(seconds)) + { + m_needsAdvance = true; + } + } + + for (auto inst : m_inputInstances) + { + inst->advanced(); + } + + return m_needsAdvance || !m_reportedEvents.empty(); +} + +void StateMachineInstance::advancedDataContext() +{ + if (m_DataContext != nullptr) + { + m_DataContext->advanced(); + } +} + +bool StateMachineInstance::advanceAndApply(float seconds) +{ + bool keepGoing = this->advance(seconds, true); + if (m_artboardInstance->advanceInternal( + seconds, + AdvanceFlags::IsRoot | AdvanceFlags::Animate | + AdvanceFlags::AdvanceNested | AdvanceFlags::NewFrame)) + { + keepGoing = true; + } + + for (int outerOptionC = 0; outerOptionC < 5; outerOptionC++) + { + if (m_artboardInstance->updatePass(true)) + { + keepGoing = true; + } + + // Advance all animations. + if (this->tryChangeState()) + { + this->advance(0.0f, false); + keepGoing = true; + } + + if (m_artboardInstance->advanceInternal( + 0.0f, + AdvanceFlags::IsRoot | AdvanceFlags::Animate | + AdvanceFlags::AdvanceNested)) + { + keepGoing = true; + } + advancedDataContext(); + + if (!m_artboardInstance->hasDirt(ComponentDirt::Components)) + { + break; + } + } + return keepGoing || !m_reportedEvents.empty(); +} + +void StateMachineInstance::markNeedsAdvance() { m_needsAdvance = true; } +bool StateMachineInstance::needsAdvance() const { return m_needsAdvance; } + +std::string StateMachineInstance::name() const { return m_machine->name(); } + +SMIInput* StateMachineInstance::input(size_t index) const +{ + if (index < m_inputInstances.size()) + { + return m_inputInstances[index]; + } + return nullptr; +} + +template +InstType* StateMachineInstance::getNamedInput(const std::string& name) const +{ + for (const auto inst : m_inputInstances) + { + auto input = inst->input(); + if (input->is() && input->name() == name) + { + return static_cast(inst); + } + } + return nullptr; +} + +SMIBool* StateMachineInstance::getBool(const std::string& name) const +{ + return getNamedInput(name); +} +SMINumber* StateMachineInstance::getNumber(const std::string& name) const +{ + return getNamedInput(name); +} +SMITrigger* StateMachineInstance::getTrigger(const std::string& name) const +{ + return getNamedInput(name); +} + +void StateMachineInstance::bindViewModelInstance( + rcp viewModelInstance) +{ + clearDataContext(); + m_ownsDataContext = true; + auto dataContext = new DataContext(viewModelInstance); + m_artboardInstance->clearDataContext(); + m_artboardInstance->internalDataContext(dataContext, true); + internalDataContext(dataContext); +} + +void StateMachineInstance::dataContext(DataContext* dataContext) +{ + clearDataContext(); + internalDataContext(dataContext); +} + +void StateMachineInstance::internalDataContext(DataContext* dataContext) +{ + m_DataContext = dataContext; + for (auto dataBind : m_dataBinds) + { + if (dataBind->is()) + { + dataBind->as()->bindFromContext(dataContext); + } + } +} + +void StateMachineInstance::clearDataContext() +{ + if (m_ownsDataContext && m_DataContext != nullptr) + { + delete m_DataContext; + m_DataContext = nullptr; + } + for (auto dataBind : m_dataBinds) + { + dataBind->unbind(); + } + m_ownsDataContext = false; +} + +size_t StateMachineInstance::stateChangedCount() const +{ + size_t count = 0; + for (size_t i = 0; i < m_layerCount; i++) + { + if (m_layers[i].stateChangedOnAdvance()) + { + count++; + } + } + return count; +} + +const LayerState* StateMachineInstance::stateChangedByIndex(size_t index) const +{ + size_t count = 0; + for (size_t i = 0; i < m_layerCount; i++) + { + if (m_layers[i].stateChangedOnAdvance()) + { + if (count == index) + { + return m_layers[i].currentState(); + } + count++; + } + } + return nullptr; +} + +size_t StateMachineInstance::currentAnimationCount() const +{ + size_t count = 0; + for (size_t i = 0; i < m_layerCount; i++) + { + if (m_layers[i].currentAnimation() != nullptr) + { + count++; + } + } + return count; +} + +const LinearAnimationInstance* StateMachineInstance::currentAnimationByIndex( + size_t index) const +{ + size_t count = 0; + for (size_t i = 0; i < m_layerCount; i++) + { + if (m_layers[i].currentAnimation() != nullptr) + { + if (count == index) + { + return m_layers[i].currentAnimation(); + } + count++; + } + } + return nullptr; +} + +void StateMachineInstance::reportEvent(Event* event, float delaySeconds) +{ + m_reportedEvents.push_back(EventReport(event, delaySeconds)); +} + +std::size_t StateMachineInstance::reportedEventCount() const +{ + return m_reportedEvents.size(); +} + +const EventReport StateMachineInstance::reportedEventAt(std::size_t index) const +{ + if (index >= m_reportedEvents.size()) + { + return EventReport(nullptr, 0.0f); + } + return m_reportedEvents[index]; +} + +void StateMachineInstance::notify(const std::vector& events, + NestedArtboard* context) +{ + notifyEventListeners(events, context); + updateDataBinds(); +} + +void StateMachineInstance::notifyEventListeners( + const std::vector& events, + NestedArtboard* source) +{ + if (events.size() > 0) + { + // We trigger the listeners in order + for (size_t i = 0; i < m_machine->listenerCount(); i++) + { + auto listener = m_machine->listener(i); + auto target = artboard()->resolve(listener->targetId()); + if (listener != nullptr && + listener->listenerType() == ListenerType::event && + (source == nullptr || source == target)) + { + for (const auto event : events) + { + auto sourceArtboard = source == nullptr + ? artboard() + : source->artboardInstance(); + + // listener->eventId() can point to an id from an + // event in the context of this artboard or the + // context of a nested artboard. Because those ids + // belong to different contexts, they can have the + // same value. So when the eventId is resolved + // within one context, but actually pointing to the + // other, it can return the wrong event object. If, + // by chance, that event exists in the other + // context, and is being reported, it will trigger + // the wrong set of actions. This validation makes + // sure that a listener must be targetting the + // current artboard to disambiguate between external + // and internal events. + if (source == nullptr && + sourceArtboard->resolve(listener->targetId()) != + artboard()) + { + continue; + } + auto listenerEvent = + sourceArtboard->resolve(listener->eventId()); + if (listenerEvent == event.event()) + { + listener->performChanges(this, Vec2D(), Vec2D()); + break; + } + } + } + } + // Bubble the event up to parent artboard state machines + // immediately + for (auto listener : nestedEventListeners()) + { + listener->notify(events, nestedArtboard()); + } + + for (auto report : events) + { + auto event = report.event(); + if (event->is()) + { + event->as()->play(); + } + } + } +} + +BindableProperty* StateMachineInstance::bindablePropertyInstance( + BindableProperty* bindableProperty) const +{ + auto bindablePropertyInstance = + m_bindablePropertyInstances.find(bindableProperty); + if (bindablePropertyInstance == m_bindablePropertyInstances.end()) + { + return nullptr; + } + return bindablePropertyInstance->second; +} + +DataBind* StateMachineInstance::bindableDataBindToSource( + BindableProperty* bindableProperty) const +{ + auto dataBind = m_bindableDataBindsToSource.find(bindableProperty); + if (dataBind == m_bindableDataBindsToSource.end()) + { + return nullptr; + } + return dataBind->second; +} + +DataBind* StateMachineInstance::bindableDataBindToTarget( + BindableProperty* bindableProperty) const +{ + auto dataBind = m_bindableDataBindsToTarget.find(bindableProperty); + if (dataBind == m_bindableDataBindsToTarget.end()) + { + return nullptr; + } + return dataBind->second; +} diff --git a/third_party/rive/source/animation/state_machine_layer.cpp b/third_party/rive/source/animation/state_machine_layer.cpp new file mode 100644 index 0000000..594e78d --- /dev/null +++ b/third_party/rive/source/animation/state_machine_layer.cpp @@ -0,0 +1,80 @@ +#include "rive/animation/state_machine_layer.hpp" +#include "rive/importers/import_stack.hpp" +#include "rive/importers/state_machine_importer.hpp" +#include "rive/generated/animation/state_machine_base.hpp" +#include "rive/animation/any_state.hpp" +#include "rive/animation/entry_state.hpp" +#include "rive/animation/exit_state.hpp" + +using namespace rive; + +StateMachineLayer::~StateMachineLayer() +{ + for (auto state : m_States) + { + delete state; + } +} + +StatusCode StateMachineLayer::onAddedDirty(CoreContext* context) +{ + StatusCode code; + for (auto state : m_States) + { + if ((code = state->onAddedDirty(context)) != StatusCode::Ok) + { + return code; + } + switch (state->coreType()) + { + case AnyState::typeKey: + m_Any = state->as(); + break; + case EntryState::typeKey: + m_Entry = state->as(); + break; + case ExitState::typeKey: + m_Exit = state->as(); + break; + } + } + if (m_Any == nullptr || m_Entry == nullptr || m_Exit == nullptr) + { + // The layer is corrupt, we must have all three of these states. + return StatusCode::InvalidObject; + } + + return StatusCode::Ok; +} + +StatusCode StateMachineLayer::onAddedClean(CoreContext* context) +{ + StatusCode code; + for (auto state : m_States) + { + if ((code = state->onAddedClean(context)) != StatusCode::Ok) + { + return code; + } + } + + return StatusCode::Ok; +} + +void StateMachineLayer::addState(LayerState* state) +{ + m_States.push_back(state); +} + +StatusCode StateMachineLayer::import(ImportStack& importStack) +{ + auto stateMachineImporter = + importStack.latest(StateMachineBase::typeKey); + if (stateMachineImporter == nullptr) + { + return StatusCode::MissingObject; + } + // WOW -- we're handing off ownership of this! + stateMachineImporter->addLayer(std::unique_ptr(this)); + return Super::import(importStack); +} diff --git a/third_party/rive/source/animation/state_machine_listener.cpp b/third_party/rive/source/animation/state_machine_listener.cpp new file mode 100644 index 0000000..bc7cbaa --- /dev/null +++ b/third_party/rive/source/animation/state_machine_listener.cpp @@ -0,0 +1,52 @@ +#include "rive/animation/state_machine_listener.hpp" +#include "rive/importers/import_stack.hpp" +#include "rive/importers/state_machine_importer.hpp" +#include "rive/generated/animation/state_machine_base.hpp" +#include "rive/artboard.hpp" +#include "rive/shapes/shape.hpp" +#include "rive/animation/state_machine_instance.hpp" +#include "rive/animation/listener_input_change.hpp" + +using namespace rive; + +StateMachineListener::StateMachineListener() {} +StateMachineListener::~StateMachineListener() {} + +void StateMachineListener::addAction(std::unique_ptr action) +{ + m_actions.push_back(std::move(action)); +} + +StatusCode StateMachineListener::import(ImportStack& importStack) +{ + auto stateMachineImporter = + importStack.latest(StateMachineBase::typeKey); + if (stateMachineImporter == nullptr) + { + return StatusCode::MissingObject; + } + // Handing off ownership of this! + stateMachineImporter->addListener( + std::unique_ptr(this)); + return Super::import(importStack); +} + +const ListenerAction* StateMachineListener::action(size_t index) const +{ + if (index < m_actions.size()) + { + return m_actions[index].get(); + } + return nullptr; +} + +void StateMachineListener::performChanges( + StateMachineInstance* stateMachineInstance, + Vec2D position, + Vec2D previousPosition) const +{ + for (auto& action : m_actions) + { + action->perform(stateMachineInstance, position, previousPosition); + } +} \ No newline at end of file diff --git a/third_party/rive/source/animation/state_transition.cpp b/third_party/rive/source/animation/state_transition.cpp new file mode 100644 index 0000000..bdcdf0a --- /dev/null +++ b/third_party/rive/source/animation/state_transition.cpp @@ -0,0 +1,231 @@ +#include "rive/animation/animation_state_instance.hpp" +#include "rive/animation/animation_state.hpp" +#include "rive/animation/cubic_interpolator.hpp" +#include "rive/animation/layer_state.hpp" +#include "rive/animation/linear_animation.hpp" +#include "rive/animation/state_machine_input_instance.hpp" +#include "rive/animation/state_machine_trigger.hpp" +#include "rive/animation/state_transition.hpp" +#include "rive/animation/transition_condition.hpp" +#include "rive/animation/transition_trigger_condition.hpp" +#include "rive/animation/transition_input_condition.hpp" +#include "rive/animation/transition_viewmodel_condition.hpp" +#include "rive/animation/state_machine_instance.hpp" +#include "rive/animation/transition_property_viewmodel_comparator.hpp" +#include "rive/importers/import_stack.hpp" +#include "rive/importers/layer_state_importer.hpp" + +using namespace rive; + +StateTransition::~StateTransition() +{ + for (auto condition : m_Conditions) + { + delete condition; + } +} + +StatusCode StateTransition::onAddedDirty(CoreContext* context) +{ + StatusCode code; + + if (interpolatorId() != -1) + { + auto coreObject = context->resolve(interpolatorId()); + if (coreObject == nullptr || !coreObject->is()) + { + return StatusCode::MissingObject; + } + m_Interpolator = coreObject->as(); + } + + for (auto condition : m_Conditions) + { + if ((code = condition->onAddedDirty(context)) != StatusCode::Ok) + { + return code; + } + } + return StatusCode::Ok; +} + +StatusCode StateTransition::onAddedClean(CoreContext* context) +{ + StatusCode code; + for (auto condition : m_Conditions) + { + if ((code = condition->onAddedClean(context)) != StatusCode::Ok) + { + return code; + } + } + return StatusCode::Ok; +} + +StatusCode StateTransition::import(ImportStack& importStack) +{ + auto stateImporter = + importStack.latest(LayerState::typeKey); + if (stateImporter == nullptr) + { + return StatusCode::MissingObject; + } + stateImporter->addTransition(this); + return Super::import(importStack); +} + +void StateTransition::addCondition(TransitionCondition* condition) +{ + m_Conditions.push_back(condition); +} + +float StateTransition::mixTime(const LayerState* stateFrom) const +{ + if (duration() == 0) + { + return 0; + } + if ((transitionFlags() & StateTransitionFlags::DurationIsPercentage) == + StateTransitionFlags::DurationIsPercentage) + { + float animationDuration = 0.0f; + if (stateFrom->is()) + { + auto animation = stateFrom->as()->animation(); + if (animation != nullptr) + { + animationDuration = animation->durationSeconds(); + } + } + return (float)duration() / 100.0f * animationDuration; + } + else + { + return (float)duration() / 1000.0f; + } +} + +float StateTransition::exitTimeSeconds(const LayerState* stateFrom, + bool absolute) const +{ + if ((transitionFlags() & StateTransitionFlags::ExitTimeIsPercentage) == + StateTransitionFlags::ExitTimeIsPercentage) + { + float animationDuration = 0.0f; + float start = 0.0f; + + auto exitAnimation = exitTimeAnimation(stateFrom); + if (exitAnimation != nullptr) + { + // TODO: needs a looking for speed + start = absolute ? exitAnimation->startSeconds() : 0.0f; + animationDuration = exitAnimation->durationSeconds(); + } + + return start + (float)exitTime() / 100.0f * animationDuration; + } + return (float)exitTime() / 1000.0f; +} + +const LinearAnimationInstance* StateTransition::exitTimeAnimationInstance( + const StateInstance* from) const +{ + return from != nullptr && from->state()->is() + ? static_cast(from) + ->animationInstance() + : nullptr; +} + +const LinearAnimation* StateTransition::exitTimeAnimation( + const LayerState* from) const +{ + return from != nullptr && from->is() + ? from->as()->animation() + : nullptr; +} + +AllowTransition StateTransition::allowed( + StateInstance* stateFrom, + StateMachineInstance* stateMachineInstance, + StateMachineLayerInstance* layerInstance) const +{ + if (isDisabled()) + { + return AllowTransition::no; + } + + for (auto condition : m_Conditions) + { + if (!condition->evaluate(stateMachineInstance, layerInstance)) + { + return AllowTransition::no; + } + } + + if (enableExitTime()) + { + auto exitAnimation = exitTimeAnimationInstance(stateFrom); + if (exitAnimation != nullptr) + { + // Exit time is specified in a value less than a single loop, so we + // want to allow exiting regardless of which loop we're on. To do + // that we bring the exit time up to the loop our lastTime is at. + auto lastTime = exitAnimation->lastTotalTime(); + auto time = exitAnimation->totalTime(); + auto exitTime = exitTimeSeconds(stateFrom->state()); + auto animationFrom = exitAnimation->animation(); + auto duration = animationFrom->durationSeconds(); + + // TODO: there are some considerations to have when exit time is + // combined with another condition (like trigger) + // - not sure how to get this to make sense with pingPing + // animations + // - also if exit time is, say 50% on a loop, this will be happy + // to fire + // - when time is anywhere in 50%-100%, 150%-200%. as opposed + // to just at 50% + // .... makes you wonder if we need some kind of exit + // after/exit before time + // .... but i suspect that will introduce some more issues? + + // There's only one iteration in oneShot, + if (exitTime <= duration && animationFrom->loop() != Loop::oneShot) + { + // Get exit time relative to the loop lastTime was in. + exitTime += std::floor(lastTime / duration) * duration; + } + + // TODO: needs a looking for speed + if (time < exitTime) + { + return AllowTransition::waitingForExit; + } + } + } + return AllowTransition::yes; +} + +bool StateTransition::applyExitCondition(StateInstance* from) const +{ + // Hold exit time when the user has set to pauseOnExit on this condition + // (only valid when exiting from an Animation). + bool useExitTime = enableExitTime() && + (from != nullptr && from->state()->is()); + if (pauseOnExit() && useExitTime) + { + static_cast(from)->animationInstance()->time( + exitTimeSeconds(from->state(), true)); + return true; + } + return useExitTime; +} + +void StateTransition::useLayerInConditions( + StateMachineInstance* stateMachineInstance, + StateMachineLayerInstance* layerInstance) const +{ + for (auto condition : m_Conditions) + { + condition->useInLayer(stateMachineInstance, layerInstance); + } +} \ No newline at end of file diff --git a/third_party/rive/source/animation/system_state_instance.cpp b/third_party/rive/source/animation/system_state_instance.cpp new file mode 100644 index 0000000..01cdcc7 --- /dev/null +++ b/third_party/rive/source/animation/system_state_instance.cpp @@ -0,0 +1,14 @@ +#include "rive/animation/system_state_instance.hpp" +using namespace rive; + +SystemStateInstance::SystemStateInstance(const LayerState* layerState, + ArtboardInstance* instance) : + StateInstance(layerState) +{} + +void SystemStateInstance::advance(float seconds, + StateMachineInstance* stateMachineInstance) +{} +void SystemStateInstance::apply(ArtboardInstance* artboard, float mix) {} + +bool SystemStateInstance::keepGoing() const { return false; } \ No newline at end of file diff --git a/third_party/rive/source/animation/transition_bool_condition.cpp b/third_party/rive/source/animation/transition_bool_condition.cpp new file mode 100644 index 0000000..aeebf23 --- /dev/null +++ b/third_party/rive/source/animation/transition_bool_condition.cpp @@ -0,0 +1,30 @@ +#include "rive/animation/transition_bool_condition.hpp" +#include "rive/animation/state_machine_input_instance.hpp" +#include "rive/animation/state_machine_bool.hpp" +#include "rive/animation/transition_condition_op.hpp" + +using namespace rive; + +bool TransitionBoolCondition::validateInputType( + const StateMachineInput* input) const +{ + // A null input is valid as the StateMachine can attempt to limp along if we + // introduce new input types that old conditions are expected to handle in + // newer runtimes. The older runtimes will just evaluate them to true. + return input == nullptr || input->is(); +} + +bool TransitionBoolCondition::evaluate( + const StateMachineInstance* stateMachineInstance, + StateMachineLayerInstance* layerInstance) const +{ + auto inputInstance = stateMachineInstance->input(inputId()); + if (inputInstance == nullptr) + { + return true; + } + auto boolInput = static_cast(inputInstance); + + return (boolInput->value() && op() == TransitionConditionOp::equal) || + (!boolInput->value() && op() == TransitionConditionOp::notEqual); +} diff --git a/third_party/rive/source/animation/transition_comparator.cpp b/third_party/rive/source/animation/transition_comparator.cpp new file mode 100644 index 0000000..b908a0a --- /dev/null +++ b/third_party/rive/source/animation/transition_comparator.cpp @@ -0,0 +1,134 @@ +#include "rive/animation/transition_comparator.hpp" +#include "rive/animation/transition_viewmodel_condition.hpp" +#include "rive/animation/state_machine_instance.hpp" +#include "rive/importers/transition_viewmodel_condition_importer.hpp" + +using namespace rive; + +StatusCode TransitionComparator::import(ImportStack& importStack) +{ + auto transitionViewModelConditionImporter = + importStack.latest( + TransitionViewModelCondition::typeKey); + if (transitionViewModelConditionImporter == nullptr) + { + return StatusCode::MissingObject; + } + transitionViewModelConditionImporter->setComparator(this); + return Super::import(importStack); +} + +bool TransitionComparator::compareNumbers(float left, + float right, + TransitionConditionOp op) +{ + switch (op) + { + case TransitionConditionOp::equal: + return left == right; + case TransitionConditionOp::notEqual: + return left != right; + case TransitionConditionOp::lessThanOrEqual: + return left <= right; + case TransitionConditionOp::lessThan: + return left < right; + case TransitionConditionOp::greaterThanOrEqual: + return left >= right; + case TransitionConditionOp::greaterThan: + return left > right; + default: + return false; + } +} + +bool TransitionComparator::compareStrings(std::string left, + std::string right, + TransitionConditionOp op) +{ + switch (op) + { + case TransitionConditionOp::equal: + return left == right; + case TransitionConditionOp::notEqual: + return left != right; + default: + return false; + } +} + +bool TransitionComparator::compareBooleans(bool left, + bool right, + TransitionConditionOp op) +{ + switch (op) + { + case TransitionConditionOp::equal: + return left == right; + case TransitionConditionOp::notEqual: + return left != right; + default: + return false; + } +} + +bool TransitionComparator::compareEnums(uint16_t left, + uint16_t right, + TransitionConditionOp op) +{ + switch (op) + { + case TransitionConditionOp::equal: + return left == right; + case TransitionConditionOp::notEqual: + return left != right; + default: + return false; + } +} + +bool TransitionComparator::compareTriggers(uint32_t left, + uint32_t right, + TransitionConditionOp op) +{ + switch (op) + { + case TransitionConditionOp::equal: + return left == right; + case TransitionConditionOp::notEqual: + return left != right; + case TransitionConditionOp::lessThanOrEqual: + return left <= right; + case TransitionConditionOp::lessThan: + return left < right; + case TransitionConditionOp::greaterThanOrEqual: + return left >= right; + case TransitionConditionOp::greaterThan: + return left > right; + default: + return false; + } +} + +bool TransitionComparator::compareColors(int left, + int right, + TransitionConditionOp op) +{ + switch (op) + { + case TransitionConditionOp::equal: + return left == right; + case TransitionConditionOp::notEqual: + return left != right; + default: + return false; + } +} + +bool TransitionComparator::compare( + TransitionComparator* comparand, + TransitionConditionOp operation, + const StateMachineInstance* stateMachineInstance, + StateMachineLayerInstance* layerInstance) +{ + return false; +} \ No newline at end of file diff --git a/third_party/rive/source/animation/transition_condition.cpp b/third_party/rive/source/animation/transition_condition.cpp new file mode 100644 index 0000000..0a990d2 --- /dev/null +++ b/third_party/rive/source/animation/transition_condition.cpp @@ -0,0 +1,27 @@ +#include "rive/animation/transition_condition.hpp" +#include "rive/animation/state_transition.hpp" +#include "rive/importers/state_transition_importer.hpp" + +using namespace rive; + +StatusCode TransitionCondition::onAddedDirty(CoreContext* context) +{ + return StatusCode::Ok; +} + +StatusCode TransitionCondition::onAddedClean(CoreContext* context) +{ + return StatusCode::Ok; +} + +StatusCode TransitionCondition::import(ImportStack& importStack) +{ + auto transitionImporter = + importStack.latest(StateTransition::typeKey); + if (transitionImporter == nullptr) + { + return StatusCode::MissingObject; + } + transitionImporter->addCondition(this); + return Super::import(importStack); +} diff --git a/third_party/rive/source/animation/transition_input_condition.cpp b/third_party/rive/source/animation/transition_input_condition.cpp new file mode 100644 index 0000000..7d149b7 --- /dev/null +++ b/third_party/rive/source/animation/transition_input_condition.cpp @@ -0,0 +1,28 @@ +#include "rive/animation/transition_input_condition.hpp" +#include "rive/importers/state_machine_importer.hpp" +#include "rive/animation/state_machine.hpp" + +using namespace rive; + +StatusCode TransitionInputCondition::import(ImportStack& importStack) +{ + auto stateMachineImporter = + importStack.latest(StateMachine::typeKey); + if (stateMachineImporter == nullptr) + { + return StatusCode::MissingObject; + } + + // Make sure the inputId doesn't overflow the input buffer. + if ((size_t)inputId() >= stateMachineImporter->stateMachine()->inputCount()) + { + return StatusCode::InvalidObject; + } + if (!validateInputType( + stateMachineImporter->stateMachine()->input((size_t)inputId()))) + { + return StatusCode::InvalidObject; + } + + return Super::import(importStack); +} \ No newline at end of file diff --git a/third_party/rive/source/animation/transition_number_condition.cpp b/third_party/rive/source/animation/transition_number_condition.cpp new file mode 100644 index 0000000..be3aa85 --- /dev/null +++ b/third_party/rive/source/animation/transition_number_condition.cpp @@ -0,0 +1,44 @@ +#include "rive/animation/transition_number_condition.hpp" +#include "rive/animation/state_machine_input_instance.hpp" +#include "rive/animation/state_machine_number.hpp" +#include "rive/animation/transition_condition_op.hpp" + +using namespace rive; + +bool TransitionNumberCondition::validateInputType( + const StateMachineInput* input) const +{ + // A null input is valid as the StateMachine can attempt to limp along if we + // introduce new input types that old conditions are expected to handle in + // newer runtimes. The older runtimes will just evaluate them to true. + return input == nullptr || input->is(); +} + +bool TransitionNumberCondition::evaluate( + const StateMachineInstance* stateMachineInstance, + StateMachineLayerInstance* layerInstance) const +{ + auto inputInstance = stateMachineInstance->input(inputId()); + if (inputInstance == nullptr) + { + return true; + } + auto numberInput = static_cast(inputInstance); + + switch (op()) + { + case TransitionConditionOp::equal: + return numberInput->value() == value(); + case TransitionConditionOp::notEqual: + return numberInput->value() != value(); + case TransitionConditionOp::lessThanOrEqual: + return numberInput->value() <= value(); + case TransitionConditionOp::lessThan: + return numberInput->value() < value(); + case TransitionConditionOp::greaterThanOrEqual: + return numberInput->value() >= value(); + case TransitionConditionOp::greaterThan: + return numberInput->value() > value(); + } + return false; +} diff --git a/third_party/rive/source/animation/transition_property_artboard_comparator.cpp b/third_party/rive/source/animation/transition_property_artboard_comparator.cpp new file mode 100644 index 0000000..1b0d14c --- /dev/null +++ b/third_party/rive/source/animation/transition_property_artboard_comparator.cpp @@ -0,0 +1,58 @@ +#include "rive/animation/transition_property_artboard_comparator.hpp" +#include "rive/animation/transition_property_viewmodel_comparator.hpp" +#include "rive/animation/transition_value_number_comparator.hpp" +#include "rive/animation/artboard_property.hpp" +#include "rive/animation/state_machine_instance.hpp" +#include "rive/data_bind/bindable_property_number.hpp" + +using namespace rive; + +float TransitionPropertyArtboardComparator::propertyValue( + const StateMachineInstance* stateMachineInstance) +{ + auto artboard = stateMachineInstance->artboard(); + if (artboard != nullptr) + { + + auto property = static_cast(propertyType()); + switch (property) + { + case ArtboardProperty::width: + return artboard->layoutWidth(); + break; + case ArtboardProperty::height: + return artboard->layoutHeight(); + break; + case ArtboardProperty::ratio: + return artboard->layoutWidth() / artboard->layoutHeight(); + break; + + default: + break; + } + } + return 0; +} + +bool TransitionPropertyArtboardComparator::compare( + TransitionComparator* comparand, + TransitionConditionOp operation, + const StateMachineInstance* stateMachineInstance, + StateMachineLayerInstance* layerInstance) +{ + auto value = propertyValue(stateMachineInstance); + if (comparand->is()) + { + auto rightValue = + comparand->as() + ->value(stateMachineInstance); + return compareNumbers(value, rightValue, operation); + } + else if (comparand->is()) + { + auto rightValue = + comparand->as()->value(); + return compareNumbers(value, rightValue, operation); + } + return false; +} \ No newline at end of file diff --git a/third_party/rive/source/animation/transition_property_comparator.cpp b/third_party/rive/source/animation/transition_property_comparator.cpp new file mode 100644 index 0000000..05d25ae --- /dev/null +++ b/third_party/rive/source/animation/transition_property_comparator.cpp @@ -0,0 +1,3 @@ +#include "rive/animation/transition_property_comparator.hpp" + +using namespace rive; \ No newline at end of file diff --git a/third_party/rive/source/animation/transition_property_viewmodel_comparator.cpp b/third_party/rive/source/animation/transition_property_viewmodel_comparator.cpp new file mode 100644 index 0000000..2e28f65 --- /dev/null +++ b/third_party/rive/source/animation/transition_property_viewmodel_comparator.cpp @@ -0,0 +1,311 @@ +#include "rive/animation/transition_property_viewmodel_comparator.hpp" +#include "rive/animation/transition_value_number_comparator.hpp" +#include "rive/animation/transition_value_string_comparator.hpp" +#include "rive/animation/transition_value_color_comparator.hpp" +#include "rive/animation/transition_value_boolean_comparator.hpp" +#include "rive/animation/transition_value_enum_comparator.hpp" +#include "rive/animation/transition_value_trigger_comparator.hpp" +#include "rive/animation/state_machine_instance.hpp" +#include "rive/importers/bindable_property_importer.hpp" +#include "rive/data_bind/bindable_property_number.hpp" +#include "rive/data_bind/bindable_property_string.hpp" +#include "rive/data_bind/bindable_property_color.hpp" +#include "rive/data_bind/bindable_property_enum.hpp" +#include "rive/data_bind/bindable_property_integer.hpp" +#include "rive/data_bind/bindable_property_boolean.hpp" +#include "rive/data_bind/bindable_property_trigger.hpp" +#include "rive/viewmodel/viewmodel_instance_trigger.hpp" + +using namespace rive; + +TransitionPropertyViewModelComparator::~TransitionPropertyViewModelComparator() +{ + if (m_bindableProperty != nullptr) + { + delete m_bindableProperty; + m_bindableProperty = nullptr; + } +} + +StatusCode TransitionPropertyViewModelComparator::import( + ImportStack& importStack) +{ + auto bindablePropertyImporter = + importStack.latest( + BindablePropertyBase::typeKey); + if (bindablePropertyImporter == nullptr) + { + return StatusCode::MissingObject; + } + m_bindableProperty = bindablePropertyImporter->bindableProperty(); + + return Super::import(importStack); +} + +float TransitionPropertyViewModelComparator::valueToFloat( + const StateMachineInstance* stateMachineInstance) +{ + auto bindableInstance = + stateMachineInstance->bindablePropertyInstance(m_bindableProperty); + if (bindableInstance != nullptr) + { + if (bindableInstance->is()) + { + return (float)this->value( + stateMachineInstance); + } + else if (bindableInstance->is()) + { + return this->value( + stateMachineInstance); + } + } + return 0; +} + +bool TransitionPropertyViewModelComparator::compare( + TransitionComparator* comparand, + TransitionConditionOp operation, + const StateMachineInstance* stateMachineInstance, + StateMachineLayerInstance* layerInstance) +{ + switch (m_bindableProperty->coreType()) + { + case BindablePropertyNumber::typeKey: + if (comparand->is()) + { + auto rightValue = + comparand->as() + ->valueToFloat(stateMachineInstance); + return compareNumbers(valueToFloat(stateMachineInstance), + rightValue, + operation); + } + else if (comparand->is()) + { + auto rightValue = + comparand->as()->value(); + return compareNumbers(valueToFloat(stateMachineInstance), + rightValue, + operation); + } + break; + case BindablePropertyString::typeKey: + if (comparand->is()) + { + auto rightValue = + comparand->as() + ->value( + stateMachineInstance); + return compareStrings( + value( + stateMachineInstance), + rightValue, + operation); + } + else if (comparand->is()) + { + auto rightValue = + comparand->as()->value(); + return compareStrings( + value( + stateMachineInstance), + rightValue, + operation); + } + break; + case BindablePropertyColor::typeKey: + if (comparand->is()) + { + auto rightValue = + comparand->as() + ->value( + stateMachineInstance); + return compareColors( + value(stateMachineInstance), + rightValue, + operation); + } + else if (comparand->is()) + { + auto rightValue = + comparand->as()->value(); + return compareColors( + value(stateMachineInstance), + rightValue, + operation); + } + break; + case BindablePropertyBoolean::typeKey: + if (comparand->is()) + { + auto rightValue = + comparand->as() + ->value( + stateMachineInstance); + return compareBooleans( + value(stateMachineInstance), + rightValue, + operation); + } + else if (comparand->is()) + { + auto rightValue = + comparand->as()->value(); + return compareBooleans( + value(stateMachineInstance), + rightValue, + operation); + } + break; + case BindablePropertyEnum::typeKey: + if (comparand->is()) + { + auto rightValue = + comparand->as() + ->value( + stateMachineInstance); + return compareEnums( + value(stateMachineInstance), + rightValue, + operation); + } + else if (comparand->is()) + { + auto rightValue = + comparand->as()->value(); + return compareEnums( + value(stateMachineInstance), + rightValue, + operation); + } + break; + case BindablePropertyTrigger::typeKey: + if (comparand->is()) + { + auto rightValue = + comparand->as() + ->value( + stateMachineInstance); + return compareTriggers(value( + stateMachineInstance), + rightValue, + operation); + } + else if (comparand->is()) + { + auto bindableInstance = + stateMachineInstance->bindablePropertyInstance( + m_bindableProperty); + auto dataBind = stateMachineInstance->bindableDataBindToTarget( + bindableInstance); + if (dataBind != nullptr) + { + auto source = dataBind->source(); + if (source != nullptr && + source->is()) + { + if (source->as() + ->isUsedInLayer(layerInstance)) + { + + return false; + } + } + } + auto leftValue = value( + stateMachineInstance); + if (leftValue != 0) + { + return true; + } + } + break; + case BindablePropertyInteger::typeKey: + if (comparand->is()) + { + auto rightValue = + comparand->as() + ->valueToFloat(stateMachineInstance); + return compareNumbers(valueToFloat(stateMachineInstance), + rightValue, + operation); + } + else if (comparand->is()) + { + auto rightValue = + comparand->as()->value(); + switch (instanceDataType(stateMachineInstance)) + { + case DataType::number: + return compareNumbers( + valueToFloat(stateMachineInstance), + rightValue, + operation); + case DataType::integer: + { + + auto val = value( + stateMachineInstance); + return compareNumbers((float)val, + rightValue, + operation); + } + default: + break; + } + } + break; + } + return false; +} + +void TransitionPropertyViewModelComparator::useInLayer( + const StateMachineInstance* stateMachineInstance, + StateMachineLayerInstance* layerInstance) const +{ + + auto bindableInstance = + stateMachineInstance->bindablePropertyInstance(m_bindableProperty); + if (bindableInstance == nullptr) + { + return; + } + auto dataBind = + stateMachineInstance->bindableDataBindToTarget(bindableInstance); + auto source = dataBind->source(); + if (source != nullptr && source->is()) + { + source->as()->useInLayer(layerInstance); + } +} + +DataType TransitionPropertyViewModelComparator::instanceDataType( + const StateMachineInstance* stateMachineInstance) +{ + auto bindableInstance = + stateMachineInstance->bindablePropertyInstance(m_bindableProperty); + if (bindableInstance != nullptr) + { + + switch (bindableInstance->coreType()) + { + case BindablePropertyNumberBase::typeKey: + + return DataType::number; + case BindablePropertyBooleanBase::typeKey: + return DataType::boolean; + case BindablePropertyColorBase::typeKey: + return DataType::color; + case BindablePropertyStringBase::typeKey: + return DataType::string; + case BindablePropertyEnumBase::typeKey: + return DataType::enumType; + case BindablePropertyTriggerBase::typeKey: + return DataType::trigger; + case BindablePropertyIntegerBase::typeKey: + return DataType::integer; + } + } + return DataType::none; +} \ No newline at end of file diff --git a/third_party/rive/source/animation/transition_trigger_condition.cpp b/third_party/rive/source/animation/transition_trigger_condition.cpp new file mode 100644 index 0000000..c60458c --- /dev/null +++ b/third_party/rive/source/animation/transition_trigger_condition.cpp @@ -0,0 +1,48 @@ +#include "rive/animation/transition_trigger_condition.hpp" +#include "rive/animation/state_machine_input_instance.hpp" +#include "rive/animation/state_machine_trigger.hpp" +#include "rive/animation/transition_condition_op.hpp" + +using namespace rive; + +bool TransitionTriggerCondition::validateInputType( + const StateMachineInput* input) const +{ + // A null input is valid as the StateMachine can attempt to limp along if we + // introduce new input types that old conditions are expected to handle in + // newer runtimes. The older runtimes will just evaluate them to true. + return input == nullptr || input->is(); +} + +bool TransitionTriggerCondition::evaluate( + const StateMachineInstance* stateMachineInstance, + StateMachineLayerInstance* layerInstance) const +{ + + auto inputInstance = stateMachineInstance->input(inputId()); + if (inputInstance == nullptr) + { + return true; + } + auto triggerInput = static_cast(inputInstance); + + if (triggerInput->m_fired && !triggerInput->isUsedInLayer(layerInstance)) + { + return true; + } + return false; +} + +void TransitionTriggerCondition::useInLayer( + const StateMachineInstance* stateMachineInstance, + StateMachineLayerInstance* layerInstance) const +{ + + auto inputInstance = stateMachineInstance->input(inputId()); + if (inputInstance == nullptr) + { + return; + } + auto triggerInput = static_cast(inputInstance); + triggerInput->useInLayer(layerInstance); +} diff --git a/third_party/rive/source/animation/transition_value_boolean_comparator.cpp b/third_party/rive/source/animation/transition_value_boolean_comparator.cpp new file mode 100644 index 0000000..7d54883 --- /dev/null +++ b/third_party/rive/source/animation/transition_value_boolean_comparator.cpp @@ -0,0 +1,19 @@ +#include "rive/animation/transition_value_boolean_comparator.hpp" + +using namespace rive; + +bool TransitionValueBooleanComparator::compare( + TransitionComparator* comparand, + TransitionConditionOp operation, + const StateMachineInstance* stateMachineInstance, + StateMachineLayerInstance* layerInstance) +{ + if (comparand->is()) + { + return compareBooleans( + value(), + comparand->as()->value(), + operation); + } + return false; +} \ No newline at end of file diff --git a/third_party/rive/source/animation/transition_value_color_comparator.cpp b/third_party/rive/source/animation/transition_value_color_comparator.cpp new file mode 100644 index 0000000..20ad28d --- /dev/null +++ b/third_party/rive/source/animation/transition_value_color_comparator.cpp @@ -0,0 +1,19 @@ +#include "rive/animation/transition_value_color_comparator.hpp" + +using namespace rive; + +bool TransitionValueColorComparator::compare( + TransitionComparator* comparand, + TransitionConditionOp operation, + const StateMachineInstance* stateMachineInstance, + StateMachineLayerInstance* layerInstance) +{ + if (comparand->is()) + { + return compareColors( + value(), + comparand->as()->value(), + operation); + } + return false; +} \ No newline at end of file diff --git a/third_party/rive/source/animation/transition_value_enum_comparator.cpp b/third_party/rive/source/animation/transition_value_enum_comparator.cpp new file mode 100644 index 0000000..8742e37 --- /dev/null +++ b/third_party/rive/source/animation/transition_value_enum_comparator.cpp @@ -0,0 +1,4 @@ +#include "rive/animation/transition_value_enum_comparator.hpp" +#include "rive/viewmodel/viewmodel_instance_enum.hpp" + +using namespace rive; \ No newline at end of file diff --git a/third_party/rive/source/animation/transition_value_number_comparator.cpp b/third_party/rive/source/animation/transition_value_number_comparator.cpp new file mode 100644 index 0000000..5f4aa10 --- /dev/null +++ b/third_party/rive/source/animation/transition_value_number_comparator.cpp @@ -0,0 +1,19 @@ +#include "rive/animation/transition_value_number_comparator.hpp" + +using namespace rive; + +bool TransitionValueNumberComparator::compare( + TransitionComparator* comparand, + TransitionConditionOp operation, + const StateMachineInstance* stateMachineInstance, + StateMachineLayerInstance* layerInstance) +{ + if (comparand->is()) + { + return compareNumbers( + value(), + comparand->as()->value(), + operation); + } + return false; +} \ No newline at end of file diff --git a/third_party/rive/source/animation/transition_value_string_comparator.cpp b/third_party/rive/source/animation/transition_value_string_comparator.cpp new file mode 100644 index 0000000..5b6e85e --- /dev/null +++ b/third_party/rive/source/animation/transition_value_string_comparator.cpp @@ -0,0 +1,19 @@ +#include "rive/animation/transition_value_string_comparator.hpp" + +using namespace rive; + +bool TransitionValueStringComparator::compare( + TransitionComparator* comparand, + TransitionConditionOp operation, + const StateMachineInstance* stateMachineInstance, + StateMachineLayerInstance* layerInstance) +{ + if (comparand->is()) + { + return compareStrings( + value(), + comparand->as()->value(), + operation); + } + return false; +} \ No newline at end of file diff --git a/third_party/rive/source/animation/transition_viewmodel_condition.cpp b/third_party/rive/source/animation/transition_viewmodel_condition.cpp new file mode 100644 index 0000000..ae564ff --- /dev/null +++ b/third_party/rive/source/animation/transition_viewmodel_condition.cpp @@ -0,0 +1,48 @@ +#include "rive/animation/transition_viewmodel_condition.hpp" +#include "rive/animation/state_transition.hpp" +#include "rive/importers/state_transition_importer.hpp" +#include "rive/importers/state_machine_importer.hpp" +#include "rive/animation/state_machine.hpp" +#include "rive/animation/state_machine_instance.hpp" +#include "rive/component_dirt.hpp" + +using namespace rive; + +TransitionViewModelCondition::~TransitionViewModelCondition() +{ + if (m_leftComparator != nullptr) + { + delete m_leftComparator; + m_leftComparator = nullptr; + } + if (m_rightComparator != nullptr) + { + delete m_rightComparator; + m_rightComparator = nullptr; + } +} + +bool TransitionViewModelCondition::evaluate( + const StateMachineInstance* stateMachineInstance, + StateMachineLayerInstance* layerInstance) const +{ + if (leftComparator() != nullptr && rightComparator() != nullptr) + { + return leftComparator()->compare(rightComparator(), + op(), + stateMachineInstance, + layerInstance); + } + return false; +} + +void TransitionViewModelCondition::useInLayer( + const StateMachineInstance* stateMachineInstance, + StateMachineLayerInstance* layerInstance) const +{ + if (leftComparator() != nullptr) + { + return leftComparator()->useInLayer(stateMachineInstance, + layerInstance); + } +} \ No newline at end of file diff --git a/third_party/rive/source/artboard.cpp b/third_party/rive/source/artboard.cpp new file mode 100644 index 0000000..1ec5a7b --- /dev/null +++ b/third_party/rive/source/artboard.cpp @@ -0,0 +1,1659 @@ +#include "rive/artboard.hpp" +#include "rive/artboard_component_list.hpp" +#include "rive/backboard.hpp" +#include "rive/animation/linear_animation_instance.hpp" +#include "rive/dependency_sorter.hpp" +#include "rive/data_bind/data_bind.hpp" +#include "rive/data_bind/data_bind_context.hpp" +#include "rive/draw_rules.hpp" +#include "rive/draw_target.hpp" +#include "rive/audio_event.hpp" +#include "rive/draw_target_placement.hpp" +#include "rive/drawable.hpp" +#include "rive/animation/keyed_object.hpp" +#include "rive/factory.hpp" +#include "rive/renderer.hpp" +#include "rive/shapes/paint/shape_paint.hpp" +#include "rive/importers/import_stack.hpp" +#include "rive/importers/backboard_importer.hpp" +#include "rive/layout_component.hpp" +#include "rive/foreground_layout_drawable.hpp" +#include "rive/nested_artboard.hpp" +#include "rive/nested_artboard_leaf.hpp" +#include "rive/nested_artboard_layout.hpp" +#include "rive/joystick.hpp" +#include "rive/data_bind_flags.hpp" +#include "rive/animation/nested_bool.hpp" +#include "rive/animation/nested_number.hpp" +#include "rive/animation/nested_trigger.hpp" +#include "rive/animation/state_machine_input_instance.hpp" +#include "rive/animation/state_machine_instance.hpp" +#include "rive/shapes/shape.hpp" +#include "rive/text/text_value_run.hpp" +#include "rive/event.hpp" +#include "rive/assets/audio_asset.hpp" +#include "rive/layout/layout_data.hpp" + +#include + +using namespace rive; + +Artboard::Artboard() +{ + // Artboards need to override default clip value to true. + m_Clip = true; +#ifdef WITH_RIVE_TOOLS + callbackUserData = this; +#endif +} + +Artboard::~Artboard() +{ +#ifdef WITH_RIVE_AUDIO +#ifdef EXTERNAL_RIVE_AUDIO_ENGINE + auto audioEngine = m_audioEngine; +#else + auto audioEngine = AudioEngine::RuntimeEngine(false); +#endif + if (audioEngine) + { + audioEngine->stop(this); + } +#endif + clearDataContext(); + for (auto object : m_Objects) + { + // First object is artboard + if (object == this) + { + continue; + } + delete object; + } + + for (auto dataBind : m_DataBinds) + { + delete dataBind; + } + + // Instances reference back to the original artboard's animations and state + // machines, so don't delete them here, they'll get cleaned up when the + // source is deleted. + // TODO: move this logic into ArtboardInstance destructor??? + if (!m_IsInstance) + { + for (auto object : m_Animations) + { + delete object; + } + for (auto object : m_StateMachines) + { + delete object; + } + } + m_dirtyLayout.clear(); + if (m_ownsDataContext && m_DataContext != nullptr) + { + delete m_DataContext; + m_DataContext = nullptr; + } +} + +static bool canContinue(StatusCode code) +{ + // We currently only cease loading on invalid object. + return code != StatusCode::InvalidObject; +} + +bool Artboard::validateObjects() +{ + auto size = m_Objects.size(); + std::vector valid(size); + + // Max iterations.. + for (int cycle = 0; cycle < 100; cycle++) + { + bool changed = false; + for (size_t i = 1; i < size; i++) + { + auto object = m_Objects[i]; + if (object == nullptr) + { + // objects can be null if they were not understood by this + // runtime. + continue; + } + bool wasValid = valid[i]; + bool isValid = object->validate(this); + if (wasValid != isValid) + { + changed = true; + valid[i] = isValid; + } + } + if (changed) + { + // Delete invalid objects. + for (size_t i = 1; i < size; i++) + { + if (valid[i]) + { + continue; + } + delete m_Objects[i]; + m_Objects[i] = nullptr; + } + } + else + { + break; + } + } + + return true; +} + +StatusCode Artboard::initialize() +{ + StatusCode code; + + // these will be re-built in update() -- are they needed here? + m_layout = Layout(0.0f, 0.0f, width(), height()); + +#ifdef WITH_RIVE_LAYOUT + markLayoutDirty(this); +#endif + // onAddedDirty guarantees that all objects are now available so they can be + // looked up by index/id. This is where nodes find their parents, but they + // can't assume that their parent's parent will have resolved yet. + for (auto object : m_Objects) + { + if (object == nullptr) + { + // objects can be null if they were not understood by this runtime. + continue; + } + if (!canContinue(code = object->onAddedDirty(this))) + { + return code; + } + } + + // Animations and StateMachines initialize only once on the source/origin + // Artboard. Instances will hold references to the original Animations and + // StateMachines, so running this code for instances will effectively + // initialize them twice. This can lead to unpredictable behaviour. One such + // example was that resolved objects like listener inputs were being added + // to lists twice. + if (!isInstance()) + { + for (auto object : m_Animations) + { + if (!canContinue(code = object->onAddedDirty(this))) + { + return code; + } + } + + for (auto object : m_StateMachines) + { + if (!canContinue(code = object->onAddedDirty(this))) + { + return code; + } + } + } + + // Store a map of the drawRules to make it easier to lookup the matching + // rule for a transform component. + std::unordered_map componentDrawRules; + + // onAddedClean is called when all individually referenced components have + // been found and so components can look at other components' references and + // assume that they have resolved too. This is where the whole hierarchy is + // linked up and we can traverse it to find other references (my parent's + // parent should be type X can be checked now). + for (auto object : m_Objects) + { + if (object == nullptr) + { + continue; + } + if (!canContinue(code = object->onAddedClean(this))) + { + return code; + } + switch (object->coreType()) + { + case DrawRulesBase::typeKey: + { + DrawRules* rules = static_cast(object); + Core* component = resolve(rules->parentId()); + if (component != nullptr) + { + componentDrawRules[component] = rules; + } + else + { + fprintf(stderr, + "Artboard::initialize - Draw rule targets missing " + "component width id %d\n", + rules->parentId()); + } + break; + } + case NestedArtboardBase::typeKey: + case NestedArtboardLeafBase::typeKey: + case NestedArtboardLayoutBase::typeKey: + { + m_NestedArtboards.push_back(object->as()); + m_ArtboardHosts.push_back(object->as()); + break; + } + case ArtboardComponentListBase::typeKey: + m_ComponentLists.push_back(object->as()); + m_ArtboardHosts.push_back(object->as()); + break; + case JoystickBase::typeKey: + { + Joystick* joystick = object->as(); + if (!joystick->canApplyBeforeUpdate()) + { + m_JoysticksApplyBeforeUpdate = false; + } + joystick->addDependents(this); + m_Joysticks.push_back(joystick); + break; + } + } + } + + if (!isInstance()) + { + for (auto object : m_Animations) + { + if (!canContinue(code = object->onAddedClean(this))) + { + return code; + } + } + + for (auto object : m_StateMachines) + { + if (!canContinue(code = object->onAddedClean(this))) + { + return code; + } + } + } + + // Multi-level references have been built up, now we can + // actually mark what's dependent on what. + for (auto object : m_Objects) + { + if (object == nullptr) + { + continue; + } + if (object->is()) + { + object->as()->buildDependencies(); + } + if (object->is() && object != this) + { + Drawable* drawable = object->as(); + m_Drawables.push_back(drawable); + // Move the foreground drawable before its parent. We traverse the + // added list of drawables and swap their positions with the + // foreground drawable until we find the parent + if (drawable->is()) + { + auto parent = drawable->parent(); + auto index = m_Drawables.size() - 1; + while (index >= 1) + { + auto swappingDrawable = m_Drawables[index - 1]; + std::swap(m_Drawables[index - 1], m_Drawables[index]); + if (swappingDrawable == parent) + { + break; + } + index--; + } + } + + for (ContainerComponent* parent = drawable; parent != nullptr; + parent = parent->parent()) + { + auto itr = componentDrawRules.find(parent); + if (itr != componentDrawRules.end()) + { + drawable->flattenedDrawRules = itr->second; + break; + } + } + } + } + // Iterate over the drawables in order to inject proxies for layouts + std::vector layouts; + for (int i = 0; i < m_Drawables.size(); i++) + { + auto drawable = m_Drawables[i]; + LayoutComponent* currentLayout = nullptr; + bool isInCurrentLayout = true; + if (!layouts.empty()) + { + currentLayout = layouts.back(); + isInCurrentLayout = drawable->isChildOfLayout(currentLayout); + } + // We inject a DrawableProxy after all of the children of a + // LayoutComponent so that we can draw a stroke above and background + // below the children This also allows us to clip the children + if (currentLayout != nullptr && !isInCurrentLayout) + { + // This is the first item in the list of drawables that isn't a + // child of the layout, so we insert a proxy before it + do + { + m_Drawables.insert(m_Drawables.begin() + i, + currentLayout->proxy()); + i += 1; + layouts.pop_back(); + if (!layouts.empty()) + { + currentLayout = layouts.back(); + } + } while (!layouts.empty() && + !drawable->isChildOfLayout(currentLayout)); + } + if (drawable->is()) + { + layouts.push_back(drawable->as()); + } + } + while (!layouts.empty()) + { + auto layout = layouts.back(); + m_Drawables.push_back(layout->proxy()); + layouts.pop_back(); + } + + sortDependencies(); + + std::vector rulesList; + // Build the rules in the right order. We use the map componentDrawRules + // to make sure we traverse the objects in the right order from parent + // to child, and add the rules accordingly. + for (auto object : m_Objects) + { + if (object == nullptr) + { + continue; + } + auto itr = componentDrawRules.find(object); + if (itr != componentDrawRules.end()) + { + rulesList.emplace_back(componentDrawRules[object]); + } + } + DrawTarget root; + // Build up the draw order. Look for draw targets and build + // their dependencies. + for (auto rules : rulesList) + { + for (auto child : rules->children()) + { + auto target = child->as(); + root.addDependent(target); + auto dependentRules = target->drawable()->flattenedDrawRules; + if (dependentRules != nullptr) + { + // Because we don't store targets on rules, we need + // to find the targets that belong to this rule + // here. + for (auto object : m_Objects) + { + if (object != nullptr && object->is()) + { + DrawTarget* dependentTarget = object->as(); + if (dependentTarget->parent() == dependentRules) + { + dependentTarget->addDependent(target); + } + } + } + } + } + } + DependencySorter sorter; + std::vector drawTargetOrder; + sorter.sort(&root, drawTargetOrder); + auto itr = drawTargetOrder.begin(); + itr++; + while (itr != drawTargetOrder.end()) + { + m_DrawTargets.push_back(static_cast(*itr++)); + } + return StatusCode::Ok; +} + +void Artboard::sortDrawOrder() +{ + m_drawOrderChangeCounter = + m_drawOrderChangeCounter == std::numeric_limits::max() + ? 0 + : m_drawOrderChangeCounter + 1; + for (auto target : m_DrawTargets) + { + target->first = target->last = nullptr; + } + + m_FirstDrawable = nullptr; + Drawable* lastDrawable = nullptr; + for (auto drawable : m_Drawables) + { + auto rules = drawable->flattenedDrawRules; + if (rules != nullptr && rules->activeTarget() != nullptr) + { + + auto target = rules->activeTarget(); + if (target->first == nullptr) + { + target->first = target->last = drawable; + drawable->prev = drawable->next = nullptr; + } + else + { + target->last->next = drawable; + drawable->prev = target->last; + target->last = drawable; + drawable->next = nullptr; + } + } + else + { + drawable->prev = lastDrawable; + drawable->next = nullptr; + if (lastDrawable == nullptr) + { + lastDrawable = m_FirstDrawable = drawable; + } + else + { + lastDrawable->next = drawable; + lastDrawable = drawable; + } + } + } + + for (auto rule : m_DrawTargets) + { + if (rule->first == nullptr) + { + continue; + } + auto targetDrawable = rule->drawable(); + switch (rule->placement()) + { + case DrawTargetPlacement::before: + { + if (targetDrawable->prev != nullptr) + { + targetDrawable->prev->next = rule->first; + rule->first->prev = targetDrawable->prev; + } + if (targetDrawable == m_FirstDrawable) + { + m_FirstDrawable = rule->first; + } + targetDrawable->prev = rule->last; + rule->last->next = targetDrawable; + break; + } + case DrawTargetPlacement::after: + { + if (targetDrawable->next != nullptr) + { + targetDrawable->next->prev = rule->last; + rule->last->next = targetDrawable->next; + } + if (targetDrawable == lastDrawable) + { + lastDrawable = rule->last; + } + targetDrawable->next = rule->first; + rule->first->prev = targetDrawable; + break; + } + } + } + + m_FirstDrawable = lastDrawable; +} + +void Artboard::sortDependencies() +{ + DependencySorter sorter; + sorter.sort(this, m_DependencyOrder); + unsigned int graphOrder = 0; + for (auto component : m_DependencyOrder) + { + component->m_GraphOrder = graphOrder++; + } + m_Dirt |= ComponentDirt::Components; +} + +void Artboard::addObject(Core* object) { m_Objects.push_back(object); } + +void Artboard::addAnimation(LinearAnimation* object) +{ + m_Animations.push_back(object); +} + +void Artboard::addStateMachine(StateMachine* object) +{ + m_StateMachines.push_back(object); +} + +Core* Artboard::resolve(uint32_t id) const +{ + if (id >= static_cast(m_Objects.size())) + { + return nullptr; + } + return m_Objects[id]; +} + +uint32_t Artboard::idOf(Core* object) const +{ + auto it = std::find(m_Objects.begin(), m_Objects.end(), object); + + if (it != m_Objects.end()) + { + return castTo(it - m_Objects.begin()); + } + else + { + return 0; + } +} + +void Artboard::onComponentDirty(Component* component) +{ + m_Dirt |= ComponentDirt::Components; + + /// If the order of the component is less than the current dirt + /// depth, update the dirt depth so that the update loop can break + /// out early and re-run (something up the tree is dirty). + if (component->graphOrder() < m_DirtDepth) + { + m_DirtDepth = component->graphOrder(); + } +} + +void Artboard::onDirty(ComponentDirt dirt) +{ + m_Dirt |= ComponentDirt::Components; +} + +#ifdef WITH_RIVE_LAYOUT +void Artboard::propagateSize() +{ + addDirt(ComponentDirt::Path); + if (sharesLayoutWithHost()) + { + m_host->markHostTransformDirty(); + } +#ifdef WITH_RIVE_TOOLS + if (m_layoutChangedCallback != nullptr) + { + m_layoutChangedCallback(callbackUserData); + } +#endif +} +#endif + +bool Artboard::sharesLayoutWithHost() const +{ + return m_host != nullptr && m_host->isLayoutProvider(); +} + +void Artboard::cloneObjectDataBinds(const Core* object, + Core* clone, + Artboard* artboard) const +{ + + for (auto dataBind : m_DataBinds) + { + if (dataBind->target() == object) + { + auto dataBindClone = static_cast(dataBind->clone()); + dataBindClone->target(clone); + dataBindClone->file(dataBind->file()); + if (dataBind->converter() != nullptr) + { + + dataBindClone->converter( + dataBind->converter()->clone()->as()); + } + artboard->m_DataBinds.push_back(dataBindClone); + } + } +} +void Artboard::host(ArtboardHost* artboardHost) +{ + m_host = artboardHost; +#ifdef WITH_RIVE_LAYOUT + if (!sharesLayoutWithHost()) + { + return; + } + Artboard* parent = parentArtboard(); + if (parent != nullptr) + { + parent->markLayoutDirty(this); + parent->syncLayoutChildren(); + } +#endif +} + +ArtboardHost* Artboard::host() const { return m_host; } + +Artboard* Artboard::parentArtboard() const +{ + if (m_host == nullptr) + { + return nullptr; + } + return m_host->parentArtboard(); +} + +float Artboard::layoutWidth() const +{ +#ifdef WITH_RIVE_LAYOUT + return m_layout.width(); +#else + return width(); +#endif +} + +float Artboard::layoutHeight() const +{ +#ifdef WITH_RIVE_LAYOUT + return m_layout.height(); +#else + return height(); +#endif +} + +float Artboard::layoutX() const +{ +#ifdef WITH_RIVE_LAYOUT + return m_layout.left(); +#else + return 0.0f; +#endif +} + +float Artboard::layoutY() const +{ +#ifdef WITH_RIVE_LAYOUT + return m_layout.top(); +#else + return 0.0f; +#endif +} + +void Artboard::updateRenderPath() +{ + AABB bg = AABB::fromLTWH(-layoutWidth() * originX(), + -layoutHeight() * originY(), + layoutWidth(), + layoutHeight()); + AABB clip; + if (m_FrameOrigin) + { + clip = {0.0f, 0.0f, layoutWidth(), layoutHeight()}; + } + else + { + clip = bg; + } + m_localPath.rewind(); + m_localPath.addRect(bg); + m_worldPath.rewind(); + m_worldPath.addRect(clip); +} + +void Artboard::update(ComponentDirt value) +{ + Super::update(value); + if (hasDirt(value, ComponentDirt::DrawOrder)) + { + sortDrawOrder(); + } +#ifdef WITH_RIVE_LAYOUT + if (hasDirt(value, ComponentDirt::LayoutStyle)) + { + bool cascadeChanged = cascadeLayoutStyle(interpolation(), + interpolator(), + interpolationTime(), + actualDirection()); + // TODO: Explore whether we can remove the syncStyleChanges call in + // updatePass. Since updatePass calls updateComponents, where the first + // component is the artboard itself, hence calling update, we end up + // calling this twice. Although it is safe, because syncStyleChanges + // checks for the list of dirty layouts that would be empty at this + // point, it seems redundant. + if (syncStyleChanges() && (m_updatesOwnLayout || cascadeChanged)) + { + calculateLayout(); + updateLayoutBounds( + /*animation*/ true); // maybe use a static to allow + // the editor to set this. + } + } +#endif +} + +void Artboard::updateDataBinds() +{ + for (auto dataBind : m_AllDataBinds) + { + dataBind->updateSourceBinding(); + auto d = dataBind->dirt(); + if (d == ComponentDirt::None) + { + continue; + } + dataBind->dirt(ComponentDirt::None); + dataBind->update(d); + } +} + +bool Artboard::updateComponents() +{ + if (!hasDirt(ComponentDirt::Components)) + { + return false; + } + const int maxSteps = 100; + int step = 0; + auto count = m_DependencyOrder.size(); + while (hasDirt(ComponentDirt::Components) && step < maxSteps) + { + m_Dirt = m_Dirt & ~ComponentDirt::Components; + + // Track dirt depth here so that if something else marks + // dirty, we restart. + for (unsigned int i = 0; i < count; i++) + { + auto component = m_DependencyOrder[i]; + m_DirtDepth = i; + auto d = component->m_Dirt; + if (d == ComponentDirt::None || + (d & ComponentDirt::Collapsed) == ComponentDirt::Collapsed) + { + continue; + } + component->m_Dirt = ComponentDirt::None; + component->update(d); + + // If the update changed the dirt depth by adding dirt + // to something before us (in the DAG), early out and + // re-run the update. + if (m_DirtDepth < i) + { + break; + } + } + step++; + } + return true; +} + +LayoutData* Artboard::takeLayoutData() +{ +#ifdef WITH_RIVE_LAYOUT + m_updatesOwnLayout = false; + return m_layoutData; +#else + return nullptr; +#endif +} + +void Artboard::cleanLayout(LayoutComponent* layoutComponent) +{ + assert(!m_isCleaningDirtyLayouts); + if (m_isCleaningDirtyLayouts) + { + fprintf(stderr, + "Artboard::cleanLayout - trying to remove a dirty layout " + "during clean pass!\n"); + return; + } + + if (!m_dirtyLayout.empty()) + { + auto itr = m_dirtyLayout.find(layoutComponent); + if (itr != m_dirtyLayout.end()) + { + m_dirtyLayout.erase(itr); + } + } + // If we called cleanLayout on ourselves, make sure to also + // call it on our parent artboard in case we were dirtied + if (layoutComponent == this) + { + Artboard* parent = parentArtboard(); + if (parent != nullptr) + { + parent->cleanLayout(layoutComponent); + } + } +} + +void Artboard::markLayoutDirty(LayoutComponent* layoutComponent) +{ + assert(!m_isCleaningDirtyLayouts); + if (m_isCleaningDirtyLayouts) + { + fprintf(stderr, + "Artboard::markLayoutDirty - trying to mark a layout dirty " + "during clean pass!\n"); + return; + } +#ifdef WITH_RIVE_TOOLS + if (m_dirtyLayout.empty() && m_layoutDirtyCallback != nullptr) + { + m_layoutDirtyCallback(callbackUserData); + } +#endif + m_dirtyLayout.insert(layoutComponent); + if (sharesLayoutWithHost() && isInstance()) + { + m_host->markHostingLayoutDirty(this->as()); + } + addDirt(ComponentDirt::Components); +} + +bool Artboard::syncStyleChanges() +{ + bool updated = false; + m_isCleaningDirtyLayouts = true; +#ifdef WITH_RIVE_LAYOUT + if (!m_dirtyLayout.empty()) + { + for (auto layout : m_dirtyLayout) + { + if (layout == nullptr) + { + continue; + } + switch (layout->coreType()) + { + case ArtboardBase::typeKey: + { + auto artboard = layout->as(); + if (artboard == this) + { + artboard->syncStyle(); + } + else + { + // This is a nested artboard, sync its changes too. + artboard->syncStyleChanges(); + } + break; + } + + default: + layout->syncStyle(); + break; + } + } + m_dirtyLayout.clear(); + updated = true; + } +#endif + m_isCleaningDirtyLayouts = false; + return updated; +} + +bool Artboard::updatePass(bool isRoot) +{ + bool didUpdate = false; +#ifdef WITH_RIVE_LAYOUT + if (syncStyleChanges() && m_updatesOwnLayout) + { + calculateLayout(); + updateLayoutBounds(/*animation*/ true); // maybe use a static to allow + // the editor to set this. + } +#endif + if (m_JoysticksApplyBeforeUpdate) + { + for (auto joystick : m_Joysticks) + { + joystick->apply(this); + } + } + updateDataBinds(); + if (updateComponents()) + { + didUpdate = true; + } + if (!m_JoysticksApplyBeforeUpdate) + { + for (auto joystick : m_Joysticks) + { + if (!joystick->canApplyBeforeUpdate()) + { + updateDataBinds(); + if (updateComponents()) + { + didUpdate = true; + } + } + joystick->apply(this); + } + updateDataBinds(); + if (updateComponents()) + { + didUpdate = true; + } + } + return didUpdate; +} + +bool Artboard::advanceInternal(float elapsedSeconds, AdvanceFlags flags) +{ + bool didUpdate = false; + + for (auto dep : m_DependencyOrder) + { + auto adv = AdvancingComponent::from(dep); + if (adv != nullptr && adv->advanceComponent(elapsedSeconds, flags)) + { + didUpdate = true; + } + } + for (auto dataBind : m_AllDataBinds) + { + if (dataBind->advance(elapsedSeconds)) + { + didUpdate = true; + } + } + + return didUpdate; +} + +bool Artboard::advance(float elapsedSeconds, AdvanceFlags flags) +{ + AdvanceFlags advancingFlags = flags; + advancingFlags |= AdvanceFlags::IsRoot; + bool didUpdate = advanceInternal(elapsedSeconds, advancingFlags); + if (updatePass(true)) + { + didUpdate = true; + } + return didUpdate || hasDirt(ComponentDirt::Components); +} + +Core* Artboard::hitTest(HitInfo* hinfo, const Mat2D& xform) +{ + if (clip()) + { + // TODO: can we get the rawpath for the clip? + } + + auto mx = xform; + if (m_FrameOrigin) + { + mx *= Mat2D::fromTranslate(layoutWidth() * originX(), + layoutHeight() * originY()); + } + + Drawable* last = m_FirstDrawable; + if (last) + { + // walk to the end, so we can visit in reverse-order + while (last->prev) + { + last = last->prev; + } + } + for (auto drawable = last; drawable; drawable = drawable->next) + { + if (drawable->isHidden()) + { + continue; + } + if (auto c = drawable->hitTest(hinfo, mx)) + { + return c; + } + } + + // TODO: should we hit-test the background? + + return nullptr; +} + +void Artboard::draw(Renderer* renderer) { draw(renderer, DrawOption::kNormal); } + +void Artboard::draw(Renderer* renderer, DrawOption option) +{ + if (renderOpacity() == 0) + { + return; + } + bool save = clip() || m_FrameOrigin; + if (save) + { + renderer->save(); + } + if (clip()) + { + renderer->clipPath(m_worldPath.renderPath(this)); + } + + if (m_FrameOrigin) + { + Mat2D artboardTransform; + artboardTransform[4] = layoutWidth() * originX(); + artboardTransform[5] = layoutHeight() * originY(); + renderer->transform(artboardTransform); + } + + if (option != DrawOption::kHideBG) + { + for (auto shapePaint : m_ShapePaints) + { + if (!shapePaint->shouldDraw()) + { + continue; + } + auto shapePaintPath = shapePaint->pickPath(this); + if (shapePaintPath == nullptr) + { + continue; + } + shapePaint->draw(renderer, shapePaintPath, worldTransform()); + } + } + + if (option != DrawOption::kHideFG) + { + for (auto drawable = m_FirstDrawable; drawable != nullptr; + drawable = drawable->prev) + { + if (drawable->isHidden()) + { + continue; + } + drawable->draw(renderer); + } + } + if (save) + { + renderer->restore(); + } +} + +void Artboard::addToRenderPath(RenderPath* path, const Mat2D& transform) +{ + for (auto drawable = m_FirstDrawable; drawable != nullptr; + drawable = drawable->prev) + { + if (drawable->isHidden() || !drawable->is()) + { + continue; + } + Shape* shape = drawable->as(); + shape->addToRenderPath(path, transform); + } +} + +Vec2D Artboard::origin() const +{ + return m_FrameOrigin + ? Vec2D(0.0f, 0.0f) + : Vec2D(-layoutWidth() * originX(), -layoutHeight() * originY()); +} + +AABB Artboard::bounds() const +{ + return m_FrameOrigin ? AABB(0.0f, 0.0f, layoutWidth(), layoutHeight()) + : AABB::fromLTWH(-layoutWidth() * originX(), + -layoutHeight() * originY(), + layoutWidth(), + layoutHeight()); +} + +bool Artboard::isTranslucent() const +{ + for (const auto sp : m_ShapePaints) + { + if (!sp->isTranslucent()) + { + return false; // one opaque fill is sufficient to be opaque + } + } + return true; +} + +bool Artboard::hasAudio() const +{ + for (auto object : m_Objects) + { + if (object != nullptr && object->coreType() == AudioEventBase::typeKey) + { + return true; + } + } + for (auto artboardHost : m_ArtboardHosts) + { + for (int i = 0; i < artboardHost->artboardCount(); i++) + { + auto artboard = artboardHost->artboardInstance(i); + if (artboard != nullptr && artboard->hasAudio()) + { + return true; + } + } + } + return false; +} + +bool Artboard::isTranslucent(const LinearAnimation* anim) const +{ + // For now we're conservative/lazy -- if we see that any of our paints are + // animated we assume that might make it non-opaque, so we early out + for (const auto& obj : anim->m_KeyedObjects) + { + const auto ptr = this->resolve(obj->objectId()); + for (const auto sp : m_ShapePaints) + { + if (ptr == sp) + { + return true; + } + } + } + + // If we get here, we have no animations, so just check our paints for + // opacity + return this->isTranslucent(); +} + +bool Artboard::isTranslucent(const LinearAnimationInstance* inst) const +{ + return this->isTranslucent(inst->animation()); +} + +std::string Artboard::animationNameAt(size_t index) const +{ + auto la = this->animation(index); + return la ? la->name() : ""; +} + +std::string Artboard::stateMachineNameAt(size_t index) const +{ + auto sm = this->stateMachine(index); + return sm ? sm->name() : ""; +} + +LinearAnimation* Artboard::animation(const std::string& name) const +{ + for (auto animation : m_Animations) + { + if (animation->name() == name) + { + return animation; + } + } + return nullptr; +} + +LinearAnimation* Artboard::animation(size_t index) const +{ + if (index >= m_Animations.size()) + { + return nullptr; + } + return m_Animations[index]; +} + +StateMachine* Artboard::stateMachine(const std::string& name) const +{ + for (auto machine : m_StateMachines) + { + if (machine->name() == name) + { + return machine; + } + } + return nullptr; +} + +StateMachine* Artboard::stateMachine(size_t index) const +{ + if (index >= m_StateMachines.size()) + { + return nullptr; + } + return m_StateMachines[index]; +} + +int Artboard::defaultStateMachineIndex() const +{ + int index = defaultStateMachineId(); + if ((size_t)index >= m_StateMachines.size()) + { + index = -1; + } + return index; +} + +NestedArtboard* Artboard::nestedArtboard(const std::string& name) const +{ + for (auto nested : m_NestedArtboards) + { + if (nested->name() == name) + { + return nested; + } + } + return nullptr; +} + +NestedArtboard* Artboard::nestedArtboardAtPath(const std::string& path) const +{ + // name parameter can be a name or a path to recursively find a nested + // artboard + std::string delimiter = "/"; + size_t firstDelim = path.find(delimiter); + std::string artboardName = + firstDelim == std::string::npos ? path : path.substr(0, firstDelim); + std::string restOfPath = firstDelim == std::string::npos + ? "" + : path.substr(firstDelim + 1, path.size()); + + // Find the nested artboard at this level + if (!artboardName.empty()) + { + auto nested = nestedArtboard(artboardName); + if (nested != nullptr) + { + if (restOfPath.empty()) + { + return nested; + } + else + { + auto artboard = nested->artboardInstance(); + return artboard->nestedArtboardAtPath(restOfPath); + } + } + } + return nullptr; +} + +// std::unique_ptr Artboard::instance() const +// { +// std::unique_ptr artboardClone(new ArtboardInstance); +// artboardClone->copy(*this); + +// artboardClone->m_Factory = m_Factory; +// artboardClone->m_FrameOrigin = m_FrameOrigin; +// artboardClone->m_IsInstance = true; + +// std::vector& cloneObjects = artboardClone->m_Objects; +// cloneObjects.push_back(artboardClone.get()); + +// if (!m_Objects.empty()) +// { +// // Skip first object (artboard). +// auto itr = m_Objects.begin(); +// while (++itr != m_Objects.end()) +// { +// auto object = *itr; +// cloneObjects.push_back(object == nullptr ? nullptr : +// object->clone()); +// } +// } + +// for (auto animation : m_Animations) +// { +// artboardClone->m_Animations.push_back(animation); +// } +// for (auto stateMachine : m_StateMachines) +// { +// artboardClone->m_StateMachines.push_back(stateMachine); +// } + +// if (artboardClone->initialize() != StatusCode::Ok) +// { +// artboardClone = nullptr; +// } + +// assert(artboardClone->isInstance()); +// return artboardClone; +// } + +void Artboard::frameOrigin(bool value) +{ + if (value == m_FrameOrigin) + { + return; + } + m_FrameOrigin = value; + addDirt(ComponentDirt::Path); +} + +StatusCode Artboard::import(ImportStack& importStack) +{ + auto backboardImporter = + importStack.latest(Backboard::typeKey); + if (backboardImporter == nullptr) + { + return StatusCode::MissingObject; + } + + StatusCode result = Super::import(importStack); + if (result == StatusCode::Ok) + { + backboardImporter->addArtboard(this); + } + else + { + backboardImporter->addMissingArtboard(); + } + return result; +} + +void Artboard::internalDataContext(DataContext* value, bool isRoot) +{ + m_DataContext = value; + for (auto artboardHost : m_NestedArtboards) + { + auto value = m_DataContext->getViewModelInstance( + artboardHost->dataBindPathIds()); + if (value != nullptr && value->is()) + { + artboardHost->bindViewModelInstance(value, m_DataContext); + } + else + { + artboardHost->internalDataContext(m_DataContext); + } + } + for (auto dataBind : m_DataBinds) + { + if (dataBind->is()) + { + dataBind->as()->bindFromContext(m_DataContext); + } + } + if (isRoot) + { + collectDataBinds(); + } +} + +void Artboard::clearDataContext() +{ + if (m_ownsDataContext && m_DataContext != nullptr) + { + delete m_DataContext; + } + m_DataContext = nullptr; + m_ownsDataContext = false; + for (auto artboardHost : m_ArtboardHosts) + { + artboardHost->clearDataContext(); + } + for (auto& dataBind : m_DataBinds) + { + dataBind->unbind(); + } +} + +void Artboard::sortDataBinds() +{ + size_t currentToSourceIndex = 0; + for (size_t i = 0; i < m_AllDataBinds.size(); i++) + { + if (m_AllDataBinds[i]->toSource()) + { + if (i != currentToSourceIndex) + { + + std::iter_swap(m_AllDataBinds.begin() + currentToSourceIndex, + m_AllDataBinds.begin() + i); + } + currentToSourceIndex += 1; + } + } +} + +float Artboard::volume() const { return m_volume; } +void Artboard::volume(float value) +{ + m_volume = value; + for (auto artboardHost : m_ArtboardHosts) + { + for (int i = 0; i < artboardHost->artboardCount(); i++) + { + auto artboard = artboardHost->artboardInstance(i); + if (artboard != nullptr) + { + artboard->volume(value); + } + } + } +} + +void Artboard::populateDataBinds(std::vector* dataBinds) +{ + for (auto dataBind : m_DataBinds) + { + dataBinds->push_back(dataBind); + } + for (auto artboardHost : m_ArtboardHosts) + { + artboardHost->populateDataBinds(dataBinds); + } +} + +void Artboard::collectDataBinds() +{ + m_AllDataBinds.clear(); + populateDataBinds(&m_AllDataBinds); + sortDataBinds(); +} + +void Artboard::addDataBind(DataBind* dataBind) +{ + m_DataBinds.push_back(dataBind); +} + +void Artboard::dataContext(DataContext* value) +{ + internalDataContext(value, true); +} + +void Artboard::bindViewModelInstance(rcp viewModelInstance) +{ + bindViewModelInstance(viewModelInstance, nullptr, true); +} + +void Artboard::bindViewModelInstance(rcp viewModelInstance, + DataContext* parent) +{ + bindViewModelInstance(viewModelInstance, parent, true); +} + +void Artboard::bindViewModelInstance(rcp viewModelInstance, + DataContext* parent, + bool isRoot) +{ + clearDataContext(); + if (viewModelInstance == nullptr) + { + return; + } + if (isRoot) + { + viewModelInstance->setAsRoot(viewModelInstance); + } + m_ownsDataContext = true; + auto dataContext = new DataContext(viewModelInstance); + dataContext->parent(parent); + internalDataContext(dataContext, isRoot); +} + +////////// ArtboardInstance + +#include "rive/animation/linear_animation_instance.hpp" +#include "rive/animation/state_machine_instance.hpp" + +ArtboardInstance::ArtboardInstance() {} + +ArtboardInstance::~ArtboardInstance() {} + +std::unique_ptr ArtboardInstance::animationAt( + size_t index) +{ + auto la = this->animation(index); + return la ? rivestd::make_unique(la, this) + : nullptr; +} + +std::unique_ptr ArtboardInstance::animationNamed( + const std::string& name) +{ + auto la = this->animation(name); + return la ? rivestd::make_unique(la, this) + : nullptr; +} + +std::unique_ptr ArtboardInstance::stateMachineAt( + size_t index) +{ + auto sm = this->stateMachine(index); + return sm ? rivestd::make_unique(sm, this) : nullptr; +} + +std::unique_ptr ArtboardInstance::stateMachineNamed( + const std::string& name) +{ + auto sm = this->stateMachine(name); + return sm ? rivestd::make_unique(sm, this) : nullptr; +} + +std::unique_ptr ArtboardInstance::defaultStateMachine() +{ + const int index = this->defaultStateMachineIndex(); + return index >= 0 ? this->stateMachineAt(index) : nullptr; +} + +std::unique_ptr ArtboardInstance::defaultScene() +{ + std::unique_ptr scene = this->defaultStateMachine(); + if (!scene) + { + scene = this->stateMachineAt(0); + } + if (!scene) + { + scene = this->animationAt(0); + } + return scene; +} + +SMIInput* ArtboardInstance::input(const std::string& name, + const std::string& path) +{ + return getNamedInput(name, path); +} + +template +InstType* ArtboardInstance::getNamedInput(const std::string& name, + const std::string& path) +{ + if (!path.empty()) + { + auto nestedArtboard = nestedArtboardAtPath(path); + if (nestedArtboard != nullptr) + { + auto input = nestedArtboard->input(name); + if (input != nullptr && input->input() != nullptr) + { + return static_cast(input->input()); + } + } + } + return nullptr; +} + +SMIBool* ArtboardInstance::getBool(const std::string& name, + const std::string& path) +{ + return getNamedInput(name, path); +} + +SMINumber* ArtboardInstance::getNumber(const std::string& name, + const std::string& path) +{ + return getNamedInput(name, path); +} +SMITrigger* ArtboardInstance::getTrigger(const std::string& name, + const std::string& path) +{ + return getNamedInput(name, path); +} + +TextValueRun* ArtboardInstance::getTextRun(const std::string& name, + const std::string& path) +{ + if (path.empty()) + { + return nullptr; + } + + auto nestedArtboard = nestedArtboardAtPath(path); + if (nestedArtboard == nullptr) + { + return nullptr; + } + + auto artboardInstance = nestedArtboard->artboardInstance(); + if (artboardInstance == nullptr) + { + return nullptr; + } + + return artboardInstance->find(name); +} + +#ifdef EXTERNAL_RIVE_AUDIO_ENGINE +rcp Artboard::audioEngine() const { return m_audioEngine; } +void Artboard::audioEngine(rcp audioEngine) +{ + m_audioEngine = audioEngine; + for (auto artboardHost : m_ArtboardHosts) + { + for (int i = 0; i < artboardHost->artboardCount(); i++) + { + auto artboard = artboardHost->artboardInstance(i); + if (artboard != nullptr) + { + artboard->audioEngine(audioEngine); + } + } + } +} +#endif diff --git a/third_party/rive/source/artboard_component_list.cpp b/third_party/rive/source/artboard_component_list.cpp new file mode 100644 index 0000000..affe67c --- /dev/null +++ b/third_party/rive/source/artboard_component_list.cpp @@ -0,0 +1,455 @@ +#include "rive/component.hpp" +#include "rive/file.hpp" +#include "rive/artboard_component_list.hpp" +#include "rive/constraints/layout_constraint.hpp" +#include "rive/layout_component.hpp" +#include "rive/viewmodel/viewmodel_instance_symbol_list_index.hpp" +#include "rive/layout/layout_data.hpp" + +using namespace rive; + +ArtboardComponentList::ArtboardComponentList() {} +ArtboardComponentList::~ArtboardComponentList() { reset(); } + +void ArtboardComponentList::reset() +{ + for (auto& artboard : m_artboardInstancesMap) + { + artboard.second.reset(); + } + for (auto& sm : m_stateMachinesMap) + { + sm.second.reset(); + } + for (auto& item : m_listItems) + { + item->unref(); + } + m_artboardInstancesMap.clear(); + m_stateMachinesMap.clear(); + m_listItems.clear(); + m_artboardsMap.clear(); +} + +#ifdef WITH_RIVE_LAYOUT +void* ArtboardComponentList::layoutNode(int index) +{ + auto artboard = artboardInstance(index); + if (artboard != nullptr) + { + return static_cast(&artboard->takeLayoutData()->node); + } + return nullptr; +} +#endif + +void ArtboardComponentList::markLayoutNodeDirty( + bool shouldForceUpdateLayoutBounds) +{ + bool parentIsRow = true; + if (parent()->is()) + { + parentIsRow = parent()->as()->mainAxisIsRow(); + } + for (int i = 0; i < artboardCount(); i++) + { + auto artboard = artboardInstance(i); + if (artboard != nullptr) + { + artboard->parentIsRow(parentIsRow); + } + } +} + +void ArtboardComponentList::updateLayoutBounds(bool animate) +{ +#ifdef WITH_RIVE_LAYOUT + for (int i = 0; i < artboardCount(); i++) + { + auto artboard = artboardInstance(i); + if (artboard != nullptr) + { + artboard->updateLayoutBounds(animate); + } + } +#endif +} + +bool ArtboardComponentList::syncStyleChanges() +{ + bool changed = false; + for (int i = 0; i < artboardCount(); i++) + { + auto artboard = artboardInstance(i); + if (artboard != nullptr) + { + bool artboardChanged = artboard->syncStyleChanges(); + if (artboardChanged) + { + changed = true; + } + } + } + return changed; +} + +Artboard* ArtboardComponentList::findArtboard( + ViewModelInstanceListItem* listItem) const +{ + auto viewModelInstance = listItem->viewModelInstance(); + if (viewModelInstance == nullptr) + { + return nullptr; + } + auto artboard = m_artboardsMap.find(viewModelInstance->viewModelId()); + if (artboard != m_artboardsMap.end()) + { + return artboard->second; + } + auto artboards = m_file->artboards(); + for (auto& artboard : artboards) + { + if (artboard->viewModelId() == viewModelInstance->viewModelId()) + { + m_artboardsMap[viewModelInstance->viewModelId()] = artboard; + return artboard; + } + } + + return nullptr; +} + +void ArtboardComponentList::disposeListItem(ViewModelInstanceListItem* listItem) +{ + auto artboard = m_artboardInstancesMap[listItem].get(); + if (artboard != nullptr) + { + m_artboardInstancesMap[listItem].reset(); + } + m_artboardInstancesMap.erase(listItem); + auto sm = m_stateMachinesMap[listItem].get(); + if (sm != nullptr) + { + m_stateMachinesMap[listItem].reset(); + } + m_stateMachinesMap.erase(listItem); + listItem->unref(); +} + +std::unique_ptr ArtboardComponentList::createArtboard( + Component* target, + ViewModelInstanceListItem* listItem) const +{ + auto artboard = findArtboard(listItem); + if (artboard != nullptr) + { + auto mainArtboard = target->artboard(); + auto dataContext = mainArtboard->dataContext(); + auto artboardCopy = artboard->instance(); + // artboardCopy->name(artboard->name()); + artboardCopy->bindViewModelInstance(listItem->viewModelInstance(), + dataContext, + true); + return artboardCopy; + } + return nullptr; +} + +std::unique_ptr ArtboardComponentList:: + createStateMachineInstance(Component* target, ArtboardInstance* artboard) +{ + if (artboard != nullptr) + { + auto dataContext = artboard->dataContext(); + auto stateMachineInstance = artboard->stateMachineAt(0); + stateMachineInstance->dataContext(dataContext); + return stateMachineInstance; + } + return nullptr; +} + +void ArtboardComponentList::updateList( + int propertyKey, + std::vector* list) +{ + std::vector oldItems; + oldItems.assign(m_listItems.begin(), m_listItems.end()); + m_listItems.clear(); + m_listItems.assign(list->begin(), list->end()); + for (auto item : oldItems) + { + auto it = std::find(m_listItems.begin(), m_listItems.end(), item); + if (it == m_listItems.end()) + { + disposeListItem(item); + } + } + if (parent()->is()) + { +#ifdef WITH_RIVE_LAYOUT + parent()->as()->clearLayoutChildren(); +#endif + } + uint32_t index = 0; + for (auto& item : m_listItems) + { + auto viewModelInstance = item->viewModelInstance(); + if (viewModelInstance != nullptr) + { + auto symbol = viewModelInstance->symbol( + ViewModelInstanceSymbolListIndexBase::typeKey); + if (symbol != nullptr) + { + symbol->as()->propertyValue( + index); + } + } + if (m_artboardInstancesMap[item] == nullptr) + { + auto artboardCopy = createArtboard(this, item); + if (artboardCopy != nullptr) + { + auto artboardInstance = artboardCopy.get(); + auto stateMachineCopy = + createStateMachineInstance(this, artboardInstance); + m_artboardInstancesMap[item] = std::move(artboardCopy); + m_stateMachinesMap[item] = std::move(stateMachineCopy); + item->ref(); + if (artboardInstance != nullptr) + { + artboardInstance->host(this); + } + } + } + index++; + } + if (parent()->is()) + { +#ifdef WITH_RIVE_LAYOUT + parent()->as()->syncLayoutChildren(); +#endif + } + markLayoutNodeDirty(); + addDirt(ComponentDirt::Components); +} + +bool ArtboardComponentList::advanceComponent(float elapsedSeconds, + AdvanceFlags flags) +{ + if (artboardCount() == 0 || isCollapsed()) + { + return false; + } + bool keepGoing = false; + bool advanceNested = + (flags & AdvanceFlags::AdvanceNested) == AdvanceFlags::AdvanceNested; + bool newFrame = (flags & AdvanceFlags::NewFrame) == AdvanceFlags::NewFrame; + auto advancingFlags = flags & ~AdvanceFlags::IsRoot; + for (int i = 0; i < artboardCount(); i++) + { + if (advanceNested) + { + auto stateMachine = stateMachineInstance(i); + if (stateMachine != nullptr) + { + // If it is not a new frame, we + // first validate whether their state has changed. Then and only + // then we advance the state machine. This avoids triggering + // dirt from advances that make intermediate value changes but + // finally settle in the same value + if (!newFrame) + { + if (stateMachine->tryChangeState()) + { + if (stateMachine->advance(elapsedSeconds, newFrame)) + { + keepGoing = true; + } + } + } + else + { + if (stateMachine->advance(elapsedSeconds, newFrame)) + { + keepGoing = true; + } + } + } + } + auto artboard = artboardInstance(i); + if (artboard != nullptr) + { + if (artboard->advanceInternal(elapsedSeconds, advancingFlags)) + { + keepGoing = true; + } + if (artboard->hasDirt(ComponentDirt::Components)) + { + // The animation(s) caused the artboard to need an update. + addDirt(ComponentDirt::Components); + } + } + } + + return keepGoing; +} + +AABB ArtboardComponentList::layoutBounds() { return AABB(); } + +AABB ArtboardComponentList::layoutBoundsForNode(int index) +{ + if (index >= 0 && index < numLayoutNodes()) + { + return artboardInstance(index)->layoutBounds(); + } + return AABB(); +} + +void ArtboardComponentList::markHostingLayoutDirty( + ArtboardInstance* artboardInstance) +{ + // TODO: Should optimize this + for (int i = 0; i < artboardCount(); i++) + { + auto artboard = this->artboardInstance(i); + if (artboard != nullptr && artboard == artboardInstance) + { + this->artboard()->markLayoutDirty(artboardInstance); + break; + } + } +} + +void ArtboardComponentList::draw(Renderer* renderer) +{ + ClipResult clipResult = applyClip(renderer); + if (clipResult == ClipResult::noClip) + { + // We didn't clip, so make sure to save as we'll be doing some + // transformations. + renderer->save(); + } + if (clipResult != ClipResult::emptyClip) + { + renderer->transform(worldTransform()); + for (int i = 0; i < artboardCount(); i++) + { + auto artboard = artboardInstance(i); + if (artboard != nullptr) + { + renderer->save(); + auto bounds = artboard->layoutBounds(); + auto artboardTransform = + Mat2D::fromTranslate(bounds.left(), bounds.top()); + renderer->transform(artboardTransform); + artboard->draw(renderer); + renderer->restore(); + } + } + } + renderer->restore(); +} + +Core* ArtboardComponentList::hitTest(HitInfo*, const Mat2D&) { return nullptr; } + +void ArtboardComponentList::update(ComponentDirt value) +{ + Super::update(value); + if (artboardCount() == 0) + { + return; + } + + if (hasDirt(value, ComponentDirt::RenderOpacity)) + { + for (int i = 0; i < artboardCount(); i++) + { + auto artboard = artboardInstance(i); + if (artboard != nullptr) + { + artboard->opacity(renderOpacity()); + } + } + } + if (hasDirt(value, ComponentDirt::Components)) + { + for (int i = 0; i < artboardCount(); i++) + { + auto artboard = artboardInstance(i); + if (artboard != nullptr) + { + artboard->updatePass(false); + } + } + } +} + +void ArtboardComponentList::updateConstraints() +{ + if (m_layoutConstraints.size() > 0) + { + for (auto parentConstraint : m_layoutConstraints) + { + parentConstraint->constrainChild(this); + } + } + Super::updateConstraints(); +} + +void ArtboardComponentList::internalDataContext(DataContext* value) +{ + // In the future, we may need to reconcile existing artboards with the + // new datacontext passed in here +} + +void ArtboardComponentList::populateDataBinds(std::vector* dataBinds) +{ + // At the time this is called, artboards will not yet have been instanced + // so its essentially a no-op and the data binds will be populated at + // artboard creation time by calling artboard->bindViewModelInstance + // passing isRoot=true +} + +void ArtboardComponentList::bindViewModelInstance( + rcp viewModelInstance, + DataContext* parent) +{ + // At the time this is called, artboards will not yet have been instanced + // so its essentially a no-op and the call to bindViewModelInstance on + // each artboard is made at the time of artboard instancing +} + +void ArtboardComponentList::clearDataContext() { reset(); } + +bool ArtboardComponentList::worldToLocal(Vec2D world, Vec2D* local, int index) +{ + assert(local != nullptr); + auto artboard = artboardInstance(index); + if (artboard == nullptr) + { + return false; + } + auto bounds = artboard->layoutBounds(); + auto artboardTransform = + worldTransform() * Mat2D::fromTranslate(bounds.left(), bounds.top()); + Mat2D toMountedArtboard; + if (!artboardTransform.invert(&toMountedArtboard)) + { + return false; + } + + *local = toMountedArtboard * world; + + return true; +} + +void ArtboardComponentList::file(File* value) { m_file = value; } +File* ArtboardComponentList::file() const { return m_file; } + +Core* ArtboardComponentList::clone() const +{ + auto clone = + static_cast(ArtboardComponentListBase::clone()); + clone->file(file()); + return clone; +} \ No newline at end of file diff --git a/third_party/rive/source/assets/audio_asset.cpp b/third_party/rive/source/assets/audio_asset.cpp new file mode 100644 index 0000000..de59fae --- /dev/null +++ b/third_party/rive/source/assets/audio_asset.cpp @@ -0,0 +1,19 @@ +#include "rive/assets/audio_asset.hpp" +#include "rive/factory.hpp" + +using namespace rive; + +AudioAsset::AudioAsset() {} + +AudioAsset::~AudioAsset() {} + +bool AudioAsset::decode(SimpleArray& bytes, Factory* factory) +{ +#ifdef WITH_RIVE_AUDIO + // Steal the bytes. + m_audioSource = rcp(new AudioSource(std::move(bytes))); +#endif + return true; +} + +std::string AudioAsset::fileExtension() const { return "wav"; } \ No newline at end of file diff --git a/third_party/rive/source/assets/file_asset.cpp b/third_party/rive/source/assets/file_asset.cpp new file mode 100644 index 0000000..8f99d2f --- /dev/null +++ b/third_party/rive/source/assets/file_asset.cpp @@ -0,0 +1,76 @@ +#include +#include +#include + +#include "rive/assets/file_asset.hpp" +#include "rive/backboard.hpp" +#include "rive/importers/backboard_importer.hpp" + +using namespace rive; + +StatusCode FileAsset::import(ImportStack& importStack) +{ + auto backboardImporter = + importStack.latest(Backboard::typeKey); + if (backboardImporter == nullptr) + { + return StatusCode::MissingObject; + } + backboardImporter->addFileAsset(this); + + return Super::import(importStack); +} + +std::string FileAsset::uniqueName() const +{ + // remove final extension + std::string uniqueName = name(); + std::size_t finalDot = uniqueName.rfind('.'); + + if (finalDot != std::string::npos) + { + uniqueName = uniqueName.substr(0, finalDot); + } + return uniqueName + "-" + std::to_string(assetId()); +} + +std::string FileAsset::uniqueFilename() const +{ + return uniqueName() + "." + fileExtension(); +} + +void FileAsset::copyCdnUuid(const FileAssetBase& object) +{ + // Should never be called. + assert(false); +} + +void FileAsset::decodeCdnUuid(Span value) +{ + m_cdnUuid = std::vector(value.begin(), value.end()); +} + +Span FileAsset::cdnUuid() const { return m_cdnUuid; } + +std::string FileAsset::cdnUuidStr() const +{ + constexpr uint8_t uuidSize = 16; + if (m_cdnUuid.size() != uuidSize) + { + return ""; + } + const std::array + indices{3, 2, 1, 0, 5, 4, 7, 6, 9, 8, 15, 14, 13, 12, 11, 10}; + + std::stringstream ss; + ss << std::hex << std::setfill('0'); + for (int idx : indices) + { + ss << std::setw(2) // always 2 chars + << static_cast(m_cdnUuid[idx]); + if (idx == 0 || idx == 4 || idx == 6 || idx == 8) + ss << '-'; + } + + return ss.str(); +} \ No newline at end of file diff --git a/third_party/rive/source/assets/file_asset_contents.cpp b/third_party/rive/source/assets/file_asset_contents.cpp new file mode 100644 index 0000000..dbe9f1b --- /dev/null +++ b/third_party/rive/source/assets/file_asset_contents.cpp @@ -0,0 +1,33 @@ +#include +#include "rive/assets/file_asset_contents.hpp" +#include "rive/assets/file_asset.hpp" +#include "rive/importers/file_asset_importer.hpp" + +using namespace rive; + +StatusCode FileAssetContents::import(ImportStack& importStack) +{ + auto fileAssetImporter = + importStack.latest(FileAsset::typeKey); + if (fileAssetImporter == nullptr) + { + return StatusCode::MissingObject; + } + fileAssetImporter->onFileAssetContents( + std::unique_ptr(this)); + + return Super::import(importStack); +} + +void FileAssetContents::decodeBytes(Span value) +{ + m_bytes = SimpleArray(value.data(), value.size()); +} + +void FileAssetContents::copyBytes(const FileAssetContentsBase& object) +{ + // Should never be called. + assert(false); +} + +SimpleArray& FileAssetContents::bytes() { return m_bytes; } diff --git a/third_party/rive/source/assets/file_asset_referencer.cpp b/third_party/rive/source/assets/file_asset_referencer.cpp new file mode 100644 index 0000000..5c703d9 --- /dev/null +++ b/third_party/rive/source/assets/file_asset_referencer.cpp @@ -0,0 +1,40 @@ +#include "rive/assets/file_asset_referencer.hpp" +#include "rive/backboard.hpp" +#include "rive/assets/file_asset.hpp" +#include "rive/importers/backboard_importer.hpp" + +using namespace rive; + +FileAssetReferencer::~FileAssetReferencer() +{ + if (m_fileAsset != nullptr) + { + m_fileAsset->removeFileAssetReferencer(this); + } +} + +StatusCode FileAssetReferencer::registerReferencer(ImportStack& importStack) +{ + auto backboardImporter = + importStack.latest(Backboard::typeKey); + if (backboardImporter == nullptr) + { + return StatusCode::MissingObject; + } + backboardImporter->addFileAssetReferencer(this); + + return StatusCode::Ok; +} + +void FileAssetReferencer::setAsset(FileAsset* asset) +{ + if (m_fileAsset != nullptr) + { + m_fileAsset->removeFileAssetReferencer(this); + } + m_fileAsset = asset; + if (asset != nullptr) + { + asset->addFileAssetReferencer(this); + } +}; \ No newline at end of file diff --git a/third_party/rive/source/assets/font_asset.cpp b/third_party/rive/source/assets/font_asset.cpp new file mode 100644 index 0000000..2708503 --- /dev/null +++ b/third_party/rive/source/assets/font_asset.cpp @@ -0,0 +1,28 @@ +#include "rive/text/text_style.hpp" +#include "rive/assets/file_asset_referencer.hpp" +#include "rive/assets/font_asset.hpp" +#include "rive/artboard.hpp" +#include "rive/factory.hpp" + +using namespace rive; + +bool FontAsset::decode(SimpleArray& data, Factory* factory) +{ + font(factory->decodeFont(data)); + return m_font != nullptr; +} +std::string FontAsset::fileExtension() const { return "ttf"; } + +void FontAsset::font(rcp font) +{ + m_font = std::move(font); + + // We could try to tie this to some generic FileAssetReferencer callback + // but for that we'd need this to be behind a more generic setter like + // ::asset(rcp asset) + for (FileAssetReferencer* fileAssetReferencer : fileAssetReferencers()) + { + static_cast(fileAssetReferencer) + ->addDirt(ComponentDirt::TextShape); + } +} \ No newline at end of file diff --git a/third_party/rive/source/assets/image_asset.cpp b/third_party/rive/source/assets/image_asset.cpp new file mode 100644 index 0000000..0c82c31 --- /dev/null +++ b/third_party/rive/source/assets/image_asset.cpp @@ -0,0 +1,51 @@ +#include "rive/assets/image_asset.hpp" +#include "rive/artboard.hpp" +#include "rive/factory.hpp" + +using namespace rive; + +ImageAsset::~ImageAsset() +{ +#if defined(__EMSCRIPTEN__) + if (m_RenderImage != nullptr) + { + m_RenderImage->delegate(nullptr); + } +#endif +} + +#if defined(__EMSCRIPTEN__) +void ImageAsset::decodedAsync() +{ + for (auto ref : fileAssetReferencers()) + { + ref->assetUpdated(); + } +} +#endif + +bool ImageAsset::decode(SimpleArray& data, Factory* factory) +{ +#ifdef TESTING + decodedByteSize = data.size(); +#endif + renderImage(factory->decodeImage(data)); + return m_RenderImage != nullptr; +} + +void ImageAsset::renderImage(rcp renderImage) +{ + m_RenderImage = std::move(renderImage); +#if defined(__EMSCRIPTEN__) + if (m_RenderImage != nullptr) + { + m_RenderImage->delegate(this); + } +#endif + for (auto ref : fileAssetReferencers()) + { + ref->assetUpdated(); + } +} + +std::string ImageAsset::fileExtension() const { return "png"; } diff --git a/third_party/rive/source/audio/audio_engine.cpp b/third_party/rive/source/audio/audio_engine.cpp new file mode 100644 index 0000000..b18e6b4 --- /dev/null +++ b/third_party/rive/source/audio/audio_engine.cpp @@ -0,0 +1,524 @@ +#ifdef WITH_RIVE_AUDIO +#include "rive/math/simd.hpp" +#include "miniaudio.h" + +#include "rive/audio/audio_engine.hpp" +#include "rive/audio/audio_sound.hpp" +#include "rive/audio/audio_source.hpp" + +#include +#include + +using namespace rive; + +void AudioEngine::SoundCompleted(void* pUserData, ma_sound* pSound) +{ + AudioSound* audioSound = (AudioSound*)pUserData; + auto engine = audioSound->m_engine; + engine->soundCompleted(ref_rcp(audioSound)); +} + +void AudioEngine::unlinkSound(rcp sound) +{ + auto next = sound->m_nextPlaying; + auto prev = sound->m_prevPlaying; + if (next != nullptr) + { + next->m_prevPlaying = prev; + } + if (prev != nullptr) + { + prev->m_nextPlaying = next; + } + + if (m_playingSoundsHead == sound) + { + m_playingSoundsHead = next; + } + + sound->m_nextPlaying = nullptr; + sound->m_prevPlaying = nullptr; +} + +void AudioEngine::soundCompleted(rcp sound) +{ + std::unique_lock lock(m_mutex); + m_completedSounds.push_back(sound); + unlinkSound(sound); +} + +#ifdef WITH_RIVE_AUDIO_TOOLS +namespace rive +{ +class LevelsNode +{ +public: + ma_node_base base; + AudioEngine* engine; + static void measureLevels(ma_node* pNode, + const float** ppFramesIn, + ma_uint32* pFrameCountIn, + float** ppFramesOut, + ma_uint32* pFrameCountOut) + { + const float* frames = ppFramesIn[0]; + + ma_uint32 frameCount = pFrameCountIn[0]; + + static_cast(pNode)->engine->measureLevels( + frames, + (uint32_t)frameCount); + } +}; +} // namespace rive + +void AudioEngine::measureLevels(const float* frames, uint32_t frameCount) +{ + uint32_t channelCount = channels(); + + for (uint32_t i = 0; i < frameCount; i++) + { + for (uint32_t c = 0; c < channelCount; c++) + { + float sample = *frames++; + m_levels[c] = std::max(m_levels[c], sample); + } + } +} + +static ma_node_vtable measure_levels_vtable = {LevelsNode::measureLevels, + nullptr, + 1, + 1, + MA_NODE_FLAG_PASSTHROUGH}; + +void AudioEngine::initLevelMonitor() +{ + if (m_levelMonitor == nullptr) + { + m_levelMonitor = new LevelsNode(); + m_levelMonitor->engine = this; + + ma_node_config nodeConfig = ma_node_config_init(); + nodeConfig.vtable = &measure_levels_vtable; + uint32_t channelCount = channels(); + nodeConfig.pInputChannels = &channelCount; + nodeConfig.pOutputChannels = &channelCount; + m_levels.resize(channelCount); + + auto graph = ma_engine_get_node_graph(m_engine); + if (ma_node_init(graph, &nodeConfig, nullptr, &m_levelMonitor->base) != + MA_SUCCESS) + { + delete m_levelMonitor; + m_levelMonitor = nullptr; + return; + } + if (ma_node_attach_output_bus(&m_levelMonitor->base, + 0, + ma_node_graph_get_endpoint(graph), + 0) != MA_SUCCESS) + { + ma_node_uninit(&m_levelMonitor->base, nullptr); + delete m_levelMonitor; + m_levelMonitor = nullptr; + return; + } + } +} + +void AudioEngine::levels(Span levels) +{ + int size = std::min((int)m_levels.size(), (int)levels.size()); + for (int i = 0; i < size; i++) + { + levels[i] = m_levels[i]; + m_levels[i] = 0.0f; + } +} + +float AudioEngine::level(uint32_t channel) +{ + if (channel < m_levels.size()) + { + float value = m_levels[channel]; + m_levels[channel] = 0.0f; + return value; + } + return 0.0f; +} +#endif + +void AudioEngine::start() { ma_engine_start(m_engine); } +void AudioEngine::stop() { ma_engine_stop(m_engine); } + +rcp AudioEngine::Make(uint32_t numChannels, uint32_t sampleRate) +{ +// I _think_ MA_NO_DEVICE_IO is defined when building for Unity; otherwise, it +// seems to pass "standard" building When defined, pContext is unavailable, +// which causes build errors when building Unity for iOS. - David +#if (TARGET_IPHONE_SIMULATOR || TARGET_OS_MACCATALYST || TARGET_OS_IPHONE) && \ + !defined(MA_NO_DEVICE_IO) + // Used for configuration only, and isn't referenced past the usage of + // ma_context_init; thus, can be locally scoped. Uses the "logical" defaults + // from miniaudio, and updates only what we need. This should automatically + // set available backends in priority order based on the target it's built + // for, which in the case of Apple is Core Audio first. + ma_context_config contextConfig = ma_context_config_init(); + + // By setting the core audio session to none, miniaudio will not + // - set a (new) category on the shared audio session + // - set any (new) options when setting a new category + // This means that the shared AVAudioSession instance will be respected + // when audio is played; the developer will have to set up the shared + // AVAudioSession instance explicitly for their own set up. + // This does not touch whether the session is made (in)active. + contextConfig.coreaudio.sessionCategory = ma_ios_session_category_none; + + // We only need to initialize space for the context if we're targeting Apple + // platforms + ma_context* context = (ma_context*)malloc(sizeof(ma_context)); + + if (ma_context_init(NULL, 0, &contextConfig, context) != MA_SUCCESS) + { + free(context); + context = nullptr; + } +#else + ma_context* context = nullptr; +#endif + + ma_engine_config engineConfig = ma_engine_config_init(); + engineConfig.channels = numChannels; + engineConfig.sampleRate = sampleRate; + +#if (TARGET_IPHONE_SIMULATOR || TARGET_OS_MACCATALYST || TARGET_OS_IPHONE) && \ + !defined(MA_NO_DEVICE_IO) + if (context != nullptr) + { + engineConfig.pContext = context; + } +#endif + +#ifdef EXTERNAL_RIVE_AUDIO_ENGINE + engineConfig.noDevice = MA_TRUE; +#endif + + ma_engine* engine = new ma_engine(); + + if (ma_engine_init(&engineConfig, engine) != MA_SUCCESS) + { +#if (TARGET_IPHONE_SIMULATOR || TARGET_OS_MACCATALYST || TARGET_OS_IPHONE) && \ + !defined(MA_NO_DEVICE_IO) + if (context != nullptr) + { + ma_context_uninit(context); + free(context); + context = nullptr; + } +#endif + fprintf(stderr, "AudioEngine::Make - failed to init engine\n"); + delete engine; + return nullptr; + } + + return rcp(new AudioEngine(engine, context)); +} + +uint32_t AudioEngine::channels() const +{ + return ma_engine_get_channels(m_engine); +} +uint32_t AudioEngine::sampleRate() const +{ + return ma_engine_get_sample_rate(m_engine); +} + +AudioEngine::AudioEngine(ma_engine* engine, ma_context* context) : + m_device(ma_engine_get_device(engine)), m_engine(engine), m_context(context) +{} + +rcp AudioEngine::play(rcp source, + uint64_t startTime, + uint64_t endTime, + uint64_t soundStartTime, + Artboard* artboard) +{ + if (endTime != 0 && startTime >= endTime) + { + // Requested to stop sound before start. + return nullptr; + } + + std::unique_lock lock(m_mutex); + // We have to dispose completed sounds out of the completed callback. So we + // do it on next play or at destruct. + for (auto sound : m_completedSounds) + { + sound->dispose(); + } + m_completedSounds.clear(); + + rcp audioSound = + rcp(new AudioSound(this, source, artboard)); + if (source->isBuffered()) + { + rive::Span samples = source->bufferedSamples(); + ma_uint64 sizeInFrames = samples.size() / source->channels(); + if (endTime != 0) + { + float durationSeconds = + (soundStartTime + endTime - startTime) / (float)sampleRate(); + ma_uint64 clippedFrames = + (ma_uint64)std::round(durationSeconds * source->sampleRate()); + if (clippedFrames < sizeInFrames) + { + sizeInFrames = clippedFrames; + } + } + ma_audio_buffer_config config = + ma_audio_buffer_config_init(ma_format_f32, + source->channels(), + sizeInFrames, + (const void*)samples.data(), + nullptr); + if (ma_audio_buffer_init(&config, audioSound->buffer()) != MA_SUCCESS) + { + fprintf(stderr, + "AudioSource::play - Failed to initialize audio buffer.\n"); + return nullptr; + } + if (ma_sound_init_from_data_source(m_engine, + audioSound->buffer(), + MA_SOUND_FLAG_NO_PITCH | + MA_SOUND_FLAG_NO_SPATIALIZATION, + nullptr, + audioSound->sound()) != MA_SUCCESS) + { + return nullptr; + } + } + else + { + // We wrapped the miniaudio decoder with a custom data source "Clipped + // Decoder" which lets us ensure that the end callback for the sound is + // called when we reach the end of the clip. This won't happen when + // using ma_sound_set_stop_time_in_pcm_frames(audioSound->sound(), + // endTime); as this keeps the sound playing/ready to fade back in. + auto clip = audioSound->clippedDecoder(); + ma_decoder_config config = + ma_decoder_config_init(ma_format_f32, channels(), sampleRate()); + auto sourceBytes = source->bytes(); + if (ma_decoder_init_memory(sourceBytes.data(), + sourceBytes.size(), + &config, + &clip->decoder) != MA_SUCCESS) + { + fprintf(stderr, + "AudioSource::play - Failed to initialize decoder.\n"); + return nullptr; + } + clip->frameCursor = 0; + clip->endFrame = endTime == 0 ? std::numeric_limits::max() + : soundStartTime + endTime - startTime; + ma_data_source_config baseConfig = ma_data_source_config_init(); + baseConfig.vtable = &g_ma_end_clipped_decoder_vtable; + if (ma_data_source_init(&baseConfig, &clip->base) != MA_SUCCESS) + { + return nullptr; + } + + if (ma_sound_init_from_data_source(m_engine, + audioSound->clippedDecoder(), + MA_SOUND_FLAG_NO_PITCH | + MA_SOUND_FLAG_NO_SPATIALIZATION, + nullptr, + audioSound->sound()) != MA_SUCCESS) + { + return nullptr; + } + } + + if (soundStartTime != 0) + { + audioSound->seek(soundStartTime); + } + + ma_sound_set_end_callback(audioSound->sound(), + SoundCompleted, + audioSound.get()); + + if (startTime != 0) + { + ma_sound_set_start_time_in_pcm_frames(audioSound->sound(), startTime); + } +#ifdef WITH_RIVE_AUDIO_TOOLS + if (m_levelMonitor != nullptr) + { + ma_node_attach_output_bus(audioSound->sound(), 0, m_levelMonitor, 0); + } +#endif + if (ma_sound_start(audioSound->sound()) != MA_SUCCESS) + { + fprintf(stderr, "AudioSource::play - failed to start sound\n"); + return nullptr; + } + + if (m_playingSoundsHead != nullptr) + { + m_playingSoundsHead->m_prevPlaying = audioSound; + } + audioSound->m_nextPlaying = m_playingSoundsHead; + m_playingSoundsHead = audioSound; + + return audioSound; +} + +#ifdef TESTING +size_t AudioEngine::playingSoundCount() +{ + std::unique_lock lock(m_mutex); + size_t count = 0; + auto sound = m_playingSoundsHead; + while (sound != nullptr) + { + count++; + sound = sound->m_nextPlaying; + } + + return count; +} +#endif + +void AudioEngine::stop(Artboard* artboard) +{ + std::unique_lock lock(m_mutex); + auto sound = m_playingSoundsHead; + while (sound != nullptr) + { + auto next = sound->m_nextPlaying; + if (sound->m_artboard == artboard) + { + sound->stop(); + m_completedSounds.push_back(sound); + unlinkSound(sound); + } + sound = next; + } +} + +AudioEngine::~AudioEngine() +{ + auto sound = m_playingSoundsHead; + while (sound != nullptr) + { + sound->dispose(); + + auto next = sound->m_nextPlaying; + sound->m_nextPlaying = nullptr; + sound->m_prevPlaying = nullptr; + sound = next; + } + + for (auto sound : m_completedSounds) + { + sound->dispose(); + } + m_completedSounds.clear(); + + ma_engine_uninit(m_engine); + delete m_engine; + +#if (TARGET_IPHONE_SIMULATOR || TARGET_OS_MACCATALYST || TARGET_OS_IPHONE) && \ + !defined(MA_NO_DEVICE_IO) + // m_context is only set when Core Audio is available + if (m_context != nullptr) + { + ma_context_uninit(m_context); + free(m_context); + m_context = nullptr; + } +#endif + +#ifdef WITH_RIVE_AUDIO_TOOLS + if (m_levelMonitor != nullptr) + { + ma_node_uninit(&m_levelMonitor->base, nullptr); + delete m_levelMonitor; + } + +#endif +} + +uint64_t AudioEngine::timeInFrames() +{ + return (uint64_t)ma_engine_get_time_in_pcm_frames(m_engine); +} + +static rcp m_runtimeAudioEngine; +rcp AudioEngine::RuntimeEngine(bool makeWhenNecessary) +{ + if (!makeWhenNecessary) + { + return m_runtimeAudioEngine; + } + else if (m_runtimeAudioEngine == nullptr) + { + m_runtimeAudioEngine = + AudioEngine::Make(defaultNumChannels, defaultSampleRate); + } + return m_runtimeAudioEngine; +} + +#ifdef EXTERNAL_RIVE_AUDIO_ENGINE +bool AudioEngine::readAudioFrames(float* frames, + uint64_t numFrames, + uint64_t* framesRead) +{ + return ma_engine_read_pcm_frames(m_engine, + (void*)frames, + (ma_uint64)numFrames, + (ma_uint64*)framesRead) == MA_SUCCESS; +} +bool AudioEngine::sumAudioFrames(float* frames, uint64_t numFrames) +{ + size_t numChannels = (size_t)channels(); + size_t count = (size_t)numFrames * numChannels; + + if (m_readFrames.size() < count) + { + m_readFrames.resize(count); + } + ma_uint64 framesRead = 0; + if (ma_engine_read_pcm_frames(m_engine, + (void*)m_readFrames.data(), + (ma_uint64)numFrames, + &framesRead) != MA_SUCCESS) + { + return false; + } + + count = framesRead * numChannels; + + const size_t alignedCount = count - count % 4; + float* src = m_readFrames.data(); + float* dst = frames; + float* srcEnd = src + alignedCount; + + while (src != srcEnd) + { + float4 sum = simd::load4f(src) + simd::load4f(dst); + simd::store(dst, sum); + + src += 4; + dst += 4; + } + for (size_t i = alignedCount; i < count; i++) + { + frames[i] += m_readFrames[i]; + } + return true; +} +#endif + +#endif \ No newline at end of file diff --git a/third_party/rive/source/audio/audio_reader.cpp b/third_party/rive/source/audio/audio_reader.cpp new file mode 100644 index 0000000..9386886 --- /dev/null +++ b/third_party/rive/source/audio/audio_reader.cpp @@ -0,0 +1,48 @@ +#ifdef WITH_RIVE_AUDIO +#include "rive/audio/audio_reader.hpp" +#include "rive/audio/audio_source.hpp" +#include "rive/audio/audio_engine.hpp" + +using namespace rive; + +AudioReader::AudioReader(rcp audioSource, uint32_t channels) : + m_source(std::move(audioSource)), m_channels(channels), m_decoder({}) +{} + +AudioReader::~AudioReader() { ma_decoder_uninit(&m_decoder); } + +uint32_t AudioReader::channels() const { return m_channels; } +uint32_t AudioReader::sampleRate() const { return m_decoder.outputSampleRate; } +ma_decoder* AudioReader::decoder() { return &m_decoder; } + +uint64_t AudioReader::lengthInFrames() +{ + ma_uint64 length; + + ma_result result = + ma_data_source_get_length_in_pcm_frames(&m_decoder, &length); + if (result != MA_SUCCESS) + { + fprintf(stderr, + "AudioReader::lengthInFrames - audioSourceLength failed to " + "determine length\n"); + return 0; + } + return (uint64_t)length; +} + +Span AudioReader::read(uint64_t frameCount) +{ + m_readBuffer.resize(frameCount * m_channels); + + ma_uint64 framesRead; + if (ma_data_source_read_pcm_frames(&m_decoder, + m_readBuffer.data(), + (ma_uint64)frameCount, + &framesRead) != MA_SUCCESS) + { + return Span(nullptr, 0); + } + return Span(m_readBuffer.data(), framesRead * m_channels); +} +#endif \ No newline at end of file diff --git a/third_party/rive/source/audio/audio_sound.cpp b/third_party/rive/source/audio/audio_sound.cpp new file mode 100644 index 0000000..cfeb8fe --- /dev/null +++ b/third_party/rive/source/audio/audio_sound.cpp @@ -0,0 +1,73 @@ +#ifdef WITH_RIVE_AUDIO +#include "rive/audio/audio_sound.hpp" +#include "rive/audio/audio_engine.hpp" +#include "rive/audio/audio_reader.hpp" +#include "rive/audio/audio_source.hpp" + +using namespace rive; + +AudioSound::AudioSound(AudioEngine* engine, + rcp source, + Artboard* artboard) : + m_decoder({}), + m_buffer({}), + m_sound({}), + m_source(std::move(source)), + m_isDisposed(false), + m_engine(engine), + m_artboard(artboard) +{} + +void AudioSound::dispose() +{ + if (m_isDisposed) + { + return; + } + m_isDisposed = true; + ma_sound_uninit(&m_sound); + ma_decoder_uninit(&m_decoder.decoder); + ma_audio_buffer_uninit(&m_buffer); +} + +float AudioSound::volume() { return ma_sound_get_volume(&m_sound); } +void AudioSound::volume(float value) { ma_sound_set_volume(&m_sound, value); } + +bool AudioSound::completed() const +{ + if (m_isDisposed) + { + return true; + } + return (bool)ma_sound_at_end(&m_sound); +} + +AudioSound::~AudioSound() { dispose(); } + +void AudioSound::stop(uint64_t fadeTimeInFrames) +{ + if (m_isDisposed) + { + return; + } + if (fadeTimeInFrames == 0) + { + ma_sound_stop(&m_sound); + } + else + { + ma_sound_stop_with_fade_in_pcm_frames(&m_sound, fadeTimeInFrames); + } +} + +bool AudioSound::seek(uint64_t timeInFrames) +{ + if (m_isDisposed) + { + return false; + } + return ma_sound_seek_to_pcm_frame(&m_sound, (ma_uint64)timeInFrames) == + MA_SUCCESS; +} + +#endif \ No newline at end of file diff --git a/third_party/rive/source/audio/audio_source.cpp b/third_party/rive/source/audio/audio_source.cpp new file mode 100644 index 0000000..a8ca91a --- /dev/null +++ b/third_party/rive/source/audio/audio_source.cpp @@ -0,0 +1,177 @@ +#include "rive/audio/audio_source.hpp" +#ifdef WITH_RIVE_AUDIO +#include "rive/audio/audio_engine.hpp" +#include "rive/audio/audio_sound.hpp" +#include "rive/audio/audio_reader.hpp" +#include "rive/audio/audio_reader.hpp" +#endif + +using namespace rive; + +#ifdef WITH_RIVE_AUDIO +AudioSource::AudioSource(rive::Span samples, + uint32_t numChannels, + uint32_t sampleRate) : + m_isBuffered(true), + m_channels(numChannels), + m_sampleRate(sampleRate), + m_ownedBytes((uint8_t*)samples.data(), samples.size() * sizeof(float)) +{ + assert(numChannels != 0); + assert(sampleRate != 0); +} + +AudioSource::AudioSource(rive::Span fileBytes) : + m_isBuffered(false), m_channels(0), m_sampleRate(0), m_fileBytes(fileBytes) +{} + +AudioSource::AudioSource(rive::SimpleArray fileBytes) : + m_isBuffered(false), + m_channels(0), + m_sampleRate(0), + m_fileBytes(fileBytes.data(), fileBytes.size()), + m_ownedBytes(std::move(fileBytes)) +{} + +const rive::Span AudioSource::bufferedSamples() const +{ + assert(m_isBuffered); + return rive::Span((float*)m_ownedBytes.data(), + m_ownedBytes.size() / sizeof(float)); +} + +class AudioSourceDecoder +{ +public: + AudioSourceDecoder(rive::Span fileBytes) : m_decoder({}) + { + ma_decoder_config config = ma_decoder_config_init(ma_format_f32, 0, 0); + if (ma_decoder_init_memory(fileBytes.data(), + fileBytes.size(), + &config, + &m_decoder) != MA_SUCCESS) + { + fprintf(stderr, + "AudioSourceDecoder - Failed to initialize decoder.\n"); + } + } + + ~AudioSourceDecoder() { ma_decoder_uninit(&m_decoder); } + + uint32_t channels() { return (uint32_t)m_decoder.outputChannels; } + + uint32_t sampleRate() { return (uint32_t)m_decoder.outputSampleRate; } + +private: + ma_decoder m_decoder; +}; + +uint32_t AudioSource::channels() +{ + if (m_channels != 0) + { + return m_channels; + } + AudioSourceDecoder audioDecoder(m_fileBytes); + return m_channels = audioDecoder.channels(); +} + +uint32_t AudioSource::sampleRate() +{ + if (m_sampleRate != 0) + { + return m_sampleRate; + } + AudioSourceDecoder audioDecoder(m_fileBytes); + return m_sampleRate = audioDecoder.sampleRate(); +} + +AudioFormat AudioSource::format() const +{ + if (m_isBuffered) + { + return AudioFormat::buffered; + } + ma_decoder decoder; + ma_decoder_config config = ma_decoder_config_init(ma_format_f32, 0, 0); + if (ma_decoder_init_memory(m_fileBytes.data(), + m_fileBytes.size(), + &config, + &decoder) != MA_SUCCESS) + { + fprintf(stderr, + "AudioSource::format - Failed to initialize decoder.\n"); + return AudioFormat::unknown; + } + ma_encoding_format encodingFormat; + + AudioFormat format = AudioFormat::unknown; + if (ma_decoder_get_encoding_format(&decoder, &encodingFormat) == MA_SUCCESS) + { + switch (encodingFormat) + { + case ma_encoding_format_mp3: + format = AudioFormat::mp3; + break; + case ma_encoding_format_wav: + format = AudioFormat::wav; + break; + case ma_encoding_format_vorbis: + format = AudioFormat::vorbis; + break; + case ma_encoding_format_flac: + format = AudioFormat::flac; + break; + default: + format = AudioFormat::unknown; + break; + } + } + + ma_decoder_uninit(&decoder); + + return format; +} + +rcp AudioSource::makeReader(uint32_t numChannels, + uint32_t sampleRate) +{ + if (m_isBuffered) + { + return nullptr; + } + + rive::rcp rcSource = rive::rcp(this); + rcSource->ref(); + auto reader = rcp(new AudioReader(rcSource, numChannels)); + + ma_decoder_config config = + ma_decoder_config_init(ma_format_f32, numChannels, sampleRate); + + if (ma_decoder_init_memory(m_fileBytes.data(), + m_fileBytes.size(), + &config, + reader->decoder()) != MA_SUCCESS) + { + fprintf(stderr, + "AudioSource::makeReader - Failed to initialize decoder.\n"); + return nullptr; + } + + return reader; +} +#else +AudioSource::AudioSource(rive::Span fileBytes) {} +AudioSource::AudioSource(rive::SimpleArray fileBytes) {} +AudioSource::AudioSource(rive::Span samples, + uint32_t numChannels, + uint32_t sampleRate) +{} +uint32_t AudioSource::channels() { return 0; } +uint32_t AudioSource::sampleRate() { return 0; } +AudioFormat AudioSource::format() const { return AudioFormat::unknown; } +const rive::Span AudioSource::bufferedSamples() const +{ + return rive::Span(nullptr, 0); +} +#endif \ No newline at end of file diff --git a/third_party/rive/source/audio_event.cpp b/third_party/rive/source/audio_event.cpp new file mode 100644 index 0000000..b2eef60 --- /dev/null +++ b/third_party/rive/source/audio_event.cpp @@ -0,0 +1,83 @@ +#include "rive/audio_event.hpp" +#include "rive/assets/audio_asset.hpp" +#include "rive/audio/audio_engine.hpp" +#include "rive/audio/audio_sound.hpp" +#include "rive/artboard.hpp" + +using namespace rive; + +void AudioEvent::play() +{ +#ifdef WITH_RIVE_AUDIO + auto audioAsset = (AudioAsset*)m_fileAsset; + if (audioAsset == nullptr) + { + return; + } + auto audioSource = audioAsset->audioSource(); + if (audioSource == nullptr) + { + return; + } + + auto volume = audioAsset->volume() * artboard()->volume(); + if (volume <= 0.0f) + { + return; + } + + auto engine = +#ifdef EXTERNAL_RIVE_AUDIO_ENGINE + artboard()->audioEngine() != nullptr ? artboard()->audioEngine() : +#endif + AudioEngine::RuntimeEngine(); + + auto sound = + engine->play(audioSource, engine->timeInFrames(), 0, 0, artboard()); + + if (volume != 1.0f) + { + sound->volume(volume); + } +#endif +} + +void AudioEvent::trigger(const CallbackData& value) +{ + Super::trigger(value); + if (!value.context()->playsAudio()) + { + // Context won't play audio, we'll do it ourselves. + play(); + } +} + +StatusCode AudioEvent::import(ImportStack& importStack) +{ + auto result = registerReferencer(importStack); + if (result != StatusCode::Ok) + { + return result; + } + return Super::import(importStack); +} + +void AudioEvent::setAsset(FileAsset* asset) +{ + if (asset->is()) + { + FileAssetReferencer::setAsset(asset); + } +} + +Core* AudioEvent::clone() const +{ + AudioEvent* twin = AudioEventBase::clone()->as(); + if (m_fileAsset != nullptr) + { + twin->setAsset(m_fileAsset); + } + return twin; +} + +uint32_t AudioEvent::assetId() { return AudioEventBase::assetId(); } \ No newline at end of file diff --git a/third_party/rive/source/bones/bone.cpp b/third_party/rive/source/bones/bone.cpp new file mode 100644 index 0000000..ccdd9d2 --- /dev/null +++ b/third_party/rive/source/bones/bone.cpp @@ -0,0 +1,43 @@ +#include "rive/bones/bone.hpp" +#include "rive/math/vec2d.hpp" +#include + +using namespace rive; + +void Bone::addChildBone(Bone* bone) { m_ChildBones.push_back(bone); } + +StatusCode Bone::onAddedClean(CoreContext* context) +{ + Super::onAddedClean(context); + if (!parent()->is()) + { + return StatusCode::MissingObject; + } + parent()->as()->addChildBone(this); + return StatusCode::Ok; +} + +void Bone::lengthChanged() +{ + for (auto bone : m_ChildBones) + { + bone->markTransformDirty(); + } +} + +float Bone::x() const { return parent()->as()->length(); } + +float Bone::y() const { return 0.0f; } + +Vec2D Bone::tipWorldTranslation() const +{ + return worldTransform() * Vec2D(length(), 0); +} + +void Bone::addPeerConstraint(Constraint* peer) +{ + assert(std::find(m_PeerConstraints.begin(), + m_PeerConstraints.end(), + peer) == m_PeerConstraints.end()); + m_PeerConstraints.push_back(peer); +} diff --git a/third_party/rive/source/bones/root_bone.cpp b/third_party/rive/source/bones/root_bone.cpp new file mode 100644 index 0000000..ff592f9 --- /dev/null +++ b/third_party/rive/source/bones/root_bone.cpp @@ -0,0 +1,15 @@ +#include "rive/bones/root_bone.hpp" + +using namespace rive; + +StatusCode RootBone::onAddedClean(CoreContext* context) +{ + // Intentionally doesn't call Super(Bone)::onAddedClean and goes straight to + // the super.super TransformComponent as that assumes the parent must be a + // Bone while a root bone is a special case Bone that can be parented to + // other TransformComponents. + return TransformComponent::onAddedClean(context); +} + +void RootBone::xChanged() { markTransformDirty(); } +void RootBone::yChanged() { markTransformDirty(); } \ No newline at end of file diff --git a/third_party/rive/source/bones/skin.cpp b/third_party/rive/source/bones/skin.cpp new file mode 100644 index 0000000..2041876 --- /dev/null +++ b/third_party/rive/source/bones/skin.cpp @@ -0,0 +1,94 @@ +#include "rive/bones/skin.hpp" +#include "rive/bones/bone.hpp" +#include "rive/bones/skinnable.hpp" +#include "rive/bones/tendon.hpp" +#include "rive/shapes/vertex.hpp" +#include "rive/shapes/path_vertex.hpp" +#include "rive/constraints/constraint.hpp" + +using namespace rive; + +Skin::~Skin() { delete[] m_BoneTransforms; } + +StatusCode Skin::onAddedDirty(CoreContext* context) +{ + StatusCode code = Super::onAddedDirty(context); + if (code != StatusCode::Ok) + { + return code; + } + m_WorldTransform[0] = xx(); + m_WorldTransform[1] = xy(); + m_WorldTransform[2] = yx(); + m_WorldTransform[3] = yy(); + m_WorldTransform[4] = tx(); + m_WorldTransform[5] = ty(); + + m_Skinnable = Skinnable::from(parent()); + if (m_Skinnable == nullptr) + { + return StatusCode::MissingObject; + } + + m_Skinnable->skin(this); + + return StatusCode::Ok; +} + +void Skin::update(ComponentDirt value) +{ + int bidx = 6; + for (auto tendon : m_Tendons) + { + auto world = tendon->bone()->worldTransform() * tendon->inverseBind(); + m_BoneTransforms[bidx++] = world[0]; + m_BoneTransforms[bidx++] = world[1]; + m_BoneTransforms[bidx++] = world[2]; + m_BoneTransforms[bidx++] = world[3]; + m_BoneTransforms[bidx++] = world[4]; + m_BoneTransforms[bidx++] = world[5]; + } +} + +void Skin::buildDependencies() +{ + // depend on bones from tendons + for (auto tendon : m_Tendons) + { + auto bone = tendon->bone(); + bone->addDependent(this); + for (auto constraint : bone->peerConstraints()) + { + constraint->parent()->addDependent(this); + } + } + + // Make sure no-one is calling this twice. + assert(m_BoneTransforms == nullptr); + // We can now init the bone buffer. + auto size = (m_Tendons.size() + 1) * 6; + m_BoneTransforms = new float[size]; + m_BoneTransforms[0] = 1; + m_BoneTransforms[1] = 0; + m_BoneTransforms[2] = 0; + m_BoneTransforms[3] = 1; + m_BoneTransforms[4] = 0; + m_BoneTransforms[5] = 0; +} + +void Skin::deform(Span vertices) +{ + for (auto vertex : vertices) + { + vertex->deform(m_WorldTransform, m_BoneTransforms); + } +} +void Skin::addTendon(Tendon* tendon) { m_Tendons.push_back(tendon); } + +void Skin::onDirty(ComponentDirt dirt) +{ + if (m_Skinnable != nullptr) + { + m_Skinnable->markSkinDirty(); + } +} diff --git a/third_party/rive/source/bones/skinnable.cpp b/third_party/rive/source/bones/skinnable.cpp new file mode 100644 index 0000000..74b33cb --- /dev/null +++ b/third_party/rive/source/bones/skinnable.cpp @@ -0,0 +1,19 @@ +#include "rive/bones/skinnable.hpp" +#include "rive/shapes/points_path.hpp" +#include "rive/shapes/mesh.hpp" + +using namespace rive; + +Skinnable* Skinnable::from(Component* component) +{ + switch (component->coreType()) + { + case PointsPath::typeKey: + return component->as(); + case Mesh::typeKey: + return component->as(); + } + return nullptr; +} + +void Skinnable::skin(Skin* skin) { m_Skin = skin; } \ No newline at end of file diff --git a/third_party/rive/source/bones/tendon.cpp b/third_party/rive/source/bones/tendon.cpp new file mode 100644 index 0000000..279b6c2 --- /dev/null +++ b/third_party/rive/source/bones/tendon.cpp @@ -0,0 +1,51 @@ +#include "rive/bones/tendon.hpp" +#include "rive/bones/bone.hpp" +#include "rive/bones/skin.hpp" +#include "rive/core_context.hpp" + +using namespace rive; + +StatusCode Tendon::onAddedDirty(CoreContext* context) +{ + Mat2D bind; + bind[0] = xx(); + bind[1] = xy(); + bind[2] = yx(); + bind[3] = yy(); + bind[4] = tx(); + bind[5] = ty(); + + // Internally, this inversion can fail because of a division by 0. + // 'm_InverseBind' will default to an identity matrix. Although + // this can be treated as undefined behavior, the editor lets it go + // through, and nothing really breaks, it just can look odd. So we + // allow the runtime to behave in the same way and return StatusCode::Ok. + bind.invert(&m_InverseBind); + + StatusCode code = Super::onAddedDirty(context); + if (code != StatusCode::Ok) + { + return code; + } + auto coreObject = context->resolve(boneId()); + if (coreObject == nullptr || !coreObject->is()) + { + return StatusCode::MissingObject; + } + + m_Bone = static_cast(coreObject); + + return StatusCode::Ok; +} + +StatusCode Tendon::onAddedClean(CoreContext* context) +{ + if (!parent()->is()) + { + return StatusCode::MissingObject; + } + + parent()->as()->addTendon(this); + + return StatusCode::Ok; +} diff --git a/third_party/rive/source/bones/weight.cpp b/third_party/rive/source/bones/weight.cpp new file mode 100644 index 0000000..642a6e4 --- /dev/null +++ b/third_party/rive/source/bones/weight.cpp @@ -0,0 +1,56 @@ +#include "rive/bones/weight.hpp" +#include "rive/container_component.hpp" +#include "rive/shapes/vertex.hpp" + +using namespace rive; + +StatusCode Weight::onAddedDirty(CoreContext* context) +{ + StatusCode code = Super::onAddedDirty(context); + if (code != StatusCode::Ok) + { + return code; + } + if (!parent()->is()) + { + return StatusCode::MissingObject; + } + + parent()->as()->weight(this); + + return StatusCode::Ok; +} + +static int encodedWeightValue(unsigned int index, unsigned int data) +{ + return (data >> (index * 8)) & 0xFF; +} + +Vec2D Weight::deform(Vec2D inPoint, + unsigned int indices, + unsigned int weights, + const Mat2D& world, + const float* boneTransforms) +{ + float xx = 0, xy = 0, yx = 0, yy = 0, tx = 0, ty = 0; + for (int i = 0; i < 4; i++) + { + int weight = encodedWeightValue(i, weights); + if (weight == 0) + { + continue; + } + + float normalizedWeight = weight / 255.0f; + int index = encodedWeightValue(i, indices); + int startBoneTransformIndex = index * 6; + xx += boneTransforms[startBoneTransformIndex++] * normalizedWeight; + xy += boneTransforms[startBoneTransformIndex++] * normalizedWeight; + yx += boneTransforms[startBoneTransformIndex++] * normalizedWeight; + yy += boneTransforms[startBoneTransformIndex++] * normalizedWeight; + tx += boneTransforms[startBoneTransformIndex++] * normalizedWeight; + ty += boneTransforms[startBoneTransformIndex++] * normalizedWeight; + } + + return Mat2D(xx, xy, yx, yy, tx, ty) * (world * inPoint); +} diff --git a/third_party/rive/source/command_queue.cpp b/third_party/rive/source/command_queue.cpp new file mode 100644 index 0000000..dccec82 --- /dev/null +++ b/third_party/rive/source/command_queue.cpp @@ -0,0 +1,407 @@ +/* + * Copyright 2025 Rive + */ + +#include "rive/command_queue.hpp" + +namespace rive +{ +namespace +{ +// RAII utility to lock a mutex, and call notify_one() on a condition variable +// immediately before unlocking. +class AutoLockAndNotify +{ +public: + AutoLockAndNotify(std::mutex& mutex, std::condition_variable& cv) : + m_mutex(mutex), m_cv(cv) + { + m_mutex.lock(); + } + + ~AutoLockAndNotify() + { + m_cv.notify_one(); + m_mutex.unlock(); + } + +private: + std::mutex& m_mutex; + std::condition_variable& m_cv; +}; +}; // namespace + +CommandQueue::CommandQueue() {} + +CommandQueue::~CommandQueue() {} + +FileHandle CommandQueue::loadFile(std::vector rivBytes, + rcp loader, + FileListener* listener, + uint64_t requestId) +{ + auto handle = reinterpret_cast(++m_currentFileHandleIdx); + + if (listener) + { + listener->m_handle = handle; + listener->m_owningQueue = ref_rcp(this); + registerListener(handle, listener); + } + + AutoLockAndNotify lock(m_commandMutex, m_commandConditionVariable); + m_commandStream << Command::loadFile; + m_commandStream << handle; + m_commandStream << requestId; + m_commandStream << loader; + m_byteVectors << std::move(rivBytes); + + return handle; +} + +void CommandQueue::deleteFile(FileHandle fileHandle, uint64_t requestId) +{ + AutoLockAndNotify lock(m_commandMutex, m_commandConditionVariable); + m_commandStream << Command::deleteFile; + m_commandStream << fileHandle; + m_commandStream << requestId; +} + +ArtboardHandle CommandQueue::instantiateArtboardNamed( + FileHandle fileHandle, + std::string name, + ArtboardListener* listener, + uint64_t requestId) +{ + auto handle = + reinterpret_cast(++m_currentArtboardHandleIdx); + + if (listener) + { + listener->m_handle = handle; + listener->m_owningQueue = ref_rcp(this); + registerListener(handle, listener); + } + + AutoLockAndNotify lock(m_commandMutex, m_commandConditionVariable); + m_commandStream << Command::instantiateArtboard; + m_commandStream << handle; + m_commandStream << fileHandle; + m_commandStream << requestId; + m_names << std::move(name); + + return handle; +} + +void CommandQueue::deleteArtboard(ArtboardHandle artboardHandle, + uint64_t requestId) +{ + AutoLockAndNotify lock(m_commandMutex, m_commandConditionVariable); + m_commandStream << Command::deleteArtboard; + m_commandStream << artboardHandle; + m_commandStream << requestId; +} + +StateMachineHandle CommandQueue::instantiateStateMachineNamed( + ArtboardHandle artboardHandle, + std::string name, + StateMachineListener* listener, + uint64_t requestId) +{ + auto handle = + reinterpret_cast(++m_currentStateMachineHandleIdx); + + if (listener) + { + listener->m_handle = handle; + listener->m_owningQueue = ref_rcp(this); + registerListener(handle, listener); + } + + AutoLockAndNotify lock(m_commandMutex, m_commandConditionVariable); + m_commandStream << Command::instantiateStateMachine; + m_commandStream << handle; + m_commandStream << artboardHandle; + m_commandStream << requestId; + m_names << std::move(name); + + return handle; +} + +void CommandQueue::pointerMove(StateMachineHandle stateMachineHandle, + Vec2D position) +{ + AutoLockAndNotify lock(m_commandMutex, m_commandConditionVariable); + m_commandStream << Command::pointerMove; + m_commandStream << stateMachineHandle; + m_commandStream << position; +} + +void CommandQueue::pointerDown(StateMachineHandle stateMachineHandle, + Vec2D position) +{ + AutoLockAndNotify lock(m_commandMutex, m_commandConditionVariable); + m_commandStream << Command::pointerDown; + m_commandStream << stateMachineHandle; + m_commandStream << position; +} + +void CommandQueue::pointerUp(StateMachineHandle stateMachineHandle, + Vec2D position) +{ + AutoLockAndNotify lock(m_commandMutex, m_commandConditionVariable); + m_commandStream << Command::pointerUp; + m_commandStream << stateMachineHandle; + m_commandStream << position; +} + +void CommandQueue::pointerExit(StateMachineHandle stateMachineHandle, + Vec2D position) +{ + AutoLockAndNotify lock(m_commandMutex, m_commandConditionVariable); + m_commandStream << Command::pointerExit; + m_commandStream << stateMachineHandle; + m_commandStream << position; +} + +void CommandQueue::advanceStateMachine(StateMachineHandle stateMachineHandle, + float timeToAdvance, + uint64_t requestId) +{ + AutoLockAndNotify lock(m_commandMutex, m_commandConditionVariable); + m_commandStream << Command::advanceStateMachine; + m_commandStream << stateMachineHandle; + m_commandStream << requestId; + m_commandStream << timeToAdvance; +} + +void CommandQueue::deleteStateMachine(StateMachineHandle stateMachineHandle, + uint64_t requestId) +{ + AutoLockAndNotify lock(m_commandMutex, m_commandConditionVariable); + m_commandStream << Command::deleteStateMachine; + m_commandStream << stateMachineHandle; + m_commandStream << requestId; +} + +DrawKey CommandQueue::createDrawKey() +{ + // lock here so we can do this from several threads safely + AutoLockAndNotify lock(m_commandMutex, m_commandConditionVariable); + auto key = reinterpret_cast(++m_currentDrawKeyIdx); + return key; +} + +void CommandQueue::draw(DrawKey drawKey, CommandServerDrawCallback callback) +{ + AutoLockAndNotify lock(m_commandMutex, m_commandConditionVariable); + m_commandStream << Command::draw; + m_commandStream << drawKey; + m_drawCallbacks << std::move(callback); +} +#ifdef TESTING +void CommandQueue::testing_commandLoopBreak() +{ + AutoLockAndNotify lock(m_commandMutex, m_commandConditionVariable); + m_commandStream << Command::commandLoopBreak; +} + +CommandQueue::FileListener* CommandQueue::testing_getFileListener( + FileHandle handle) +{ + auto iter = m_fileListeners.find(handle); + if (iter != m_fileListeners.end()) + return iter->second; + return nullptr; +} + +CommandQueue::ArtboardListener* CommandQueue::testing_getArtboardListener( + ArtboardHandle handle) +{ + auto iter = m_artboardListeners.find(handle); + if (iter != m_artboardListeners.end()) + return iter->second; + return nullptr; +} + +CommandQueue::StateMachineListener* CommandQueue:: + testing_getStateMachineListener(StateMachineHandle handle) +{ + auto iter = m_stateMachineListeners.find(handle); + if (iter != m_stateMachineListeners.end()) + return iter->second; + return nullptr; +} + +#endif +void CommandQueue::runOnce(CommandServerCallback callback) +{ + AutoLockAndNotify lock(m_commandMutex, m_commandConditionVariable); + m_commandStream << Command::runOnce; + m_callbacks << std::move(callback); +} + +void CommandQueue::disconnect() +{ + AutoLockAndNotify lock(m_commandMutex, m_commandConditionVariable); + m_commandStream << Command::disconnect; +} + +void CommandQueue::requestArtboardNames(FileHandle fileHandle, + uint64_t requestId) +{ + AutoLockAndNotify lock(m_commandMutex, m_commandConditionVariable); + m_commandStream << Command::listArtboards; + m_commandStream << fileHandle; + m_commandStream << requestId; +} + +void CommandQueue::requestStateMachineNames(ArtboardHandle artboardHandle, + uint64_t requestId) +{ + AutoLockAndNotify lock(m_commandMutex, m_commandConditionVariable); + m_commandStream << Command::listStateMachines; + m_commandStream << artboardHandle; + m_commandStream << requestId; +} + +void CommandQueue::processMessages() +{ + std::unique_lock lock(m_messageMutex); + + if (m_messageStream.empty()) + return; + + // Mark where we will end processing messages. This way if new messages come + // in while we're processing the existing ones, we won't loop forever. + m_messageStream << Message::messageLoopBreak; + + do + { + Message message; + m_messageStream >> message; + + switch (message) + { + case Message::messageLoopBreak: + lock.unlock(); + return; + case Message::artboardsListed: + { + size_t numArtboards; + FileHandle handle; + uint64_t requestId; + m_messageStream >> handle; + m_messageStream >> requestId; + m_messageStream >> numArtboards; + std::vector artboardNames(numArtboards); + for (auto& name : artboardNames) + { + m_messageNames >> name; + } + lock.unlock(); + + auto itr = m_fileListeners.find(handle); + if (itr != m_fileListeners.end()) + { + itr->second->onArtboardsListed(itr->first, + requestId, + std::move(artboardNames)); + } + break; + } + case Message::stateMachinesListed: + { + size_t numStateMachines; + ArtboardHandle handle; + uint64_t requestId; + m_messageStream >> handle; + m_messageStream >> requestId; + m_messageStream >> numStateMachines; + std::vector stateMachineNames(numStateMachines); + for (auto& name : stateMachineNames) + { + m_messageNames >> name; + } + lock.unlock(); + + auto itr = m_artboardListeners.find(handle); + if (itr != m_artboardListeners.end()) + { + itr->second->onStateMachinesListed( + itr->first, + requestId, + std::move(stateMachineNames)); + } + + break; + } + case Message::fileDeleted: + { + FileHandle handle; + uint64_t requestId; + m_messageStream >> handle; + m_messageStream >> requestId; + lock.unlock(); + auto itr = m_fileListeners.find(handle); + if (itr != m_fileListeners.end()) + { + itr->second->onFileDeleted(handle, requestId); + } + break; + } + case Message::artboardDeleted: + { + ArtboardHandle handle; + uint64_t requestId; + m_messageStream >> handle; + m_messageStream >> requestId; + lock.unlock(); + auto itr = m_artboardListeners.find(handle); + if (itr != m_artboardListeners.end()) + { + itr->second->onArtboardDeleted(handle, requestId); + } + break; + } + case Message::stateMachineSettled: + { + StateMachineHandle handle; + uint64_t requestId; + m_messageStream >> handle; + m_messageStream >> requestId; + lock.unlock(); + auto itr = m_stateMachineListeners.find(handle); + if (itr != m_stateMachineListeners.end()) + { + itr->second->onStateMachineSettled(handle, requestId); + } + break; + } + case Message::stateMachineDeleted: + { + StateMachineHandle handle; + uint64_t requestId; + m_messageStream >> handle; + m_messageStream >> requestId; + lock.unlock(); + auto itr = m_stateMachineListeners.find(handle); + if (itr != m_stateMachineListeners.end()) + { + itr->second->onStateMachineDeleted(handle, requestId); + } + break; + } + default: + { + RIVE_UNREACHABLE(); + break; + } + } + + assert(!lock.owns_lock()); + lock.lock(); + } while (!m_messageStream.empty()); +} + +}; // namespace rive diff --git a/third_party/rive/source/command_server.cpp b/third_party/rive/source/command_server.cpp new file mode 100644 index 0000000..7a1d197 --- /dev/null +++ b/third_party/rive/source/command_server.cpp @@ -0,0 +1,450 @@ +/* + * Copyright 2025 Rive + */ + +#include "rive/command_server.hpp" + +#include "rive/file.hpp" +#include "rive/animation/state_machine_instance.hpp" + +namespace rive +{ +CommandServer::CommandServer(rcp commandBuffer, + Factory* factory) : + m_commandQueue(std::move(commandBuffer)), + m_factory(factory) +#ifndef NDEBUG + , + m_threadID(std::this_thread::get_id()) +#endif +{} + +CommandServer::~CommandServer() {} + +File* CommandServer::getFile(FileHandle handle) const +{ + assert(std::this_thread::get_id() == m_threadID); + auto it = m_files.find(handle); + return it != m_files.end() ? it->second.get() : nullptr; +} + +ArtboardInstance* CommandServer::getArtboardInstance( + ArtboardHandle handle) const +{ + assert(std::this_thread::get_id() == m_threadID); + auto it = m_artboards.find(handle); + return it != m_artboards.end() ? it->second.get() : nullptr; +} + +StateMachineInstance* CommandServer::getStateMachineInstance( + StateMachineHandle handle) const +{ + assert(std::this_thread::get_id() == m_threadID); + auto it = m_stateMachines.find(handle); + return it != m_stateMachines.end() ? it->second.get() : nullptr; +} + +void CommandServer::serveUntilDisconnect() +{ + while (waitCommands()) + { + } +} + +bool CommandServer::waitCommands() +{ + PODStream& commandStream = m_commandQueue->m_commandStream; + if (commandStream.empty()) + { + std::unique_lock lock(m_commandQueue->m_commandMutex); + while (commandStream.empty()) + m_commandQueue->m_commandConditionVariable.wait(lock); + } + + return processCommands(); +} + +bool CommandServer::processCommands() +{ + assert(m_wasDisconnectReceived == false); + assert(std::this_thread::get_id() == m_threadID); + + PODStream& commandStream = m_commandQueue->m_commandStream; + std::unique_lock lock(m_commandQueue->m_commandMutex); + + // Early out if we don't have anything to process. + if (commandStream.empty()) + return !m_wasDisconnectReceived; + + // Ensure we stop processing messages and get to the draw loop. + // This avoids a race condition where we never stop processing messages and + // therefore never draw anything. + commandStream << CommandQueue::Command::commandLoopBreak; + + // The map should be empty at this point. + assert(m_uniqueDraws.empty()); + + bool shouldProcessCommands = true; + do + { + CommandQueue::Command command; + commandStream >> command; + switch (command) + { + case CommandQueue::Command::loadFile: + { + FileHandle handle; + uint64_t requestId; + std::vector rivBytes; + rcp loader; + commandStream >> handle; + commandStream >> requestId; + commandStream >> loader; + m_commandQueue->m_byteVectors >> rivBytes; + lock.unlock(); + std::unique_ptr file = + rive::File::import(rivBytes, + m_factory, + nullptr, + std::move(loader)); + if (file != nullptr) + { + m_files[handle] = std::move(file); + } + else + { + fprintf(stderr, "ERROR: failed to load Rive file.\n"); + } + break; + } + + case CommandQueue::Command::deleteFile: + { + FileHandle handle; + uint64_t requestId; + commandStream >> handle; + commandStream >> requestId; + lock.unlock(); + m_files.erase(handle); + std::unique_lock messageLock( + m_commandQueue->m_messageMutex); + m_commandQueue->m_messageStream + << CommandQueue::Message::fileDeleted; + m_commandQueue->m_messageStream << handle; + m_commandQueue->m_messageStream << requestId; + break; + } + + case CommandQueue::Command::instantiateArtboard: + { + ArtboardHandle handle; + FileHandle fileHandle; + uint64_t requestId; + std::string name; + commandStream >> handle; + commandStream >> fileHandle; + commandStream >> requestId; + m_commandQueue->m_names >> name; + lock.unlock(); + if (rive::File* file = getFile(fileHandle)) + { + if (auto artboard = name.empty() + ? file->artboardDefault() + : file->artboardNamed(name)) + { + m_artboards[handle] = std::move(artboard); + } + else + { + fprintf(stderr, + "ERROR: artboard \"%s\" not found.\n", + name.c_str()); + } + } + break; + } + + case CommandQueue::Command::deleteArtboard: + { + ArtboardHandle handle; + uint64_t requestId; + commandStream >> handle; + commandStream >> requestId; + lock.unlock(); + m_artboards.erase(handle); + std::unique_lock messageLock( + m_commandQueue->m_messageMutex); + m_commandQueue->m_messageStream + << CommandQueue::Message::artboardDeleted; + m_commandQueue->m_messageStream << handle; + m_commandQueue->m_messageStream << requestId; + break; + } + + case CommandQueue::Command::instantiateStateMachine: + { + StateMachineHandle handle; + ArtboardHandle artboardHandle; + uint64_t requestId; + std::string name; + commandStream >> handle; + commandStream >> artboardHandle; + commandStream >> requestId; + m_commandQueue->m_names >> name; + lock.unlock(); + if (rive::ArtboardInstance* artboard = + getArtboardInstance(artboardHandle)) + { + if (auto stateMachine = + name.empty() ? artboard->defaultStateMachine() + : artboard->stateMachineNamed(name)) + { + m_stateMachines[handle] = std::move(stateMachine); + } + else + { + fprintf(stderr, + "ERROR: Could not create state machine with " + "name \"%s\" because it was not found.\n", + name.c_str()); + } + } + break; + } + + case CommandQueue::Command::advanceStateMachine: + { + StateMachineHandle handle; + uint64_t requestId; + float timeToAdvance; + commandStream >> handle; + commandStream >> requestId; + commandStream >> timeToAdvance; + lock.unlock(); + + if (auto stateMachine = getStateMachineInstance(handle)) + { + if (!stateMachine->advanceAndApply(timeToAdvance)) + { + std::unique_lock messageLock( + m_commandQueue->m_messageMutex); + m_commandQueue->m_messageStream + << CommandQueue::Message::stateMachineSettled; + m_commandQueue->m_messageStream << handle; + m_commandQueue->m_messageStream << requestId; + } + } + else + { + fprintf(stderr, + "ERROR: State machine \"%llu\" not found for " + "advance.\n", + reinterpret_cast(handle)); + } + + break; + } + + case CommandQueue::Command::deleteStateMachine: + { + StateMachineHandle handle; + uint64_t requestId; + commandStream >> handle; + commandStream >> requestId; + lock.unlock(); + m_stateMachines.erase(handle); + std::unique_lock messageLock( + m_commandQueue->m_messageMutex); + m_commandQueue->m_messageStream + << CommandQueue::Message::stateMachineDeleted; + m_commandQueue->m_messageStream << handle; + m_commandQueue->m_messageStream << requestId; + break; + } + + case CommandQueue::Command::runOnce: + { + CommandServerCallback callback; + m_commandQueue->m_callbacks >> callback; + lock.unlock(); + callback(this); + break; + } + + case CommandQueue::Command::draw: + { + DrawKey drawKey; + CommandServerDrawCallback drawCallback; + commandStream >> drawKey; + m_commandQueue->m_drawCallbacks >> drawCallback; + lock.unlock(); + m_uniqueDraws[drawKey] = std::move(drawCallback); + break; + } + + case CommandQueue::Command::commandLoopBreak: + { + lock.unlock(); + shouldProcessCommands = false; + break; + } + + case CommandQueue::Command::listArtboards: + { + FileHandle handle; + uint64_t requestId; + commandStream >> handle; + commandStream >> requestId; + lock.unlock(); + auto file = getFile(handle); + if (file) + { + auto artboards = file->artboards(); + + std::unique_lock messageLock( + m_commandQueue->m_messageMutex); + m_commandQueue->m_messageStream + << CommandQueue::Message::artboardsListed; + m_commandQueue->m_messageStream << handle; + m_commandQueue->m_messageStream << requestId; + m_commandQueue->m_messageStream << artboards.size(); + for (auto artboard : artboards) + { + m_commandQueue->m_messageNames << artboard->name(); + } + } + + break; + } + + case CommandQueue::Command::listStateMachines: + { + ArtboardHandle handle; + uint64_t requestId; + commandStream >> handle; + commandStream >> requestId; + lock.unlock(); + auto artboard = getArtboardInstance(handle); + if (artboard) + { + auto numStateMachines = artboard->stateMachineCount(); + std::unique_lock messageLock( + m_commandQueue->m_messageMutex); + m_commandQueue->m_messageStream + << CommandQueue::Message::stateMachinesListed; + m_commandQueue->m_messageStream << handle; + m_commandQueue->m_messageStream << requestId; + m_commandQueue->m_messageStream << numStateMachines; + for (int i = 0; i < numStateMachines; ++i) + { + m_commandQueue->m_messageNames + << artboard->stateMachineNameAt(i); + } + } + break; + } + + case CommandQueue::Command::pointerMove: + { + StateMachineHandle handle; + Vec2D position; + commandStream >> handle; + commandStream >> position; + lock.unlock(); + if (auto stateMachine = getStateMachineInstance(handle)) + { + stateMachine->pointerMove(position); + } + else + { + fprintf(stderr, + "ERROR: State machine \"%llu\" not found for " + "pointerMove.\n", + reinterpret_cast(handle)); + } + break; + } + + case CommandQueue::Command::pointerDown: + { + StateMachineHandle handle; + Vec2D position; + commandStream >> handle; + commandStream >> position; + lock.unlock(); + if (auto stateMachine = getStateMachineInstance(handle)) + { + stateMachine->pointerDown(position); + } + { + fprintf(stderr, + "ERROR: State machine \"%llu\" not found for " + "pointerDown.\n", + reinterpret_cast(handle)); + } + break; + } + + case CommandQueue::Command::pointerUp: + { + StateMachineHandle handle; + Vec2D position; + commandStream >> handle; + commandStream >> position; + lock.unlock(); + if (auto stateMachine = getStateMachineInstance(handle)) + { + stateMachine->pointerUp(position); + } + { + fprintf(stderr, + "ERROR: State machine \"%llu\" not found for " + "pointerUp.\n", + reinterpret_cast(handle)); + } + break; + } + + case CommandQueue::Command::pointerExit: + { + StateMachineHandle handle; + Vec2D position; + commandStream >> handle; + commandStream >> position; + lock.unlock(); + if (auto stateMachine = getStateMachineInstance(handle)) + { + stateMachine->pointerExit(position); + } + { + fprintf(stderr, + "ERROR: State machine \"%llu\" not found for " + "pointerExit.\n", + reinterpret_cast(handle)); + } + break; + } + + case CommandQueue::Command::disconnect: + { + lock.unlock(); + m_wasDisconnectReceived = true; + return false; + } + } + + // Should have unlocked by now. + assert(!lock.owns_lock()); + lock.lock(); + } while (!commandStream.empty() && shouldProcessCommands); + + for (const auto& drawPair : m_uniqueDraws) + { + drawPair.second(drawPair.first, this); + } + + m_uniqueDraws.clear(); + + return !m_wasDisconnectReceived; +} +}; // namespace rive diff --git a/third_party/rive/source/component.cpp b/third_party/rive/source/component.cpp new file mode 100644 index 0000000..e7dd01e --- /dev/null +++ b/third_party/rive/source/component.cpp @@ -0,0 +1,98 @@ +#include "rive/component.hpp" +#include "rive/artboard.hpp" +#include "rive/container_component.hpp" +#include "rive/core_context.hpp" +#include "rive/importers/artboard_importer.hpp" +#include "rive/importers/import_stack.hpp" +#include "rive/layout_component.hpp" +#include + +using namespace rive; + +bool Component::validate(CoreContext* context) +{ + auto coreObject = context->resolve(parentId()); + return coreObject != nullptr && coreObject->is(); +} + +StatusCode Component::onAddedDirty(CoreContext* context) +{ + m_Artboard = static_cast(context); + m_DependencyHelper.dependecyRoot(m_Artboard); + if (this == m_Artboard) + { + // We're the artboard, don't parent to ourselves. + return StatusCode::Ok; + } + m_Parent = context->resolve(parentId())->as(); + m_Parent->addChild(this); + return StatusCode::Ok; +} + +void Component::addDependent(Component* component) +{ + m_DependencyHelper.addDependent(component); +} + +bool Component::addDirt(ComponentDirt value, bool recurse) +{ + if ((m_Dirt & value) == value) + { + // Already marked. + return false; + } + + // Make sure dirt is set before calling anything that can set more dirt. + m_Dirt |= value; + + onDirty(m_Dirt); + + m_DependencyHelper.onComponentDirty(this); + + if (!recurse) + { + return true; + } + + m_DependencyHelper.addDirt(value); + return true; +} + +StatusCode Component::import(ImportStack& importStack) +{ + if (is()) + { + // Artboards are always their first object. + assert(as()->objects().size() == 0); + as()->addObject(this); + return Super::import(importStack); + } + + auto artboardImporter = + importStack.latest(ArtboardBase::typeKey); + if (artboardImporter == nullptr) + { + return StatusCode::MissingObject; + } + artboardImporter->addComponent(this); + return Super::import(importStack); +} + +bool Component::collapse(bool value) +{ + if (isCollapsed() == value) + { + return false; + } + if (value) + { + m_Dirt |= ComponentDirt::Collapsed; + } + else + { + m_Dirt &= ~ComponentDirt::Collapsed; + } + onDirty(m_Dirt); + m_DependencyHelper.onComponentDirty(this); + return true; +} \ No newline at end of file diff --git a/third_party/rive/source/constraints/constraint.cpp b/third_party/rive/source/constraints/constraint.cpp new file mode 100644 index 0000000..7da213c --- /dev/null +++ b/third_party/rive/source/constraints/constraint.cpp @@ -0,0 +1,50 @@ +#include "rive/constraints/constraint.hpp" +#include "rive/container_component.hpp" +#include "rive/transform_component.hpp" +#include "rive/core_context.hpp" +#include "rive/math/mat2d.hpp" + +using namespace rive; + +StatusCode Constraint::onAddedClean(CoreContext* context) +{ + if (!parent()->is()) + { + return StatusCode::InvalidObject; + } + + parent()->as()->addConstraint(this); + + return StatusCode::Ok; +} + +void Constraint::markConstraintDirty() +{ + parent()->as()->markTransformDirty(); +} + +void Constraint::strengthChanged() { markConstraintDirty(); } + +void Constraint::buildDependencies() +{ + Super::buildDependencies(); + parent()->addDependent(this); +} + +void Constraint::onDirty(ComponentDirt dirt) +{ + // Whenever the constraint gets any dirt, make sure to mark the constrained + // component dirty. + markConstraintDirty(); +} + +static Mat2D identity; +const Mat2D& rive::getParentWorld(const TransformComponent& component) +{ + auto parent = component.parent(); + if (parent->is()) + { + return parent->as()->worldTransform(); + } + return identity; +} \ No newline at end of file diff --git a/third_party/rive/source/constraints/distance_constraint.cpp b/third_party/rive/source/constraints/distance_constraint.cpp new file mode 100644 index 0000000..3ea5e66 --- /dev/null +++ b/third_party/rive/source/constraints/distance_constraint.cpp @@ -0,0 +1,61 @@ +#include "rive/constraints/distance_constraint.hpp" +#include "rive/bones/bone.hpp" +#include "rive/artboard.hpp" +#include + +using namespace rive; + +enum class Mode +{ + Closer = 0, + Further = 1, + Exact = 2 +}; + +void DistanceConstraint::constrain(TransformComponent* component) +{ + if (m_Target == nullptr || m_Target->isCollapsed()) + { + return; + } + + const Vec2D targetTranslation = m_Target->worldTranslation(); + const Vec2D ourTranslation = component->worldTranslation(); + + Vec2D toTarget = ourTranslation - targetTranslation; + float currentDistance = toTarget.length(); + + switch (static_cast(modeValue())) + { + case Mode::Closer: + if (currentDistance < distance()) + { + return; + } + break; + case Mode::Further: + if (currentDistance > distance()) + { + return; + } + break; + case Mode::Exact: + break; + } + if (currentDistance < 0.001f) + { + return; + } + + toTarget *= (distance() / currentDistance); + + Mat2D& world = component->mutableWorldTransform(); + Vec2D position = targetTranslation + toTarget; + position = Vec2D::lerp(ourTranslation, position, strength()); + world[4] = position.x; + world[5] = position.y; +} + +void DistanceConstraint::distanceChanged() { markConstraintDirty(); } + +void DistanceConstraint::modeValueChanged() { markConstraintDirty(); } \ No newline at end of file diff --git a/third_party/rive/source/constraints/follow_path_constraint.cpp b/third_party/rive/source/constraints/follow_path_constraint.cpp new file mode 100644 index 0000000..ac6334d --- /dev/null +++ b/third_party/rive/source/constraints/follow_path_constraint.cpp @@ -0,0 +1,165 @@ +#include "rive/artboard.hpp" +#include "rive/command_path.hpp" +#include "rive/constraints/follow_path_constraint.hpp" +#include "rive/factory.hpp" +#include "rive/math/contour_measure.hpp" +#include "rive/math/mat2d.hpp" +#include "rive/math/math_types.hpp" +#include "rive/shapes/path.hpp" +#include "rive/shapes/shape.hpp" +#include "rive/transform_component.hpp" +#include +#include +#include + +using namespace rive; + +void FollowPathConstraint::distanceChanged() { markConstraintDirty(); } +void FollowPathConstraint::orientChanged() { markConstraintDirty(); } + +const Mat2D FollowPathConstraint::targetTransform() const +{ + if (m_Target->is() || m_Target->is()) + { + auto result = m_pathMeasure.atPercentage(distance()); + Vec2D position = result.pos; + Mat2D transformB = Mat2D(m_Target->worldTransform()); + + if (orient()) + { + transformB = + Mat2D::fromRotation(std::atan2(result.tan.y, result.tan.x)); + } + Vec2D offsetPosition = Vec2D(); + if (offset()) + { + if (parent()->is()) + { + Mat2D components = + parent()->as()->transform(); + offsetPosition.x = components[4]; + offsetPosition.y = components[5]; + } + } + transformB[4] = position.x + offsetPosition.x; + transformB[5] = position.y + offsetPosition.y; + return transformB; + } + else + { + return m_Target->worldTransform(); + } +} + +void FollowPathConstraint::constrain(TransformComponent* component) +{ + if (m_Target == nullptr || m_Target->isCollapsed()) + { + return; + } + const Mat2D& transformA = component->worldTransform(); + Mat2D transformB(targetTransform()); + if (sourceSpace() == TransformSpace::local) + { + const Mat2D& targetParentWorld = getParentWorld(*m_Target); + + Mat2D inverse; + if (!targetParentWorld.invert(&inverse)) + { + return; + } + transformB = inverse * transformB; + } + if (destSpace() == TransformSpace::local) + { + const Mat2D& targetParentWorld = getParentWorld(*component); + transformB = targetParentWorld * transformB; + } + + m_ComponentsA = transformA.decompose(); + m_ComponentsB = transformB.decompose(); + + float t = strength(); + float ti = 1.0f - t; + + if (!orient()) + { + float angleA = std::fmod(m_ComponentsA.rotation(), math::PI * 2); + m_ComponentsB.rotation(angleA); + } + m_ComponentsB.x(m_ComponentsA.x() * ti + m_ComponentsB.x() * t); + m_ComponentsB.y(m_ComponentsA.y() * ti + m_ComponentsB.y() * t); + m_ComponentsB.scaleX(m_ComponentsA.scaleX()); + m_ComponentsB.scaleY(m_ComponentsA.scaleY()); + m_ComponentsB.skew(m_ComponentsA.skew()); + + component->mutableWorldTransform() = Mat2D::compose(m_ComponentsB); +} + +void FollowPathConstraint::update(ComponentDirt value) +{ + std::vector paths; + if (m_Target->is()) + { + auto shape = m_Target->as(); + for (auto path : shape->paths()) + { + paths.push_back(path); + } + } + else if (m_Target->is()) + { + paths.push_back(m_Target->as()); + } + if (paths.size() > 0) + { + m_rawPath.rewind(); + for (auto path : paths) + { + m_rawPath.addPath(path->rawPath(), &path->pathTransform()); + } + + m_pathMeasure = PathMeasure(&m_rawPath); + } +} + +StatusCode FollowPathConstraint::onAddedClean(CoreContext* context) +{ + if (m_Target != nullptr) + { + if (m_Target->is()) + { + Shape* shape = static_cast(m_Target); + shape->addFlags(PathFlags::followPath); + } + else if (m_Target->is()) + { + Path* path = static_cast(m_Target); + path->addFlags(PathFlags::followPath); + } + } + return Super::onAddedClean(context); +} + +void FollowPathConstraint::buildDependencies() +{ + + if (m_Target != nullptr && + m_Target->is()) // which should never happen + { + // Follow path should update after the target's path composer + Shape* shape = static_cast(m_Target); + shape->pathComposer()->addDependent(this); + } + // ok this appears to be enough to get the inital layout & animations to be + // working. + else if (m_Target != nullptr && + m_Target->is()) // which should never happen + { + // or do we need to be dependent on the shape still??? + Path* path = static_cast(m_Target); + path->addDependent(this); + } + // The constrained component should update after follow path + addDependent(parent()); +} diff --git a/third_party/rive/source/constraints/ik_constraint.cpp b/third_party/rive/source/constraints/ik_constraint.cpp new file mode 100644 index 0000000..1727066 --- /dev/null +++ b/third_party/rive/source/constraints/ik_constraint.cpp @@ -0,0 +1,300 @@ +#include "rive/constraints/ik_constraint.hpp" +#include "rive/bones/bone.hpp" +#include "rive/artboard.hpp" +#include "rive/math/math_types.hpp" +#include + +using namespace rive; + +static float atan2(Vec2D v) { return std::atan2(v.y, v.x); } + +void IKConstraint::buildDependencies() +{ + Super::buildDependencies(); + + // IK Constraint needs to depend on the target so that world transform + // changes can propagate to the bones (and they can be reset before IK + // runs). + if (m_Target != nullptr) + { + m_Target->addDependent(this); + } +} + +StatusCode IKConstraint::onAddedClean(CoreContext* context) +{ + if (!parent()->is()) + { + return StatusCode::InvalidObject; + } + + auto boneCount = parentBoneCount(); + auto bone = parent()->as(); + std::vector bones; + bones.push_back(bone); + // Get the reverse FK chain of bones (from tip up). + while (bone->parent()->is() && boneCount > 0) + { + boneCount--; + bone = bone->parent()->as(); + bone->addPeerConstraint(this); + bones.push_back(bone); + } + int numBones = (int)bones.size(); + m_FkChain.resize(numBones); + // Now put them in FK order (top to bottom). + int idx = 0; + for (auto boneItr = bones.rbegin(); boneItr != bones.rend(); ++boneItr) + { + BoneChainLink& link = m_FkChain[idx]; + link.index = idx++; + link.bone = *boneItr; + link.angle = 0.0f; + } + + // Make sure all of the first level children of each bone depend on the + // tip (constrainedComponent). + auto tip = parent()->as(); + + auto artboard = static_cast(context); + + // Find all children of this bone (we don't directly build up + // hierarchy at runtime, so we have to traverse everything and check + // parents). + for (auto core : artboard->objects()) + { + if (core == nullptr || !core->is()) + { + continue; + } + auto transformComponent = core->as(); + + for (int i = 1; i < numBones; i++) + { + auto childBone = bones[i]; + if (transformComponent->parent() == childBone && + std::find(bones.begin(), bones.end(), transformComponent) == + bones.end()) + { + tip->addDependent(transformComponent); + } + } + } + return Super::onAddedClean(context); +} + +void IKConstraint::markConstraintDirty() +{ + Super::markConstraintDirty(); + // We automatically propagate dirt to the parent constrained bone, but we + // also need to make sure the other bones we influence above it rebuild + // their transforms. + for (int i = 0, length = (int)m_FkChain.size() - 1; i < length; i++) + { + m_FkChain[i].bone->markTransformDirty(); + } +} + +void IKConstraint::solve1(BoneChainLink* fk1, + const Vec2D& worldTargetTranslation) +{ + Mat2D iworld = fk1->parentWorldInverse; + Vec2D pA = fk1->bone->worldTranslation(); + Vec2D pBT(worldTargetTranslation); + + // To target in worldspace + const Vec2D toTarget = pBT - pA; + + // Note this is directional, hence not transformMat2d + Vec2D toTargetLocal = Vec2D::transformDir(toTarget, iworld); + float r = atan2(toTargetLocal); + + constrainRotation(*fk1, r); + fk1->angle = r; +} + +void IKConstraint::solve2(BoneChainLink* fk1, + BoneChainLink* fk2, + const Vec2D& worldTargetTranslation) +{ + Bone* b1 = fk1->bone; + Bone* b2 = fk2->bone; + BoneChainLink* firstChild = &(m_FkChain[fk1->index + 1]); + + const Mat2D& iworld = fk1->parentWorldInverse; + + Vec2D pA = b1->worldTranslation(); + Vec2D pC = firstChild->bone->worldTranslation(); + Vec2D pB = b2->tipWorldTranslation(); + Vec2D pBT(worldTargetTranslation); + + pA = iworld * pA; + pC = iworld * pC; + pB = iworld * pB; + pBT = iworld * pBT; + + // http://mathworld.wolfram.com/LawofCosines.html + Vec2D av = pB - pC, bv = pC - pA, cv = pBT - pA; + float a = av.length(), b = bv.length(), c = cv.length(); + + float A = std::acos( + std::max(-1.0f, + std::min(1.0f, (-a * a + b * b + c * c) / (2.0f * b * c)))); + float C = std::acos( + std::max(-1.0f, + std::min(1.0f, (a * a + b * b - c * c) / (2.0f * a * b)))); + + float r1, r2; + if (b2->parent() != b1) + { + BoneChainLink& secondChild = m_FkChain[fk1->index + 2]; + + const Mat2D& secondChildWorldInverse = secondChild.parentWorldInverse; + + pC = firstChild->bone->worldTranslation(); + pB = b2->tipWorldTranslation(); + + Vec2D avLocal = Vec2D::transformDir(pB - pC, secondChildWorldInverse); + float angleCorrection = -atan2(avLocal); + + if (invertDirection()) + { + r1 = atan2(cv) - A; + r2 = -C + math::PI + angleCorrection; + } + else + { + r1 = A + atan2(cv); + r2 = C - math::PI + angleCorrection; + } + } + else if (invertDirection()) + { + r1 = atan2(cv) - A; + r2 = -C + math::PI; + } + else + { + r1 = A + atan2(cv); + r2 = C - math::PI; + } + + constrainRotation(*fk1, r1); + constrainRotation(*firstChild, r2); + if (firstChild != fk2) + { + Bone* bone = fk2->bone; + bone->mutableWorldTransform() = + getParentWorld(*bone) * bone->transform(); + } + + // Simple storage, need this for interpolation. + fk1->angle = r1; + firstChild->angle = r2; +} + +void IKConstraint::invertDirectionChanged() { markConstraintDirty(); } + +void IKConstraint::constrainRotation(BoneChainLink& fk, float rotation) +{ + Bone* bone = fk.bone; + const Mat2D& parentWorld = getParentWorld(*bone); + Mat2D& transform = bone->mutableTransform(); + TransformComponents& c = fk.transformComponents; + + transform = Mat2D::fromRotation(rotation); + + // Translate + transform[4] = c.x(); + transform[5] = c.y(); + // Scale + float scaleX = c.scaleX(); + float scaleY = c.scaleY(); + transform[0] *= scaleX; + transform[1] *= scaleX; + transform[2] *= scaleY; + transform[3] *= scaleY; + + // Skew + const float skew = c.skew(); + if (skew != 0.0f) + { + transform[2] = transform[0] * skew + transform[2]; + transform[3] = transform[1] * skew + transform[3]; + } + + bone->mutableWorldTransform() = parentWorld * transform; +} + +void IKConstraint::constrain(TransformComponent* component) +{ + if (m_Target == nullptr || m_Target->isCollapsed()) + { + return; + } + + Vec2D worldTargetTranslation = m_Target->worldTranslation(); + + // Decompose the chain. + for (BoneChainLink& item : m_FkChain) + { + auto bone = item.bone; + const Mat2D& parentWorld = getParentWorld(*bone); + item.parentWorldInverse = parentWorld.invertOrIdentity(); + + Mat2D& boneTransform = bone->mutableTransform(); + boneTransform = item.parentWorldInverse * bone->worldTransform(); + item.transformComponents = boneTransform.decompose(); + } + + int count = (int)m_FkChain.size(); + switch (count) + { + case 1: + solve1(&m_FkChain[0], worldTargetTranslation); + break; + case 2: + solve2(&m_FkChain[0], &m_FkChain[1], worldTargetTranslation); + break; + default: + { + auto last = count - 1; + BoneChainLink* tip = &m_FkChain[last]; + for (int i = 0; i < last; i++) + { + BoneChainLink* item = &m_FkChain[i]; + solve2(item, tip, worldTargetTranslation); + for (int j = item->index + 1, end = (int)m_FkChain.size() - 1; + j < end; + j++) + { + BoneChainLink& fk = m_FkChain[j]; + fk.parentWorldInverse = + getParentWorld(*fk.bone).invertOrIdentity(); + } + } + break; + } + } + // At the end, mix the FK angle with the IK angle by strength + if (strength() != 1.0f) + { + for (BoneChainLink& fk : m_FkChain) + { + float fromAngle = + std::fmod(fk.transformComponents.rotation(), math::PI * 2); + float toAngle = std::fmod(fk.angle, math::PI * 2); + float diff = toAngle - fromAngle; + if (diff > math::PI) + { + diff -= math::PI * 2; + } + else if (diff < -math::PI) + { + diff += math::PI * 2; + } + float angle = fromAngle + diff * strength(); + constrainRotation(fk, angle); + } + } +} diff --git a/third_party/rive/source/constraints/rotation_constraint.cpp b/third_party/rive/source/constraints/rotation_constraint.cpp new file mode 100644 index 0000000..eeb49ef --- /dev/null +++ b/third_party/rive/source/constraints/rotation_constraint.cpp @@ -0,0 +1,115 @@ +#include "rive/constraints/rotation_constraint.hpp" +#include "rive/transform_component.hpp" +#include "rive/math/mat2d.hpp" +#include "rive/math/math_types.hpp" + +using namespace rive; + +void RotationConstraint::constrain(TransformComponent* component) +{ + if (m_Target != nullptr && m_Target->isCollapsed()) + { + return; + } + const Mat2D& transformA = component->worldTransform(); + Mat2D transformB; + m_ComponentsA = transformA.decompose(); + if (m_Target == nullptr) + { + transformB = transformA; + m_ComponentsB = m_ComponentsA; + } + else + { + transformB = m_Target->worldTransform(); + if (sourceSpace() == TransformSpace::local) + { + Mat2D inverse; + + if (!getParentWorld(*m_Target).invert(&inverse)) + { + return; + } + transformB = inverse * transformB; + } + + m_ComponentsB = transformB.decompose(); + + if (!doesCopy()) + { + m_ComponentsB.rotation(destSpace() == TransformSpace::local + ? 0.0f + : m_ComponentsA.rotation()); + } + else + { + m_ComponentsB.rotation(m_ComponentsB.rotation() * copyFactor()); + if (offset()) + { + m_ComponentsB.rotation(m_ComponentsB.rotation() + + component->rotation()); + } + } + + if (destSpace() == TransformSpace::local) + { + // Destination space is in parent transform coordinates. Recompose + // the parent local transform and get it in world, then decompose + // the world for interpolation. + + transformB = Mat2D::compose(m_ComponentsB); + transformB = getParentWorld(*component) * transformB; + m_ComponentsB = transformB.decompose(); + } + } + bool clampLocal = minMaxSpace() == TransformSpace::local; + if (clampLocal) + { + // Apply min max in local space, so transform to local coordinates + // first. + transformB = Mat2D::compose(m_ComponentsB); + Mat2D inverse; + if (!getParentWorld(*component).invert(&inverse)) + { + return; + } + m_ComponentsB = (inverse * transformB).decompose(); + } + if (max() && m_ComponentsB.rotation() > maxValue()) + { + m_ComponentsB.rotation(maxValue()); + } + if (min() && m_ComponentsB.rotation() < minValue()) + { + m_ComponentsB.rotation(minValue()); + } + if (clampLocal) + { + // Transform back to world. + transformB = Mat2D::compose(m_ComponentsB); + transformB = getParentWorld(*component) * transformB; + m_ComponentsB = transformB.decompose(); + } + + float angleA = std::fmod(m_ComponentsA.rotation(), math::PI * 2); + float angleB = std::fmod(m_ComponentsB.rotation(), math::PI * 2); + float diff = angleB - angleA; + + if (diff > math::PI) + { + diff -= math::PI * 2; + } + else if (diff < -math::PI) + { + diff += math::PI * 2; + } + + m_ComponentsB.rotation(m_ComponentsA.rotation() + diff * strength()); + m_ComponentsB.x(m_ComponentsA.x()); + m_ComponentsB.y(m_ComponentsA.y()); + m_ComponentsB.scaleX(m_ComponentsA.scaleX()); + m_ComponentsB.scaleY(m_ComponentsA.scaleY()); + m_ComponentsB.skew(m_ComponentsA.skew()); + + component->mutableWorldTransform() = Mat2D::compose(m_ComponentsB); +} diff --git a/third_party/rive/source/constraints/scale_constraint.cpp b/third_party/rive/source/constraints/scale_constraint.cpp new file mode 100644 index 0000000..ae059cf --- /dev/null +++ b/third_party/rive/source/constraints/scale_constraint.cpp @@ -0,0 +1,131 @@ +#include "rive/constraints/scale_constraint.hpp" +#include "rive/transform_component.hpp" +#include "rive/math/mat2d.hpp" +#include + +using namespace rive; + +void ScaleConstraint::constrain(TransformComponent* component) +{ + if (m_Target != nullptr && m_Target->isCollapsed()) + { + return; + } + const Mat2D& transformA = component->worldTransform(); + Mat2D transformB; + m_ComponentsA = transformA.decompose(); + if (m_Target == nullptr) + { + transformB = transformA; + m_ComponentsB = m_ComponentsA; + } + else + { + transformB = m_Target->worldTransform(); + if (sourceSpace() == TransformSpace::local) + { + Mat2D inverse; + if (!getParentWorld(*m_Target).invert(&inverse)) + { + return; + } + transformB = inverse * transformB; + } + m_ComponentsB = transformB.decompose(); + + if (!doesCopy()) + { + m_ComponentsB.scaleX(destSpace() == TransformSpace::local + ? 1.0f + : m_ComponentsA.scaleX()); + } + else + { + m_ComponentsB.scaleX(m_ComponentsB.scaleX() * copyFactor()); + if (offset()) + { + m_ComponentsB.scaleX(m_ComponentsB.scaleX() * + component->scaleX()); + } + } + + if (!doesCopyY()) + { + m_ComponentsB.scaleY(destSpace() == TransformSpace::local + ? 1.0f + : m_ComponentsA.scaleY()); + } + else + { + m_ComponentsB.scaleY(m_ComponentsB.scaleY() * copyFactorY()); + if (offset()) + { + m_ComponentsB.scaleY(m_ComponentsB.scaleY() * + component->scaleY()); + } + } + + if (destSpace() == TransformSpace::local) + { + // Destination space is in parent transform coordinates. Recompose + // the parent local transform and get it in world, then decompose + // the world for interpolation. + + transformB = Mat2D::compose(m_ComponentsB); + transformB = getParentWorld(*component) * transformB; + m_ComponentsB = transformB.decompose(); + } + } + + bool clamplocal = minMaxSpace() == TransformSpace::local; + if (clamplocal) + { + // Apply min max in local space, so transform to local coordinates + // first. + transformB = Mat2D::compose(m_ComponentsB); + Mat2D inverse; + if (!getParentWorld(*component).invert(&inverse)) + { + return; + } + transformB = inverse * transformB; + m_ComponentsB = transformB.decompose(); + } + if (max() && m_ComponentsB.scaleX() > maxValue()) + { + m_ComponentsB.scaleX(maxValue()); + } + if (min() && m_ComponentsB.scaleX() < minValue()) + { + m_ComponentsB.scaleX(minValue()); + } + if (maxY() && m_ComponentsB.scaleY() > maxValueY()) + { + m_ComponentsB.scaleY(maxValueY()); + } + if (minY() && m_ComponentsB.scaleY() < minValueY()) + { + m_ComponentsB.scaleY(minValueY()); + } + if (clamplocal) + { + // Transform back to world. + transformB = Mat2D::compose(m_ComponentsB); + transformB = getParentWorld(*component) * transformB; + m_ComponentsB = transformB.decompose(); + } + + float t = strength(); + float ti = 1.0f - t; + + m_ComponentsB.rotation(m_ComponentsA.rotation()); + m_ComponentsB.x(m_ComponentsA.x()); + m_ComponentsB.y(m_ComponentsA.y()); + m_ComponentsB.scaleX(m_ComponentsA.scaleX() * ti + + m_ComponentsB.scaleX() * t); + m_ComponentsB.scaleY(m_ComponentsA.scaleY() * ti + + m_ComponentsB.scaleY() * t); + m_ComponentsB.skew(m_ComponentsA.skew()); + + component->mutableWorldTransform() = Mat2D::compose(m_ComponentsB); +} diff --git a/third_party/rive/source/constraints/scrolling/clamped_scroll_physics.cpp b/third_party/rive/source/constraints/scrolling/clamped_scroll_physics.cpp new file mode 100644 index 0000000..318a20e --- /dev/null +++ b/third_party/rive/source/constraints/scrolling/clamped_scroll_physics.cpp @@ -0,0 +1,24 @@ +#include "rive/constraints/scrolling/clamped_scroll_physics.hpp" +#include "math.h" + +using namespace rive; + +Vec2D ClampedScrollPhysics::advance(float elapsedSeconds) +{ + stop(); + return m_value; +} + +void ClampedScrollPhysics::run(Vec2D range, + Vec2D value, + std::vector snappingPoints) +{ + ScrollPhysics::run(range, value, snappingPoints); + m_value = clamp(range, value); +} + +Vec2D ClampedScrollPhysics::clamp(Vec2D range, Vec2D value) +{ + return Vec2D(math::clamp(value.x, range.x, 0), + math::clamp(value.y, range.y, 0)); +} \ No newline at end of file diff --git a/third_party/rive/source/constraints/scrolling/elastic_scroll_physics.cpp b/third_party/rive/source/constraints/scrolling/elastic_scroll_physics.cpp new file mode 100644 index 0000000..2f153f5 --- /dev/null +++ b/third_party/rive/source/constraints/scrolling/elastic_scroll_physics.cpp @@ -0,0 +1,191 @@ +#include "rive/constraints/scrolling/elastic_scroll_physics.hpp" +#include "math.h" + +using namespace rive; + +ElasticScrollPhysics::~ElasticScrollPhysics() +{ + delete m_physicsX; + delete m_physicsY; +} + +Vec2D ElasticScrollPhysics::advance(float elapsedSeconds) +{ + float advanceX = + m_physicsX != nullptr ? m_physicsX->advance(elapsedSeconds) : 0.0f; + float advanceY = + m_physicsY != nullptr ? m_physicsY->advance(elapsedSeconds) : 0.0f; + bool isRunningX = m_physicsX != nullptr && m_physicsX->isRunning(); + bool isRunningY = m_physicsY != nullptr && m_physicsY->isRunning(); + if (!isRunningX && !isRunningY) + { + reset(); + } + return Vec2D(advanceX, advanceY); +} + +Vec2D ElasticScrollPhysics::clamp(Vec2D range, Vec2D value) +{ + float clampX = + m_physicsX != nullptr ? m_physicsX->clamp(range.x, value.x) : 0.0f; + float clampY = + m_physicsY != nullptr ? m_physicsY->clamp(range.y, value.y) : 0.0f; + return Vec2D(clampX, clampY); +} + +void ElasticScrollPhysics::run(Vec2D range, + Vec2D value, + std::vector snappingPoints) +{ + Super::run(range, value, snappingPoints); + std::vector xPoints; + std::vector yPoints; + for (auto pt : snappingPoints) + { + xPoints.push_back(pt.x); + yPoints.push_back(pt.y); + } + if (m_physicsX != nullptr) + { + m_physicsX->run(m_acceleration.x, range.x, value.x, xPoints); + } + if (m_physicsY != nullptr) + { + m_physicsY->run(m_acceleration.y, range.y, value.y, yPoints); + } +} + +void ElasticScrollPhysics::prepare(DraggableConstraintDirection dir) +{ + Super::prepare(dir); + if (dir == DraggableConstraintDirection::horizontal || + dir == DraggableConstraintDirection::all) + { + m_physicsX = new ElasticScrollPhysicsHelper(friction(), + speedMultiplier(), + elasticFactor()); + } + if (dir == DraggableConstraintDirection::vertical || + dir == DraggableConstraintDirection::all) + { + m_physicsY = new ElasticScrollPhysicsHelper(friction(), + speedMultiplier(), + elasticFactor()); + } +} + +void ElasticScrollPhysics::reset() +{ + Super::reset(); + m_physicsX = nullptr; + m_physicsY = nullptr; +} + +float ElasticScrollPhysicsHelper::advance(float elapsedSeconds) +{ + if (m_speed != 0) + { + m_current += m_speed * elapsedSeconds; + + auto friction = m_friction; + if (m_current < m_runRange) + { + friction *= 4; + } + else if (m_current > 0) + { + friction *= 4; + } + + m_speed += -m_speed * std::min(1.0f, elapsedSeconds * friction); + + if (abs(m_speed) < 5) + { + m_speed = 0; + if (m_current < m_runRange) + { + m_target = m_runRange; + } + else if (m_current > 0) + { + m_target = 0; + } + else + { + m_target = m_current; + } + } + return m_current; + } + auto diff = m_target - m_current; + if (abs(diff) < 0.1) + { + m_current = m_target; + m_isRunning = false; + } + else + { + m_current += diff * std::min(1.0f, elapsedSeconds * 15.0f); + } + return m_current; +} + +float ElasticScrollPhysicsHelper::clamp(float range, float value) +{ + if (value < range) + { + return range - pow(-(value - range), m_elasticFactor); + } + else if (value > 0) + { + return pow(value, m_elasticFactor); + } + return value; +} + +void ElasticScrollPhysicsHelper::run(float acceleration, + float range, + float value, + std::vector snappingPoints) +{ + m_isRunning = true; + m_runRange = range; + if (abs(acceleration) > 100) + { + m_speed = acceleration * 0.16f * 0.16f * 0.1f * m_speedMultiplier; + } + else + { + m_speed = 0; + } + if (value < range) + { + m_target = range; + } + else if (value > 0) + { + m_target = 0; + } + else + { + m_target = value; + } + m_current = value; + + if (!snappingPoints.empty()) + { + float endTarget = -(m_current + m_speed / m_friction); + float closest = std::numeric_limits::max(); + float snapTarget = 0; + for (auto snap : snappingPoints) + { + float diff = std::abs(snap - endTarget); + if (diff < closest) + { + closest = diff; + snapTarget = snap; + } + } + m_speed = -(snapTarget + m_current) * m_friction; + } +} \ No newline at end of file diff --git a/third_party/rive/source/constraints/scrolling/scroll_bar_constraint.cpp b/third_party/rive/source/constraints/scrolling/scroll_bar_constraint.cpp new file mode 100644 index 0000000..086fc16 --- /dev/null +++ b/third_party/rive/source/constraints/scrolling/scroll_bar_constraint.cpp @@ -0,0 +1,229 @@ +#include "rive/constraints/draggable_constraint.hpp" +#include "rive/constraints/scrolling/scroll_bar_constraint.hpp" +#include "rive/constraints/scrolling/scroll_bar_constraint_proxy.hpp" +#include "rive/constraints/transform_constraint.hpp" +#include "rive/core_context.hpp" +#include "rive/layout_component.hpp" +#include "rive/transform_component.hpp" +#include "rive/math/mat2d.hpp" + +using namespace rive; + +float ScrollBarConstraint::computedThumbWidth() +{ + if (autoSize() && m_scrollConstraint != nullptr) + { + return track()->innerWidth() * m_scrollConstraint->visibleWidthRatio(); + } + return thumb()->layoutWidth(); +} + +float ScrollBarConstraint::computedThumbHeight() +{ + if (autoSize() && m_scrollConstraint != nullptr) + { + return track()->innerHeight() * + m_scrollConstraint->visibleHeightRatio(); + } + return thumb()->layoutHeight(); +} + +std::vector ScrollBarConstraint::draggables() +{ + std::vector items; + if (parent()->is()) + { + items.push_back( + new ThumbDraggableProxy(this, + parent()->as()->proxy())); + } + if (parent()->parent() != nullptr && + parent()->parent()->is()) + { + items.push_back(new TrackDraggableProxy( + this, + parent()->parent()->as()->proxy())); + } + return items; +} + +void ScrollBarConstraint::constrain(TransformComponent* component) +{ + if (m_scrollConstraint == nullptr || track() == nullptr || + thumb() == nullptr) + { + return; + } + float thumbOffsetX = 0; + float thumbOffsetY = 0; + if (constrainsHorizontal()) + { + auto innerWidth = track()->innerWidth(); + auto thumbWidth = computedThumbWidth(); + auto maxThumbOffset = innerWidth - thumbWidth; + thumbOffsetX = (m_scrollConstraint->maxOffsetX() == 0) + ? 0 + : m_scrollConstraint->clampedOffsetX() / + m_scrollConstraint->maxOffsetX() * + maxThumbOffset; + if (thumbOffsetX < 0) + { + thumbWidth += thumbOffsetX; + thumbOffsetX = 0; + } + else if (thumbOffsetX > maxThumbOffset) + { + thumbWidth -= thumbOffsetX - maxThumbOffset; + thumbOffsetX = autoSize() ? thumbOffsetX : maxThumbOffset; + } + if (autoSize()) + { + thumb()->forcedWidth(thumbWidth); + } + } + if (constrainsVertical()) + { + auto innerHeight = track()->innerHeight(); + auto thumbHeight = computedThumbHeight(); + auto maxThumbOffset = innerHeight - thumbHeight; + thumbOffsetY = (m_scrollConstraint->maxOffsetY() == 0) + ? 0 + : m_scrollConstraint->clampedOffsetY() / + m_scrollConstraint->maxOffsetY() * + maxThumbOffset; + if (thumbOffsetY < 0) + { + thumbHeight += thumbOffsetY; + thumbOffsetY = 0; + } + else if (thumbOffsetY > maxThumbOffset) + { + thumbHeight -= thumbOffsetY - maxThumbOffset; + thumbOffsetY = autoSize() ? thumbOffsetY : maxThumbOffset; + } + if (autoSize()) + { + thumb()->forcedHeight(thumbHeight); + } + } + auto targetTransform = + Mat2D::multiply(component->worldTransform(), + Mat2D::fromTranslate(thumbOffsetX, thumbOffsetY)); + TransformConstraint::constrainWorld(component, + component->worldTransform(), + m_componentsA, + targetTransform, + m_componentsB, + strength()); +} + +void ScrollBarConstraint::buildDependencies() +{ + m_scrollConstraint->addDependent(this); + Super::buildDependencies(); +} + +StatusCode ScrollBarConstraint::onAddedDirty(CoreContext* context) +{ + StatusCode result = Super::onAddedDirty(context); + if (result != StatusCode::Ok) + { + return result; + } + auto coreObject = context->resolve(scrollConstraintId()); + if (coreObject == nullptr || !coreObject->is()) + { + return StatusCode::MissingObject; + } + m_scrollConstraint = static_cast(coreObject); + return StatusCode::Ok; +} + +void ScrollBarConstraint::hitTrack(Vec2D worldPosition) +{ + if (m_scrollConstraint == nullptr || track() == nullptr) + { + return; + } + Mat2D inverseWorld; + if (!track()->worldTransform().invert(&inverseWorld)) + { + return; + } + auto localPosition = inverseWorld * worldPosition; + if (constrainsHorizontal()) + { + localPosition.x -= track()->paddingLeft(); + auto innerWidth = track()->innerWidth(); + auto thumbWidth = computedThumbWidth(); + auto trackRange = innerWidth - thumbWidth; + auto maxOffsetX = m_scrollConstraint->maxOffsetX(); + m_scrollConstraint->scrollOffsetX( + math::clamp(localPosition.x / trackRange * maxOffsetX, + maxOffsetX, + 0)); + } + if (constrainsVertical()) + { + localPosition.y -= track()->paddingTop(); + auto innerHeight = track()->innerHeight(); + auto thumbHeight = computedThumbHeight(); + auto trackRange = innerHeight - thumbHeight; + auto maxOffsetY = m_scrollConstraint->maxOffsetY(); + m_scrollConstraint->scrollOffsetY( + math::clamp(localPosition.y / trackRange * maxOffsetY, + maxOffsetY, + 0)); + } +} + +void ScrollBarConstraint::dragThumb(Vec2D delta) +{ + if (m_scrollConstraint == nullptr || thumb() == nullptr || + track() == nullptr) + { + return; + } + if (constrainsHorizontal()) + { + auto innerWidth = track()->innerWidth(); + auto thumbWidth = computedThumbWidth(); + if (autoSize()) + { + thumb()->forcedWidth(thumbWidth); + } + + auto trackRange = innerWidth - thumbWidth; + auto maxOffsetX = m_scrollConstraint->maxOffsetX(); + auto thumbOffset = + (m_scrollConstraint->offsetX() / maxOffsetX * trackRange) + delta.x; + m_scrollConstraint->scrollOffsetX( + math::clamp((thumbOffset / trackRange * maxOffsetX), + maxOffsetX, + 0)); + } + if (constrainsVertical()) + { + auto innerHeight = track()->innerHeight(); + auto thumbHeight = computedThumbHeight(); + if (autoSize()) + { + thumb()->forcedHeight(thumbHeight); + } + + auto trackRange = innerHeight - thumbHeight; + auto maxOffsetY = m_scrollConstraint->maxOffsetY(); + auto thumbOffset = + (m_scrollConstraint->offsetY() / maxOffsetY * trackRange) + delta.y; + m_scrollConstraint->scrollOffsetY( + math::clamp((thumbOffset / trackRange * maxOffsetY), + maxOffsetY, + 0)); + } +} + +bool ScrollBarConstraint::validate(CoreContext* context) +{ + auto coreObject = context->resolve(scrollConstraintId()); + return coreObject != nullptr && coreObject->is(); +} \ No newline at end of file diff --git a/third_party/rive/source/constraints/scrolling/scroll_bar_constraint_proxy.cpp b/third_party/rive/source/constraints/scrolling/scroll_bar_constraint_proxy.cpp new file mode 100644 index 0000000..b8e7974 --- /dev/null +++ b/third_party/rive/source/constraints/scrolling/scroll_bar_constraint_proxy.cpp @@ -0,0 +1,21 @@ +#include "rive/constraints/scrolling/scroll_bar_constraint.hpp" +#include "rive/constraints/scrolling/scroll_bar_constraint_proxy.hpp" +#include "rive/math/vec2d.hpp" + +using namespace rive; + +void ThumbDraggableProxy::drag(Vec2D mousePosition) +{ + m_constraint->dragThumb(mousePosition - m_lastPosition); + m_lastPosition = mousePosition; +} + +void ThumbDraggableProxy::startDrag(Vec2D mousePosition) +{ + m_lastPosition = mousePosition; +} + +void TrackDraggableProxy::startDrag(Vec2D mousePosition) +{ + m_constraint->hitTrack(mousePosition); +} \ No newline at end of file diff --git a/third_party/rive/source/constraints/scrolling/scroll_constraint.cpp b/third_party/rive/source/constraints/scrolling/scroll_constraint.cpp new file mode 100644 index 0000000..c990692 --- /dev/null +++ b/third_party/rive/source/constraints/scrolling/scroll_constraint.cpp @@ -0,0 +1,347 @@ +#include "rive/constraints/scrolling/scroll_constraint.hpp" +#include "rive/constraints/scrolling/scroll_constraint_proxy.hpp" +#include "rive/constraints/transform_constraint.hpp" +#include "rive/core_context.hpp" +#include "rive/layout/layout_node_provider.hpp" +#include "rive/transform_component.hpp" +#include "rive/math/mat2d.hpp" + +using namespace rive; + +ScrollConstraint::~ScrollConstraint() { delete m_physics; } + +void ScrollConstraint::constrain(TransformComponent* component) +{ + m_scrollTransform = + Mat2D::fromTranslate(constrainsHorizontal() ? clampedOffsetX() : 0, + constrainsVertical() ? clampedOffsetY() : 0); +} + +void ScrollConstraint::constrainChild(LayoutNodeProvider* child) +{ + auto component = child->transformComponent(); + if (component == nullptr) + { + return; + } + auto targetTransform = + Mat2D::multiply(component->worldTransform(), m_scrollTransform); + TransformConstraint::constrainWorld(component, + component->worldTransform(), + m_componentsA, + targetTransform, + m_componentsB, + strength()); +} + +void ScrollConstraint::dragView(Vec2D delta) +{ + if (m_physics != nullptr) + { + m_physics->accumulate(delta); + } + scrollOffsetX(offsetX() + delta.x); + scrollOffsetY(offsetY() + delta.y); +} + +void ScrollConstraint::runPhysics() +{ + m_isDragging = false; + std::vector snappingPoints; + if (snap()) + { + for (auto child : content()->children()) + { + auto c = LayoutNodeProvider::from(child); + if (c != nullptr) + { + size_t count = c->numLayoutNodes(); + for (int j = 0; j < count; j++) + { + auto bounds = c->layoutBoundsForNode(j); + snappingPoints.push_back( + Vec2D(bounds.left(), bounds.top())); + } + } + } + } + if (m_physics != nullptr) + { + m_physics->run(Vec2D(maxOffsetX(), maxOffsetY()), + Vec2D(offsetX(), offsetY()), + snap() ? snappingPoints : std::vector()); + } +} + +bool ScrollConstraint::advanceComponent(float elapsedSeconds, + AdvanceFlags flags) +{ + if ((flags & AdvanceFlags::AdvanceNested) != AdvanceFlags::AdvanceNested) + { + // offsetX(0); + // offsetY(0); + return false; + } + if (m_physics == nullptr) + { + return false; + } + if (m_physics->isRunning()) + { + auto offset = m_physics->advance(elapsedSeconds); + scrollOffsetX(offset.x); + scrollOffsetY(offset.y); + } + return m_physics->enabled(); +} + +std::vector ScrollConstraint::draggables() +{ + std::vector items; + items.push_back(new ViewportDraggableProxy(this, viewport()->proxy())); + return items; +} + +void ScrollConstraint::buildDependencies() +{ + Super::buildDependencies(); + for (auto child : content()->children()) + { + auto layout = LayoutNodeProvider::from(child); + if (layout != nullptr) + { + addDependent(child); + layout->addLayoutConstraint(static_cast(this)); + } + } +} + +Core* ScrollConstraint::clone() const +{ + auto cloned = ScrollConstraintBase::clone(); + if (physics() != nullptr) + { + auto constraint = cloned->as(); + auto clonedPhysics = physics()->clone()->as(); + constraint->physics(clonedPhysics); + } + return cloned; +} + +StatusCode ScrollConstraint::import(ImportStack& importStack) +{ + auto backboardImporter = + importStack.latest(BackboardBase::typeKey); + if (backboardImporter != nullptr) + { + std::vector physicsObjects = + backboardImporter->physics(); + if (physicsId() != -1 && physicsId() < physicsObjects.size()) + { + auto phys = physicsObjects[physicsId()]; + if (phys != nullptr) + { + auto cloned = phys->clone()->as(); + physics(cloned); + } + } + } + else + { + return StatusCode::MissingObject; + } + return Super::import(importStack); +} + +StatusCode ScrollConstraint::onAddedDirty(CoreContext* context) +{ + StatusCode result = Super::onAddedDirty(context); + offsetX(scrollOffsetX()); + offsetY(scrollOffsetY()); + return result; +} + +void ScrollConstraint::initPhysics() +{ + m_isDragging = true; + if (m_physics != nullptr) + { + m_physics->prepare(direction()); + } +} + +void ScrollConstraint::stopPhysics() +{ + if (m_physics != nullptr) + { + m_physics->reset(); + } +} + +float ScrollConstraint::scrollPercentX() +{ + return maxOffsetX() != 0 ? scrollOffsetX() / maxOffsetX() : 0; +} + +float ScrollConstraint::scrollPercentY() +{ + return maxOffsetY() != 0 ? scrollOffsetY() / maxOffsetY() : 0; +} + +float ScrollConstraint::scrollIndex() +{ + return indexAtPosition(Vec2D(scrollOffsetX(), scrollOffsetY())); +} + +void ScrollConstraint::setScrollPercentX(float value) +{ + if (m_isDragging) + { + return; + } + stopPhysics(); + float to = value * maxOffsetX(); + scrollOffsetX(to); +} + +void ScrollConstraint::setScrollPercentY(float value) +{ + if (m_isDragging) + { + return; + } + stopPhysics(); + float to = value * maxOffsetY(); + scrollOffsetY(to); +} + +void ScrollConstraint::setScrollIndex(float value) +{ + if (m_isDragging) + { + return; + } + stopPhysics(); + Vec2D to = positionAtIndex(value); + if (constrainsHorizontal()) + { + scrollOffsetX(to.x); + } + else if (constrainsVertical()) + { + scrollOffsetY(to.y); + } +} + +Vec2D ScrollConstraint::positionAtIndex(float index) +{ + if (content() == nullptr || content()->children().size() == 0) + { + return Vec2D(); + } + uint32_t i = 0; + Vec2D contentGap = gap(); + float floorIndex = std::floor(index); + LayoutNodeProvider* lastChild; + for (auto child : content()->children()) + { + auto c = LayoutNodeProvider::from(child); + if (c != nullptr) + { + size_t count = c->numLayoutNodes(); + if ((uint32_t)floorIndex < i + count) + { + float mod = index - floorIndex; + auto bounds = c->layoutBoundsForNode(floorIndex - i); + return Vec2D( + -bounds.left() - (bounds.width() + contentGap.x) * mod, + -bounds.top() - (bounds.height() + contentGap.y) * mod); + } + lastChild = c; + i += count; + } + } + auto bounds = + lastChild->layoutBoundsForNode((int)lastChild->numLayoutNodes() - 1); + return Vec2D(-bounds.left(), -bounds.top()); +} + +float ScrollConstraint::indexAtPosition(Vec2D pos) +{ + if (content() == nullptr || content()->children().size() == 0) + { + return 0; + } + float i = 0.0f; + Vec2D contentGap = gap(); + if (constrainsHorizontal()) + { + for (auto child : content()->children()) + { + auto c = LayoutNodeProvider::from(child); + if (c != nullptr) + { + size_t count = c->numLayoutNodes(); + for (int j = 0; j < count; j++) + { + auto bounds = c->layoutBoundsForNode(j); + if (pos.x > + -bounds.left() - (bounds.width() + contentGap.x)) + { + return (i + j) + (-pos.x - bounds.left()) / + (bounds.width() + contentGap.x); + } + } + i += count; + } + } + return i; + } + else if (constrainsVertical()) + { + for (auto child : content()->children()) + { + auto c = LayoutNodeProvider::from(child); + if (c != nullptr) + { + size_t count = c->numLayoutNodes(); + for (int j = 0; j < count; j++) + { + auto bounds = c->layoutBoundsForNode(j); + if (pos.y > + -bounds.top() - (bounds.height() + contentGap.y)) + { + return (i + j) + (-pos.y - bounds.top()) / + (bounds.height() + contentGap.y); + } + } + i += count; + } + } + return i; + } + return 0; +} + +size_t ScrollConstraint::scrollItemCount() +{ + size_t count = 0; + for (auto child : content()->children()) + { + auto c = LayoutNodeProvider::from(child); + if (c != nullptr) + { + count += c->numLayoutNodes(); + } + } + return count; +} + +Vec2D ScrollConstraint::gap() +{ + if (content() == nullptr) + { + return Vec2D(); + } + return Vec2D(content()->gapHorizontal(), content()->gapVertical()); +} \ No newline at end of file diff --git a/third_party/rive/source/constraints/scrolling/scroll_constraint_proxy.cpp b/third_party/rive/source/constraints/scrolling/scroll_constraint_proxy.cpp new file mode 100644 index 0000000..36fee88 --- /dev/null +++ b/third_party/rive/source/constraints/scrolling/scroll_constraint_proxy.cpp @@ -0,0 +1,23 @@ +#include "rive/constraints/scrolling/scroll_bar_constraint.hpp" +#include "rive/constraints/scrolling/scroll_constraint.hpp" +#include "rive/constraints/scrolling/scroll_constraint_proxy.hpp" +#include "rive/math/vec2d.hpp" + +using namespace rive; + +void ViewportDraggableProxy::drag(Vec2D mousePosition) +{ + m_constraint->dragView(mousePosition - m_lastPosition); + m_lastPosition = mousePosition; +} + +void ViewportDraggableProxy::startDrag(Vec2D mousePosition) +{ + m_constraint->initPhysics(); + m_lastPosition = mousePosition; +} + +void ViewportDraggableProxy::endDrag(Vec2D mousePosition) +{ + m_constraint->runPhysics(); +} \ No newline at end of file diff --git a/third_party/rive/source/constraints/scrolling/scroll_physics.cpp b/third_party/rive/source/constraints/scrolling/scroll_physics.cpp new file mode 100644 index 0000000..74740e0 --- /dev/null +++ b/third_party/rive/source/constraints/scrolling/scroll_physics.cpp @@ -0,0 +1,38 @@ +#include "rive/constraints/scrolling/scroll_constraint.hpp" +#include "rive/constraints/scrolling/scroll_physics.hpp" +#include "rive/core_context.hpp" +#include "math.h" + +using namespace rive; + +void ScrollPhysics::accumulate(Vec2D delta) +{ + auto now = std::chrono::high_resolution_clock::now(); + auto ms = std::chrono::duration_cast( + now.time_since_epoch()) + .count(); + float elapsedSeconds = (float)(ms - m_lastTime) / 1000000.0f; + if (elapsedSeconds > 0) + { + auto lastSpeed = m_speed; + m_speed = Vec2D(delta.x / elapsedSeconds, delta.y / elapsedSeconds); + m_acceleration = Vec2D((lastSpeed.x + m_speed.x) / elapsedSeconds, + (lastSpeed.y + m_speed.y) / elapsedSeconds); + } + m_lastTime = ms; +} + +StatusCode ScrollPhysics::import(ImportStack& importStack) +{ + auto backboardImporter = + importStack.latest(BackboardBase::typeKey); + if (backboardImporter != nullptr) + { + backboardImporter->addPhysics(this); + } + else + { + return StatusCode::MissingObject; + } + return StatusCode::Ok; +} \ No newline at end of file diff --git a/third_party/rive/source/constraints/targeted_constraint.cpp b/third_party/rive/source/constraints/targeted_constraint.cpp new file mode 100644 index 0000000..101565c --- /dev/null +++ b/third_party/rive/source/constraints/targeted_constraint.cpp @@ -0,0 +1,49 @@ +#include "rive/constraints/targeted_constraint.hpp" +#include "rive/transform_component.hpp" +#include "rive/core_context.hpp" + +using namespace rive; + +bool TargetedConstraint::validate(CoreContext* context) +{ + if (!Super::validate(context)) + { + return false; + } + auto coreObject = context->resolve(targetId()); + // If core object is not null and is not a TransformComponent it should + // always be invalid + if (coreObject != nullptr && !coreObject->is()) + { + return false; + } + return !requiresTarget() || coreObject != nullptr; +} + +StatusCode TargetedConstraint::onAddedDirty(CoreContext* context) +{ + StatusCode code = Super::onAddedDirty(context); + if (code != StatusCode::Ok) + { + return code; + } + auto coreObject = context->resolve(targetId()); + if (requiresTarget() && coreObject == nullptr) + { + return StatusCode::MissingObject; + } + + m_Target = static_cast(coreObject); + + return StatusCode::Ok; +} + +void TargetedConstraint::buildDependencies() +{ + // Targeted constraints must have their constrained component (parent) + // update after the target. + if (m_Target != nullptr) + { + m_Target->addDependent(parent()); + } +} diff --git a/third_party/rive/source/constraints/transform_constraint.cpp b/third_party/rive/source/constraints/transform_constraint.cpp new file mode 100644 index 0000000..f74dd6e --- /dev/null +++ b/third_party/rive/source/constraints/transform_constraint.cpp @@ -0,0 +1,91 @@ +#include "rive/constraints/transform_constraint.hpp" +#include "rive/transform_component.hpp" +#include "rive/math/mat2d.hpp" +#include "rive/math/math_types.hpp" +#include "rive/math/aabb.hpp" + +using namespace rive; + +const Mat2D TransformConstraint::targetTransform() const +{ + AABB bounds = m_Target->localBounds(); + Mat2D local = + Mat2D::fromTranslate(bounds.left() + bounds.width() * originX(), + bounds.top() + bounds.height() * originY()); + return m_Target->worldTransform() * local; +} + +void TransformConstraint::originXChanged() { markConstraintDirty(); } + +void TransformConstraint::originYChanged() { markConstraintDirty(); } + +void TransformConstraint::constrain(TransformComponent* component) +{ + if (m_Target == nullptr || m_Target->isCollapsed()) + { + return; + } + + const Mat2D& transformA = component->worldTransform(); + Mat2D transformB(targetTransform()); + if (sourceSpace() == TransformSpace::local) + { + const Mat2D& targetParentWorld = getParentWorld(*m_Target); + + Mat2D inverse; + if (!targetParentWorld.invert(&inverse)) + { + return; + } + transformB = inverse * transformB; + } + if (destSpace() == TransformSpace::local) + { + const Mat2D& targetParentWorld = getParentWorld(*component); + transformB = targetParentWorld * transformB; + } + + TransformConstraint::constrainWorld(component, + transformA, + m_ComponentsA, + transformB, + m_ComponentsB, + strength()); +} + +void TransformConstraint::constrainWorld(TransformComponent* component, + Mat2D from, + TransformComponents componentsFrom, + Mat2D to, + TransformComponents componentsTo, + float strength) +{ + componentsFrom = from.decompose(); + componentsTo = to.decompose(); + + float angleA = std::fmod(componentsFrom.rotation(), math::PI * 2); + float angleB = std::fmod(componentsTo.rotation(), math::PI * 2); + float diff = angleB - angleA; + if (diff > math::PI) + { + diff -= math::PI * 2; + } + else if (diff < -math::PI) + { + diff += math::PI * 2; + } + + float t = strength; + float ti = 1.0f - t; + + componentsTo.rotation(angleA + diff * t); + componentsTo.x(componentsFrom.x() * ti + componentsTo.x() * t); + componentsTo.y(componentsFrom.y() * ti + componentsTo.y() * t); + componentsTo.scaleX(componentsFrom.scaleX() * ti + + componentsTo.scaleX() * t); + componentsTo.scaleY(componentsFrom.scaleY() * ti + + componentsTo.scaleY() * t); + componentsTo.skew(componentsFrom.skew() * ti + componentsTo.skew() * t); + + component->mutableWorldTransform() = Mat2D::compose(componentsTo); +} \ No newline at end of file diff --git a/third_party/rive/source/constraints/translation_constraint.cpp b/third_party/rive/source/constraints/translation_constraint.cpp new file mode 100644 index 0000000..7302f55 --- /dev/null +++ b/third_party/rive/source/constraints/translation_constraint.cpp @@ -0,0 +1,115 @@ +#include "rive/constraints/translation_constraint.hpp" +#include "rive/transform_component.hpp" +#include "rive/math/mat2d.hpp" +#include "rive/math/vec2d.hpp" +#include + +using namespace rive; + +void TranslationConstraint::constrain(TransformComponent* component) +{ + if (m_Target != nullptr && m_Target->isCollapsed()) + { + return; + } + Mat2D& transformA = component->mutableWorldTransform(); + Vec2D translationA(transformA[4], transformA[5]); + Vec2D translationB; + if (m_Target == nullptr) + { + translationB = translationA; + } + else + { + Mat2D transformB(m_Target->worldTransform()); + if (sourceSpace() == TransformSpace::local) + { + const Mat2D& targetParentWorld = getParentWorld(*m_Target); + + Mat2D inverse; + if (!targetParentWorld.invert(&inverse)) + { + return; + } + transformB = inverse * transformB; + } + translationB = transformB.translation(); + + if (!doesCopy()) + { + translationB.x = + destSpace() == TransformSpace::local ? 0.0f : translationA.x; + } + else + { + translationB.x *= copyFactor(); + if (offset()) + { + translationB.x += component->x(); + } + } + + if (!doesCopyY()) + { + translationB.y = + destSpace() == TransformSpace::local ? 0.0f : translationA.y; + } + else + { + translationB.y *= copyFactorY(); + + if (offset()) + { + translationB.y += component->y(); + } + } + + if (destSpace() == TransformSpace::local) + { + // Destination space is in parent transform coordinates. + translationB = getParentWorld(*component) * translationB; + } + } + + bool clampLocal = minMaxSpace() == TransformSpace::local; + if (clampLocal) + { + // Apply min max in local space, so transform to local coordinates + // first. + Mat2D inverse; + if (!getParentWorld(*component).invert(&inverse)) + { + return; + } + // Get our target world coordinates in parent local. + translationB = inverse * translationB; + } + if (max() && translationB.x > maxValue()) + { + translationB.x = maxValue(); + } + if (min() && translationB.x < minValue()) + { + translationB.x = minValue(); + } + if (maxY() && translationB.y > maxValueY()) + { + translationB.y = maxValueY(); + } + if (minY() && translationB.y < minValueY()) + { + translationB.y = minValueY(); + } + if (clampLocal) + { + // Transform back to world. + translationB = getParentWorld(*component) * translationB; + } + + float t = strength(); + float ti = 1.0f - t; + + // Just interpolate world translation + transformA[4] = translationA.x * ti + translationB.x * t; + transformA[5] = translationA.y * ti + translationB.y * t; +} diff --git a/third_party/rive/source/container_component.cpp b/third_party/rive/source/container_component.cpp new file mode 100644 index 0000000..4808c36 --- /dev/null +++ b/third_party/rive/source/container_component.cpp @@ -0,0 +1,45 @@ +#include "rive/container_component.hpp" +using namespace rive; + +void ContainerComponent::addChild(Component* component) +{ + m_children.push_back(component); +} + +bool ContainerComponent::collapse(bool value) +{ + if (!Super::collapse(value)) + { + return false; + } + for (Component* child : m_children) + { + child->collapse(value); + } + return true; +} + +bool ContainerComponent::forAll(std::function predicate) +{ + if (!predicate(this)) + { + return false; + } + forEachChild(predicate); + return true; +} + +void ContainerComponent::forEachChild(std::function predicate) +{ + for (Component* child : m_children) + { + if (!predicate(child)) + { + continue; + } + if (child->is()) + { + child->as()->forEachChild(predicate); + } + } +} \ No newline at end of file diff --git a/third_party/rive/source/core/binary_data_reader.cpp b/third_party/rive/source/core/binary_data_reader.cpp new file mode 100644 index 0000000..41ab9a7 --- /dev/null +++ b/third_party/rive/source/core/binary_data_reader.cpp @@ -0,0 +1,105 @@ +#include "rive/core/binary_data_reader.hpp" +#include "rive/core/reader.h" + +using namespace rive; + +BinaryDataReader::BinaryDataReader(uint8_t* bytes, size_t length) : + m_Position(bytes), + m_End(bytes + length), + m_Overflowed(false), + m_Length(length) +{} + +size_t BinaryDataReader::lengthInBytes() const { return m_Length; } + +bool BinaryDataReader::didOverflow() const { return m_Overflowed; } + +void BinaryDataReader::overflow() +{ + m_Overflowed = true; + m_Position = m_End; +} + +uint64_t BinaryDataReader::readVarUint() +{ + uint64_t value; + auto readBytes = decode_uint_leb(m_Position, m_End, &value); + if (readBytes == 0) + { + overflow(); + return 0; + } + m_Position += readBytes; + return value; +} + +uint32_t BinaryDataReader::readVarUint32() +{ + uint32_t value; + auto readBytes = decode_uint_leb32(m_Position, m_End, &value); + if (readBytes == 0) + { + overflow(); + return 0; + } + m_Position += readBytes; + return value; +} + +double BinaryDataReader::readFloat64() +{ + double value; + auto readBytes = decode_double(m_Position, m_End, &value); + if (readBytes == 0) + { + overflow(); + return 0.0; + } + m_Position += readBytes; + return value; +} + +float BinaryDataReader::readFloat32() +{ + float value; + auto readBytes = decode_float(m_Position, m_End, &value); + if (readBytes == 0) + { + overflow(); + return 0.0f; + } + m_Position += readBytes; + return value; +} + +uint8_t BinaryDataReader::readByte() +{ + if (m_End - m_Position < 1) + { + overflow(); + return 0; + } + return *m_Position++; +} + +uint32_t BinaryDataReader::readUint32() +{ + uint32_t value; + auto readBytes = decode_uint_32(m_Position, m_End, &value); + if (readBytes == 0) + { + overflow(); + return 0; + } + m_Position += readBytes; + return value; +} + +void BinaryDataReader::complete(uint8_t* bytes, size_t length) +{ + m_Position = bytes; + m_End = bytes + length; + m_Length = length; +} + +void BinaryDataReader::reset(uint8_t* bytes) { m_Position = bytes; } diff --git a/third_party/rive/source/core/binary_reader.cpp b/third_party/rive/source/core/binary_reader.cpp new file mode 100644 index 0000000..0cf9e7a --- /dev/null +++ b/third_party/rive/source/core/binary_reader.cpp @@ -0,0 +1,134 @@ +#include "rive/core/binary_reader.hpp" +#include "rive/core/reader.h" +#include "rive/span.hpp" +#include + +using namespace rive; + +BinaryReader::BinaryReader(Span bytes) : + m_Bytes(bytes), + m_Position(bytes.begin()), + m_Overflowed(false), + m_IntRangeError(false) +{} + +bool BinaryReader::reachedEnd() const +{ + return m_Position == m_Bytes.end() || didOverflow() || didIntRangeError(); +} + +size_t BinaryReader::lengthInBytes() const { return m_Bytes.size(); } +const uint8_t* BinaryReader::position() const { return m_Position; } + +bool BinaryReader::didOverflow() const { return m_Overflowed; } + +bool BinaryReader::didIntRangeError() const { return m_IntRangeError; } + +void BinaryReader::overflow() +{ + m_Overflowed = true; + m_Position = m_Bytes.end(); +} + +void BinaryReader::intRangeError() +{ + m_IntRangeError = true; + m_Position = m_Bytes.end(); +} + +uint64_t BinaryReader::readVarUint64() +{ + uint64_t value; + auto readBytes = decode_uint_leb(m_Position, m_Bytes.end(), &value); + if (readBytes == 0) + { + overflow(); + return 0; + } + m_Position += readBytes; + return value; +} + +std::string BinaryReader::readString() +{ + uint64_t length = readVarUint64(); + if (didOverflow()) + { + return std::string(); + } + + std::vector rawValue((size_t)length + 1); + auto readBytes = + decode_string(length, m_Position, m_Bytes.end(), &rawValue[0]); + if (readBytes != length) + { + overflow(); + return std::string(); + } + m_Position += readBytes; + return std::string(rawValue.data(), (size_t)length); +} + +Span BinaryReader::readBytes() +{ + uint64_t length = readVarUint64(); + if (didOverflow()) + { + return Span(m_Position, 0); + } + + const uint8_t* start = m_Position; + m_Position += length; + return {start, (size_t)length}; +} + +float BinaryReader::readFloat32() +{ + float value; + auto readBytes = decode_float(m_Position, m_Bytes.end(), &value); + if (readBytes == 0) + { + overflow(); + return 0.0f; + } + m_Position += readBytes; + return value; +} + +uint8_t BinaryReader::readByte() +{ + if (m_Bytes.end() - m_Position < 1) + { + overflow(); + return 0; + } + return *m_Position++; +} + +uint16_t BinaryReader::readUint16() +{ + uint16_t value; + auto readBytes = decode_uint_16(m_Position, m_Bytes.end(), &value); + if (readBytes == 0) + { + overflow(); + return 0; + } + m_Position += readBytes; + return value; +} + +uint32_t BinaryReader::readUint32() +{ + uint32_t value; + auto readBytes = decode_uint_32(m_Position, m_Bytes.end(), &value); + if (readBytes == 0) + { + overflow(); + return 0; + } + m_Position += readBytes; + return value; +} + +void BinaryReader::reset() { m_Position = m_Bytes.begin(); } diff --git a/third_party/rive/source/core/binary_writer.cpp b/third_party/rive/source/core/binary_writer.cpp new file mode 100644 index 0000000..9d5ac5f --- /dev/null +++ b/third_party/rive/source/core/binary_writer.cpp @@ -0,0 +1,152 @@ +#include "rive/core/binary_writer.hpp" +#include "rive/core/binary_stream.hpp" +#include "rive/core/reader.h" +#include + +using namespace rive; + +BinaryWriter::BinaryWriter(BinaryStream* stream) : m_Stream(stream) {} +BinaryWriter::~BinaryWriter() { m_Stream->flush(); } + +void BinaryWriter::write(float value) +{ + auto bytes = reinterpret_cast(&value); + if (is_big_endian()) + { + uint8_t backwards[4] = {bytes[3], bytes[2], bytes[1], bytes[0]}; + m_Stream->write(backwards, 4); + } + else + { + m_Stream->write(bytes, 4); + } +} + +void BinaryWriter::writeFloat(float value) +{ + auto bytes = reinterpret_cast(&value); + if (is_big_endian()) + { + uint8_t backwards[4] = {bytes[3], bytes[2], bytes[1], bytes[0]}; + m_Stream->write(backwards, 4); + } + else + { + m_Stream->write(bytes, 4); + } +} + +void BinaryWriter::write(double value) +{ + auto bytes = reinterpret_cast(&value); + if (is_big_endian()) + { + uint8_t backwards[8] = {bytes[7], + bytes[6], + bytes[5], + bytes[4], + bytes[3], + bytes[2], + bytes[1], + bytes[0]}; + m_Stream->write(backwards, 8); + } + else + { + m_Stream->write(bytes, 8); + } +} + +void BinaryWriter::writeVarUint(uint64_t value) +{ + uint8_t buffer[16]; + int index = 0; + do + { + uint8_t byte = value & 0x7f; + value >>= 7; + + if (value != 0) + { + // more bytes follow + byte |= 0x80; + } + + buffer[index++] = byte; + } while (value != 0); + m_Stream->write(buffer, index); +} + +void BinaryWriter::writeVarUint(uint32_t value) +{ + uint8_t buffer[16]; + int index = 0; + do + { + uint8_t byte = value & 0x7f; + value >>= 7; + + if (value != 0) + { + // more bytes follow + byte |= 0x80; + } + + buffer[index++] = byte; + } while (value != 0); + m_Stream->write(buffer, index); +} + +void BinaryWriter::write(const uint8_t* bytes, size_t length) +{ + if (length == 0) + { + return; + } + m_Stream->write(bytes, length); +} + +void BinaryWriter::writeDouble(double value) +{ + auto bytes = reinterpret_cast(&value); + if (is_big_endian()) + { + uint8_t backwards[8] = {bytes[7], + bytes[6], + bytes[5], + bytes[4], + bytes[3], + bytes[2], + bytes[1], + bytes[0]}; + m_Stream->write(backwards, 8); + } + else + { + m_Stream->write(bytes, 8); + } +} + +void BinaryWriter::write(uint8_t value) +{ + m_Stream->write((const uint8_t*)&value, 1); +} + +void BinaryWriter::write(uint16_t value) +{ + m_Stream->write((const uint8_t*)&value, 2); +} + +void BinaryWriter::write(uint32_t value) +{ + m_Stream->write((const uint8_t*)&value, 4); +} + +void BinaryWriter::write(std::string value) +{ + auto length = value.size(); + writeVarUint((uint64_t)length); + write((uint8_t*)value.c_str(), length); +} + +void BinaryWriter::clear() { m_Stream->clear(); } \ No newline at end of file diff --git a/third_party/rive/source/core/field_types/core_bool_type.cpp b/third_party/rive/source/core/field_types/core_bool_type.cpp new file mode 100644 index 0000000..d738b74 --- /dev/null +++ b/third_party/rive/source/core/field_types/core_bool_type.cpp @@ -0,0 +1,9 @@ +#include "rive/core/field_types/core_bool_type.hpp" +#include "rive/core/binary_reader.hpp" + +using namespace rive; + +bool CoreBoolType::deserialize(BinaryReader& reader) +{ + return reader.readByte() == 1; +} \ No newline at end of file diff --git a/third_party/rive/source/core/field_types/core_bytes_type.cpp b/third_party/rive/source/core/field_types/core_bytes_type.cpp new file mode 100644 index 0000000..b2a1e5d --- /dev/null +++ b/third_party/rive/source/core/field_types/core_bytes_type.cpp @@ -0,0 +1,9 @@ +#include "rive/core/field_types/core_bytes_type.hpp" +#include "rive/core/binary_reader.hpp" + +using namespace rive; + +Span CoreBytesType::deserialize(BinaryReader& reader) +{ + return reader.readBytes(); +} \ No newline at end of file diff --git a/third_party/rive/source/core/field_types/core_color_type.cpp b/third_party/rive/source/core/field_types/core_color_type.cpp new file mode 100644 index 0000000..2809d4f --- /dev/null +++ b/third_party/rive/source/core/field_types/core_color_type.cpp @@ -0,0 +1,9 @@ +#include "rive/core/field_types/core_color_type.hpp" +#include "rive/core/binary_reader.hpp" + +using namespace rive; + +int CoreColorType::deserialize(BinaryReader& reader) +{ + return reader.readUint32(); +} \ No newline at end of file diff --git a/third_party/rive/source/core/field_types/core_double_type.cpp b/third_party/rive/source/core/field_types/core_double_type.cpp new file mode 100644 index 0000000..0c72e97 --- /dev/null +++ b/third_party/rive/source/core/field_types/core_double_type.cpp @@ -0,0 +1,9 @@ +#include "rive/core/field_types/core_double_type.hpp" +#include "rive/core/binary_reader.hpp" + +using namespace rive; + +float CoreDoubleType::deserialize(BinaryReader& reader) +{ + return reader.readFloat32(); +} \ No newline at end of file diff --git a/third_party/rive/source/core/field_types/core_string_type.cpp b/third_party/rive/source/core/field_types/core_string_type.cpp new file mode 100644 index 0000000..c9d7ed0 --- /dev/null +++ b/third_party/rive/source/core/field_types/core_string_type.cpp @@ -0,0 +1,9 @@ +#include "rive/core/field_types/core_string_type.hpp" +#include "rive/core/binary_reader.hpp" + +using namespace rive; + +std::string CoreStringType::deserialize(BinaryReader& reader) +{ + return reader.readString(); +} \ No newline at end of file diff --git a/third_party/rive/source/core/field_types/core_uint_type.cpp b/third_party/rive/source/core/field_types/core_uint_type.cpp new file mode 100644 index 0000000..4009f50 --- /dev/null +++ b/third_party/rive/source/core/field_types/core_uint_type.cpp @@ -0,0 +1,9 @@ +#include "rive/core/field_types/core_uint_type.hpp" +#include "rive/core/binary_reader.hpp" + +using namespace rive; + +unsigned int CoreUintType::deserialize(BinaryReader& reader) +{ + return reader.readVarUintAs(); +} diff --git a/third_party/rive/source/data_bind/context/context_value.cpp b/third_party/rive/source/data_bind/context/context_value.cpp new file mode 100644 index 0000000..8bdfafe --- /dev/null +++ b/third_party/rive/source/data_bind/context/context_value.cpp @@ -0,0 +1,226 @@ +#include "rive/data_bind/context/context_value.hpp" +#include "rive/data_bind/context/context_value_color.hpp" +#include "rive/data_bind/data_values/data_type.hpp" +#include "rive/data_bind/data_values/data_value.hpp" +#include "rive/data_bind/data_values/data_value_number.hpp" +#include "rive/data_bind/data_values/data_value_string.hpp" +#include "rive/data_bind/data_values/data_value_enum.hpp" +#include "rive/data_bind/data_values/data_value_color.hpp" +#include "rive/data_bind/data_values/data_value_boolean.hpp" +#include "rive/data_bind/data_values/data_value_trigger.hpp" +#include "rive/data_bind/data_values/data_value_list.hpp" +#include "rive/data_bind/data_values/data_value_symbol_list_index.hpp" +#include "rive/data_bind/data_values/data_value_asset_image.hpp" +#include "rive/generated/core_registry.hpp" + +using namespace rive; + +DataBindContextValue::DataBindContextValue(DataBind* dataBind) : + m_dataBind(dataBind) +{ + auto source = dataBind->source(); + if (source != nullptr) + { + switch (source->coreType()) + { + case ViewModelInstanceNumberBase::typeKey: + m_dataValue = new DataValueNumber( + source->as()->propertyValue()); + break; + case ViewModelInstanceStringBase::typeKey: + m_dataValue = new DataValueString( + source->as()->propertyValue()); + break; + case ViewModelInstanceColorBase::typeKey: + m_dataValue = new DataValueColor( + source->as()->propertyValue()); + break; + case ViewModelInstanceBooleanBase::typeKey: + m_dataValue = new DataValueBoolean( + source->as()->propertyValue()); + break; + case ViewModelInstanceEnumBase::typeKey: + { + auto viewmodelInstanceEnum = + source->as(); + auto viewModelPropertyEnum = + viewmodelInstanceEnum->viewModelProperty() + ->as(); + m_dataValue = + new DataValueEnum(viewmodelInstanceEnum->propertyValue(), + viewModelPropertyEnum->dataEnum()); + } + break; + case ViewModelInstanceTriggerBase::typeKey: + m_dataValue = new DataValueTrigger( + source->as()->propertyValue()); + break; + case ViewModelInstanceListBase::typeKey: + m_dataValue = new DataValueList(); + break; + case ViewModelInstanceSymbolListIndexBase::typeKey: + m_dataValue = new DataValueSymbolListIndex(); + break; + case ViewModelInstanceAssetImageBase::typeKey: + m_dataValue = new DataValueAssetImage( + source->as()->propertyValue()); + break; + default: + m_dataValue = new DataValue(); + } + } +} + +void DataBindContextValue::syncSourceValue() +{ + auto source = m_dataBind->source(); + if (source != nullptr) + { + switch (source->coreType()) + { + case ViewModelInstanceNumberBase::typeKey: + m_dataValue->as()->value( + source->as()->propertyValue()); + break; + case ViewModelInstanceStringBase::typeKey: + m_dataValue->as()->value( + source->as()->propertyValue()); + break; + case ViewModelInstanceColorBase::typeKey: + m_dataValue->as()->value( + source->as()->propertyValue()); + break; + case ViewModelInstanceBooleanBase::typeKey: + m_dataValue->as()->value( + source->as()->propertyValue()); + break; + case ViewModelInstanceEnumBase::typeKey: + m_dataValue->as()->value( + source->as()->propertyValue()); + break; + case ViewModelInstanceTriggerBase::typeKey: + m_dataValue->as()->value( + source->as()->propertyValue()); + break; + case ViewModelInstanceListBase::typeKey: + { + m_dataValue->as()->clear(); + auto items = source->as()->listItems(); + for (auto& item : items) + { + m_dataValue->as()->addItem(item); + } + break; + } + case ViewModelInstanceSymbolListIndexBase::typeKey: + m_dataValue->as()->value( + source->as() + ->propertyValue()); + break; + + case ViewModelInstanceAssetImageBase::typeKey: + m_dataValue->as()->value( + source->as()->propertyValue()); + break; + } + } +} + +void DataBindContextValue::applyToSource(Core* component, + uint32_t propertyKey, + bool isMainDirection) +{ + auto source = m_dataBind->source(); + switch (source->coreType()) + { + case ViewModelInstanceNumberBase::typeKey: + { + + calculateValueAndApply(targetValue(), + isMainDirection, + m_dataBind, + component, + propertyKey); + } + break; + case ViewModelInstanceStringBase::typeKey: + { + calculateValueAndApply(targetValue(), + isMainDirection, + m_dataBind, + component, + propertyKey); + } + break; + case ViewModelInstanceColorBase::typeKey: + { + calculateValueAndApply( + targetValue(), + isMainDirection, + m_dataBind, + component, + propertyKey); + } + break; + case ViewModelInstanceBooleanBase::typeKey: + { + calculateValueAndApply(targetValue(), + isMainDirection, + m_dataBind, + component, + propertyKey); + } + break; + case ViewModelInstanceEnumBase::typeKey: + { + calculateValueAndApply(targetValue(), + isMainDirection, + m_dataBind, + component, + propertyKey); + } + break; + case ViewModelInstanceTriggerBase::typeKey: + { + calculateValueAndApply(targetValue(), + isMainDirection, + m_dataBind, + component, + propertyKey); + } + break; + case ViewModelInstanceSymbolListIndexBase::typeKey: + { + calculateValueAndApply( + targetValue(), + isMainDirection, + m_dataBind, + component, + propertyKey); + } + break; + case ViewModelInstanceAssetImageBase::typeKey: + { + calculateValueAndApply(targetValue(), + isMainDirection, + m_dataBind, + component, + propertyKey); + } + break; + } +} \ No newline at end of file diff --git a/third_party/rive/source/data_bind/context/context_value_asset_image.cpp b/third_party/rive/source/data_bind/context/context_value_asset_image.cpp new file mode 100644 index 0000000..6fceef2 --- /dev/null +++ b/third_party/rive/source/data_bind/context/context_value_asset_image.cpp @@ -0,0 +1,71 @@ +#include "rive/data_bind/context/context_value_asset_image.hpp" +#include "rive/data_bind/data_values/data_value_asset_image.hpp" +#include "rive/generated/core_registry.hpp" +#include "rive/file.hpp" + +using namespace rive; + +DataBindContextValueAssetImage::DataBindContextValueAssetImage( + DataBind* dataBind) : + DataBindContextValue(dataBind) +{} + +ImageAsset* DataBindContextValueAssetImage::fileAsset() +{ + auto file = m_dataBind->file(); + auto source = m_dataBind->source(); + if (file != nullptr && source != nullptr && + source->is()) + { + + auto asset = file->asset( + source->as()->propertyValue()); + if (asset != nullptr) + { + return asset->as(); + } + } + return nullptr; +} + +void DataBindContextValueAssetImage::apply(Core* target, + uint32_t propertyKey, + bool isMainDirection) +{ + if (target->is()) + { + auto asset = fileAsset(); + if (asset != nullptr) + { + target->as()->setAsset(asset); + } + else + { + auto source = m_dataBind->source(); + target->as()->setAsset( + source->as()->asset()); + } + } + else + { + auto source = m_dataBind->source(); + CoreRegistry::setUint( + target, + propertyKey, + source->as()->propertyValue()); + } +} + +bool DataBindContextValueAssetImage::syncTargetValue(Core* target, + uint32_t propertyKey) +{ + auto value = CoreRegistry::getUint(target, propertyKey); + + if (m_previousValue != value) + { + m_previousValue = value; + m_targetDataValue.value(value); + return true; + } + return false; +} \ No newline at end of file diff --git a/third_party/rive/source/data_bind/context/context_value_boolean.cpp b/third_party/rive/source/data_bind/context/context_value_boolean.cpp new file mode 100644 index 0000000..d4b209b --- /dev/null +++ b/third_party/rive/source/data_bind/context/context_value_boolean.cpp @@ -0,0 +1,34 @@ +#include "rive/data_bind/context/context_value_boolean.hpp" +#include "rive/data_bind/data_values/data_value_boolean.hpp" +#include "rive/generated/core_registry.hpp" + +using namespace rive; + +DataBindContextValueBoolean::DataBindContextValueBoolean(DataBind* dataBind) : + DataBindContextValue(dataBind) +{} + +void DataBindContextValueBoolean::apply(Core* target, + uint32_t propertyKey, + bool isMainDirection) +{ + syncSourceValue(); + auto value = calculateValue(m_dataValue, + isMainDirection, + m_dataBind); + CoreRegistry::setBool(target, propertyKey, value); +} + +bool DataBindContextValueBoolean::syncTargetValue(Core* target, + uint32_t propertyKey) +{ + auto value = CoreRegistry::getBool(target, propertyKey); + + if (m_previousValue != value) + { + m_previousValue = value; + m_targetDataValue.value(value); + return true; + } + return false; +} \ No newline at end of file diff --git a/third_party/rive/source/data_bind/context/context_value_color.cpp b/third_party/rive/source/data_bind/context/context_value_color.cpp new file mode 100644 index 0000000..40d95eb --- /dev/null +++ b/third_party/rive/source/data_bind/context/context_value_color.cpp @@ -0,0 +1,34 @@ +#include "rive/data_bind/context/context_value_color.hpp" +#include "rive/data_bind/data_values/data_value_color.hpp" +#include "rive/generated/core_registry.hpp" + +using namespace rive; + +DataBindContextValueColor::DataBindContextValueColor(DataBind* dataBind) : + DataBindContextValue(dataBind) +{} + +void DataBindContextValueColor::apply(Core* target, + uint32_t propertyKey, + bool isMainDirection) +{ + syncSourceValue(); + auto value = calculateValue(m_dataValue, + isMainDirection, + m_dataBind); + CoreRegistry::setColor(target, propertyKey, value); +} + +bool DataBindContextValueColor::syncTargetValue(Core* target, + uint32_t propertyKey) +{ + auto value = CoreRegistry::getColor(target, propertyKey); + + if (m_previousValue != value) + { + m_previousValue = value; + m_targetDataValue.value(value); + return true; + } + return false; +} \ No newline at end of file diff --git a/third_party/rive/source/data_bind/context/context_value_enum.cpp b/third_party/rive/source/data_bind/context/context_value_enum.cpp new file mode 100644 index 0000000..3b81b02 --- /dev/null +++ b/third_party/rive/source/data_bind/context/context_value_enum.cpp @@ -0,0 +1,41 @@ +#include "rive/data_bind/context/context_value_enum.hpp" +#include "rive/data_bind/data_values/data_value_enum.hpp" +#include "rive/generated/core_registry.hpp" + +using namespace rive; + +DataBindContextValueEnum::DataBindContextValueEnum(DataBind* dataBind) : + DataBindContextValue(dataBind) +{ + auto source = m_dataBind->source(); + auto viewmodelInstanceEnum = source->as(); + auto viewModelPropertyEnum = + viewmodelInstanceEnum->viewModelProperty()->as(); + m_targetDataValue.dataEnum(viewModelPropertyEnum->dataEnum()); +} + +void DataBindContextValueEnum::apply(Core* target, + uint32_t propertyKey, + bool isMainDirection) +{ + + syncSourceValue(); + auto value = calculateValue(m_dataValue, + isMainDirection, + m_dataBind); + CoreRegistry::setUint(target, propertyKey, value); +} + +bool DataBindContextValueEnum::syncTargetValue(Core* target, + uint32_t propertyKey) +{ + auto value = CoreRegistry::getUint(target, propertyKey); + + if (m_previousValue != value) + { + m_previousValue = value; + m_targetDataValue.value(value); + return true; + } + return false; +} \ No newline at end of file diff --git a/third_party/rive/source/data_bind/context/context_value_list.cpp b/third_party/rive/source/data_bind/context/context_value_list.cpp new file mode 100644 index 0000000..2242e5e --- /dev/null +++ b/third_party/rive/source/data_bind/context/context_value_list.cpp @@ -0,0 +1,37 @@ +#include "rive/data_bind/context/context_value_list.hpp" +#include "rive/data_bind/data_bind_list_item_consumer.hpp" +#include "rive/generated/core_registry.hpp" +#include "rive/viewmodel/viewmodel_instance_list_item.hpp" + +using namespace rive; + +DataBindContextValueList::DataBindContextValueList(DataBind* dataBind) : + DataBindContextValue(dataBind) +{} + +void DataBindContextValueList::apply(Core* target, + uint32_t propertyKey, + bool isMainDirection) +{ + syncSourceValue(); + auto value = + calculateValue*>( + m_dataValue, + isMainDirection, + m_dataBind); + if (target != nullptr) + { + auto consumer = DataBindListItemConsumer::from(target); + if (consumer != nullptr) + { + consumer->updateList(m_dataBind->propertyKey(), value); + } + } +} + +void DataBindContextValueList::applyToSource(Core* target, + uint32_t propertyKey, + bool isMainDirection) +{ + // TODO: @hernan does applyToSource make sense? Should we block it somehow? +} \ No newline at end of file diff --git a/third_party/rive/source/data_bind/context/context_value_number.cpp b/third_party/rive/source/data_bind/context/context_value_number.cpp new file mode 100644 index 0000000..5a4fd7e --- /dev/null +++ b/third_party/rive/source/data_bind/context/context_value_number.cpp @@ -0,0 +1,56 @@ +#include "rive/data_bind/context/context_value_number.hpp" +#include "rive/generated/core_registry.hpp" +#include + +using namespace rive; + +DataBindContextValueNumber::DataBindContextValueNumber(DataBind* dataBind) : + DataBindContextValue(dataBind) +{} + +void DataBindContextValueNumber::apply(Core* target, + uint32_t propertyKey, + bool isMainDirection) +{ + syncSourceValue(); + auto value = calculateValue(m_dataValue, + isMainDirection, + m_dataBind); + switch (CoreRegistry::propertyFieldId(propertyKey)) + { + case CoreDoubleType::id: + CoreRegistry::setDouble(target, propertyKey, value); + break; + case CoreUintType::id: + int rounded = value < 0 ? 0 : std::round(value); + CoreRegistry::setUint(target, propertyKey, rounded); + break; + } +} + +bool DataBindContextValueNumber::syncTargetValue(Core* target, + uint32_t propertyKey) +{ + float value = 0; + switch (CoreRegistry::propertyFieldId(propertyKey)) + { + case CoreDoubleType::id: + { + value = CoreRegistry::getDouble(target, propertyKey); + } + break; + case CoreUintType::id: + { + value = (float)CoreRegistry::getUint(target, propertyKey); + break; + } + } + if (m_previousValue != value) + { + m_previousValue = value; + + m_targetDataValue.value(value); + return true; + } + return false; +} \ No newline at end of file diff --git a/third_party/rive/source/data_bind/context/context_value_string.cpp b/third_party/rive/source/data_bind/context/context_value_string.cpp new file mode 100644 index 0000000..e4b8c6c --- /dev/null +++ b/third_party/rive/source/data_bind/context/context_value_string.cpp @@ -0,0 +1,34 @@ +#include "rive/data_bind/context/context_value_string.hpp" +#include "rive/data_bind/data_values/data_value_string.hpp" +#include "rive/generated/core_registry.hpp" + +using namespace rive; + +DataBindContextValueString::DataBindContextValueString(DataBind* dataBind) : + DataBindContextValue(dataBind) +{} + +void DataBindContextValueString::apply(Core* target, + uint32_t propertyKey, + bool isMainDirection) +{ + syncSourceValue(); + auto value = calculateValue(m_dataValue, + isMainDirection, + m_dataBind); + CoreRegistry::setString(target, propertyKey, value); +} + +bool DataBindContextValueString::syncTargetValue(Core* target, + uint32_t propertyKey) +{ + auto value = CoreRegistry::getString(target, propertyKey); + + if (m_previousValue != value) + { + m_previousValue = value; + m_targetDataValue.value(value); + return true; + } + return false; +} \ No newline at end of file diff --git a/third_party/rive/source/data_bind/context/context_value_symbol_list_index.cpp b/third_party/rive/source/data_bind/context/context_value_symbol_list_index.cpp new file mode 100644 index 0000000..1e34cc4 --- /dev/null +++ b/third_party/rive/source/data_bind/context/context_value_symbol_list_index.cpp @@ -0,0 +1,44 @@ +#include "rive/data_bind/context/context_value_symbol_list_index.hpp" +#include "rive/data_bind/data_values/data_value_symbol_list_index.hpp" +#include "rive/generated/core_registry.hpp" + +using namespace rive; + +DataBindContextValueSymbolListIndex::DataBindContextValueSymbolListIndex( + DataBind* dataBind) : + DataBindContextValue(dataBind) +{} + +void DataBindContextValueSymbolListIndex::apply(Core* target, + uint32_t propertyKey, + bool isMainDirection) +{ + syncSourceValue(); + auto value = + calculateValue(m_dataValue, + isMainDirection, + m_dataBind); + switch (CoreRegistry::propertyFieldId(propertyKey)) + { + case CoreDoubleType::id: + CoreRegistry::setDouble(target, propertyKey, (float)value); + break; + case CoreUintType::id: + CoreRegistry::setUint(target, propertyKey, value); + break; + } +} + +bool DataBindContextValueSymbolListIndex::syncTargetValue(Core* target, + uint32_t propertyKey) +{ + auto value = CoreRegistry::getUint(target, propertyKey); + + if (m_previousValue != value) + { + m_previousValue = value; + m_targetDataValue.value(value); + return true; + } + return false; +} \ No newline at end of file diff --git a/third_party/rive/source/data_bind/context/context_value_trigger.cpp b/third_party/rive/source/data_bind/context/context_value_trigger.cpp new file mode 100644 index 0000000..e4a9376 --- /dev/null +++ b/third_party/rive/source/data_bind/context/context_value_trigger.cpp @@ -0,0 +1,34 @@ +#include "rive/data_bind/context/context_value_trigger.hpp" +#include "rive/data_bind/data_values/data_value_trigger.hpp" +#include "rive/generated/core_registry.hpp" + +using namespace rive; + +DataBindContextValueTrigger::DataBindContextValueTrigger(DataBind* dataBind) : + DataBindContextValue(dataBind) +{} + +void DataBindContextValueTrigger::apply(Core* target, + uint32_t propertyKey, + bool isMainDirection) +{ + syncSourceValue(); + auto value = calculateValue(m_dataValue, + isMainDirection, + m_dataBind); + CoreRegistry::setUint(target, propertyKey, value); +} + +bool DataBindContextValueTrigger::syncTargetValue(Core* target, + uint32_t propertyKey) +{ + auto value = CoreRegistry::getUint(target, propertyKey); + + if (m_previousValue != value) + { + m_previousValue = value; + m_targetDataValue.value(value); + return true; + } + return false; +} \ No newline at end of file diff --git a/third_party/rive/source/data_bind/converters/data_converter.cpp b/third_party/rive/source/data_bind/converters/data_converter.cpp new file mode 100644 index 0000000..1dea5b6 --- /dev/null +++ b/third_party/rive/source/data_bind/converters/data_converter.cpp @@ -0,0 +1,91 @@ +#include "rive/data_bind/converters/data_converter.hpp" +#include "rive/importers/import_stack.hpp" +#include "rive/importers/backboard_importer.hpp" +#include "rive/backboard.hpp" +#include "rive/data_bind/data_bind.hpp" +#include "rive/data_bind/data_bind_context.hpp" + +using namespace rive; + +DataConverter::~DataConverter() +{ + for (auto dataBind : m_dataBinds) + { + delete dataBind; + } +} + +StatusCode DataConverter::import(ImportStack& importStack) +{ + auto backboardImporter = + importStack.latest(Backboard::typeKey); + if (backboardImporter == nullptr) + { + return StatusCode::MissingObject; + } + backboardImporter->addDataConverter(this); + + return Super::import(importStack); +} + +void DataConverter::addDataBind(DataBind* dataBind) +{ + m_dataBinds.push_back(dataBind); +} + +void DataConverter::bindFromContext(DataContext* dataContext, + DataBind* dataBind) +{ + m_parentDataBind = dataBind; + for (auto dataBind : m_dataBinds) + { + if (dataBind->is()) + { + + dataBind->as()->bindFromContext(dataContext); + } + } +} + +void DataConverter::unbind() +{ + for (auto dataBind : m_dataBinds) + { + dataBind->unbind(); + } +} + +void DataConverter::markConverterDirty() +{ + m_parentDataBind->addDirt(ComponentDirt::Dependents | + ComponentDirt::Bindings, + false); +} + +void DataConverter::update() +{ + for (auto dataBind : m_dataBinds) + { + auto d = dataBind->dirt(); + if (d == ComponentDirt::None) + { + continue; + } + dataBind->dirt(ComponentDirt::None); + dataBind->update(d); + } +} + +void DataConverter::copy(const DataConverter& object) +{ + auto dataBinds = object.dataBinds(); + for (auto dataBind : dataBinds) + { + auto dataBindClone = dataBind->clone()->as(); + dataBindClone->target(this); + addDataBind(dataBindClone); + } + DataConverterBase::copy(object); +} + +bool DataConverter::advance(float elapsedTime) { return false; } \ No newline at end of file diff --git a/third_party/rive/source/data_bind/converters/data_converter_boolean_negate.cpp b/third_party/rive/source/data_bind/converters/data_converter_boolean_negate.cpp new file mode 100644 index 0000000..94d458f --- /dev/null +++ b/third_party/rive/source/data_bind/converters/data_converter_boolean_negate.cpp @@ -0,0 +1,25 @@ +#include "rive/math/math_types.hpp" +#include "rive/data_bind/converters/data_converter_boolean_negate.hpp" +#include "rive/data_bind/data_values/data_value_boolean.hpp" + +using namespace rive; + +DataValue* DataConverterBooleanNegate::convert(DataValue* input, + DataBind* dataBind) +{ + if (input->is()) + { + m_output.value(!input->as()->value()); + } + else + { + m_output.value(DataValueBoolean::defaultValue); + } + return &m_output; +} + +DataValue* DataConverterBooleanNegate::reverseConvert(DataValue* input, + DataBind* dataBind) +{ + return convert(input, dataBind); +} \ No newline at end of file diff --git a/third_party/rive/source/data_bind/converters/data_converter_formula.cpp b/third_party/rive/source/data_bind/converters/data_converter_formula.cpp new file mode 100644 index 0000000..5a1392b --- /dev/null +++ b/third_party/rive/source/data_bind/converters/data_converter_formula.cpp @@ -0,0 +1,537 @@ +#include "rive/data_bind/converters/data_converter_formula.hpp" +#include "rive/data_bind/data_values/data_value_number.hpp" +#include "rive/data_bind/data_values/data_value_symbol_list_index.hpp" +#include "rive/data_bind/converters/formula/formula_token_value.hpp" +#include "rive/data_bind/converters/formula/formula_token_argument_separator.hpp" +#include "rive/data_bind/converters/formula/formula_token_input.hpp" +#include "rive/data_bind/converters/formula/formula_token_operation.hpp" +#include "rive/data_bind/converters/formula/formula_token_parenthesis.hpp" +#include "rive/data_bind/converters/formula/formula_token_function.hpp" +#include "rive/data_bind/converters/formula/formula_token_parenthesis_open.hpp" +#include "rive/data_bind/converters/formula/formula_token_parenthesis_close.hpp" +#include "rive/animation/arithmetic_operation.hpp" +#include "rive/function_type.hpp" +#include "rive/math/math_types.hpp" +#include + +using namespace rive; + +DataConverterFormula::~DataConverterFormula() +{ + if (m_isInstance) + { + + for (auto& token : m_outputQueue) + { + delete token; + } + } + else + { + + for (auto& token : m_tokens) + { + delete token; + } + } +} + +int DataConverterFormula::getPrecedence(FormulaToken* token) +{ + if (token->is()) + { + return 1; + } + if (token->is()) + { + return 1; + } + if (token->is()) + { + auto operationToken = token->as(); + auto operationType = + (ArithmeticOperation)operationToken->operationType(); + if (operationType == ArithmeticOperation::add) + { + return 2; + } + else if (operationType == ArithmeticOperation::subtract) + { + return 2; + } + else if (operationType == ArithmeticOperation::multiply) + { + return 3; + } + else if (operationType == ArithmeticOperation::divide) + { + return 3; + } + } + return 0; +} + +void DataConverterFormula::initialize() +{ + // convert the formula to Reverse Polish Notation using a version of + // the Shunting yard algorithm + // Some optimizations could be done here by precomputing constant parts + // of the equation + std::vector operationsStack; + int tokenIndex = 0; + for (auto& token : m_tokens) + { + if (token->is() || token->is()) + { + m_outputQueue.push_back(token); + } + else if (token->is()) + { + while (operationsStack.size() > 0 && + !operationsStack.back()->is() && + getPrecedence(operationsStack.back()) >= + getPrecedence(token)) + { + FormulaToken* higherToken = operationsStack.back(); + operationsStack.pop_back(); + m_outputQueue.push_back(higherToken); + } + operationsStack.push_back(token); + } + else if (token->is() || + token->is()) + { + + // Peeking into the next token to identify whether the current + // function has no arguments. Is there a better way to reliably + // count the number of arguments? + FormulaToken* nextToken = tokenIndex == m_tokens.size() - 1 + ? nullptr + : m_tokens[tokenIndex + 1]; + m_argumentsCount[token] = + (nextToken != nullptr && + nextToken->is()) + ? 0 + : 1; + operationsStack.push_back(token); + } + else if (token->is()) + { + + while ( + operationsStack.size() > 0 && + (!operationsStack.back()->is() && + !operationsStack.back()->is())) + { + auto higherToken = operationsStack.back(); + operationsStack.pop_back(); + m_outputQueue.push_back(higherToken); + } + if (operationsStack.size() == 0) + { + // mismatched parenthesis + } + else + { + auto openingToken = operationsStack.back(); + operationsStack.pop_back(); + if (openingToken->is()) + { + m_outputQueue.push_back(openingToken); + } + else + { + // Discarding open parenthesis + } + } + } + else if (token->is() && + operationsStack.size() > 0) + { + size_t index = operationsStack.size() - 1; + while (index >= 0) + { + auto operationTokenCandidate = operationsStack[index]; + auto argumentsCount = + m_argumentsCount.find(operationTokenCandidate); + if (argumentsCount != m_argumentsCount.end()) + { + + int count = argumentsCount->second; + m_argumentsCount[operationTokenCandidate] = count + 1; + break; + } + if (index == 0) + { + break; + } + index -= 1; + } + while ( + operationsStack.size() > 0 && + (!operationsStack.back()->is() && + !operationsStack.back()->is())) + { + auto higherToken = operationsStack.back(); + operationsStack.pop_back(); + m_outputQueue.push_back(higherToken); + } + } + tokenIndex++; + } + while (operationsStack.size() > 0) + { + auto operation = operationsStack.back(); + operationsStack.pop_back(); + if (operation->is()) + { + // mismatched parenthesis + } + else + { + m_outputQueue.push_back(operation); + } + } +} + +float DataConverterFormula::applyOperation(float left, + float right, + int operationTypeInt) +{ + auto operationType = (ArithmeticOperation)operationTypeInt; + switch (operationType) + { + case ArithmeticOperation::add: + return left + right; + case ArithmeticOperation::subtract: + return left - right; + case ArithmeticOperation::multiply: + return left * right; + case ArithmeticOperation::divide: + return left / right; + case ArithmeticOperation::modulo: + return math::positive_mod(left, right); + default: + return 0.0f; + } +} + +float DataConverterFormula::getRandom(int randomIndex) +{ +#ifdef TESTING + int testInt = 0; +#endif + while (m_randoms.size() <= randomIndex) + { +#ifdef TESTING + m_randoms.push_back(testInt++); +#else + m_randoms.push_back((float)rand() / float(RAND_MAX)); +#endif + } + return m_randoms[randomIndex]; +} + +float DataConverterFormula::applyFunction(std::vector& stack, + int functionTypeIndex, + int totalArguments) +{ + + std::vector functionArguments; + int index = 0; + int currentRandom = 0; + while (index < totalArguments) + { + if (stack.size() > 0) + { + auto functionArgument = stack.back(); + stack.pop_back(); + functionArguments.push_back(functionArgument); + } + index++; + } + auto functionType = (FunctionType)functionTypeIndex; + switch (functionType) + { + case FunctionType::min: + { + if (functionArguments.size() > 0) + { + float minValue = functionArguments[0]; + for (auto i = 1; i < functionArguments.size(); i++) + { + if (functionArguments[i] < minValue) + { + minValue = functionArguments[i]; + } + } + return minValue; + } + } + break; + case FunctionType::max: + { + if (functionArguments.size() > 0) + { + float maxValue = functionArguments[0]; + for (auto i = 1; i < functionArguments.size(); i++) + { + if (functionArguments[i] > maxValue) + { + maxValue = functionArguments[i]; + } + } + return maxValue; + } + } + break; + case FunctionType::round: + if (functionArguments.size() > 0) + { + return roundf(functionArguments.back()); + } + break; + case FunctionType::ceil: + if (functionArguments.size() > 0) + { + return ceilf(functionArguments.back()); + } + break; + case FunctionType::floor: + if (functionArguments.size() > 0) + { + return floorf(functionArguments.back()); + } + break; + case FunctionType::sqrt: + if (functionArguments.size() > 0) + { + return sqrtf(functionArguments.back()); + } + break; + case FunctionType::pow: + { + if (functionArguments.size() > 1) + { + auto exponent = functionArguments[functionArguments.size() - 2]; + auto x = functionArguments.back(); + return powf(x, exponent); + } + } + break; + case FunctionType::exp: + if (functionArguments.size() > 0) + { + return exp(functionArguments.back()); + } + break; + case FunctionType::log: + if (functionArguments.size() > 0) + { + return log(functionArguments.back()); + } + break; + case FunctionType::cosine: + if (functionArguments.size() > 0) + { + return cos(functionArguments.back()); + } + break; + case FunctionType::sine: + if (functionArguments.size() > 0) + { + return sin(functionArguments.back()); + } + break; + case FunctionType::tangent: + if (functionArguments.size() > 0) + { + return tan(functionArguments.back()); + } + break; + case FunctionType::acosine: + + if (functionArguments.size() > 0) + { + return acos(functionArguments.back()); + } + break; + case FunctionType::asine: + + if (functionArguments.size() > 0) + { + return asin(functionArguments.back()); + } + break; + case FunctionType::atangent: + + if (functionArguments.size() > 0) + { + return atan(functionArguments.back()); + } + break; + case FunctionType::atangent2: + { + if (functionArguments.size() > 1) + { + auto argument1 = functionArguments.back(); + auto argument2 = + functionArguments[functionArguments.size() - 2]; + return atan2(argument1, argument2); + } + } + break; + case FunctionType::random: + { + float randomValue = getRandom(currentRandom++); + float lowerBound = 0; + float upperBound = 1; + if (functionArguments.size() == 1) + { + upperBound = functionArguments.back(); + } + else if (functionArguments.size() > 1) + { + lowerBound = functionArguments.back(); + upperBound = functionArguments[functionArguments.size() - 2]; + } + return lowerBound + (upperBound - lowerBound) * randomValue; + } + break; + default: + return 0.0f; + } + return 0; +} + +DataValue* DataConverterFormula::convert(DataValue* value, DataBind* dataBind) +{ + if (value->is() || value->is()) + { + float inputValue = + value->is() + ? value->as()->value() + : (float)(value->as()->value()); + float resultValue = inputValue; + + std::vector stack; + for (auto& token : m_outputQueue) + { + if (token->is()) + { + if (stack.size() > 1) + { + auto right = stack.back(); + stack.pop_back(); + auto left = stack.back(); + stack.pop_back(); + float operationResult = applyOperation( + left, + right, + token->as()->operationType()); + stack.push_back(operationResult); + } + } + else if (token->is()) + { + auto argumentsCount = m_argumentsCount.find(token); + float operationResult = applyFunction( + stack, + token->as()->functionType(), + argumentsCount == m_argumentsCount.end() + ? 0 + : argumentsCount->second); + stack.push_back(operationResult); + } + else if (token->is()) + { + stack.push_back(inputValue); + } + else if (token->is()) + { + stack.push_back( + token->as()->operationValue()); + } + } + + // If the formula is well formed, the stack at the end has to be of size + // 1 + if (stack.size() == 1) + { + resultValue = stack.back(); + stack.pop_back(); + } + + m_output.value(resultValue); + } + else + { + m_output.value(DataValueNumber::defaultValue); + } + return &m_output; +} + +DataValue* DataConverterFormula::reverseConvert(DataValue* value, + DataBind* dataBind) +{ + return convert(value, dataBind); +} + +void DataConverterFormula::addToken(FormulaToken* token) +{ + m_tokens.push_back(token); +} + +void DataConverterFormula::addOutputToken(FormulaToken* token, + int argumentsCount) +{ + m_outputQueue.push_back(token); + m_argumentsCount[token] = argumentsCount; +} + +// Warning! this clone override is not making a clean copy of the core object. +// It creates a limited instance to avoid recalculating the output stack every +// time +Core* DataConverterFormula::clone() const +{ + auto cloned = DataConverterFormulaBase::clone()->as(); + // Instead of cloning all tookens, we can clone the processed tokens that + // will be used during conversion + for (auto& token : m_outputQueue) + { + auto tokenArgumentsCountSearch = m_argumentsCount.find(token); + auto argumentsCount = + tokenArgumentsCountSearch == m_argumentsCount.end() + ? 0 + : tokenArgumentsCountSearch->second; + auto clonedToken = token->clone()->as(); + cloned->addOutputToken(clonedToken, argumentsCount); + } + cloned->isInstance(true); + return cloned; +} + +void DataConverterFormula::bindFromContext(DataContext* dataContext, + DataBind* dataBind) +{ + for (auto& token : m_outputQueue) + { + token->bindFromContext(dataContext, dataBind); + } +} + +void DataConverterFormula::unbind() +{ + for (auto& token : m_outputQueue) + { + token->unbind(); + } +} + +void DataConverterFormula::update() +{ + for (auto& token : m_outputQueue) + { + token->update(); + } +} \ No newline at end of file diff --git a/third_party/rive/source/data_bind/converters/data_converter_group.cpp b/third_party/rive/source/data_bind/converters/data_converter_group.cpp new file mode 100644 index 0000000..94ddb0c --- /dev/null +++ b/third_party/rive/source/data_bind/converters/data_converter_group.cpp @@ -0,0 +1,115 @@ +#include "rive/math/math_types.hpp" +#include "rive/data_bind/converters/data_converter_group.hpp" +#include "rive/data_bind/data_values/data_value_number.hpp" +#include "rive/data_bind/data_values/data_value_string.hpp" + +using namespace rive; + +DataConverterGroup::~DataConverterGroup() +{ + for (auto& item : m_items) + { + delete item; + } +} + +void DataConverterGroup::addItem(DataConverterGroupItem* item) +{ + m_items.push_back(item); +} + +DataValue* DataConverterGroup::convert(DataValue* input, DataBind* dataBind) +{ + DataValue* value = input; + for (auto& item : m_items) + { + if (item->converter() != nullptr) + { + value = item->converter()->convert(value, dataBind); + } + } + return value; +} + +DataValue* DataConverterGroup::reverseConvert(DataValue* input, + DataBind* dataBind) +{ + DataValue* value = input; + for (auto it = m_items.rbegin(); it != m_items.rend(); ++it) + { + if ((*it)->converter() != nullptr) + { + value = (*it)->converter()->reverseConvert(value, dataBind); + } + } + return value; +} + +Core* DataConverterGroup::clone() const +{ + auto cloned = DataConverterGroupBase::clone()->as(); + for (auto& item : m_items) + { + if (item->converter() == nullptr) + { + continue; + } + auto clonedItem = item->clone()->as(); + cloned->addItem(clonedItem); + } + return cloned; +} + +void DataConverterGroup::bindFromContext(DataContext* dataContext, + DataBind* dataBind) +{ + for (auto& item : m_items) + { + auto converter = item->converter(); + if (converter != nullptr) + { + converter->bindFromContext(dataContext, dataBind); + } + } +} + +void DataConverterGroup::unbind() +{ + for (auto& item : m_items) + { + auto converter = item->converter(); + if (converter != nullptr) + { + converter->unbind(); + } + } +} + +void DataConverterGroup::update() +{ + for (auto& item : m_items) + { + auto converter = item->converter(); + if (converter != nullptr) + { + converter->update(); + } + } +} + +bool DataConverterGroup::advance(float elapsedSeconds) +{ + bool didUpdate = false; + for (auto& item : m_items) + { + auto converter = item->converter(); + if (converter != nullptr) + { + if (converter->advance(elapsedSeconds)) + { + didUpdate = true; + } + } + } + return didUpdate; +} \ No newline at end of file diff --git a/third_party/rive/source/data_bind/converters/data_converter_group_item.cpp b/third_party/rive/source/data_bind/converters/data_converter_group_item.cpp new file mode 100644 index 0000000..a552c8d --- /dev/null +++ b/third_party/rive/source/data_bind/converters/data_converter_group_item.cpp @@ -0,0 +1,49 @@ +#include "rive/backboard.hpp" +#include "rive/math/math_types.hpp" +#include "rive/data_bind/converters/data_converter_group_item.hpp" +#include "rive/data_bind/converters/data_converter_group.hpp" +#include "rive/importers/data_converter_group_importer.hpp" +#include "rive/importers/backboard_importer.hpp" + +using namespace rive; + +DataConverterGroupItem::~DataConverterGroupItem() +{ + if (m_ownsConverter) + { + + delete m_dataConverter; + } +} + +StatusCode DataConverterGroupItem::import(ImportStack& importStack) +{ + auto backboardImporter = + importStack.latest(Backboard::typeKey); + if (backboardImporter == nullptr) + { + return StatusCode::MissingObject; + } + backboardImporter->addDataConverterGroupItemReferencer(this); + auto dataConveterGroupImporter = + importStack.latest( + DataConverterGroupBase::typeKey); + if (dataConveterGroupImporter == nullptr) + { + return StatusCode::MissingObject; + } + dataConveterGroupImporter->group()->addItem(this); + return Super::import(importStack); +} + +Core* DataConverterGroupItem::clone() const +{ + auto cloned = + DataConverterGroupItemBase::clone()->as(); + if (converter() != nullptr) + { + cloned->converter(converter()->clone()->as()); + cloned->ownsConverter(true); + } + return cloned; +} \ No newline at end of file diff --git a/third_party/rive/source/data_bind/converters/data_converter_interpolator.cpp b/third_party/rive/source/data_bind/converters/data_converter_interpolator.cpp new file mode 100644 index 0000000..096fa30 --- /dev/null +++ b/third_party/rive/source/data_bind/converters/data_converter_interpolator.cpp @@ -0,0 +1,151 @@ +#include "rive/math/math_types.hpp" +#include "rive/data_bind/converters/data_converter_interpolator.hpp" +#include "rive/data_bind/data_values/data_value_number.hpp" + +using namespace rive; + +void DataConverterInterpolator::copy( + const DataConverterInterpolatorBase& object) +{ + interpolator(object.as()->interpolator()); + DataConverterInterpolatorBase::copy(object); +} + +InterpolatorAnimationData* DataConverterInterpolator::currentAnimationData() +{ + return m_isSmoothingAnimation ? &m_animationDataB : &m_animationDataA; +} + +void DataConverterInterpolator::interpolator(KeyFrameInterpolator* interpolator) +{ + m_interpolator = interpolator; +} + +void DataConverterInterpolator::advanceAnimationData(float elapsedTime) +{ + auto animationData = currentAnimationData(); + if (m_isSmoothingAnimation) + { + float f = std::fmin(1.0f, + duration() > 0 + ? m_animationDataA.elapsedSeconds / duration() + : 1.0f); + if (m_interpolator != nullptr) + { + f = m_interpolator->transform(f); + } + m_animationDataB.from = m_animationDataA.interpolate(f); + if (f == 1) + { + m_animationDataA.copy(m_animationDataB); + m_isSmoothingAnimation = false; + } + else + { + m_animationDataA.elapsedSeconds += elapsedTime; + } + } + if (animationData->elapsedSeconds >= duration()) + { + m_currentValue = animationData->to; + + if (m_isSmoothingAnimation) + { + m_isSmoothingAnimation = false; + m_animationDataA.copy(m_animationDataB); + m_animationDataA.elapsedSeconds = m_animationDataB.elapsedSeconds = + 0; + } + else + { + m_animationDataA.elapsedSeconds = 0; + } + return; + } + float f = std::fmin( + 1.0f, + duration() > 0 ? animationData->elapsedSeconds / duration() : 1.0f); + if (m_interpolator != nullptr) + { + f = m_interpolator->transform(f); + } + auto current = animationData->interpolate(f); + if (m_currentValue != current) + { + m_currentValue = current; + } + + animationData->elapsedSeconds += elapsedTime; +} + +bool DataConverterInterpolator::advance(float elapsedTime) +{ + auto animationData = currentAnimationData(); + if (animationData->to == m_currentValue) + { + return false; + } + advanceAnimationData(elapsedTime); + if (animationData->elapsedSeconds < duration()) + { + markConverterDirty(); + return true; + } + return false; +} + +DataValue* DataConverterInterpolator::convert(DataValue* input, + DataBind* dataBind) +{ + if (input->is()) + { + auto animationData = currentAnimationData(); + auto numberInput = input->as(); + if (m_isFirstRun) + { + animationData->from = numberInput->value(); + animationData->to = numberInput->value(); + m_currentValue = numberInput->value(); + m_isFirstRun = false; + } + else + { + if (animationData->to != numberInput->value()) + { + if (animationData->elapsedSeconds != 0) + { + if (m_isSmoothingAnimation) + { + m_animationDataA.copy(m_animationDataB); + } + m_isSmoothingAnimation = true; + } + else + { + m_isSmoothingAnimation = false; + } + animationData = currentAnimationData(); + animationData->from = m_currentValue; + animationData->to = numberInput->value(); + animationData->elapsedSeconds = 0; + } + } + m_output.value(m_currentValue); + } + return &m_output; +} + +DataValue* DataConverterInterpolator::reverseConvert(DataValue* input, + DataBind* dataBind) +{ + return convert(input, dataBind); +} + +void DataConverterInterpolator::durationChanged() { markConverterDirty(); } + +void InterpolatorAnimationData::copy(const InterpolatorAnimationData& source) +{ + from = source.from; + to = source.to; + elapsedSeconds = source.elapsedSeconds; +} diff --git a/third_party/rive/source/data_bind/converters/data_converter_number_to_list.cpp b/third_party/rive/source/data_bind/converters/data_converter_number_to_list.cpp new file mode 100644 index 0000000..e1e7df2 --- /dev/null +++ b/third_party/rive/source/data_bind/converters/data_converter_number_to_list.cpp @@ -0,0 +1,93 @@ +#include "rive/data_bind/converters/data_converter_number_to_list.hpp" +#include "rive/data_bind/data_values/data_value_list.hpp" +#include "rive/data_bind/data_values/data_value_number.hpp" +#include "rive/file.hpp" +#include "rive/math/math_types.hpp" +#include "rive/refcnt.hpp" + +using namespace rive; + +DataConverterNumberToList::~DataConverterNumberToList() +{ + for (auto& item : m_listItems) + { + item->unref(); + } +} + +DataValue* DataConverterNumberToList::convert(DataValue* input, + DataBind* dataBind) +{ + if (input->is()) + { + return input; + } + else if (input->is()) + { + m_output.clear(); + auto inputNumber = input->as(); + auto count = std::max(0, (int)std::floor(inputNumber->value())); + if (m_file != nullptr && m_file->viewModel(viewModelId()) != nullptr) + { + auto viewModel = m_file->viewModel(viewModelId()); + if (count > m_listItems.size()) + { + auto defaultInstance = viewModel->defaultInstance(); + while (m_listItems.size() < count) + { + auto item = new ViewModelInstanceListItem(); + auto copy = rcp( + defaultInstance->clone()->as()); + item->viewModelInstance(copy); + m_listItems.push_back(item); + } + } + else if (count < m_listItems.size()) + { + while (m_listItems.size() > count) + { + auto item = m_listItems.back(); + m_listItems.pop_back(); + item->unref(); + } + } + } + else + { + clearItems(); + } + for (auto item : m_listItems) + { + m_output.addItem(item); + } + return &m_output; + } + return nullptr; +} + +void DataConverterNumberToList::clearItems() +{ + for (auto& item : m_listItems) + { + item->unref(); + } + m_listItems.clear(); +} + +void DataConverterNumberToList::viewModelIdChanged() +{ + // Clear the cached items if viewmodel changes + clearItems(); + markConverterDirty(); +} + +void DataConverterNumberToList::file(File* value) { m_file = value; } +File* DataConverterNumberToList::file() const { return m_file; } + +Core* DataConverterNumberToList::clone() const +{ + auto clone = static_cast( + DataConverterNumberToListBase::clone()); + clone->file(file()); + return clone; +} \ No newline at end of file diff --git a/third_party/rive/source/data_bind/converters/data_converter_operation.cpp b/third_party/rive/source/data_bind/converters/data_converter_operation.cpp new file mode 100644 index 0000000..c071c44 --- /dev/null +++ b/third_party/rive/source/data_bind/converters/data_converter_operation.cpp @@ -0,0 +1,155 @@ +#include "rive/math/math_types.hpp" +#include "rive/data_bind/converters/data_converter_operation.hpp" +#include "rive/data_bind/data_values/data_value_number.hpp" +#include "rive/data_bind/data_values/data_value_symbol_list_index.hpp" +#include + +using namespace rive; + +DataValue* DataConverterOperation::convertValue(DataValue* input, float value) +{ + if (input->is() || input->is()) + { + float inputValue = + input->is() + ? input->as()->value() + : (float)(input->as()->value()); + float resultValue = value; + switch (op()) + { + case ArithmeticOperation::add: + resultValue = inputValue + resultValue; + break; + case ArithmeticOperation::subtract: + resultValue = inputValue - resultValue; + break; + case ArithmeticOperation::multiply: + resultValue = inputValue * resultValue; + break; + case ArithmeticOperation::divide: + resultValue = inputValue / resultValue; + break; + case ArithmeticOperation::modulo: + resultValue = math::positive_mod(inputValue, resultValue); + break; + case ArithmeticOperation::squareRoot: + resultValue = sqrtf(inputValue); + break; + case ArithmeticOperation::power: + resultValue = powf(inputValue, resultValue); + break; + case ArithmeticOperation::exp: + resultValue = exp(inputValue); + break; + case ArithmeticOperation::log: + resultValue = log(inputValue); + break; + case ArithmeticOperation::cosine: + resultValue = cos(inputValue); + break; + case ArithmeticOperation::sine: + resultValue = sin(inputValue); + break; + case ArithmeticOperation::tangent: + resultValue = tan(inputValue); + break; + case ArithmeticOperation::acosine: + resultValue = acos(inputValue); + break; + case ArithmeticOperation::asine: + resultValue = asin(inputValue); + break; + case ArithmeticOperation::atangent: + resultValue = atan(inputValue); + break; + case ArithmeticOperation::atangent2: + resultValue = atan2(inputValue, resultValue); + break; + case ArithmeticOperation::round: + resultValue = roundf(inputValue); + break; + case ArithmeticOperation::floor: + resultValue = floorf(inputValue); + break; + case ArithmeticOperation::ceil: + resultValue = ceilf(inputValue); + break; + } + m_output.value(resultValue); + } + else + { + m_output.value(DataValueNumber::defaultValue); + } + return &m_output; +} + +DataValue* DataConverterOperation::reverseConvertValue(DataValue* input, + float value) +{ + auto output = new DataValueNumber(); + if (input->is()) + { + float inputValue = input->as()->value(); + float resultValue = value; + switch (op()) + { + case ArithmeticOperation::add: + resultValue = inputValue - resultValue; + break; + case ArithmeticOperation::subtract: + resultValue = inputValue + resultValue; + break; + case ArithmeticOperation::multiply: + resultValue = inputValue / resultValue; + break; + case ArithmeticOperation::divide: + resultValue = inputValue * resultValue; + break; + // + case ArithmeticOperation::modulo: + resultValue = inputValue; // No reverse operation for modulo + break; + case ArithmeticOperation::squareRoot: + resultValue = powf(inputValue, 2); + break; + case ArithmeticOperation::power: + resultValue = powf(inputValue, 1 / resultValue); + break; + case ArithmeticOperation::exp: + resultValue = log(inputValue); + break; + case ArithmeticOperation::log: + resultValue = exp(inputValue); + break; + case ArithmeticOperation::cosine: + resultValue = acos(inputValue); + break; + case ArithmeticOperation::sine: + resultValue = asin(inputValue); + break; + case ArithmeticOperation::tangent: + resultValue = atan(inputValue); + break; + case ArithmeticOperation::acosine: + resultValue = cos(inputValue); + break; + case ArithmeticOperation::asine: + resultValue = sin(inputValue); + break; + case ArithmeticOperation::atangent: + resultValue = tan(inputValue); + break; + case ArithmeticOperation::atangent2: + resultValue = inputValue; // No reverse operation for atan2 + break; + case ArithmeticOperation::round: + case ArithmeticOperation::floor: + case ArithmeticOperation::ceil: + resultValue = inputValue; // No reverse operation + break; + } + output->value(resultValue); + } + return output; +} \ No newline at end of file diff --git a/third_party/rive/source/data_bind/converters/data_converter_operation_value.cpp b/third_party/rive/source/data_bind/converters/data_converter_operation_value.cpp new file mode 100644 index 0000000..ee9e2c7 --- /dev/null +++ b/third_party/rive/source/data_bind/converters/data_converter_operation_value.cpp @@ -0,0 +1,22 @@ +#include "rive/math/math_types.hpp" +#include "rive/data_bind/converters/data_converter_operation_value.hpp" +#include "rive/data_bind/data_values/data_value_number.hpp" + +using namespace rive; + +DataValue* DataConverterOperationValue::convert(DataValue* input, + DataBind* dataBind) +{ + return convertValue(input, operationValue()); +} + +DataValue* DataConverterOperationValue::reverseConvert(DataValue* input, + DataBind* dataBind) +{ + return reverseConvertValue(input, operationValue()); +} + +void DataConverterOperationValue::operationValueChanged() +{ + markConverterDirty(); +} \ No newline at end of file diff --git a/third_party/rive/source/data_bind/converters/data_converter_operation_viewmodel.cpp b/third_party/rive/source/data_bind/converters/data_converter_operation_viewmodel.cpp new file mode 100644 index 0000000..a132578 --- /dev/null +++ b/third_party/rive/source/data_bind/converters/data_converter_operation_viewmodel.cpp @@ -0,0 +1,59 @@ +#include "rive/math/math_types.hpp" +#include "rive/data_bind/converters/data_converter_operation_viewmodel.hpp" +#include "rive/data_bind/data_values/data_value_number.hpp" +#include "rive/data_bind/data_bind_context.hpp" + +using namespace rive; + +float DataConverterOperationViewModel::resolveValue(DataBind* dataBind) +{ + + if (m_source != nullptr) + { + return m_source->propertyValue(); + } + return 0.0f; +} + +DataValue* DataConverterOperationViewModel::convert(DataValue* input, + DataBind* dataBind) +{ + return convertValue(input, resolveValue(dataBind)); +} + +DataValue* DataConverterOperationViewModel::reverseConvert(DataValue* input, + DataBind* dataBind) +{ + return reverseConvertValue(input, resolveValue(dataBind)); +} + +void DataConverterOperationViewModel::decodeSourcePathIds( + Span value) +{ + BinaryReader reader(value); + while (!reader.reachedEnd()) + { + auto val = reader.readVarUintAs(); + m_SourcePathIdsBuffer.push_back(val); + } +} + +void DataConverterOperationViewModel::copySourcePathIds( + const DataConverterOperationViewModelBase& object) +{ + m_SourcePathIdsBuffer = + object.as()->m_SourcePathIdsBuffer; +} + +void DataConverterOperationViewModel::bindFromContext(DataContext* dataContext, + DataBind* dataBind) +{ + auto propertyValue = + dataContext->getViewModelProperty(m_SourcePathIdsBuffer); + if (propertyValue != nullptr && + propertyValue->is()) + { + m_source = propertyValue->as(); + m_source->addDependent(dataBind); + } +} \ No newline at end of file diff --git a/third_party/rive/source/data_bind/converters/data_converter_range_mapper.cpp b/third_party/rive/source/data_bind/converters/data_converter_range_mapper.cpp new file mode 100644 index 0000000..ff509a7 --- /dev/null +++ b/third_party/rive/source/data_bind/converters/data_converter_range_mapper.cpp @@ -0,0 +1,124 @@ +#include "rive/math/math_types.hpp" +#include "rive/data_bind/converters/data_converter_range_mapper.hpp" +#include "rive/data_bind/data_values/data_value_number.hpp" +#include "rive/animation/data_converter_range_mapper_flags.hpp" + +using namespace rive; + +void DataConverterRangeMapper::copy(const DataConverterRangeMapperBase& object) +{ + interpolator(object.as()->interpolator()); + DataConverterRangeMapperBase::copy(object); +} + +DataValueNumber* DataConverterRangeMapper::calculateRange(DataValue* input, + float minInput, + float maxInput, + float minOutput, + float maxOutput) +{ + if (input->is()) + { + if (minOutput == maxOutput) + { + m_output.value(minOutput); + } + else + { + auto flagsValue = + static_cast(flags()); + float value = input->as()->value(); + + // Clamp value to min input if flag is on + if (value < minInput && + (flagsValue & DataConverterRangeMapperFlags::ClampLower) == + DataConverterRangeMapperFlags::ClampLower) + { + value = minInput; + } + // Clamp value to max input if flag is on + else if (value > maxInput && + (flagsValue & DataConverterRangeMapperFlags::ClampUpper) == + DataConverterRangeMapperFlags::ClampUpper) + { + value = maxInput; + } + if ((value < minInput || value > maxInput) && + (flagsValue & DataConverterRangeMapperFlags::Modulo) == + DataConverterRangeMapperFlags::Modulo) + { + // apply modulo to value to wrap whithin the min - max input if + // it exceeds its range + value = + std::abs(math::positive_mod(value, (maxInput - minInput)) + + minInput); + } + float perc = (value - minInput) / (maxInput - minInput); + // If reverse flag is on, flip the values + if ((flagsValue & DataConverterRangeMapperFlags::Reverse) == + DataConverterRangeMapperFlags::Reverse) + { + perc = 1 - perc; + } + // Apply interpolator if exists and value is within range + if (m_interpolator != nullptr && perc > 0 && perc < 1) + { + perc = m_interpolator->transform(perc); + } + // hold keyframe interpolation + else if (interpolationType() == 0) + { + perc = perc <= 0 ? 0 : 1; + } + m_output.value(perc * maxOutput + (1 - perc) * minOutput); + } + } + else + { + m_output.value(DataValueNumber::defaultValue); + } + return &m_output; +} + +DataValueNumber* DataConverterRangeMapper::calculateReverseRange( + DataValue* input, + float minInput, + float maxInput, + float minOutput, + float maxOutput) +{ + return calculateRange(input, minOutput, maxOutput, minInput, maxInput); +} + +void DataConverterRangeMapper::interpolator(KeyFrameInterpolator* interpolator) +{ + m_interpolator = interpolator; +} + +DataValue* DataConverterRangeMapper::convert(DataValue* input, + DataBind* dataBind) +{ + return calculateRange(input, + minInput(), + maxInput(), + minOutput(), + maxOutput()); +} + +DataValue* DataConverterRangeMapper::reverseConvert(DataValue* input, + DataBind* dataBind) +{ + return calculateReverseRange(input, + minInput(), + maxInput(), + minOutput(), + maxOutput()); +} + +void DataConverterRangeMapper::minInputChanged() { markConverterDirty(); } + +void DataConverterRangeMapper::maxInputChanged() { markConverterDirty(); } + +void DataConverterRangeMapper::minOutputChanged() { markConverterDirty(); } + +void DataConverterRangeMapper::maxOutputChanged() { markConverterDirty(); } \ No newline at end of file diff --git a/third_party/rive/source/data_bind/converters/data_converter_rounder.cpp b/third_party/rive/source/data_bind/converters/data_converter_rounder.cpp new file mode 100644 index 0000000..96db649 --- /dev/null +++ b/third_party/rive/source/data_bind/converters/data_converter_rounder.cpp @@ -0,0 +1,22 @@ +#include "rive/math/math_types.hpp" +#include "rive/data_bind/converters/data_converter_rounder.hpp" +#include "rive/data_bind/data_values/data_value_number.hpp" + +using namespace rive; + +DataValue* DataConverterRounder::convert(DataValue* input, DataBind* dataBind) +{ + if (input->is()) + { + float value = input->as()->value(); + auto numberOfPlaces = decimals(); + // TODO: @hernan review this way of rounding + float rounder = pow(10.0f, (float)numberOfPlaces); + m_output.value(std::round(value * rounder) / rounder); + } + else + { + m_output.value(DataValueNumber::defaultValue); + } + return &m_output; +} \ No newline at end of file diff --git a/third_party/rive/source/data_bind/converters/data_converter_string_pad.cpp b/third_party/rive/source/data_bind/converters/data_converter_string_pad.cpp new file mode 100644 index 0000000..8ff34af --- /dev/null +++ b/third_party/rive/source/data_bind/converters/data_converter_string_pad.cpp @@ -0,0 +1,50 @@ +#include "rive/math/math_types.hpp" +#include "rive/data_bind/converters/data_converter_string_pad.hpp" +#include "rive/data_bind/data_values/data_value_string.hpp" + +using namespace rive; + +DataValue* DataConverterStringPad::convert(DataValue* input, DataBind* dataBind) +{ + if (input->is()) + { + auto inputValue = input->as()->value(); + auto inputLength = inputValue.size(); + if (inputLength < length()) + { + auto padPattern = text(); + auto padLength = padPattern.size(); + inputValue.reserve(length()); + std::string padText{""}; + size_t padTextSize = length() - inputLength; + padText.reserve(padTextSize); + while (inputLength < length()) + { + auto maxLength = + (padTextSize > padLength) ? padLength : padTextSize; + padText.append(padPattern, 0, maxLength); + inputLength += maxLength; + } + if (padType() == 1) + { + inputValue.append(padText, 0, padTextSize); + } + else + { + inputValue.insert(0, padText, 0, padTextSize); + } + } + m_output.value(inputValue); + } + else + { + m_output.value(DataValueString::defaultValue); + } + return &m_output; +} + +void DataConverterStringPad::lengthChanged() { markConverterDirty(); } + +void DataConverterStringPad::padTypeChanged() { markConverterDirty(); } + +void DataConverterStringPad::textChanged() { markConverterDirty(); } diff --git a/third_party/rive/source/data_bind/converters/data_converter_string_remove_zeros.cpp b/third_party/rive/source/data_bind/converters/data_converter_string_remove_zeros.cpp new file mode 100644 index 0000000..981a8db --- /dev/null +++ b/third_party/rive/source/data_bind/converters/data_converter_string_remove_zeros.cpp @@ -0,0 +1,37 @@ +#include "rive/math/math_types.hpp" +#include "rive/data_bind/converters/data_converter_string_remove_zeros.hpp" +#include "rive/data_bind/data_values/data_value_string.hpp" + +using namespace rive; + +std::string DataConverterStringRemoveZeros::removeZeros(std::string value) +{ + std::string inputValue = value; + if (inputValue.find('.') != std::string::npos) + { + // Remove trailing zeroes + inputValue = inputValue.substr(0, inputValue.find_last_not_of('0') + 1); + // If the decimal point is now the last character, remove that as + // well + if (inputValue.find('.') == inputValue.size() - 1) + { + inputValue = inputValue.substr(0, inputValue.size() - 1); + } + } + return inputValue; +} + +DataValue* DataConverterStringRemoveZeros::convert(DataValue* input, + DataBind* dataBind) +{ + if (input->is()) + { + auto inputValue = removeZeros(input->as()->value()); + m_output.value(inputValue); + } + else + { + m_output.value(DataValueString::defaultValue); + } + return &m_output; +} \ No newline at end of file diff --git a/third_party/rive/source/data_bind/converters/data_converter_string_trim.cpp b/third_party/rive/source/data_bind/converters/data_converter_string_trim.cpp new file mode 100644 index 0000000..ca82fd7 --- /dev/null +++ b/third_party/rive/source/data_bind/converters/data_converter_string_trim.cpp @@ -0,0 +1,37 @@ +#include "rive/math/math_types.hpp" +#include "rive/data_bind/converters/data_converter_string_trim.hpp" +#include "rive/data_bind/data_values/data_value_string.hpp" + +using namespace rive; + +DataValue* DataConverterStringTrim::convert(DataValue* input, + DataBind* dataBind) +{ + if (input->is()) + { + auto inputValue = input->as()->value(); + switch (trimValue()) + { + case TrimType::start: + ltrim(inputValue); + break; + case TrimType::end: + rtrim(inputValue); + break; + case TrimType::all: + trim(inputValue); + break; + default: + break; + } + + m_output.value(inputValue); + } + else + { + m_output.value(DataValueString::defaultValue); + } + return &m_output; +} + +void DataConverterStringTrim::trimTypeChanged() { markConverterDirty(); } \ No newline at end of file diff --git a/third_party/rive/source/data_bind/converters/data_converter_system_degs_to_rads.cpp b/third_party/rive/source/data_bind/converters/data_converter_system_degs_to_rads.cpp new file mode 100644 index 0000000..707f03e --- /dev/null +++ b/third_party/rive/source/data_bind/converters/data_converter_system_degs_to_rads.cpp @@ -0,0 +1,28 @@ +#include "rive/data_bind/converters/data_converter_system_degs_to_rads.hpp" +#include "rive/math/math_types.hpp" +#include "rive/data_bind/data_values/data_value_number.hpp" +#include "rive/data_bind_flags.hpp" + +using namespace rive; + +DataValue* DataConverterSystemDegsToRads::convert(DataValue* input, + DataBind* dataBind) +{ + auto flagsValue = static_cast(dataBind->flags()); + if (((flagsValue & DataBindFlags::Direction) == DataBindFlags::ToSource)) + { + return DataConverterOperationValue::reverseConvert(input, dataBind); + } + return DataConverterOperationValue::convert(input, dataBind); +} + +DataValue* DataConverterSystemDegsToRads::reverseConvert(DataValue* input, + DataBind* dataBind) +{ + auto flagsValue = static_cast(dataBind->flags()); + if (((flagsValue & DataBindFlags::Direction) == DataBindFlags::ToTarget)) + { + return DataConverterOperationValue::convert(input, dataBind); + } + return DataConverterOperationValue::reverseConvert(input, dataBind); +} \ No newline at end of file diff --git a/third_party/rive/source/data_bind/converters/data_converter_system_normalizer.cpp b/third_party/rive/source/data_bind/converters/data_converter_system_normalizer.cpp new file mode 100644 index 0000000..851dfc7 --- /dev/null +++ b/third_party/rive/source/data_bind/converters/data_converter_system_normalizer.cpp @@ -0,0 +1,27 @@ +#include "rive/data_bind/converters/data_converter_system_normalizer.hpp" +#include "rive/data_bind/data_values/data_value_number.hpp" +#include "rive/data_bind_flags.hpp" + +using namespace rive; + +DataValue* DataConverterSystemNormalizer::convert(DataValue* input, + DataBind* dataBind) +{ + auto flagsValue = static_cast(dataBind->flags()); + if (((flagsValue & DataBindFlags::Direction) == DataBindFlags::ToSource)) + { + return DataConverterOperationValue::reverseConvert(input, dataBind); + } + return DataConverterOperationValue::convert(input, dataBind); +} + +DataValue* DataConverterSystemNormalizer::reverseConvert(DataValue* input, + DataBind* dataBind) +{ + auto flagsValue = static_cast(dataBind->flags()); + if (((flagsValue & DataBindFlags::Direction) == DataBindFlags::ToTarget)) + { + return DataConverterOperationValue::convert(input, dataBind); + } + return DataConverterOperationValue::reverseConvert(input, dataBind); +} \ No newline at end of file diff --git a/third_party/rive/source/data_bind/converters/data_converter_to_string.cpp b/third_party/rive/source/data_bind/converters/data_converter_to_string.cpp new file mode 100644 index 0000000..9c19051 --- /dev/null +++ b/third_party/rive/source/data_bind/converters/data_converter_to_string.cpp @@ -0,0 +1,195 @@ +#include "rive/math/math_types.hpp" +#include "rive/data_bind/converters/data_converter_to_string.hpp" +#include "rive/data_bind/data_values/data_value_number.hpp" +#include "rive/data_bind/data_values/data_value_enum.hpp" +#include "rive/data_bind/data_values/data_value_color.hpp" +#include "rive/data_bind/data_values/data_value_string.hpp" +#include "rive/data_bind/data_values/data_value_boolean.hpp" +#include "rive/data_bind/data_values/data_value_trigger.hpp" +#include "rive/data_bind/data_values/data_value_symbol_list_index.hpp" +#include "rive/animation/data_converter_to_string_flags.hpp" +#include "rive/data_bind/converters/data_converter_string_remove_zeros.hpp" +#include +#include + +using namespace rive; + +DataValue* DataConverterToString::convertNumber(DataValueNumber* input) +{ + auto flagsValue = static_cast(flags()); + float value = input->as()->value(); + std::string outputValue; + if ((flagsValue & DataConverterToStringFlags::Round) == + DataConverterToStringFlags::Round) + { + std::stringstream stream; + stream << std::fixed << std::setprecision(decimals()) << value; + outputValue = stream.str(); + } + else + { + outputValue = std::to_string(value); + } + if ((flagsValue & DataConverterToStringFlags::TrailingZeros) == + DataConverterToStringFlags::TrailingZeros) + { + outputValue = DataConverterStringRemoveZeros::removeZeros(outputValue); + } + m_output.value(outputValue); + return &m_output; +} + +DataValue* DataConverterToString::convertColor(DataValueColor* input) +{ + auto colorValue = input->value(); + std::string outputValue = ""; + std::stringstream stream; + if (colorFormat() != "") + { + m_converter.color(colorValue); + + bool isEscaped = false; + bool isMarker = false; + + for (const char& c : colorFormat()) + { + if (isEscaped) + { + stream << c; + isEscaped = false; + } + // Escape + else if (c == '\\') + { + if (isMarker) + { + stream << '%'; + isMarker = false; + } + isEscaped = true; + } + // Marker + else if (c == '%') + { + if (isMarker) + { + stream << '%'; + } + isMarker = true; + } + else if (isMarker) + { + if (c == 'r') + { + stream << m_converter.red(); + } + else if (c == 'g') + { + stream << m_converter.green(); + } + else if (c == 'b') + { + stream << m_converter.blue(); + } + else if (c == 'a') + { + stream << m_converter.alpha(); + } + else if (c == 'R') + { + m_converter.redHex(stream); + } + else if (c == 'G') + { + m_converter.greenHex(stream); + } + else if (c == 'B') + { + m_converter.blueHex(stream); + } + else if (c == 'A') + { + m_converter.alphaHex(stream); + } + else if (c == 'h') + { + stream << m_converter.hue(); + } + else if (c == 'l') + { + stream << m_converter.luminance(); + } + else if (c == 's') + { + stream << m_converter.saturation(); + } + else + { + stream << '%'; + stream << c; + } + isMarker = false; + } + else + { + stream << c; + } + outputValue = stream.str(); + } + } + else + { + outputValue = std::to_string(colorValue); + } + m_output.value(outputValue); + return &m_output; +} + +DataValue* DataConverterToString::convert(DataValue* input, DataBind* dataBind) +{ + if (input->is()) + { + return convertNumber(input->as()); + } + else if (input->is()) + { + auto dataEnum = input->as()->dataEnum(); + auto index = input->as()->value(); + auto enumValue = dataEnum->value(index); + m_output.value(enumValue); + } + else if (input->is()) + { + m_output.value(input->as()->value()); + } + else if (input->is()) + { + return convertColor(input->as()); + } + else if (input->is()) + { + + auto value = input->as()->value(); + m_output.value(value ? "1" : "0"); + } + else if (input->is()) + { + + auto value = input->as()->value(); + m_output.value(std::to_string(value)); + } + else if (input->is()) + { + auto value = input->as()->value(); + m_output.value(std::to_string(value)); + } + else + { + m_output.value(DataValueString::defaultValue); + } + return &m_output; +} + +void DataConverterToString::decimalsChanged() { markConverterDirty(); } + +void DataConverterToString::colorFormatChanged() { markConverterDirty(); } \ No newline at end of file diff --git a/third_party/rive/source/data_bind/converters/data_converter_trigger.cpp b/third_party/rive/source/data_bind/converters/data_converter_trigger.cpp new file mode 100644 index 0000000..5b12b8f --- /dev/null +++ b/third_party/rive/source/data_bind/converters/data_converter_trigger.cpp @@ -0,0 +1,19 @@ +#include "rive/math/math_types.hpp" +#include "rive/data_bind/converters/data_converter_trigger.hpp" +#include "rive/data_bind/data_values/data_value_trigger.hpp" + +using namespace rive; + +DataValue* DataConverterTrigger::convert(DataValue* input, DataBind* dataBind) +{ + if (input->is()) + { + uint32_t inputValue = input->as()->value(); + m_output.value(inputValue + 1); + } + else + { + m_output.value(DataValueTrigger::defaultValue); + } + return &m_output; +} \ No newline at end of file diff --git a/third_party/rive/source/data_bind/converters/formula/formula_token.cpp b/third_party/rive/source/data_bind/converters/formula/formula_token.cpp new file mode 100644 index 0000000..d6972b7 --- /dev/null +++ b/third_party/rive/source/data_bind/converters/formula/formula_token.cpp @@ -0,0 +1,87 @@ +#include "rive/data_bind/converters/formula/formula_token.hpp" +#include "rive/data_bind/converters/data_converter_formula.hpp" +#include "rive/importers/data_converter_formula_importer.hpp" +#include "rive/data_bind/data_bind_context.hpp" +#include + +using namespace rive; + +FormulaToken::~FormulaToken() +{ + for (auto dataBind : m_dataBinds) + { + delete dataBind; + } +} + +StatusCode FormulaToken::import(ImportStack& importStack) +{ + auto dataConveterFormulaImporter = + importStack.latest( + DataConverterFormulaBase::typeKey); + if (dataConveterFormulaImporter == nullptr) + { + return StatusCode::MissingObject; + } + dataConveterFormulaImporter->formula()->addToken(this); + return Super::import(importStack); +} + +void FormulaToken::addDataBind(DataBind* dataBind) +{ + m_dataBinds.push_back(dataBind); +} + +void FormulaToken::markDirty() +{ + m_parentDataBind->addDirt(ComponentDirt::Dependents | + ComponentDirt::Bindings, + false); +} + +void FormulaToken::bindFromContext(DataContext* dataContext, DataBind* dataBind) +{ + m_parentDataBind = dataBind; + for (auto dataBind : m_dataBinds) + { + if (dataBind->is()) + { + + dataBind->as()->bindFromContext(dataContext); + } + } +} + +void FormulaToken::unbind() +{ + for (auto dataBind : m_dataBinds) + { + dataBind->unbind(); + } +} + +void FormulaToken::update() +{ + for (auto dataBind : m_dataBinds) + { + auto d = dataBind->dirt(); + if (d == ComponentDirt::None) + { + continue; + } + dataBind->dirt(ComponentDirt::None); + dataBind->update(d); + } +} + +void FormulaToken::copy(const FormulaTokenBase& object) +{ + auto dataBinds = object.as()->dataBinds(); + for (auto dataBind : dataBinds) + { + auto dataBindClone = dataBind->clone()->as(); + dataBindClone->target(this); + addDataBind(dataBindClone); + } + FormulaTokenBase::copy(object); +} \ No newline at end of file diff --git a/third_party/rive/source/data_bind/data_bind.cpp b/third_party/rive/source/data_bind/data_bind.cpp new file mode 100644 index 0000000..822a76d --- /dev/null +++ b/third_party/rive/source/data_bind/data_bind.cpp @@ -0,0 +1,347 @@ +#include "rive/data_bind/data_bind.hpp" +#include "rive/artboard.hpp" +#include "rive/data_bind_flags.hpp" +#include "rive/generated/core_registry.hpp" +#include "rive/data_bind/bindable_property_asset.hpp" +#include "rive/data_bind/bindable_property_number.hpp" +#include "rive/data_bind/bindable_property_string.hpp" +#include "rive/data_bind/bindable_property_color.hpp" +#include "rive/data_bind/bindable_property_enum.hpp" +#include "rive/data_bind/bindable_property_boolean.hpp" +#include "rive/data_bind/bindable_property_trigger.hpp" +#include "rive/data_bind/bindable_property_integer.hpp" +#include "rive/data_bind/context/context_value.hpp" +#include "rive/data_bind/context/context_value_asset_image.hpp" +#include "rive/data_bind/context/context_value_boolean.hpp" +#include "rive/data_bind/context/context_value_number.hpp" +#include "rive/data_bind/context/context_value_string.hpp" +#include "rive/data_bind/context/context_value_enum.hpp" +#include "rive/data_bind/context/context_value_list.hpp" +#include "rive/data_bind/context/context_value_color.hpp" +#include "rive/data_bind/context/context_value_trigger.hpp" +#include "rive/data_bind/context/context_value_symbol_list_index.hpp" +#include "rive/data_bind/data_values/data_type.hpp" +#include "rive/data_bind/converters/data_converter.hpp" +#include "rive/data_bind/converters/formula/formula_token.hpp" +#include "rive/animation/transition_viewmodel_condition.hpp" +#include "rive/animation/state_machine.hpp" +#include "rive/importers/artboard_importer.hpp" +#include "rive/importers/state_machine_importer.hpp" +#include "rive/importers/backboard_importer.hpp" + +using namespace rive; + +StatusCode DataBind::onAddedDirty(CoreContext* context) +{ + StatusCode code = Super::onAddedDirty(context); + if (code != StatusCode::Ok) + { + return code; + } + + return StatusCode::Ok; +} + +StatusCode DataBind::import(ImportStack& importStack) +{ + auto backboardImporter = + importStack.latest(Backboard::typeKey); + if (backboardImporter == nullptr) + { + return StatusCode::MissingObject; + } + file(backboardImporter->file()); + backboardImporter->addDataConverterReferencer(this); + if (target()) + { + if (target()->is()) + { + target()->as()->addDataBind(this); + } + else if (target()->is()) + { + target()->as()->addDataBind(this); + } + else + { + switch (target()->coreType()) + { + case BindablePropertyNumberBase::typeKey: + case BindablePropertyStringBase::typeKey: + case BindablePropertyBooleanBase::typeKey: + case BindablePropertyEnumBase::typeKey: + case BindablePropertyColorBase::typeKey: + case BindablePropertyTriggerBase::typeKey: + case BindablePropertyIntegerBase::typeKey: + case BindablePropertyAssetBase::typeKey: + case TransitionPropertyViewModelComparatorBase::typeKey: + case StateTransitionBase::typeKey: + { + auto stateMachineImporter = + importStack.latest( + StateMachineBase::typeKey); + if (stateMachineImporter != nullptr) + { + stateMachineImporter->addDataBind( + std::unique_ptr(this)); + return Super::import(importStack); + } + break; + } + default: + { + auto artboardImporter = + importStack.latest( + ArtboardBase::typeKey); + if (artboardImporter != nullptr) + { + artboardImporter->addDataBind(this); + return Super::import(importStack); + } + break; + } + } + } + } + + return Super::import(importStack); +} + +DataType DataBind::outputType() +{ + if (converter()) + { + return converter()->outputType(); + } + switch (m_Source->coreType()) + { + case ViewModelInstanceNumberBase::typeKey: + return DataType::number; + case ViewModelInstanceStringBase::typeKey: + return DataType::string; + case ViewModelInstanceEnumBase::typeKey: + return DataType::enumType; + case ViewModelInstanceColorBase::typeKey: + return DataType::color; + case ViewModelInstanceBooleanBase::typeKey: + return DataType::boolean; + case ViewModelInstanceListBase::typeKey: + return DataType::list; + case ViewModelInstanceTriggerBase::typeKey: + return DataType::trigger; + case ViewModelInstanceSymbolListIndexBase::typeKey: + return DataType::symbolListIndex; + case ViewModelInstanceAssetImageBase::typeKey: + return DataType::assetImage; + } + return DataType::none; +} + +void DataBind::source(ViewModelInstanceValue* value) +{ + if (!bindsOnce()) + { + value->addDependent(this); + value->ref(); + } + m_Source = value; +} + +void DataBind::clearSource() +{ + if (m_Source != nullptr) + { + + if (!bindsOnce()) + { + m_Source->removeDependent(this); + m_Source->unref(); + } + if (m_dataConverter != nullptr) + { + m_dataConverter->unbind(); + } + m_Source = nullptr; + } +} + +DataBind::~DataBind() +{ + clearSource(); + delete m_ContextValue; + m_ContextValue = nullptr; + delete m_dataConverter; + m_dataConverter = nullptr; +} + +void DataBind::bind() +{ + delete m_ContextValue; + m_ContextValue = nullptr; + switch (outputType()) + { + case DataType::number: + m_ContextValue = new DataBindContextValueNumber(this); + break; + case DataType::string: + m_ContextValue = new DataBindContextValueString(this); + break; + case DataType::boolean: + m_ContextValue = new DataBindContextValueBoolean(this); + break; + case DataType::color: + m_ContextValue = new DataBindContextValueColor(this); + break; + case DataType::enumType: + m_ContextValue = new DataBindContextValueEnum(this); + break; + case DataType::list: + m_ContextValue = new DataBindContextValueList(this); + break; + case DataType::trigger: + m_ContextValue = new DataBindContextValueTrigger(this); + break; + case DataType::symbolListIndex: + m_ContextValue = new DataBindContextValueSymbolListIndex(this); + break; + case DataType::assetImage: + m_ContextValue = new DataBindContextValueAssetImage(this); + break; + default: + break; + } + addDirt(ComponentDirt::Bindings, true); +} + +void DataBind::unbind() +{ + clearSource(); + if (m_ContextValue != nullptr) + { + delete m_ContextValue; + m_ContextValue = nullptr; + } +} + +void DataBind::update(ComponentDirt value) +{ + if ((value & ComponentDirt::Dependents) == ComponentDirt::Dependents && + m_dataConverter != nullptr) + { + m_dataConverter->update(); + } + if (m_Source != nullptr && m_ContextValue != nullptr) + { + if ((value & ComponentDirt::Bindings) == ComponentDirt::Bindings) + { + // TODO: @hernan review how dirt and mode work together. If dirt is + // not set for certain modes, we might be able to skip the mode + // validation. + auto flagsValue = static_cast(flags()); + if (toTarget()) + { + m_ContextValue->apply(m_target, + propertyKey(), + (flagsValue & DataBindFlags::Direction) == + DataBindFlags::ToTarget); + } + } + } +} + +void DataBind::updateSourceBinding(bool invalidate) +{ + if ((m_Dirt & ComponentDirt::Dependents) == ComponentDirt::Dependents && + m_dataConverter != nullptr) + { + m_Dirt &= ~ComponentDirt::Dependents; + m_dataConverter->update(); + } + auto flagsValue = static_cast(flags()); + if (toSource()) + { + if (m_ContextValue != nullptr) + { + if (invalidate) + { + m_ContextValue->invalidate(); + } + m_ContextValue->applyToSource( + m_target, + propertyKey(), + (flagsValue & DataBindFlags::Direction) == + DataBindFlags::ToSource); + } + } +} + +void DataBind::addDirt(ComponentDirt value, bool recurse) +{ + if (m_suppressDirt || (m_Dirt & value) == value) + { + // Already marked. + return; + } + + m_Dirt |= value; +#ifdef WITH_RIVE_TOOLS + if (m_changedCallback != nullptr) + { + m_changedCallback(); + } +#endif + if (target() != nullptr) + { + if (target()->is()) + { + + target()->as()->markConverterDirty(); + } + else if (target()->is()) + { + + target()->as()->markDirty(); + } + else if (target()->is()) + { + auto artboard = target()->as()->artboard(); + if (artboard != nullptr) + { + artboard->onComponentDirty(target()->as()); + } + } + } + if ((m_Dirt & ComponentDirt::Dependents) != 0 && m_ContextValue != nullptr) + { + m_ContextValue->invalidate(); + } +} + +bool DataBind::bindsOnce() +{ + auto flagsValue = static_cast(flags()); + return (flagsValue & DataBindFlags::Once) == DataBindFlags::Once; +} + +bool DataBind::toSource() +{ + auto flagsValue = static_cast(flags()); + return (flagsValue & (DataBindFlags::TwoWay | DataBindFlags::ToSource)) != + 0; +} + +bool DataBind::toTarget() +{ + auto flagsValue = static_cast(flags()); + return (flagsValue & DataBindFlags::TwoWay) != 0 || + (flagsValue & DataBindFlags::ToSource) == 0; +} + +bool DataBind::advance(float elapsedTime) +{ + if (converter()) + { + return converter()->advance(elapsedTime); + } + return false; +} \ No newline at end of file diff --git a/third_party/rive/source/data_bind/data_bind_context.cpp b/third_party/rive/source/data_bind/data_bind_context.cpp new file mode 100644 index 0000000..edf3f01 --- /dev/null +++ b/third_party/rive/source/data_bind/data_bind_context.cpp @@ -0,0 +1,46 @@ +#include "rive/data_bind_flags.hpp" +#include "rive/data_bind/data_bind_context.hpp" +#include "rive/data_bind/context/context_value_number.hpp" +#include "rive/data_bind/context/context_value_string.hpp" +#include "rive/data_bind/context/context_value_enum.hpp" +#include "rive/data_bind/context/context_value_list.hpp" +#include "rive/data_bind/context/context_value_color.hpp" +#include "rive/data_bind/converters/data_converter_group.hpp" +#include "rive/artboard.hpp" +#include "rive/generated/core_registry.hpp" +#include + +using namespace rive; + +void DataBindContext::decodeSourcePathIds(Span value) +{ + BinaryReader reader(value); + while (!reader.reachedEnd()) + { + auto val = reader.readVarUintAs(); + m_SourcePathIdsBuffer.push_back(val); + } +} + +void DataBindContext::copySourcePathIds(const DataBindContextBase& object) +{ + m_SourcePathIdsBuffer = object.as()->m_SourcePathIdsBuffer; +} + +void DataBindContext::bindFromContext(DataContext* dataContext) +{ + if (dataContext != nullptr) + { + auto vmSource = + dataContext->getViewModelProperty(m_SourcePathIdsBuffer); + if (vmSource != nullptr) + { + source(vmSource); + bind(); + } + if (m_dataConverter != nullptr) + { + m_dataConverter->bindFromContext(dataContext, this); + } + } +} diff --git a/third_party/rive/source/data_bind/data_bind_list_item_consumer.cpp b/third_party/rive/source/data_bind/data_bind_list_item_consumer.cpp new file mode 100644 index 0000000..4f8e55a --- /dev/null +++ b/third_party/rive/source/data_bind/data_bind_list_item_consumer.cpp @@ -0,0 +1,16 @@ +#include "rive/artboard_component_list.hpp" +#include "rive/component.hpp" +#include "rive/data_bind/data_bind_list_item_consumer.hpp" +#include "rive/generated/core_registry.hpp" + +using namespace rive; + +DataBindListItemConsumer* DataBindListItemConsumer::from(Core* component) +{ + switch (component->coreType()) + { + case ArtboardComponentList::typeKey: + return component->as(); + } + return nullptr; +} \ No newline at end of file diff --git a/third_party/rive/source/data_bind/data_context.cpp b/third_party/rive/source/data_bind/data_context.cpp new file mode 100644 index 0000000..c96bde1 --- /dev/null +++ b/third_party/rive/source/data_bind/data_context.cpp @@ -0,0 +1,94 @@ +#include "rive/data_bind/data_context.hpp" +#include "rive/viewmodel/viewmodel_instance_viewmodel.hpp" + +using namespace rive; + +DataContext::DataContext(rcp viewModelInstance) : + m_ViewModelInstance(viewModelInstance) +{} + +void DataContext::viewModelInstance(rcp value) +{ + m_ViewModelInstance = value; +} + +void DataContext::advanced() { m_ViewModelInstance->advanced(); } + +ViewModelInstanceValue* DataContext::getViewModelProperty( + const std::vector path) const +{ + std::vector::const_iterator it; + if (path.size() == 0) + { + return nullptr; + } + if (m_ViewModelInstance != nullptr && + m_ViewModelInstance->viewModelId() == path[0]) + { + rcp instance = m_ViewModelInstance; + for (it = path.begin() + 1; it != path.end() - 1; it++) + { + auto viewModelInstanceValue = instance->propertyValue(*it); + if (viewModelInstanceValue != nullptr && + viewModelInstanceValue->is()) + { + instance = + viewModelInstanceValue->as() + ->referenceViewModelInstance(); + } + else + { + goto skip_path; + } + } + ViewModelInstanceValue* value = instance->propertyValue(*it++); + return value; + } +skip_path: + if (m_Parent != nullptr) + { + return m_Parent->getViewModelProperty(path); + } + return nullptr; +} + +rcp DataContext::getViewModelInstance( + const std::vector path) const +{ + std::vector::const_iterator it; + if (path.size() == 0) + { + return nullptr; + } + if (m_ViewModelInstance != nullptr && + m_ViewModelInstance->viewModelId() == path[0]) + { + rcp instance = m_ViewModelInstance; + for (it = path.begin() + 1; it != path.end(); it++) + { + auto viewModelInstanceValue = instance->propertyValue(*it); + if (viewModelInstanceValue != nullptr && + viewModelInstanceValue->is()) + { + instance = + viewModelInstanceValue->as() + ->referenceViewModelInstance(); + } + else + { + instance = nullptr; + } + if (instance == nullptr) + { + goto skip_path; + } + } + return instance; + } +skip_path: + if (m_Parent != nullptr) + { + return m_Parent->getViewModelInstance(path); + } + return nullptr; +} \ No newline at end of file diff --git a/third_party/rive/source/dependency_sorter.cpp b/third_party/rive/source/dependency_sorter.cpp new file mode 100644 index 0000000..fbf6668 --- /dev/null +++ b/third_party/rive/source/dependency_sorter.cpp @@ -0,0 +1,49 @@ +#include "rive/dependency_sorter.hpp" +#include "rive/component.hpp" + +using namespace rive; + +void DependencySorter::sort(Component* root, std::vector& order) +{ + order.clear(); + visit(root, order); +} + +void DependencySorter::sort(std::vector roots, + std::vector& order) +{ + order.clear(); + for (auto root : roots) + { + visit(root, order); + } +} + +bool DependencySorter::visit(Component* component, + std::vector& order) +{ + if (m_Perm.find(component) != m_Perm.end()) + { + return true; + } + if (m_Temp.find(component) != m_Temp.end()) + { + fprintf(stderr, "Dependency cycle!\n"); + return false; + } + + m_Temp.emplace(component); + + auto dependents = component->dependents(); + for (auto dependent : dependents) + { + if (!visit(dependent, order)) + { + return false; + } + } + m_Perm.emplace(component); + order.insert(order.begin(), component); + + return true; +} \ No newline at end of file diff --git a/third_party/rive/source/draw_rules.cpp b/third_party/rive/source/draw_rules.cpp new file mode 100644 index 0000000..a882057 --- /dev/null +++ b/third_party/rive/source/draw_rules.cpp @@ -0,0 +1,41 @@ +#include "rive/draw_rules.hpp" +#include "rive/artboard.hpp" +#include "rive/core_context.hpp" +#include "rive/draw_target.hpp" + +using namespace rive; + +StatusCode DrawRules::onAddedDirty(CoreContext* context) +{ + StatusCode result = Super::onAddedDirty(context); + if (result != StatusCode::Ok) + { + return result; + } + auto coreObject = context->resolve(drawTargetId()); + if (coreObject != nullptr && coreObject->is()) + { + m_ActiveTarget = static_cast(coreObject); + } + + return StatusCode::Ok; +} + +StatusCode DrawRules::onAddedClean(CoreContext* context) +{ + return StatusCode::Ok; +} + +void DrawRules::drawTargetIdChanged() +{ + auto coreObject = artboard()->resolve(drawTargetId()); + if (coreObject == nullptr || !coreObject->is()) + { + m_ActiveTarget = nullptr; + } + else + { + m_ActiveTarget = static_cast(coreObject); + } + artboard()->addDirt(ComponentDirt::DrawOrder); +} diff --git a/third_party/rive/source/draw_target.cpp b/third_party/rive/source/draw_target.cpp new file mode 100644 index 0000000..efdc463 --- /dev/null +++ b/third_party/rive/source/draw_target.cpp @@ -0,0 +1,32 @@ +#include "rive/draw_target.hpp" +#include "rive/core_context.hpp" +#include "rive/drawable.hpp" +#include "rive/artboard.hpp" + +using namespace rive; + +StatusCode DrawTarget::onAddedDirty(CoreContext* context) +{ + StatusCode code = Super::onAddedDirty(context); + if (code != StatusCode::Ok) + { + return code; + } + auto coreObject = context->resolve(drawableId()); + if (coreObject == nullptr || !coreObject->is()) + { + return StatusCode::MissingObject; + } + m_Drawable = static_cast(coreObject); + return StatusCode::Ok; +} + +StatusCode DrawTarget::onAddedClean(CoreContext* context) +{ + return StatusCode::Ok; +} + +void DrawTarget::placementValueChanged() +{ + artboard()->addDirt(ComponentDirt::DrawOrder); +} diff --git a/third_party/rive/source/drawable.cpp b/third_party/rive/source/drawable.cpp new file mode 100644 index 0000000..25103a8 --- /dev/null +++ b/third_party/rive/source/drawable.cpp @@ -0,0 +1,100 @@ +#include "rive/drawable.hpp" +#include "rive/artboard.hpp" +#include "rive/shapes/clipping_shape.hpp" +#include "rive/shapes/path_composer.hpp" +#include "rive/shapes/shape.hpp" +#include "rive/clip_result.hpp" + +using namespace rive; + +StatusCode Drawable::onAddedDirty(CoreContext* context) +{ + auto code = Super::onAddedDirty(context); + if (code != StatusCode::Ok) + { + return code; + } + auto blendMode = static_cast(blendModeValue()); + switch (blendMode) + { + case rive::BlendMode::srcOver: + case rive::BlendMode::screen: + case rive::BlendMode::overlay: + case rive::BlendMode::darken: + case rive::BlendMode::lighten: + case rive::BlendMode::colorDodge: + case rive::BlendMode::colorBurn: + case rive::BlendMode::hardLight: + case rive::BlendMode::softLight: + case rive::BlendMode::difference: + case rive::BlendMode::exclusion: + case rive::BlendMode::multiply: + case rive::BlendMode::hue: + case rive::BlendMode::saturation: + case rive::BlendMode::color: + case rive::BlendMode::luminosity: + return StatusCode::Ok; + } + return StatusCode::InvalidObject; +} + +void Drawable::addClippingShape(ClippingShape* shape) +{ + m_ClippingShapes.push_back(shape); +} + +ClipResult Drawable::applyClip(Renderer* renderer) const +{ + if (m_ClippingShapes.size() == 0) + { + return ClipResult::noClip; + } + + renderer->save(); + + for (auto clippingShape : m_ClippingShapes) + { + if (!clippingShape->isVisible()) + { + continue; + } + + ShapePaintPath* path = clippingShape->path(); + if (path == nullptr) + { + return ClipResult::emptyClip; + } + RenderPath* renderPath = path->renderPath(this); + if (renderPath == nullptr) + { + return ClipResult::emptyClip; + } + + renderer->clipPath(renderPath); + } + return ClipResult::clip; +} + +bool Drawable::isChildOfLayout(LayoutComponent* layout) +{ + for (ContainerComponent* parent = this; parent != nullptr; + parent = parent->parent()) + { + if (parent->is() && + parent->as() == layout) + { + return true; + } + } + return false; +} + +Drawable* DrawableProxy::hittableComponent() +{ + return static_cast(proxyDrawing()); +} + +bool DrawableProxy::isTargetOpaque() +{ + return hittableComponent()->isTargetOpaque(); +} diff --git a/third_party/rive/source/event.cpp b/third_party/rive/source/event.cpp new file mode 100644 index 0000000..ad1582e --- /dev/null +++ b/third_party/rive/source/event.cpp @@ -0,0 +1,11 @@ +#include "rive/event.hpp" +#include "rive/animation/state_machine_instance.hpp" +#include "rive/artboard.hpp" +#include "rive/importers/artboard_importer.hpp" + +using namespace rive; + +void Event::trigger(const CallbackData& value) +{ + value.context()->reportEvent(this, value.delaySeconds()); +} \ No newline at end of file diff --git a/third_party/rive/source/factory.cpp b/third_party/rive/source/factory.cpp new file mode 100644 index 0000000..edb0180 --- /dev/null +++ b/third_party/rive/source/factory.cpp @@ -0,0 +1,39 @@ +/* + * Copyright 2022 Rive + */ + +#include "rive/factory.hpp" +#include "rive/math/aabb.hpp" +#include "rive/math/raw_path.hpp" +#include "rive/text/raw_text.hpp" +#ifdef WITH_RIVE_TEXT +#include "rive/text/font_hb.hpp" +#endif + +using namespace rive; + +rcp Factory::makeRenderPath(const AABB& r) +{ + RawPath rawPath; + rawPath.addRect(r); + return makeRenderPath(rawPath, FillRule::nonZero); +} + +rcp Factory::decodeFont(Span span) +{ +#ifdef WITH_RIVE_TEXT + return HBFont::Decode(span); +#else + return nullptr; +#endif +} + +rcp Factory::decodeAudio(Span span) +{ +#ifdef WITH_RIVE_AUDIO + return rcp( + new AudioSource(SimpleArray(span.data(), span.size()))); +#else + return nullptr; +#endif +} diff --git a/third_party/rive/source/file.cpp b/third_party/rive/source/file.cpp new file mode 100644 index 0000000..cab80af --- /dev/null +++ b/third_party/rive/source/file.cpp @@ -0,0 +1,1029 @@ +#include "rive/file.hpp" +#include "rive/runtime_header.hpp" +#include "rive/animation/animation.hpp" +#include "rive/artboard_component_list.hpp" +#include "rive/core/field_types/core_color_type.hpp" +#include "rive/core/field_types/core_double_type.hpp" +#include "rive/core/field_types/core_string_type.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +#include "rive/generated/core_registry.hpp" +#include "rive/importers/artboard_importer.hpp" +#include "rive/importers/backboard_importer.hpp" +#include "rive/importers/bindable_property_importer.hpp" +#include "rive/importers/data_converter_group_importer.hpp" +#include "rive/importers/data_converter_formula_importer.hpp" +#include "rive/importers/enum_importer.hpp" +#include "rive/importers/file_asset_importer.hpp" +#include "rive/importers/import_stack.hpp" +#include "rive/importers/keyed_object_importer.hpp" +#include "rive/importers/keyed_property_importer.hpp" +#include "rive/importers/linear_animation_importer.hpp" +#include "rive/importers/state_machine_importer.hpp" +#include "rive/importers/state_machine_listener_importer.hpp" +#include "rive/importers/state_machine_layer_importer.hpp" +#include "rive/importers/layer_state_importer.hpp" +#include "rive/importers/state_transition_importer.hpp" +#include "rive/importers/state_machine_layer_component_importer.hpp" +#include "rive/importers/transition_viewmodel_condition_importer.hpp" +#include "rive/importers/viewmodel_importer.hpp" +#include "rive/importers/viewmodel_instance_importer.hpp" +#include "rive/importers/viewmodel_instance_list_importer.hpp" +#include "rive/animation/blend_state_transition.hpp" +#include "rive/animation/any_state.hpp" +#include "rive/animation/entry_state.hpp" +#include "rive/animation/exit_state.hpp" +#include "rive/animation/animation_state.hpp" +#include "rive/animation/blend_state_1d_input.hpp" +#include "rive/animation/blend_state_1d_viewmodel.hpp" +#include "rive/animation/blend_state_direct.hpp" +#include "rive/animation/transition_property_viewmodel_comparator.hpp" +#include "rive/constraints/scrolling/scroll_physics.hpp" +#include "rive/data_bind/bindable_property.hpp" +#include "rive/data_bind/bindable_property_asset.hpp" +#include "rive/data_bind/bindable_property_number.hpp" +#include "rive/data_bind/bindable_property_string.hpp" +#include "rive/data_bind/bindable_property_color.hpp" +#include "rive/data_bind/bindable_property_enum.hpp" +#include "rive/data_bind/bindable_property_integer.hpp" +#include "rive/data_bind/bindable_property_boolean.hpp" +#include "rive/data_bind/bindable_property_trigger.hpp" +#include "rive/data_bind/bindable_property_asset.hpp" +#include "rive/data_bind/converters/data_converter_group.hpp" +#include "rive/data_bind/converters/data_converter_number_to_list.hpp" +#include "rive/assets/file_asset.hpp" +#include "rive/assets/audio_asset.hpp" +#include "rive/assets/file_asset_contents.hpp" +#include "rive/viewmodel/viewmodel.hpp" +#include "rive/viewmodel/data_enum.hpp" +#include "rive/viewmodel/viewmodel_instance.hpp" +#include "rive/viewmodel/viewmodel_instance_list.hpp" +#include "rive/viewmodel/viewmodel_instance_viewmodel.hpp" +#include "rive/viewmodel/viewmodel_instance_number.hpp" +#include "rive/viewmodel/viewmodel_instance_string.hpp" +#include "rive/viewmodel/viewmodel_property_viewmodel.hpp" +#include "rive/viewmodel/viewmodel_property_string.hpp" +#include "rive/viewmodel/viewmodel_property_number.hpp" +#include "rive/viewmodel/viewmodel_property_enum.hpp" +#include "rive/viewmodel/viewmodel_property_enum_custom.hpp" +#include "rive/viewmodel/viewmodel_property_enum_system.hpp" +#include "rive/viewmodel/viewmodel_property_list.hpp" +#include "rive/viewmodel/viewmodel_property_trigger.hpp" +#include "rive/viewmodel/viewmodel_property_symbol_list_index.hpp" +#include "rive/viewmodel/runtime/viewmodel_runtime.hpp" + +// Default namespace for Rive Cpp code +using namespace rive; + +#if !defined(RIVE_FMT_U64) +#if defined(__ANDROID__) +#if INTPTR_MAX == INT64_MAX +#define RIVE_FMT_U64 "%lu" +#define RIVE_FMT_I64 "%ld" +#else +#define RIVE_FMT_U64 "%llu" +#define RIVE_FMT_I64 "%lld" +#endif +#elif defined(_WIN32) +#define RIVE_FMT_U64 "%lld" +#define RIVE_FMT_I64 "%llu" +#else +#include +#define RIVE_FMT_U64 "%" PRIu64 +#define RIVE_FMT_I64 "%" PRId64 +#endif +#endif + +// Import a single Rive runtime object. +// Used by the file importer. +static Core* readRuntimeObject(BinaryReader& reader, + const RuntimeHeader& header) +{ + auto coreObjectKey = reader.readVarUintAs(); + auto object = CoreRegistry::makeCoreInstance(coreObjectKey); + while (true) + { + auto propertyKey = reader.readVarUintAs(); + if (propertyKey == 0) + { + // Terminator. https://media.giphy.com/media/7TtvTUMm9mp20/giphy.gif + break; + } + + if (reader.hasError()) + { + delete object; + return nullptr; + } + if (object == nullptr || !object->deserialize(propertyKey, reader)) + { + // We have an unknown object or property, first see if core knows + // the property type. + int id = CoreRegistry::propertyFieldId(propertyKey); + if (id == -1) + { + // No, check if it's in toc. + id = header.propertyFieldId(propertyKey); + } + + if (id == -1) + { + // Still couldn't find it, give up. + fprintf(stderr, + "Unknown property key %d, missing from property ToC.\n", + propertyKey); + delete object; + return nullptr; + } + + switch (id) + { + case CoreUintType::id: + CoreUintType::deserialize(reader); + break; + case CoreStringType::id: + CoreStringType::deserialize(reader); + break; + case CoreDoubleType::id: + CoreDoubleType::deserialize(reader); + break; + case CoreColorType::id: + CoreColorType::deserialize(reader); + break; + } + } + } + if (object == nullptr) + { + // fprintf(stderr, + // "File contains an unknown object with coreType " RIVE_FMT_U64 + // ", which " "this runtime doesn't understand.\n", + // coreObjectKey); + return nullptr; + } + return object; +} + +File::File(Factory* factory, rcp assetLoader) : + m_factory(factory), m_assetLoader(std::move(assetLoader)) +{ + assert(factory); +} + +File::~File() +{ + for (auto artboard : m_artboards) + { + delete artboard; + } + // Assets delete after artboards as they reference them. + for (auto asset : m_fileAssets) + { + delete asset; + } + for (auto& viewModel : m_ViewModels) + { + viewModel->unref(); + } + for (auto& viewModelInstance : m_ViewModelInstances) + { + viewModelInstance->unref(); + } + for (auto& enumData : m_Enums) + { + enumData->unref(); + } + for (auto& dataConverter : m_DataConverters) + { + delete dataConverter; + } + for (auto& viewModelRuntime : m_viewModelRuntimes) + { + delete viewModelRuntime; + } + for (auto& keyframeInterpolator : m_keyframeInterpolators) + { + delete keyframeInterpolator; + } + for (auto& physics : m_scrollPhysics) + { + delete physics; + } + delete m_backboard; +} + +std::unique_ptr File::import(Span bytes, + Factory* factory, + ImportResult* result, + rcp assetLoader) +{ + BinaryReader reader(bytes); + RuntimeHeader header; + if (!RuntimeHeader::read(reader, header)) + { + fprintf(stderr, "Bad header\n"); + if (result) + { + *result = ImportResult::malformed; + } + return nullptr; + } + if (header.majorVersion() != majorVersion) + { + fprintf(stderr, + "Unsupported version %u.%u expected %u.%u.\n", + header.majorVersion(), + header.minorVersion(), + majorVersion, + minorVersion); + if (result) + { + *result = ImportResult::unsupportedVersion; + } + return nullptr; + } + auto file = rivestd::make_unique(factory, std::move(assetLoader)); + + auto readResult = file->read(reader, header); + if (result) + { + *result = readResult; + } + if (readResult != ImportResult::success) + { + file.reset(nullptr); + } + return file; +} + +ImportResult File::read(BinaryReader& reader, const RuntimeHeader& header) +{ + ImportStack importStack; + // TODO: @hernan consider moving this to a special importer. It's not that + // simple because Core doesn't have a typeKey, so it should be treated as + // a special case. In any case, it's not that bad having it here for now. + Core* lastBindableObject; + while (!reader.reachedEnd()) + { + auto object = readRuntimeObject(reader, header); + if (object == nullptr) + { + importStack.readNullObject(); + continue; + } + if (!object->is()) + { + lastBindableObject = object; + } + else if (lastBindableObject != nullptr) + { + object->as()->target(lastBindableObject); + } + if (object->import(importStack) == StatusCode::Ok) + { + switch (object->coreType()) + { + case Backboard::typeKey: + m_backboard = object->as(); + break; + case Artboard::typeKey: + { + Artboard* ab = object->as(); + ab->m_Factory = m_factory; + m_artboards.push_back(ab); + } + break; + case ImageAsset::typeKey: + case FontAsset::typeKey: + case AudioAsset::typeKey: + { + auto fa = object->as(); + m_fileAssets.push_back(fa); + } + break; + case ViewModel::typeKey: + { + auto vmc = object->as(); + m_ViewModels.push_back(vmc); + break; + } + case ViewModelInstance::typeKey: + { + auto vmi = object->as(); + m_ViewModelInstances.push_back(vmi); + break; + } + case DataEnum::typeKey: + case DataEnumCustom::typeKey: + { + auto de = object->as(); + m_Enums.push_back(de); + break; + } + case ViewModelPropertyEnumCustom::typeKey: + { + auto vme = object->as(); + if (vme->enumId() < m_Enums.size()) + { + vme->dataEnum(m_Enums[vme->enumId()]); + } + } + break; + } + } + else + { + fprintf(stderr, + "Failed to import object of type %d\n", + object->coreType()); + delete object; + continue; + } + std::unique_ptr stackObject = nullptr; + auto stackType = object->coreType(); + + switch (stackType) + { + case Backboard::typeKey: + stackObject = rivestd::make_unique( + object->as()); + static_cast(stackObject.get())->file(this); + break; + case Artboard::typeKey: + stackObject = rivestd::make_unique( + object->as()); + break; + case DataEnumCustom::typeKey: + stackObject = rivestd::make_unique( + object->as()); + break; + case LinearAnimation::typeKey: + stackObject = rivestd::make_unique( + object->as()); + break; + case KeyedObject::typeKey: + stackObject = rivestd::make_unique( + object->as()); + break; + case KeyedProperty::typeKey: + { + auto importer = importStack.latest( + LinearAnimation::typeKey); + if (importer == nullptr) + { + return ImportResult::malformed; + } + stackObject = rivestd::make_unique( + importer->animation(), + object->as()); + break; + } + case StateMachine::typeKey: + stackObject = rivestd::make_unique( + object->as()); + break; + case StateMachineLayer::typeKey: + { + auto artboardImporter = + importStack.latest(ArtboardBase::typeKey); + if (artboardImporter == nullptr) + { + return ImportResult::malformed; + } + + stackObject = rivestd::make_unique( + object->as(), + artboardImporter->artboard()); + + break; + } + case EntryState::typeKey: + case ExitState::typeKey: + case AnyState::typeKey: + case AnimationState::typeKey: + case BlendState1DViewModel::typeKey: + case BlendState1DInput::typeKey: + case BlendStateDirect::typeKey: + stackObject = rivestd::make_unique( + object->as()); + stackType = LayerState::typeKey; + break; + case StateTransition::typeKey: + case BlendStateTransition::typeKey: + stackObject = rivestd::make_unique( + object->as()); + stackType = StateTransition::typeKey; + break; + case StateMachineListener::typeKey: + stackObject = + rivestd::make_unique( + object->as()); + break; + case ImageAsset::typeKey: + case FontAsset::typeKey: + case AudioAsset::typeKey: + stackObject = rivestd::make_unique( + object->as(), + m_assetLoader, + m_factory); + stackType = FileAsset::typeKey; + break; + case ViewModel::typeKey: + stackObject = rivestd::make_unique( + object->as()); + stackType = ViewModel::typeKey; + break; + case ViewModelInstance::typeKey: + stackObject = rivestd::make_unique( + object->as()); + stackType = ViewModelInstance::typeKey; + break; + case ViewModelInstanceList::typeKey: + stackObject = + rivestd::make_unique( + object->as()); + stackType = ViewModelInstanceList::typeKey; + break; + case TransitionViewModelCondition::typeKey: + case TransitionArtboardCondition::typeKey: + stackObject = + rivestd::make_unique( + object->as()); + stackType = TransitionViewModelCondition::typeKey; + break; + case BindablePropertyNumber::typeKey: + case BindablePropertyString::typeKey: + case BindablePropertyColor::typeKey: + case BindablePropertyEnum::typeKey: + case BindablePropertyBoolean::typeKey: + case BindablePropertyAsset::typeKey: + case BindablePropertyTrigger::typeKey: + case BindablePropertyInteger::typeKey: + stackObject = rivestd::make_unique( + object->as()); + stackType = BindablePropertyBase::typeKey; + break; + case DataConverterGroupBase::typeKey: + stackObject = rivestd::make_unique( + object->as()); + stackType = DataConverterGroupBase::typeKey; + break; + case DataConverterFormulaBase::typeKey: + stackObject = + rivestd::make_unique( + object->as()); + stackType = DataConverterFormulaBase::typeKey; + break; + case DataConverterNumberToList::typeKey: + object->as()->file(this); + break; + case ArtboardComponentList::typeKey: + object->as()->file(this); + break; + } + if (importStack.makeLatest(stackType, std::move(stackObject)) != + StatusCode::Ok) + { + // Some previous stack item didn't resolve. + return ImportResult::malformed; + } + if (object->is() && + importStack.makeLatest( + StateMachineLayerComponent::typeKey, + rivestd::make_unique( + object->as())) != + StatusCode::Ok) + { + return ImportResult::malformed; + } + if (object->is()) + { + m_DataConverters.push_back(object->as()); + } + else if (object->is()) + { + // The file only owns the interpolators that don't belong to a + // specific artboard + auto artboardImporter = + importStack.latest(ArtboardBase::typeKey); + if (artboardImporter == nullptr) + { + m_keyframeInterpolators.push_back( + object->as()); + } + } + else if (object->is()) + { + m_scrollPhysics.push_back(object->as()); + } + } + + return !reader.hasError() && importStack.resolve() == StatusCode::Ok + ? ImportResult::success + : ImportResult::malformed; +} + +Artboard* File::artboard(std::string name) const +{ + for (const auto& artboard : m_artboards) + { + if (artboard->name() == name) + { + return artboard; + } + } + return nullptr; +} + +Artboard* File::artboard() const +{ + if (m_artboards.empty()) + { + return nullptr; + } + return m_artboards[0]; +} + +Artboard* File::artboard(size_t index) const +{ + if (index >= m_artboards.size()) + { + return nullptr; + } + return m_artboards[index]; +} + +std::string File::artboardNameAt(size_t index) const +{ + auto ab = this->artboard(index); + return ab ? ab->name() : ""; +} + +std::unique_ptr File::artboardDefault() const +{ + auto ab = this->artboard(); + return ab ? ab->instance() : nullptr; +} + +std::unique_ptr File::artboardAt(size_t index) const +{ + auto ab = this->artboard(index); + return ab ? ab->instance() : nullptr; +} + +std::unique_ptr File::artboardNamed(std::string name) const +{ + auto ab = this->artboard(name); + return ab ? ab->instance() : nullptr; +} + +void File::completeViewModelInstance( + rcp viewModelInstance) const +{ + std::unordered_map> instancesMap; + completeViewModelInstance(viewModelInstance, instancesMap); +} + +void File::completeViewModelInstance( + rcp viewModelInstance, + std::unordered_map> instancesMap) + const +{ + auto viewModel = m_ViewModels[viewModelInstance->viewModelId()]; + auto propertyValues = viewModelInstance->propertyValues(); + for (auto& value : propertyValues) + { + if (value->is()) + { + auto property = viewModel->property(value->viewModelPropertyId()); + if (property->is()) + { + auto valueViewModel = value->as(); + auto propertViewModel = + property->as(); + auto viewModelReference = + m_ViewModels[propertViewModel->viewModelReferenceId()]; + auto viewModelInstance = viewModelReference->instance( + valueViewModel->propertyValue()); + if (viewModelInstance != nullptr) + { + auto itr = instancesMap.find(viewModelInstance); + + if (itr == instancesMap.end()) + { + auto viewModelInstanceCopy = + copyViewModelInstance(viewModelInstance, + instancesMap); + instancesMap[viewModelInstance] = viewModelInstanceCopy; + valueViewModel->referenceViewModelInstance( + viewModelInstanceCopy); + } + else + { + valueViewModel->referenceViewModelInstance(itr->second); + } + } + } + } + else if (value->is()) + { + auto viewModelList = value->as(); + for (auto& listItem : viewModelList->listItems()) + { + auto viewModel = m_ViewModels[listItem->viewModelId()]; + auto viewModelInstance = + viewModel->instance(listItem->viewModelInstanceId()); + if (viewModelInstance != nullptr) + { + + auto itr = instancesMap.find(viewModelInstance); + + if (itr == instancesMap.end()) + { + auto viewModelInstanceCopy = + copyViewModelInstance(viewModelInstance, + instancesMap); + instancesMap[viewModelInstance] = viewModelInstanceCopy; + listItem->viewModelInstance(viewModelInstanceCopy); + } + else + { + listItem->viewModelInstance(itr->second); + } + } + } + } + value->viewModelProperty( + viewModel->property(value->viewModelPropertyId())); + } +} + +rcp File::copyViewModelInstance( + ViewModelInstance* viewModelInstance, + std::unordered_map> instancesMap) + const +{ + auto copy = rcp( + viewModelInstance->clone()->as()); + completeViewModelInstance(copy, instancesMap); + return copy; +} + +rcp File::createViewModelInstance(std::string name) const +{ + for (auto& viewModel : m_ViewModels) + { + if (viewModel->is()) + { + if (viewModel->name() == name) + { + return createViewModelInstance(viewModel); + } + } + } + return nullptr; +} + +rcp File::createViewModelInstance( + std::string name, + std::string instanceName) const +{ + for (auto& viewModel : m_ViewModels) + { + if (viewModel->name() == name) + { + auto instance = viewModel->instance(instanceName); + if (instance != nullptr) + { + std::unordered_map> + instancesMap; + return copyViewModelInstance(instance, instancesMap); + } + } + } + return nullptr; +} + +rcp File::createViewModelInstance(size_t index, + size_t instanceIndex) const +{ + if (index < m_ViewModels.size()) + { + auto viewModel = m_ViewModels[index]; + auto instance = viewModel->instance(instanceIndex); + if (instance != nullptr) + { + std::unordered_map> + instancesMap; + return copyViewModelInstance(instance, instancesMap); + } + } + return nullptr; +} + +uint32_t File::findViewModelId(ViewModel* search) const +{ + uint32_t viewModelId = 0; + for (auto& viewModel : m_ViewModels) + { + if (viewModel == search) + { + break; + } + viewModelId++; + } + return viewModelId; +} + +rcp File::createViewModelInstance(ViewModel* viewModel) const +{ + if (viewModel != nullptr) + { + uint32_t viewModelId = findViewModelId(viewModel); + + auto viewModelInstance = new ViewModelInstance(); + viewModelInstance->viewModelId(viewModelId); + viewModelInstance->viewModel(viewModel); + auto properties = viewModel->properties(); + uint32_t propertyId = 0; + for (auto& property : properties) + { + ViewModelInstanceValue* viewModelInstanceValue = nullptr; + switch (property->coreType()) + { + case ViewModelPropertyStringBase::typeKey: + viewModelInstanceValue = new ViewModelInstanceString(); + break; + case ViewModelPropertyNumberBase::typeKey: + viewModelInstanceValue = new ViewModelInstanceNumber(); + break; + case ViewModelPropertyBooleanBase::typeKey: + viewModelInstanceValue = new ViewModelInstanceBoolean(); + break; + case ViewModelPropertyColorBase::typeKey: + viewModelInstanceValue = new ViewModelInstanceColor(); + break; + case ViewModelPropertyListBase::typeKey: + viewModelInstanceValue = new ViewModelInstanceList(); + break; + case ViewModelPropertyEnumSystemBase::typeKey: + case ViewModelPropertyEnumCustomBase::typeKey: + case ViewModelPropertyEnumBase::typeKey: + viewModelInstanceValue = new ViewModelInstanceEnum(); + break; + case ViewModelPropertyTriggerBase::typeKey: + viewModelInstanceValue = new ViewModelInstanceTrigger(); + break; + case ViewModelPropertyViewModelBase::typeKey: + { + viewModelInstanceValue = new ViewModelInstanceViewModel(); + auto propertViewModel = + property->as(); + auto viewModelReference = + m_ViewModels[propertViewModel->viewModelReferenceId()]; + auto viewModelInstanceViewModel = + viewModelInstanceValue + ->as(); + viewModelInstanceViewModel->referenceViewModelInstance( + createViewModelInstance(viewModelReference)); + } + break; + case ViewModelPropertyAssetImageBase::typeKey: + viewModelInstanceValue = new ViewModelInstanceAssetImage(); + break; + case ViewModelPropertySymbolListIndexBase::typeKey: + viewModelInstanceValue = + new ViewModelInstanceSymbolListIndex(); + break; + default: + break; + } + if (viewModelInstanceValue != nullptr) + { + viewModelInstanceValue->viewModelProperty(property); + viewModelInstanceValue->viewModelPropertyId(propertyId); + } + viewModelInstance->addValue(viewModelInstanceValue); + propertyId++; + } + return rcp(viewModelInstance); + } + return nullptr; +} + +rcp File::createViewModelInstance(Artboard* artboard) const +{ + if ((size_t)artboard->viewModelId() < m_ViewModels.size()) + { + auto viewModel = m_ViewModels[artboard->viewModelId()]; + if (viewModel != nullptr) + { + return createViewModelInstance(viewModel); + } + } + return nullptr; +} + +rcp File::createDefaultViewModelInstance( + Artboard* artboard) const +{ + if ((size_t)artboard->viewModelId() < m_ViewModels.size()) + { + auto viewModel = m_ViewModels[artboard->viewModelId()]; + if (viewModel != nullptr) + { + return createDefaultViewModelInstance(viewModel); + } + } + return nullptr; +} + +rcp File::createDefaultViewModelInstance( + ViewModel* viewModel) const +{ + auto viewModelInstance = viewModel->instance(0); + if (viewModelInstance != nullptr) + { + auto copy = rcp( + viewModelInstance->clone()->as()); + completeViewModelInstance(copy); + return copy; + } + return createViewModelInstance(viewModel); +} + +ViewModelInstanceListItem* File::viewModelInstanceListItem( + rcp viewModelInstance) +{ + // Search for an implicit artboard linked to the viewModel. + // It will return the first one it finds, but there could be more. + // We should decide if we want to be more restrictive and only return + // an artboard if one and only one is found. + for (auto& artboard : m_artboards) + { + if (artboard->viewModelId() == viewModelInstance->viewModelId()) + { + return viewModelInstanceListItem(viewModelInstance, artboard); + } + } + return nullptr; +} + +ViewModelInstanceListItem* File::viewModelInstanceListItem( + rcp viewModelInstance, + Artboard* artboard) +{ + auto viewModelInstanceListItem = new ViewModelInstanceListItem(); + viewModelInstanceListItem->viewModelInstance(viewModelInstance); + viewModelInstanceListItem->artboard(artboard); + return viewModelInstanceListItem; +} + +ViewModel* File::viewModel(std::string name) +{ + for (auto& viewModel : m_ViewModels) + { + if (viewModel->name() == name) + { + return viewModel; + } + } + return nullptr; +} + +ViewModel* File::viewModel(size_t index) +{ + if (index < m_ViewModels.size()) + { + return m_ViewModels[index]; + } + return nullptr; +} + +ViewModelRuntime* File::viewModelByIndex(size_t index) const +{ + if (index < m_ViewModels.size()) + { + return createViewModelRuntime(m_ViewModels[index]); + } + fprintf(stderr, + "Could not find View Model. Index %zu is out of range.\n", + index); + return nullptr; +} + +ViewModelRuntime* File::viewModelByName(std::string name) const +{ + for (auto& viewModel : m_ViewModels) + { + if (viewModel->name() == name) + { + return createViewModelRuntime(viewModel); + } + } + fprintf(stderr, "Could not find View Model named %s.\n", name.c_str()); + return nullptr; +} + +ViewModelRuntime* File::defaultArtboardViewModel(Artboard* artboard) const +{ + if (artboard == nullptr) + { + fprintf(stderr, "Invalid Artboard\n"); + return nullptr; + } + if ((size_t)artboard->viewModelId() < m_ViewModels.size()) + { + auto viewModel = m_ViewModels[artboard->viewModelId()]; + return createViewModelRuntime(viewModel); + } + fprintf(stderr, + "Could not find a View Model linked to Artboard %s.\n", + artboard->name().c_str()); + return nullptr; +} + +ViewModelRuntime* File::createViewModelRuntime(ViewModel* viewModel) const +{ + + auto viewModelRuntime = new ViewModelRuntime(viewModel, this); + m_viewModelRuntimes.push_back(viewModelRuntime); + return viewModelRuntime; +} + +const std::vector& File::assets() const { return m_fileAssets; } + +const std::vector& File::enums() const { return m_Enums; } + +#ifdef WITH_RIVE_TOOLS +const std::vector File::stripAssets(Span bytes, + std::set typeKeys, + ImportResult* result) +{ + std::vector strippedData; + strippedData.reserve(bytes.size()); + BinaryReader reader(bytes); + RuntimeHeader header; + if (!RuntimeHeader::read(reader, header)) + { + if (result) + { + *result = ImportResult::malformed; + } + } + else if (header.majorVersion() != majorVersion) + { + if (result) + { + *result = ImportResult::unsupportedVersion; + } + } + else + { + strippedData.insert(strippedData.end(), + bytes.data(), + reader.position()); + const uint8_t* from = reader.position(); + const uint8_t* to = reader.position(); + uint16_t lastAssetType = 0; + while (!reader.reachedEnd()) + { + auto object = readRuntimeObject(reader, header); + if (object == nullptr) + { + continue; + } + if (object->is()) + { + lastAssetType = object->coreType(); + } + if (object->is() && + typeKeys.find(lastAssetType) != typeKeys.end()) + { + if (from != to) + { + strippedData.insert(strippedData.end(), from, to); + } + from = reader.position(); + } + delete object; + to = reader.position(); + } + if (from != to) + { + strippedData.insert(strippedData.end(), from, to); + } + *result = ImportResult::success; + } + return strippedData; +} + +#endif + +FileAsset* File::asset(size_t index) +{ + if (index >= 0 && index < m_fileAssets.size()) + { + return m_fileAssets[index]; + } + return nullptr; +} diff --git a/third_party/rive/source/foreground_layout_drawable.cpp b/third_party/rive/source/foreground_layout_drawable.cpp new file mode 100644 index 0000000..a54bb3f --- /dev/null +++ b/third_party/rive/source/foreground_layout_drawable.cpp @@ -0,0 +1,79 @@ + +#include "rive/foreground_layout_drawable.hpp" +#include "rive/layout_component.hpp" +#include "rive/shapes/paint/fill.hpp" +#include "rive/shapes/paint/stroke.hpp" + +using namespace rive; + +void ForegroundLayoutDrawable::buildDependencies() +{ + Super::buildDependencies(); + // Set the blend mode on all the shape paints. If we ever animate this + // property, we'll need to update it in the update cycle/mark dirty when the + // blend mode changes. + auto parentLayout = (parent()->as()); + if (parentLayout != nullptr) + { + for (auto paint : m_ShapePaints) + { + paint->blendMode(parentLayout->blendMode()); + } + } +} + +void ForegroundLayoutDrawable::update(ComponentDirt value) +{ + Super::update(value); + auto parentLayout = (parent()->as()); + if (parentLayout != nullptr) + { + if (hasDirt(value, ComponentDirt::RenderOpacity)) + { + propagateOpacity(parentLayout->childOpacity()); + } + } +} + +void ForegroundLayoutDrawable::draw(Renderer* renderer) +{ + auto parentLayoutComponent = (parent()->as()); + + for (auto shapePaint : m_ShapePaints) + { + if (!shapePaint->shouldDraw()) + { + continue; + } + auto shapePaintPath = shapePaint->pickPath(parentLayoutComponent); + if (shapePaintPath == nullptr) + { + continue; + } + shapePaint->draw(renderer, + shapePaintPath, + parentLayoutComponent->worldTransform()); + } +} + +Core* ForegroundLayoutDrawable::hitTest(HitInfo* hinfo, const Mat2D& xform) +{ + return nullptr; +} + +Component* ForegroundLayoutDrawable::pathBuilder() { return parent(); } + +ShapePaintPath* ForegroundLayoutDrawable::worldPath() +{ + return parent()->as()->worldPath(); +} + +ShapePaintPath* ForegroundLayoutDrawable::localPath() +{ + return parent()->as()->localPath(); +} + +ShapePaintPath* ForegroundLayoutDrawable::localClockwisePath() +{ + return parent()->as()->localClockwisePath(); +} diff --git a/third_party/rive/source/generated/animation/animation_base.cpp b/third_party/rive/source/generated/animation/animation_base.cpp new file mode 100644 index 0000000..e832aeb --- /dev/null +++ b/third_party/rive/source/generated/animation/animation_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/animation/animation_base.hpp" +#include "rive/animation/animation.hpp" + +using namespace rive; + +Core* AnimationBase::clone() const +{ + auto cloned = new Animation(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/animation/animation_state_base.cpp b/third_party/rive/source/generated/animation/animation_state_base.cpp new file mode 100644 index 0000000..922ea8e --- /dev/null +++ b/third_party/rive/source/generated/animation/animation_state_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/animation/animation_state_base.hpp" +#include "rive/animation/animation_state.hpp" + +using namespace rive; + +Core* AnimationStateBase::clone() const +{ + auto cloned = new AnimationState(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/animation/any_state_base.cpp b/third_party/rive/source/generated/animation/any_state_base.cpp new file mode 100644 index 0000000..54b2a42 --- /dev/null +++ b/third_party/rive/source/generated/animation/any_state_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/animation/any_state_base.hpp" +#include "rive/animation/any_state.hpp" + +using namespace rive; + +Core* AnyStateBase::clone() const +{ + auto cloned = new AnyState(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/animation/blend_animation_1d_base.cpp b/third_party/rive/source/generated/animation/blend_animation_1d_base.cpp new file mode 100644 index 0000000..a04b71f --- /dev/null +++ b/third_party/rive/source/generated/animation/blend_animation_1d_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/animation/blend_animation_1d_base.hpp" +#include "rive/animation/blend_animation_1d.hpp" + +using namespace rive; + +Core* BlendAnimation1DBase::clone() const +{ + auto cloned = new BlendAnimation1D(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/animation/blend_animation_direct_base.cpp b/third_party/rive/source/generated/animation/blend_animation_direct_base.cpp new file mode 100644 index 0000000..98bd50a --- /dev/null +++ b/third_party/rive/source/generated/animation/blend_animation_direct_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/animation/blend_animation_direct_base.hpp" +#include "rive/animation/blend_animation_direct.hpp" + +using namespace rive; + +Core* BlendAnimationDirectBase::clone() const +{ + auto cloned = new BlendAnimationDirect(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/animation/blend_state_1d_input_base.cpp b/third_party/rive/source/generated/animation/blend_state_1d_input_base.cpp new file mode 100644 index 0000000..1642dad --- /dev/null +++ b/third_party/rive/source/generated/animation/blend_state_1d_input_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/animation/blend_state_1d_input_base.hpp" +#include "rive/animation/blend_state_1d_input.hpp" + +using namespace rive; + +Core* BlendState1DInputBase::clone() const +{ + auto cloned = new BlendState1DInput(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/animation/blend_state_1d_viewmodel_base.cpp b/third_party/rive/source/generated/animation/blend_state_1d_viewmodel_base.cpp new file mode 100644 index 0000000..d685629 --- /dev/null +++ b/third_party/rive/source/generated/animation/blend_state_1d_viewmodel_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/animation/blend_state_1d_viewmodel_base.hpp" +#include "rive/animation/blend_state_1d_viewmodel.hpp" + +using namespace rive; + +Core* BlendState1DViewModelBase::clone() const +{ + auto cloned = new BlendState1DViewModel(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/animation/blend_state_direct_base.cpp b/third_party/rive/source/generated/animation/blend_state_direct_base.cpp new file mode 100644 index 0000000..a0349bc --- /dev/null +++ b/third_party/rive/source/generated/animation/blend_state_direct_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/animation/blend_state_direct_base.hpp" +#include "rive/animation/blend_state_direct.hpp" + +using namespace rive; + +Core* BlendStateDirectBase::clone() const +{ + auto cloned = new BlendStateDirect(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/animation/blend_state_transition_base.cpp b/third_party/rive/source/generated/animation/blend_state_transition_base.cpp new file mode 100644 index 0000000..a4b74d4 --- /dev/null +++ b/third_party/rive/source/generated/animation/blend_state_transition_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/animation/blend_state_transition_base.hpp" +#include "rive/animation/blend_state_transition.hpp" + +using namespace rive; + +Core* BlendStateTransitionBase::clone() const +{ + auto cloned = new BlendStateTransition(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/animation/cubic_ease_interpolator_base.cpp b/third_party/rive/source/generated/animation/cubic_ease_interpolator_base.cpp new file mode 100644 index 0000000..8dbda91 --- /dev/null +++ b/third_party/rive/source/generated/animation/cubic_ease_interpolator_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/animation/cubic_ease_interpolator_base.hpp" +#include "rive/animation/cubic_ease_interpolator.hpp" + +using namespace rive; + +Core* CubicEaseInterpolatorBase::clone() const +{ + auto cloned = new CubicEaseInterpolator(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/animation/cubic_interpolator_component_base.cpp b/third_party/rive/source/generated/animation/cubic_interpolator_component_base.cpp new file mode 100644 index 0000000..4cb5db0 --- /dev/null +++ b/third_party/rive/source/generated/animation/cubic_interpolator_component_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/animation/cubic_interpolator_component_base.hpp" +#include "rive/animation/cubic_interpolator_component.hpp" + +using namespace rive; + +Core* CubicInterpolatorComponentBase::clone() const +{ + auto cloned = new CubicInterpolatorComponent(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/animation/cubic_value_interpolator_base.cpp b/third_party/rive/source/generated/animation/cubic_value_interpolator_base.cpp new file mode 100644 index 0000000..3f64039 --- /dev/null +++ b/third_party/rive/source/generated/animation/cubic_value_interpolator_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/animation/cubic_value_interpolator_base.hpp" +#include "rive/animation/cubic_value_interpolator.hpp" + +using namespace rive; + +Core* CubicValueInterpolatorBase::clone() const +{ + auto cloned = new CubicValueInterpolator(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/animation/elastic_interpolator_base.cpp b/third_party/rive/source/generated/animation/elastic_interpolator_base.cpp new file mode 100644 index 0000000..757cb6b --- /dev/null +++ b/third_party/rive/source/generated/animation/elastic_interpolator_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/animation/elastic_interpolator_base.hpp" +#include "rive/animation/elastic_interpolator.hpp" + +using namespace rive; + +Core* ElasticInterpolatorBase::clone() const +{ + auto cloned = new ElasticInterpolator(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/animation/entry_state_base.cpp b/third_party/rive/source/generated/animation/entry_state_base.cpp new file mode 100644 index 0000000..68ec90e --- /dev/null +++ b/third_party/rive/source/generated/animation/entry_state_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/animation/entry_state_base.hpp" +#include "rive/animation/entry_state.hpp" + +using namespace rive; + +Core* EntryStateBase::clone() const +{ + auto cloned = new EntryState(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/animation/exit_state_base.cpp b/third_party/rive/source/generated/animation/exit_state_base.cpp new file mode 100644 index 0000000..12f5ad5 --- /dev/null +++ b/third_party/rive/source/generated/animation/exit_state_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/animation/exit_state_base.hpp" +#include "rive/animation/exit_state.hpp" + +using namespace rive; + +Core* ExitStateBase::clone() const +{ + auto cloned = new ExitState(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/animation/keyed_object_base.cpp b/third_party/rive/source/generated/animation/keyed_object_base.cpp new file mode 100644 index 0000000..57cb7a2 --- /dev/null +++ b/third_party/rive/source/generated/animation/keyed_object_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/animation/keyed_object_base.hpp" +#include "rive/animation/keyed_object.hpp" + +using namespace rive; + +Core* KeyedObjectBase::clone() const +{ + auto cloned = new KeyedObject(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/animation/keyed_property_base.cpp b/third_party/rive/source/generated/animation/keyed_property_base.cpp new file mode 100644 index 0000000..fe175e5 --- /dev/null +++ b/third_party/rive/source/generated/animation/keyed_property_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/animation/keyed_property_base.hpp" +#include "rive/animation/keyed_property.hpp" + +using namespace rive; + +Core* KeyedPropertyBase::clone() const +{ + auto cloned = new KeyedProperty(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/animation/keyframe_bool_base.cpp b/third_party/rive/source/generated/animation/keyframe_bool_base.cpp new file mode 100644 index 0000000..72b141d --- /dev/null +++ b/third_party/rive/source/generated/animation/keyframe_bool_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/animation/keyframe_bool_base.hpp" +#include "rive/animation/keyframe_bool.hpp" + +using namespace rive; + +Core* KeyFrameBoolBase::clone() const +{ + auto cloned = new KeyFrameBool(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/animation/keyframe_callback_base.cpp b/third_party/rive/source/generated/animation/keyframe_callback_base.cpp new file mode 100644 index 0000000..d68eefb --- /dev/null +++ b/third_party/rive/source/generated/animation/keyframe_callback_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/animation/keyframe_callback_base.hpp" +#include "rive/animation/keyframe_callback.hpp" + +using namespace rive; + +Core* KeyFrameCallbackBase::clone() const +{ + auto cloned = new KeyFrameCallback(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/animation/keyframe_color_base.cpp b/third_party/rive/source/generated/animation/keyframe_color_base.cpp new file mode 100644 index 0000000..93d2a15 --- /dev/null +++ b/third_party/rive/source/generated/animation/keyframe_color_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/animation/keyframe_color_base.hpp" +#include "rive/animation/keyframe_color.hpp" + +using namespace rive; + +Core* KeyFrameColorBase::clone() const +{ + auto cloned = new KeyFrameColor(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/animation/keyframe_double_base.cpp b/third_party/rive/source/generated/animation/keyframe_double_base.cpp new file mode 100644 index 0000000..b991a0e --- /dev/null +++ b/third_party/rive/source/generated/animation/keyframe_double_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/animation/keyframe_double_base.hpp" +#include "rive/animation/keyframe_double.hpp" + +using namespace rive; + +Core* KeyFrameDoubleBase::clone() const +{ + auto cloned = new KeyFrameDouble(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/animation/keyframe_id_base.cpp b/third_party/rive/source/generated/animation/keyframe_id_base.cpp new file mode 100644 index 0000000..a228b47 --- /dev/null +++ b/third_party/rive/source/generated/animation/keyframe_id_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/animation/keyframe_id_base.hpp" +#include "rive/animation/keyframe_id.hpp" + +using namespace rive; + +Core* KeyFrameIdBase::clone() const +{ + auto cloned = new KeyFrameId(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/animation/keyframe_string_base.cpp b/third_party/rive/source/generated/animation/keyframe_string_base.cpp new file mode 100644 index 0000000..ff1fa86 --- /dev/null +++ b/third_party/rive/source/generated/animation/keyframe_string_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/animation/keyframe_string_base.hpp" +#include "rive/animation/keyframe_string.hpp" + +using namespace rive; + +Core* KeyFrameStringBase::clone() const +{ + auto cloned = new KeyFrameString(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/animation/keyframe_uint_base.cpp b/third_party/rive/source/generated/animation/keyframe_uint_base.cpp new file mode 100644 index 0000000..35ddbed --- /dev/null +++ b/third_party/rive/source/generated/animation/keyframe_uint_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/animation/keyframe_uint_base.hpp" +#include "rive/animation/keyframe_uint.hpp" + +using namespace rive; + +Core* KeyFrameUintBase::clone() const +{ + auto cloned = new KeyFrameUint(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/animation/linear_animation_base.cpp b/third_party/rive/source/generated/animation/linear_animation_base.cpp new file mode 100644 index 0000000..b55beef --- /dev/null +++ b/third_party/rive/source/generated/animation/linear_animation_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/animation/linear_animation_base.hpp" +#include "rive/animation/linear_animation.hpp" + +using namespace rive; + +Core* LinearAnimationBase::clone() const +{ + auto cloned = new LinearAnimation(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/animation/listener_align_target_base.cpp b/third_party/rive/source/generated/animation/listener_align_target_base.cpp new file mode 100644 index 0000000..f0c1c95 --- /dev/null +++ b/third_party/rive/source/generated/animation/listener_align_target_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/animation/listener_align_target_base.hpp" +#include "rive/animation/listener_align_target.hpp" + +using namespace rive; + +Core* ListenerAlignTargetBase::clone() const +{ + auto cloned = new ListenerAlignTarget(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/animation/listener_bool_change_base.cpp b/third_party/rive/source/generated/animation/listener_bool_change_base.cpp new file mode 100644 index 0000000..3cd4cc3 --- /dev/null +++ b/third_party/rive/source/generated/animation/listener_bool_change_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/animation/listener_bool_change_base.hpp" +#include "rive/animation/listener_bool_change.hpp" + +using namespace rive; + +Core* ListenerBoolChangeBase::clone() const +{ + auto cloned = new ListenerBoolChange(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/animation/listener_fire_event_base.cpp b/third_party/rive/source/generated/animation/listener_fire_event_base.cpp new file mode 100644 index 0000000..e7ae04f --- /dev/null +++ b/third_party/rive/source/generated/animation/listener_fire_event_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/animation/listener_fire_event_base.hpp" +#include "rive/animation/listener_fire_event.hpp" + +using namespace rive; + +Core* ListenerFireEventBase::clone() const +{ + auto cloned = new ListenerFireEvent(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/animation/listener_number_change_base.cpp b/third_party/rive/source/generated/animation/listener_number_change_base.cpp new file mode 100644 index 0000000..55d6212 --- /dev/null +++ b/third_party/rive/source/generated/animation/listener_number_change_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/animation/listener_number_change_base.hpp" +#include "rive/animation/listener_number_change.hpp" + +using namespace rive; + +Core* ListenerNumberChangeBase::clone() const +{ + auto cloned = new ListenerNumberChange(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/animation/listener_trigger_change_base.cpp b/third_party/rive/source/generated/animation/listener_trigger_change_base.cpp new file mode 100644 index 0000000..4ead315 --- /dev/null +++ b/third_party/rive/source/generated/animation/listener_trigger_change_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/animation/listener_trigger_change_base.hpp" +#include "rive/animation/listener_trigger_change.hpp" + +using namespace rive; + +Core* ListenerTriggerChangeBase::clone() const +{ + auto cloned = new ListenerTriggerChange(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/animation/listener_viewmodel_change_base.cpp b/third_party/rive/source/generated/animation/listener_viewmodel_change_base.cpp new file mode 100644 index 0000000..96d9e9a --- /dev/null +++ b/third_party/rive/source/generated/animation/listener_viewmodel_change_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/animation/listener_viewmodel_change_base.hpp" +#include "rive/animation/listener_viewmodel_change.hpp" + +using namespace rive; + +Core* ListenerViewModelChangeBase::clone() const +{ + auto cloned = new ListenerViewModelChange(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/animation/nested_bool_base.cpp b/third_party/rive/source/generated/animation/nested_bool_base.cpp new file mode 100644 index 0000000..f21b56c --- /dev/null +++ b/third_party/rive/source/generated/animation/nested_bool_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/animation/nested_bool_base.hpp" +#include "rive/animation/nested_bool.hpp" + +using namespace rive; + +Core* NestedBoolBase::clone() const +{ + auto cloned = new NestedBool(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/animation/nested_number_base.cpp b/third_party/rive/source/generated/animation/nested_number_base.cpp new file mode 100644 index 0000000..6e5613c --- /dev/null +++ b/third_party/rive/source/generated/animation/nested_number_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/animation/nested_number_base.hpp" +#include "rive/animation/nested_number.hpp" + +using namespace rive; + +Core* NestedNumberBase::clone() const +{ + auto cloned = new NestedNumber(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/animation/nested_remap_animation_base.cpp b/third_party/rive/source/generated/animation/nested_remap_animation_base.cpp new file mode 100644 index 0000000..ff0a6c6 --- /dev/null +++ b/third_party/rive/source/generated/animation/nested_remap_animation_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/animation/nested_remap_animation_base.hpp" +#include "rive/animation/nested_remap_animation.hpp" + +using namespace rive; + +Core* NestedRemapAnimationBase::clone() const +{ + auto cloned = new NestedRemapAnimation(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/animation/nested_simple_animation_base.cpp b/third_party/rive/source/generated/animation/nested_simple_animation_base.cpp new file mode 100644 index 0000000..283d353 --- /dev/null +++ b/third_party/rive/source/generated/animation/nested_simple_animation_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/animation/nested_simple_animation_base.hpp" +#include "rive/animation/nested_simple_animation.hpp" + +using namespace rive; + +Core* NestedSimpleAnimationBase::clone() const +{ + auto cloned = new NestedSimpleAnimation(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/animation/nested_state_machine_base.cpp b/third_party/rive/source/generated/animation/nested_state_machine_base.cpp new file mode 100644 index 0000000..ef221f1 --- /dev/null +++ b/third_party/rive/source/generated/animation/nested_state_machine_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/animation/nested_state_machine_base.hpp" +#include "rive/animation/nested_state_machine.hpp" + +using namespace rive; + +Core* NestedStateMachineBase::clone() const +{ + auto cloned = new NestedStateMachine(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/animation/nested_trigger_base.cpp b/third_party/rive/source/generated/animation/nested_trigger_base.cpp new file mode 100644 index 0000000..526737b --- /dev/null +++ b/third_party/rive/source/generated/animation/nested_trigger_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/animation/nested_trigger_base.hpp" +#include "rive/animation/nested_trigger.hpp" + +using namespace rive; + +Core* NestedTriggerBase::clone() const +{ + auto cloned = new NestedTrigger(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/animation/state_machine_base.cpp b/third_party/rive/source/generated/animation/state_machine_base.cpp new file mode 100644 index 0000000..7d34670 --- /dev/null +++ b/third_party/rive/source/generated/animation/state_machine_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/animation/state_machine_base.hpp" +#include "rive/animation/state_machine.hpp" + +using namespace rive; + +Core* StateMachineBase::clone() const +{ + auto cloned = new StateMachine(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/animation/state_machine_bool_base.cpp b/third_party/rive/source/generated/animation/state_machine_bool_base.cpp new file mode 100644 index 0000000..3db764d --- /dev/null +++ b/third_party/rive/source/generated/animation/state_machine_bool_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/animation/state_machine_bool_base.hpp" +#include "rive/animation/state_machine_bool.hpp" + +using namespace rive; + +Core* StateMachineBoolBase::clone() const +{ + auto cloned = new StateMachineBool(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/animation/state_machine_fire_event.cpp b/third_party/rive/source/generated/animation/state_machine_fire_event.cpp new file mode 100644 index 0000000..568d11b --- /dev/null +++ b/third_party/rive/source/generated/animation/state_machine_fire_event.cpp @@ -0,0 +1,31 @@ +#include "rive/generated/animation/state_machine_fire_event_base.hpp" +#include "rive/animation/state_machine_fire_event.hpp" +#include "rive/animation/state_machine_layer_component.hpp" +#include "rive/animation/state_machine_instance.hpp" +#include "rive/event.hpp" +#include "rive/importers/state_machine_layer_component_importer.hpp" + +using namespace rive; + +StatusCode StateMachineFireEvent::import(ImportStack& importStack) +{ + auto stateImporter = importStack.latest( + StateMachineLayerComponent::typeKey); + if (stateImporter == nullptr) + { + return StatusCode::MissingObject; + } + stateImporter->addFireEvent(this); + return Super::import(importStack); +} + +void StateMachineFireEvent::perform( + StateMachineInstance* stateMachineInstance) const +{ + auto coreEvent = stateMachineInstance->artboard()->resolve(eventId()); + if (coreEvent == nullptr || !coreEvent->is()) + { + return; + } + stateMachineInstance->reportEvent(coreEvent->as()); +} \ No newline at end of file diff --git a/third_party/rive/source/generated/animation/state_machine_fire_event_base.cpp b/third_party/rive/source/generated/animation/state_machine_fire_event_base.cpp new file mode 100644 index 0000000..b43b331 --- /dev/null +++ b/third_party/rive/source/generated/animation/state_machine_fire_event_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/animation/state_machine_fire_event_base.hpp" +#include "rive/animation/state_machine_fire_event.hpp" + +using namespace rive; + +Core* StateMachineFireEventBase::clone() const +{ + auto cloned = new StateMachineFireEvent(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/animation/state_machine_layer_base.cpp b/third_party/rive/source/generated/animation/state_machine_layer_base.cpp new file mode 100644 index 0000000..acafe6e --- /dev/null +++ b/third_party/rive/source/generated/animation/state_machine_layer_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/animation/state_machine_layer_base.hpp" +#include "rive/animation/state_machine_layer.hpp" + +using namespace rive; + +Core* StateMachineLayerBase::clone() const +{ + auto cloned = new StateMachineLayer(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/animation/state_machine_listener_base.cpp b/third_party/rive/source/generated/animation/state_machine_listener_base.cpp new file mode 100644 index 0000000..37e95cf --- /dev/null +++ b/third_party/rive/source/generated/animation/state_machine_listener_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/animation/state_machine_listener_base.hpp" +#include "rive/animation/state_machine_listener.hpp" + +using namespace rive; + +Core* StateMachineListenerBase::clone() const +{ + auto cloned = new StateMachineListener(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/animation/state_machine_number_base.cpp b/third_party/rive/source/generated/animation/state_machine_number_base.cpp new file mode 100644 index 0000000..b821aa4 --- /dev/null +++ b/third_party/rive/source/generated/animation/state_machine_number_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/animation/state_machine_number_base.hpp" +#include "rive/animation/state_machine_number.hpp" + +using namespace rive; + +Core* StateMachineNumberBase::clone() const +{ + auto cloned = new StateMachineNumber(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/animation/state_machine_trigger_base.cpp b/third_party/rive/source/generated/animation/state_machine_trigger_base.cpp new file mode 100644 index 0000000..d7890be --- /dev/null +++ b/third_party/rive/source/generated/animation/state_machine_trigger_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/animation/state_machine_trigger_base.hpp" +#include "rive/animation/state_machine_trigger.hpp" + +using namespace rive; + +Core* StateMachineTriggerBase::clone() const +{ + auto cloned = new StateMachineTrigger(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/animation/state_transition_base.cpp b/third_party/rive/source/generated/animation/state_transition_base.cpp new file mode 100644 index 0000000..f535fbd --- /dev/null +++ b/third_party/rive/source/generated/animation/state_transition_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/animation/state_transition_base.hpp" +#include "rive/animation/state_transition.hpp" + +using namespace rive; + +Core* StateTransitionBase::clone() const +{ + auto cloned = new StateTransition(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/animation/transition_artboard_condition_base.cpp b/third_party/rive/source/generated/animation/transition_artboard_condition_base.cpp new file mode 100644 index 0000000..4adb3c8 --- /dev/null +++ b/third_party/rive/source/generated/animation/transition_artboard_condition_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/animation/transition_artboard_condition_base.hpp" +#include "rive/animation/transition_artboard_condition.hpp" + +using namespace rive; + +Core* TransitionArtboardConditionBase::clone() const +{ + auto cloned = new TransitionArtboardCondition(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/animation/transition_bool_condition_base.cpp b/third_party/rive/source/generated/animation/transition_bool_condition_base.cpp new file mode 100644 index 0000000..3b92f3d --- /dev/null +++ b/third_party/rive/source/generated/animation/transition_bool_condition_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/animation/transition_bool_condition_base.hpp" +#include "rive/animation/transition_bool_condition.hpp" + +using namespace rive; + +Core* TransitionBoolConditionBase::clone() const +{ + auto cloned = new TransitionBoolCondition(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/animation/transition_number_condition_base.cpp b/third_party/rive/source/generated/animation/transition_number_condition_base.cpp new file mode 100644 index 0000000..537addf --- /dev/null +++ b/third_party/rive/source/generated/animation/transition_number_condition_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/animation/transition_number_condition_base.hpp" +#include "rive/animation/transition_number_condition.hpp" + +using namespace rive; + +Core* TransitionNumberConditionBase::clone() const +{ + auto cloned = new TransitionNumberCondition(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/animation/transition_property_artboard_comparator_base.cpp b/third_party/rive/source/generated/animation/transition_property_artboard_comparator_base.cpp new file mode 100644 index 0000000..31a068a --- /dev/null +++ b/third_party/rive/source/generated/animation/transition_property_artboard_comparator_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/animation/transition_property_artboard_comparator_base.hpp" +#include "rive/animation/transition_property_artboard_comparator.hpp" + +using namespace rive; + +Core* TransitionPropertyArtboardComparatorBase::clone() const +{ + auto cloned = new TransitionPropertyArtboardComparator(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/animation/transition_property_viewmodel_comparator_base.cpp b/third_party/rive/source/generated/animation/transition_property_viewmodel_comparator_base.cpp new file mode 100644 index 0000000..8c0c2d6 --- /dev/null +++ b/third_party/rive/source/generated/animation/transition_property_viewmodel_comparator_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/animation/transition_property_viewmodel_comparator_base.hpp" +#include "rive/animation/transition_property_viewmodel_comparator.hpp" + +using namespace rive; + +Core* TransitionPropertyViewModelComparatorBase::clone() const +{ + auto cloned = new TransitionPropertyViewModelComparator(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/animation/transition_trigger_condition_base.cpp b/third_party/rive/source/generated/animation/transition_trigger_condition_base.cpp new file mode 100644 index 0000000..31dadd3 --- /dev/null +++ b/third_party/rive/source/generated/animation/transition_trigger_condition_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/animation/transition_trigger_condition_base.hpp" +#include "rive/animation/transition_trigger_condition.hpp" + +using namespace rive; + +Core* TransitionTriggerConditionBase::clone() const +{ + auto cloned = new TransitionTriggerCondition(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/animation/transition_value_boolean_comparator_base.cpp b/third_party/rive/source/generated/animation/transition_value_boolean_comparator_base.cpp new file mode 100644 index 0000000..3e9a2ef --- /dev/null +++ b/third_party/rive/source/generated/animation/transition_value_boolean_comparator_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/animation/transition_value_boolean_comparator_base.hpp" +#include "rive/animation/transition_value_boolean_comparator.hpp" + +using namespace rive; + +Core* TransitionValueBooleanComparatorBase::clone() const +{ + auto cloned = new TransitionValueBooleanComparator(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/animation/transition_value_color_comparator_base.cpp b/third_party/rive/source/generated/animation/transition_value_color_comparator_base.cpp new file mode 100644 index 0000000..a199f5f --- /dev/null +++ b/third_party/rive/source/generated/animation/transition_value_color_comparator_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/animation/transition_value_color_comparator_base.hpp" +#include "rive/animation/transition_value_color_comparator.hpp" + +using namespace rive; + +Core* TransitionValueColorComparatorBase::clone() const +{ + auto cloned = new TransitionValueColorComparator(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/animation/transition_value_enum_comparator_base.cpp b/third_party/rive/source/generated/animation/transition_value_enum_comparator_base.cpp new file mode 100644 index 0000000..dad8789 --- /dev/null +++ b/third_party/rive/source/generated/animation/transition_value_enum_comparator_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/animation/transition_value_enum_comparator_base.hpp" +#include "rive/animation/transition_value_enum_comparator.hpp" + +using namespace rive; + +Core* TransitionValueEnumComparatorBase::clone() const +{ + auto cloned = new TransitionValueEnumComparator(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/animation/transition_value_number_comparator_base.cpp b/third_party/rive/source/generated/animation/transition_value_number_comparator_base.cpp new file mode 100644 index 0000000..8ebecac --- /dev/null +++ b/third_party/rive/source/generated/animation/transition_value_number_comparator_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/animation/transition_value_number_comparator_base.hpp" +#include "rive/animation/transition_value_number_comparator.hpp" + +using namespace rive; + +Core* TransitionValueNumberComparatorBase::clone() const +{ + auto cloned = new TransitionValueNumberComparator(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/animation/transition_value_string_comparator_base.cpp b/third_party/rive/source/generated/animation/transition_value_string_comparator_base.cpp new file mode 100644 index 0000000..07db01d --- /dev/null +++ b/third_party/rive/source/generated/animation/transition_value_string_comparator_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/animation/transition_value_string_comparator_base.hpp" +#include "rive/animation/transition_value_string_comparator.hpp" + +using namespace rive; + +Core* TransitionValueStringComparatorBase::clone() const +{ + auto cloned = new TransitionValueStringComparator(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/animation/transition_value_trigger_comparator_base.cpp b/third_party/rive/source/generated/animation/transition_value_trigger_comparator_base.cpp new file mode 100644 index 0000000..a21d49c --- /dev/null +++ b/third_party/rive/source/generated/animation/transition_value_trigger_comparator_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/animation/transition_value_trigger_comparator_base.hpp" +#include "rive/animation/transition_value_trigger_comparator.hpp" + +using namespace rive; + +Core* TransitionValueTriggerComparatorBase::clone() const +{ + auto cloned = new TransitionValueTriggerComparator(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/animation/transition_viewmodel_condition_base.cpp b/third_party/rive/source/generated/animation/transition_viewmodel_condition_base.cpp new file mode 100644 index 0000000..a0d3b25 --- /dev/null +++ b/third_party/rive/source/generated/animation/transition_viewmodel_condition_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/animation/transition_viewmodel_condition_base.hpp" +#include "rive/animation/transition_viewmodel_condition.hpp" + +using namespace rive; + +Core* TransitionViewModelConditionBase::clone() const +{ + auto cloned = new TransitionViewModelCondition(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/artboard_base.cpp b/third_party/rive/source/generated/artboard_base.cpp new file mode 100644 index 0000000..612c270 --- /dev/null +++ b/third_party/rive/source/generated/artboard_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/artboard_base.hpp" +#include "rive/artboard.hpp" + +using namespace rive; + +Core* ArtboardBase::clone() const +{ + auto cloned = new Artboard(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/artboard_component_list_base.cpp b/third_party/rive/source/generated/artboard_component_list_base.cpp new file mode 100644 index 0000000..58c00d2 --- /dev/null +++ b/third_party/rive/source/generated/artboard_component_list_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/artboard_component_list_base.hpp" +#include "rive/artboard_component_list.hpp" + +using namespace rive; + +Core* ArtboardComponentListBase::clone() const +{ + auto cloned = new ArtboardComponentList(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/assets/audio_asset_base.cpp b/third_party/rive/source/generated/assets/audio_asset_base.cpp new file mode 100644 index 0000000..0b7504d --- /dev/null +++ b/third_party/rive/source/generated/assets/audio_asset_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/assets/audio_asset_base.hpp" +#include "rive/assets/audio_asset.hpp" + +using namespace rive; + +Core* AudioAssetBase::clone() const +{ + auto cloned = new AudioAsset(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/assets/file_asset_contents_base.cpp b/third_party/rive/source/generated/assets/file_asset_contents_base.cpp new file mode 100644 index 0000000..8d0e376 --- /dev/null +++ b/third_party/rive/source/generated/assets/file_asset_contents_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/assets/file_asset_contents_base.hpp" +#include "rive/assets/file_asset_contents.hpp" + +using namespace rive; + +Core* FileAssetContentsBase::clone() const +{ + auto cloned = new FileAssetContents(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/assets/folder_base.cpp b/third_party/rive/source/generated/assets/folder_base.cpp new file mode 100644 index 0000000..ba27d04 --- /dev/null +++ b/third_party/rive/source/generated/assets/folder_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/assets/folder_base.hpp" +#include "rive/assets/folder.hpp" + +using namespace rive; + +Core* FolderBase::clone() const +{ + auto cloned = new Folder(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/assets/font_asset_base.cpp b/third_party/rive/source/generated/assets/font_asset_base.cpp new file mode 100644 index 0000000..95101bd --- /dev/null +++ b/third_party/rive/source/generated/assets/font_asset_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/assets/font_asset_base.hpp" +#include "rive/assets/font_asset.hpp" + +using namespace rive; + +Core* FontAssetBase::clone() const +{ + auto cloned = new FontAsset(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/assets/image_asset_base.cpp b/third_party/rive/source/generated/assets/image_asset_base.cpp new file mode 100644 index 0000000..6b32b1d --- /dev/null +++ b/third_party/rive/source/generated/assets/image_asset_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/assets/image_asset_base.hpp" +#include "rive/assets/image_asset.hpp" + +using namespace rive; + +Core* ImageAssetBase::clone() const +{ + auto cloned = new ImageAsset(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/audio_event_base.cpp b/third_party/rive/source/generated/audio_event_base.cpp new file mode 100644 index 0000000..83ef474 --- /dev/null +++ b/third_party/rive/source/generated/audio_event_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/audio_event_base.hpp" +#include "rive/audio_event.hpp" + +using namespace rive; + +Core* AudioEventBase::clone() const +{ + auto cloned = new AudioEvent(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/backboard_base.cpp b/third_party/rive/source/generated/backboard_base.cpp new file mode 100644 index 0000000..c5dfd7a --- /dev/null +++ b/third_party/rive/source/generated/backboard_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/backboard_base.hpp" +#include "rive/backboard.hpp" + +using namespace rive; + +Core* BackboardBase::clone() const +{ + auto cloned = new Backboard(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/bones/bone_base.cpp b/third_party/rive/source/generated/bones/bone_base.cpp new file mode 100644 index 0000000..0ad594f --- /dev/null +++ b/third_party/rive/source/generated/bones/bone_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/bones/bone_base.hpp" +#include "rive/bones/bone.hpp" + +using namespace rive; + +Core* BoneBase::clone() const +{ + auto cloned = new Bone(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/bones/cubic_weight_base.cpp b/third_party/rive/source/generated/bones/cubic_weight_base.cpp new file mode 100644 index 0000000..4192b74 --- /dev/null +++ b/third_party/rive/source/generated/bones/cubic_weight_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/bones/cubic_weight_base.hpp" +#include "rive/bones/cubic_weight.hpp" + +using namespace rive; + +Core* CubicWeightBase::clone() const +{ + auto cloned = new CubicWeight(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/bones/root_bone_base.cpp b/third_party/rive/source/generated/bones/root_bone_base.cpp new file mode 100644 index 0000000..faf1c91 --- /dev/null +++ b/third_party/rive/source/generated/bones/root_bone_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/bones/root_bone_base.hpp" +#include "rive/bones/root_bone.hpp" + +using namespace rive; + +Core* RootBoneBase::clone() const +{ + auto cloned = new RootBone(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/bones/skin_base.cpp b/third_party/rive/source/generated/bones/skin_base.cpp new file mode 100644 index 0000000..401c65f --- /dev/null +++ b/third_party/rive/source/generated/bones/skin_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/bones/skin_base.hpp" +#include "rive/bones/skin.hpp" + +using namespace rive; + +Core* SkinBase::clone() const +{ + auto cloned = new Skin(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/bones/tendon_base.cpp b/third_party/rive/source/generated/bones/tendon_base.cpp new file mode 100644 index 0000000..866209b --- /dev/null +++ b/third_party/rive/source/generated/bones/tendon_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/bones/tendon_base.hpp" +#include "rive/bones/tendon.hpp" + +using namespace rive; + +Core* TendonBase::clone() const +{ + auto cloned = new Tendon(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/bones/weight_base.cpp b/third_party/rive/source/generated/bones/weight_base.cpp new file mode 100644 index 0000000..f62cb02 --- /dev/null +++ b/third_party/rive/source/generated/bones/weight_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/bones/weight_base.hpp" +#include "rive/bones/weight.hpp" + +using namespace rive; + +Core* WeightBase::clone() const +{ + auto cloned = new Weight(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/constraints/distance_constraint_base.cpp b/third_party/rive/source/generated/constraints/distance_constraint_base.cpp new file mode 100644 index 0000000..457fe8c --- /dev/null +++ b/third_party/rive/source/generated/constraints/distance_constraint_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/constraints/distance_constraint_base.hpp" +#include "rive/constraints/distance_constraint.hpp" + +using namespace rive; + +Core* DistanceConstraintBase::clone() const +{ + auto cloned = new DistanceConstraint(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/constraints/follow_path_constraint_base.cpp b/third_party/rive/source/generated/constraints/follow_path_constraint_base.cpp new file mode 100644 index 0000000..c35b2cf --- /dev/null +++ b/third_party/rive/source/generated/constraints/follow_path_constraint_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/constraints/follow_path_constraint_base.hpp" +#include "rive/constraints/follow_path_constraint.hpp" + +using namespace rive; + +Core* FollowPathConstraintBase::clone() const +{ + auto cloned = new FollowPathConstraint(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/constraints/ik_constraint_base.cpp b/third_party/rive/source/generated/constraints/ik_constraint_base.cpp new file mode 100644 index 0000000..8a16dac --- /dev/null +++ b/third_party/rive/source/generated/constraints/ik_constraint_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/constraints/ik_constraint_base.hpp" +#include "rive/constraints/ik_constraint.hpp" + +using namespace rive; + +Core* IKConstraintBase::clone() const +{ + auto cloned = new IKConstraint(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/constraints/rotation_constraint_base.cpp b/third_party/rive/source/generated/constraints/rotation_constraint_base.cpp new file mode 100644 index 0000000..870570f --- /dev/null +++ b/third_party/rive/source/generated/constraints/rotation_constraint_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/constraints/rotation_constraint_base.hpp" +#include "rive/constraints/rotation_constraint.hpp" + +using namespace rive; + +Core* RotationConstraintBase::clone() const +{ + auto cloned = new RotationConstraint(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/constraints/scale_constraint_base.cpp b/third_party/rive/source/generated/constraints/scale_constraint_base.cpp new file mode 100644 index 0000000..612fcd4 --- /dev/null +++ b/third_party/rive/source/generated/constraints/scale_constraint_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/constraints/scale_constraint_base.hpp" +#include "rive/constraints/scale_constraint.hpp" + +using namespace rive; + +Core* ScaleConstraintBase::clone() const +{ + auto cloned = new ScaleConstraint(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/constraints/scrolling/clamped_scroll_physics_base.cpp b/third_party/rive/source/generated/constraints/scrolling/clamped_scroll_physics_base.cpp new file mode 100644 index 0000000..2f51a51 --- /dev/null +++ b/third_party/rive/source/generated/constraints/scrolling/clamped_scroll_physics_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/constraints/scrolling/clamped_scroll_physics_base.hpp" +#include "rive/constraints/scrolling/clamped_scroll_physics.hpp" + +using namespace rive; + +Core* ClampedScrollPhysicsBase::clone() const +{ + auto cloned = new ClampedScrollPhysics(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/constraints/scrolling/elastic_scroll_physics_base.cpp b/third_party/rive/source/generated/constraints/scrolling/elastic_scroll_physics_base.cpp new file mode 100644 index 0000000..806e189 --- /dev/null +++ b/third_party/rive/source/generated/constraints/scrolling/elastic_scroll_physics_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/constraints/scrolling/elastic_scroll_physics_base.hpp" +#include "rive/constraints/scrolling/elastic_scroll_physics.hpp" + +using namespace rive; + +Core* ElasticScrollPhysicsBase::clone() const +{ + auto cloned = new ElasticScrollPhysics(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/constraints/scrolling/scroll_bar_constraint_base.cpp b/third_party/rive/source/generated/constraints/scrolling/scroll_bar_constraint_base.cpp new file mode 100644 index 0000000..2e9535a --- /dev/null +++ b/third_party/rive/source/generated/constraints/scrolling/scroll_bar_constraint_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/constraints/scrolling/scroll_bar_constraint_base.hpp" +#include "rive/constraints/scrolling/scroll_bar_constraint.hpp" + +using namespace rive; + +Core* ScrollBarConstraintBase::clone() const +{ + auto cloned = new ScrollBarConstraint(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/constraints/scrolling/scroll_constraint_base.cpp b/third_party/rive/source/generated/constraints/scrolling/scroll_constraint_base.cpp new file mode 100644 index 0000000..deea3f0 --- /dev/null +++ b/third_party/rive/source/generated/constraints/scrolling/scroll_constraint_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/constraints/scrolling/scroll_constraint_base.hpp" +#include "rive/constraints/scrolling/scroll_constraint.hpp" + +using namespace rive; + +Core* ScrollConstraintBase::clone() const +{ + auto cloned = new ScrollConstraint(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/constraints/transform_constraint_base.cpp b/third_party/rive/source/generated/constraints/transform_constraint_base.cpp new file mode 100644 index 0000000..0c594f0 --- /dev/null +++ b/third_party/rive/source/generated/constraints/transform_constraint_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/constraints/transform_constraint_base.hpp" +#include "rive/constraints/transform_constraint.hpp" + +using namespace rive; + +Core* TransformConstraintBase::clone() const +{ + auto cloned = new TransformConstraint(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/constraints/translation_constraint_base.cpp b/third_party/rive/source/generated/constraints/translation_constraint_base.cpp new file mode 100644 index 0000000..3de3c2a --- /dev/null +++ b/third_party/rive/source/generated/constraints/translation_constraint_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/constraints/translation_constraint_base.hpp" +#include "rive/constraints/translation_constraint.hpp" + +using namespace rive; + +Core* TranslationConstraintBase::clone() const +{ + auto cloned = new TranslationConstraint(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/custom_property_boolean_base.cpp b/third_party/rive/source/generated/custom_property_boolean_base.cpp new file mode 100644 index 0000000..b999ee8 --- /dev/null +++ b/third_party/rive/source/generated/custom_property_boolean_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/custom_property_boolean_base.hpp" +#include "rive/custom_property_boolean.hpp" + +using namespace rive; + +Core* CustomPropertyBooleanBase::clone() const +{ + auto cloned = new CustomPropertyBoolean(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/custom_property_group_base.cpp b/third_party/rive/source/generated/custom_property_group_base.cpp new file mode 100644 index 0000000..13a9613 --- /dev/null +++ b/third_party/rive/source/generated/custom_property_group_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/custom_property_group_base.hpp" +#include "rive/custom_property_group.hpp" + +using namespace rive; + +Core* CustomPropertyGroupBase::clone() const +{ + auto cloned = new CustomPropertyGroup(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/custom_property_number_base.cpp b/third_party/rive/source/generated/custom_property_number_base.cpp new file mode 100644 index 0000000..e1d0dd8 --- /dev/null +++ b/third_party/rive/source/generated/custom_property_number_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/custom_property_number_base.hpp" +#include "rive/custom_property_number.hpp" + +using namespace rive; + +Core* CustomPropertyNumberBase::clone() const +{ + auto cloned = new CustomPropertyNumber(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/custom_property_string_base.cpp b/third_party/rive/source/generated/custom_property_string_base.cpp new file mode 100644 index 0000000..c7e27ec --- /dev/null +++ b/third_party/rive/source/generated/custom_property_string_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/custom_property_string_base.hpp" +#include "rive/custom_property_string.hpp" + +using namespace rive; + +Core* CustomPropertyStringBase::clone() const +{ + auto cloned = new CustomPropertyString(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/data_bind/bindable_property_asset_base.cpp b/third_party/rive/source/generated/data_bind/bindable_property_asset_base.cpp new file mode 100644 index 0000000..d18831a --- /dev/null +++ b/third_party/rive/source/generated/data_bind/bindable_property_asset_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/data_bind/bindable_property_asset_base.hpp" +#include "rive/data_bind/bindable_property_asset.hpp" + +using namespace rive; + +Core* BindablePropertyAssetBase::clone() const +{ + auto cloned = new BindablePropertyAsset(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/data_bind/bindable_property_boolean_base.cpp b/third_party/rive/source/generated/data_bind/bindable_property_boolean_base.cpp new file mode 100644 index 0000000..4e3dcc2 --- /dev/null +++ b/third_party/rive/source/generated/data_bind/bindable_property_boolean_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/data_bind/bindable_property_boolean_base.hpp" +#include "rive/data_bind/bindable_property_boolean.hpp" + +using namespace rive; + +Core* BindablePropertyBooleanBase::clone() const +{ + auto cloned = new BindablePropertyBoolean(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/data_bind/bindable_property_color_base.cpp b/third_party/rive/source/generated/data_bind/bindable_property_color_base.cpp new file mode 100644 index 0000000..fa64a07 --- /dev/null +++ b/third_party/rive/source/generated/data_bind/bindable_property_color_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/data_bind/bindable_property_color_base.hpp" +#include "rive/data_bind/bindable_property_color.hpp" + +using namespace rive; + +Core* BindablePropertyColorBase::clone() const +{ + auto cloned = new BindablePropertyColor(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/data_bind/bindable_property_enum_base.cpp b/third_party/rive/source/generated/data_bind/bindable_property_enum_base.cpp new file mode 100644 index 0000000..acd5be6 --- /dev/null +++ b/third_party/rive/source/generated/data_bind/bindable_property_enum_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/data_bind/bindable_property_enum_base.hpp" +#include "rive/data_bind/bindable_property_enum.hpp" + +using namespace rive; + +Core* BindablePropertyEnumBase::clone() const +{ + auto cloned = new BindablePropertyEnum(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/data_bind/bindable_property_integer_base.cpp b/third_party/rive/source/generated/data_bind/bindable_property_integer_base.cpp new file mode 100644 index 0000000..4ee9a28 --- /dev/null +++ b/third_party/rive/source/generated/data_bind/bindable_property_integer_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/data_bind/bindable_property_integer_base.hpp" +#include "rive/data_bind/bindable_property_integer.hpp" + +using namespace rive; + +Core* BindablePropertyIntegerBase::clone() const +{ + auto cloned = new BindablePropertyInteger(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/data_bind/bindable_property_number_base.cpp b/third_party/rive/source/generated/data_bind/bindable_property_number_base.cpp new file mode 100644 index 0000000..95b0453 --- /dev/null +++ b/third_party/rive/source/generated/data_bind/bindable_property_number_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/data_bind/bindable_property_number_base.hpp" +#include "rive/data_bind/bindable_property_number.hpp" + +using namespace rive; + +Core* BindablePropertyNumberBase::clone() const +{ + auto cloned = new BindablePropertyNumber(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/data_bind/bindable_property_string_base.cpp b/third_party/rive/source/generated/data_bind/bindable_property_string_base.cpp new file mode 100644 index 0000000..04133c7 --- /dev/null +++ b/third_party/rive/source/generated/data_bind/bindable_property_string_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/data_bind/bindable_property_string_base.hpp" +#include "rive/data_bind/bindable_property_string.hpp" + +using namespace rive; + +Core* BindablePropertyStringBase::clone() const +{ + auto cloned = new BindablePropertyString(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/data_bind/bindable_property_trigger_base.cpp b/third_party/rive/source/generated/data_bind/bindable_property_trigger_base.cpp new file mode 100644 index 0000000..0660325 --- /dev/null +++ b/third_party/rive/source/generated/data_bind/bindable_property_trigger_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/data_bind/bindable_property_trigger_base.hpp" +#include "rive/data_bind/bindable_property_trigger.hpp" + +using namespace rive; + +Core* BindablePropertyTriggerBase::clone() const +{ + auto cloned = new BindablePropertyTrigger(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/data_bind/converters/data_converter_boolean_negate_base.cpp b/third_party/rive/source/generated/data_bind/converters/data_converter_boolean_negate_base.cpp new file mode 100644 index 0000000..c9e9280 --- /dev/null +++ b/third_party/rive/source/generated/data_bind/converters/data_converter_boolean_negate_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/data_bind/converters/data_converter_boolean_negate_base.hpp" +#include "rive/data_bind/converters/data_converter_boolean_negate.hpp" + +using namespace rive; + +Core* DataConverterBooleanNegateBase::clone() const +{ + auto cloned = new DataConverterBooleanNegate(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/data_bind/converters/data_converter_formula_base.cpp b/third_party/rive/source/generated/data_bind/converters/data_converter_formula_base.cpp new file mode 100644 index 0000000..7c11710 --- /dev/null +++ b/third_party/rive/source/generated/data_bind/converters/data_converter_formula_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/data_bind/converters/data_converter_formula_base.hpp" +#include "rive/data_bind/converters/data_converter_formula.hpp" + +using namespace rive; + +Core* DataConverterFormulaBase::clone() const +{ + auto cloned = new DataConverterFormula(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/data_bind/converters/data_converter_group_base.cpp b/third_party/rive/source/generated/data_bind/converters/data_converter_group_base.cpp new file mode 100644 index 0000000..23ee770 --- /dev/null +++ b/third_party/rive/source/generated/data_bind/converters/data_converter_group_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/data_bind/converters/data_converter_group_base.hpp" +#include "rive/data_bind/converters/data_converter_group.hpp" + +using namespace rive; + +Core* DataConverterGroupBase::clone() const +{ + auto cloned = new DataConverterGroup(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/data_bind/converters/data_converter_group_item_base.cpp b/third_party/rive/source/generated/data_bind/converters/data_converter_group_item_base.cpp new file mode 100644 index 0000000..8f1e17b --- /dev/null +++ b/third_party/rive/source/generated/data_bind/converters/data_converter_group_item_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/data_bind/converters/data_converter_group_item_base.hpp" +#include "rive/data_bind/converters/data_converter_group_item.hpp" + +using namespace rive; + +Core* DataConverterGroupItemBase::clone() const +{ + auto cloned = new DataConverterGroupItem(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/data_bind/converters/data_converter_interpolator_base.cpp b/third_party/rive/source/generated/data_bind/converters/data_converter_interpolator_base.cpp new file mode 100644 index 0000000..ad4607a --- /dev/null +++ b/third_party/rive/source/generated/data_bind/converters/data_converter_interpolator_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/data_bind/converters/data_converter_interpolator_base.hpp" +#include "rive/data_bind/converters/data_converter_interpolator.hpp" + +using namespace rive; + +Core* DataConverterInterpolatorBase::clone() const +{ + auto cloned = new DataConverterInterpolator(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/data_bind/converters/data_converter_number_to_list_base.cpp b/third_party/rive/source/generated/data_bind/converters/data_converter_number_to_list_base.cpp new file mode 100644 index 0000000..7128586 --- /dev/null +++ b/third_party/rive/source/generated/data_bind/converters/data_converter_number_to_list_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/data_bind/converters/data_converter_number_to_list_base.hpp" +#include "rive/data_bind/converters/data_converter_number_to_list.hpp" + +using namespace rive; + +Core* DataConverterNumberToListBase::clone() const +{ + auto cloned = new DataConverterNumberToList(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/data_bind/converters/data_converter_operation_base.cpp b/third_party/rive/source/generated/data_bind/converters/data_converter_operation_base.cpp new file mode 100644 index 0000000..77ee84b --- /dev/null +++ b/third_party/rive/source/generated/data_bind/converters/data_converter_operation_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/data_bind/converters/data_converter_operation_base.hpp" +#include "rive/data_bind/converters/data_converter_operation.hpp" + +using namespace rive; + +Core* DataConverterOperationBase::clone() const +{ + auto cloned = new DataConverterOperation(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/data_bind/converters/data_converter_operation_value_base.cpp b/third_party/rive/source/generated/data_bind/converters/data_converter_operation_value_base.cpp new file mode 100644 index 0000000..27eff2f --- /dev/null +++ b/third_party/rive/source/generated/data_bind/converters/data_converter_operation_value_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/data_bind/converters/data_converter_operation_value_base.hpp" +#include "rive/data_bind/converters/data_converter_operation_value.hpp" + +using namespace rive; + +Core* DataConverterOperationValueBase::clone() const +{ + auto cloned = new DataConverterOperationValue(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/data_bind/converters/data_converter_operation_viewmodel_base.cpp b/third_party/rive/source/generated/data_bind/converters/data_converter_operation_viewmodel_base.cpp new file mode 100644 index 0000000..54b85a3 --- /dev/null +++ b/third_party/rive/source/generated/data_bind/converters/data_converter_operation_viewmodel_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/data_bind/converters/data_converter_operation_viewmodel_base.hpp" +#include "rive/data_bind/converters/data_converter_operation_viewmodel.hpp" + +using namespace rive; + +Core* DataConverterOperationViewModelBase::clone() const +{ + auto cloned = new DataConverterOperationViewModel(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/data_bind/converters/data_converter_range_mapper_base.cpp b/third_party/rive/source/generated/data_bind/converters/data_converter_range_mapper_base.cpp new file mode 100644 index 0000000..c8b3466 --- /dev/null +++ b/third_party/rive/source/generated/data_bind/converters/data_converter_range_mapper_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/data_bind/converters/data_converter_range_mapper_base.hpp" +#include "rive/data_bind/converters/data_converter_range_mapper.hpp" + +using namespace rive; + +Core* DataConverterRangeMapperBase::clone() const +{ + auto cloned = new DataConverterRangeMapper(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/data_bind/converters/data_converter_rounder_base.cpp b/third_party/rive/source/generated/data_bind/converters/data_converter_rounder_base.cpp new file mode 100644 index 0000000..e6a03a3 --- /dev/null +++ b/third_party/rive/source/generated/data_bind/converters/data_converter_rounder_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/data_bind/converters/data_converter_rounder_base.hpp" +#include "rive/data_bind/converters/data_converter_rounder.hpp" + +using namespace rive; + +Core* DataConverterRounderBase::clone() const +{ + auto cloned = new DataConverterRounder(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/data_bind/converters/data_converter_string_pad_base.cpp b/third_party/rive/source/generated/data_bind/converters/data_converter_string_pad_base.cpp new file mode 100644 index 0000000..112cbeb --- /dev/null +++ b/third_party/rive/source/generated/data_bind/converters/data_converter_string_pad_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/data_bind/converters/data_converter_string_pad_base.hpp" +#include "rive/data_bind/converters/data_converter_string_pad.hpp" + +using namespace rive; + +Core* DataConverterStringPadBase::clone() const +{ + auto cloned = new DataConverterStringPad(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/data_bind/converters/data_converter_string_remove_zeros_base.cpp b/third_party/rive/source/generated/data_bind/converters/data_converter_string_remove_zeros_base.cpp new file mode 100644 index 0000000..9b1cb5a --- /dev/null +++ b/third_party/rive/source/generated/data_bind/converters/data_converter_string_remove_zeros_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/data_bind/converters/data_converter_string_remove_zeros_base.hpp" +#include "rive/data_bind/converters/data_converter_string_remove_zeros.hpp" + +using namespace rive; + +Core* DataConverterStringRemoveZerosBase::clone() const +{ + auto cloned = new DataConverterStringRemoveZeros(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/data_bind/converters/data_converter_string_trim_base.cpp b/third_party/rive/source/generated/data_bind/converters/data_converter_string_trim_base.cpp new file mode 100644 index 0000000..ed5c030 --- /dev/null +++ b/third_party/rive/source/generated/data_bind/converters/data_converter_string_trim_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/data_bind/converters/data_converter_string_trim_base.hpp" +#include "rive/data_bind/converters/data_converter_string_trim.hpp" + +using namespace rive; + +Core* DataConverterStringTrimBase::clone() const +{ + auto cloned = new DataConverterStringTrim(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/data_bind/converters/data_converter_system_degs_to_rads_base.cpp b/third_party/rive/source/generated/data_bind/converters/data_converter_system_degs_to_rads_base.cpp new file mode 100644 index 0000000..38b3611 --- /dev/null +++ b/third_party/rive/source/generated/data_bind/converters/data_converter_system_degs_to_rads_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/data_bind/converters/data_converter_system_degs_to_rads_base.hpp" +#include "rive/data_bind/converters/data_converter_system_degs_to_rads.hpp" + +using namespace rive; + +Core* DataConverterSystemDegsToRadsBase::clone() const +{ + auto cloned = new DataConverterSystemDegsToRads(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/data_bind/converters/data_converter_system_normalizer_base.cpp b/third_party/rive/source/generated/data_bind/converters/data_converter_system_normalizer_base.cpp new file mode 100644 index 0000000..1bb4415 --- /dev/null +++ b/third_party/rive/source/generated/data_bind/converters/data_converter_system_normalizer_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/data_bind/converters/data_converter_system_normalizer_base.hpp" +#include "rive/data_bind/converters/data_converter_system_normalizer.hpp" + +using namespace rive; + +Core* DataConverterSystemNormalizerBase::clone() const +{ + auto cloned = new DataConverterSystemNormalizer(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/data_bind/converters/data_converter_to_string_base.cpp b/third_party/rive/source/generated/data_bind/converters/data_converter_to_string_base.cpp new file mode 100644 index 0000000..c600a8d --- /dev/null +++ b/third_party/rive/source/generated/data_bind/converters/data_converter_to_string_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/data_bind/converters/data_converter_to_string_base.hpp" +#include "rive/data_bind/converters/data_converter_to_string.hpp" + +using namespace rive; + +Core* DataConverterToStringBase::clone() const +{ + auto cloned = new DataConverterToString(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/data_bind/converters/data_converter_trigger_base.cpp b/third_party/rive/source/generated/data_bind/converters/data_converter_trigger_base.cpp new file mode 100644 index 0000000..0fb8dcb --- /dev/null +++ b/third_party/rive/source/generated/data_bind/converters/data_converter_trigger_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/data_bind/converters/data_converter_trigger_base.hpp" +#include "rive/data_bind/converters/data_converter_trigger.hpp" + +using namespace rive; + +Core* DataConverterTriggerBase::clone() const +{ + auto cloned = new DataConverterTrigger(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/data_bind/converters/formula/formula_token_argument_separator_base.cpp b/third_party/rive/source/generated/data_bind/converters/formula/formula_token_argument_separator_base.cpp new file mode 100644 index 0000000..76e96b8 --- /dev/null +++ b/third_party/rive/source/generated/data_bind/converters/formula/formula_token_argument_separator_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/data_bind/converters/formula/formula_token_argument_separator_base.hpp" +#include "rive/data_bind/converters/formula/formula_token_argument_separator.hpp" + +using namespace rive; + +Core* FormulaTokenArgumentSeparatorBase::clone() const +{ + auto cloned = new FormulaTokenArgumentSeparator(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/data_bind/converters/formula/formula_token_base.cpp b/third_party/rive/source/generated/data_bind/converters/formula/formula_token_base.cpp new file mode 100644 index 0000000..69dea2c --- /dev/null +++ b/third_party/rive/source/generated/data_bind/converters/formula/formula_token_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/data_bind/converters/formula/formula_token_base.hpp" +#include "rive/data_bind/converters/formula/formula_token.hpp" + +using namespace rive; + +Core* FormulaTokenBase::clone() const +{ + auto cloned = new FormulaToken(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/data_bind/converters/formula/formula_token_function_base.cpp b/third_party/rive/source/generated/data_bind/converters/formula/formula_token_function_base.cpp new file mode 100644 index 0000000..938ed1d --- /dev/null +++ b/third_party/rive/source/generated/data_bind/converters/formula/formula_token_function_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/data_bind/converters/formula/formula_token_function_base.hpp" +#include "rive/data_bind/converters/formula/formula_token_function.hpp" + +using namespace rive; + +Core* FormulaTokenFunctionBase::clone() const +{ + auto cloned = new FormulaTokenFunction(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/data_bind/converters/formula/formula_token_input_base.cpp b/third_party/rive/source/generated/data_bind/converters/formula/formula_token_input_base.cpp new file mode 100644 index 0000000..b723bfb --- /dev/null +++ b/third_party/rive/source/generated/data_bind/converters/formula/formula_token_input_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/data_bind/converters/formula/formula_token_input_base.hpp" +#include "rive/data_bind/converters/formula/formula_token_input.hpp" + +using namespace rive; + +Core* FormulaTokenInputBase::clone() const +{ + auto cloned = new FormulaTokenInput(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/data_bind/converters/formula/formula_token_operation_base.cpp b/third_party/rive/source/generated/data_bind/converters/formula/formula_token_operation_base.cpp new file mode 100644 index 0000000..39715f6 --- /dev/null +++ b/third_party/rive/source/generated/data_bind/converters/formula/formula_token_operation_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/data_bind/converters/formula/formula_token_operation_base.hpp" +#include "rive/data_bind/converters/formula/formula_token_operation.hpp" + +using namespace rive; + +Core* FormulaTokenOperationBase::clone() const +{ + auto cloned = new FormulaTokenOperation(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/data_bind/converters/formula/formula_token_parenthesis_base.cpp b/third_party/rive/source/generated/data_bind/converters/formula/formula_token_parenthesis_base.cpp new file mode 100644 index 0000000..690a33e --- /dev/null +++ b/third_party/rive/source/generated/data_bind/converters/formula/formula_token_parenthesis_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/data_bind/converters/formula/formula_token_parenthesis_base.hpp" +#include "rive/data_bind/converters/formula/formula_token_parenthesis.hpp" + +using namespace rive; + +Core* FormulaTokenParenthesisBase::clone() const +{ + auto cloned = new FormulaTokenParenthesis(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/data_bind/converters/formula/formula_token_parenthesis_close_base.cpp b/third_party/rive/source/generated/data_bind/converters/formula/formula_token_parenthesis_close_base.cpp new file mode 100644 index 0000000..f7e5926 --- /dev/null +++ b/third_party/rive/source/generated/data_bind/converters/formula/formula_token_parenthesis_close_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/data_bind/converters/formula/formula_token_parenthesis_close_base.hpp" +#include "rive/data_bind/converters/formula/formula_token_parenthesis_close.hpp" + +using namespace rive; + +Core* FormulaTokenParenthesisCloseBase::clone() const +{ + auto cloned = new FormulaTokenParenthesisClose(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/data_bind/converters/formula/formula_token_parenthesis_open_base.cpp b/third_party/rive/source/generated/data_bind/converters/formula/formula_token_parenthesis_open_base.cpp new file mode 100644 index 0000000..36ad205 --- /dev/null +++ b/third_party/rive/source/generated/data_bind/converters/formula/formula_token_parenthesis_open_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/data_bind/converters/formula/formula_token_parenthesis_open_base.hpp" +#include "rive/data_bind/converters/formula/formula_token_parenthesis_open.hpp" + +using namespace rive; + +Core* FormulaTokenParenthesisOpenBase::clone() const +{ + auto cloned = new FormulaTokenParenthesisOpen(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/data_bind/converters/formula/formula_token_value_base.cpp b/third_party/rive/source/generated/data_bind/converters/formula/formula_token_value_base.cpp new file mode 100644 index 0000000..4938293 --- /dev/null +++ b/third_party/rive/source/generated/data_bind/converters/formula/formula_token_value_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/data_bind/converters/formula/formula_token_value_base.hpp" +#include "rive/data_bind/converters/formula/formula_token_value.hpp" + +using namespace rive; + +Core* FormulaTokenValueBase::clone() const +{ + auto cloned = new FormulaTokenValue(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/data_bind/data_bind_base.cpp b/third_party/rive/source/generated/data_bind/data_bind_base.cpp new file mode 100644 index 0000000..cc993f8 --- /dev/null +++ b/third_party/rive/source/generated/data_bind/data_bind_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/data_bind/data_bind_base.hpp" +#include "rive/data_bind/data_bind.hpp" + +using namespace rive; + +Core* DataBindBase::clone() const +{ + auto cloned = new DataBind(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/data_bind/data_bind_context_base.cpp b/third_party/rive/source/generated/data_bind/data_bind_context_base.cpp new file mode 100644 index 0000000..4691f4c --- /dev/null +++ b/third_party/rive/source/generated/data_bind/data_bind_context_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/data_bind/data_bind_context_base.hpp" +#include "rive/data_bind/data_bind_context.hpp" + +using namespace rive; + +Core* DataBindContextBase::clone() const +{ + auto cloned = new DataBindContext(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/draw_rules_base.cpp b/third_party/rive/source/generated/draw_rules_base.cpp new file mode 100644 index 0000000..67b9c81 --- /dev/null +++ b/third_party/rive/source/generated/draw_rules_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/draw_rules_base.hpp" +#include "rive/draw_rules.hpp" + +using namespace rive; + +Core* DrawRulesBase::clone() const +{ + auto cloned = new DrawRules(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/draw_target_base.cpp b/third_party/rive/source/generated/draw_target_base.cpp new file mode 100644 index 0000000..0578be9 --- /dev/null +++ b/third_party/rive/source/generated/draw_target_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/draw_target_base.hpp" +#include "rive/draw_target.hpp" + +using namespace rive; + +Core* DrawTargetBase::clone() const +{ + auto cloned = new DrawTarget(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/event_base.cpp b/third_party/rive/source/generated/event_base.cpp new file mode 100644 index 0000000..1829228 --- /dev/null +++ b/third_party/rive/source/generated/event_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/event_base.hpp" +#include "rive/event.hpp" + +using namespace rive; + +Core* EventBase::clone() const +{ + auto cloned = new Event(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/foreground_layout_drawable_base.cpp b/third_party/rive/source/generated/foreground_layout_drawable_base.cpp new file mode 100644 index 0000000..2e47d6c --- /dev/null +++ b/third_party/rive/source/generated/foreground_layout_drawable_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/foreground_layout_drawable_base.hpp" +#include "rive/foreground_layout_drawable.hpp" + +using namespace rive; + +Core* ForegroundLayoutDrawableBase::clone() const +{ + auto cloned = new ForegroundLayoutDrawable(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/joystick_base.cpp b/third_party/rive/source/generated/joystick_base.cpp new file mode 100644 index 0000000..19e3602 --- /dev/null +++ b/third_party/rive/source/generated/joystick_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/joystick_base.hpp" +#include "rive/joystick.hpp" + +using namespace rive; + +Core* JoystickBase::clone() const +{ + auto cloned = new Joystick(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/layout/axis_x_base.cpp b/third_party/rive/source/generated/layout/axis_x_base.cpp new file mode 100644 index 0000000..172c284 --- /dev/null +++ b/third_party/rive/source/generated/layout/axis_x_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/layout/axis_x_base.hpp" +#include "rive/layout/axis_x.hpp" + +using namespace rive; + +Core* AxisXBase::clone() const +{ + auto cloned = new AxisX(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/layout/axis_y_base.cpp b/third_party/rive/source/generated/layout/axis_y_base.cpp new file mode 100644 index 0000000..8815cef --- /dev/null +++ b/third_party/rive/source/generated/layout/axis_y_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/layout/axis_y_base.hpp" +#include "rive/layout/axis_y.hpp" + +using namespace rive; + +Core* AxisYBase::clone() const +{ + auto cloned = new AxisY(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/layout/layout_component_style_base.cpp b/third_party/rive/source/generated/layout/layout_component_style_base.cpp new file mode 100644 index 0000000..22c4da8 --- /dev/null +++ b/third_party/rive/source/generated/layout/layout_component_style_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/layout/layout_component_style_base.hpp" +#include "rive/layout/layout_component_style.hpp" + +using namespace rive; + +Core* LayoutComponentStyleBase::clone() const +{ + auto cloned = new LayoutComponentStyle(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/layout/n_sliced_node_base.cpp b/third_party/rive/source/generated/layout/n_sliced_node_base.cpp new file mode 100644 index 0000000..47fb47e --- /dev/null +++ b/third_party/rive/source/generated/layout/n_sliced_node_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/layout/n_sliced_node_base.hpp" +#include "rive/layout/n_sliced_node.hpp" + +using namespace rive; + +Core* NSlicedNodeBase::clone() const +{ + auto cloned = new NSlicedNode(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/layout/n_slicer_base.cpp b/third_party/rive/source/generated/layout/n_slicer_base.cpp new file mode 100644 index 0000000..49d6f37 --- /dev/null +++ b/third_party/rive/source/generated/layout/n_slicer_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/layout/n_slicer_base.hpp" +#include "rive/layout/n_slicer.hpp" + +using namespace rive; + +Core* NSlicerBase::clone() const +{ + auto cloned = new NSlicer(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/layout/n_slicer_tile_mode_base.cpp b/third_party/rive/source/generated/layout/n_slicer_tile_mode_base.cpp new file mode 100644 index 0000000..068c59c --- /dev/null +++ b/third_party/rive/source/generated/layout/n_slicer_tile_mode_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/layout/n_slicer_tile_mode_base.hpp" +#include "rive/layout/n_slicer_tile_mode.hpp" + +using namespace rive; + +Core* NSlicerTileModeBase::clone() const +{ + auto cloned = new NSlicerTileMode(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/layout_component_base.cpp b/third_party/rive/source/generated/layout_component_base.cpp new file mode 100644 index 0000000..13e6c86 --- /dev/null +++ b/third_party/rive/source/generated/layout_component_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/layout_component_base.hpp" +#include "rive/layout_component.hpp" + +using namespace rive; + +Core* LayoutComponentBase::clone() const +{ + auto cloned = new LayoutComponent(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/nested_artboard_base.cpp b/third_party/rive/source/generated/nested_artboard_base.cpp new file mode 100644 index 0000000..46a277e --- /dev/null +++ b/third_party/rive/source/generated/nested_artboard_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/nested_artboard_base.hpp" +#include "rive/nested_artboard.hpp" + +using namespace rive; + +Core* NestedArtboardBase::clone() const +{ + auto cloned = new NestedArtboard(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/nested_artboard_layout_base.cpp b/third_party/rive/source/generated/nested_artboard_layout_base.cpp new file mode 100644 index 0000000..069c374 --- /dev/null +++ b/third_party/rive/source/generated/nested_artboard_layout_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/nested_artboard_layout_base.hpp" +#include "rive/nested_artboard_layout.hpp" + +using namespace rive; + +Core* NestedArtboardLayoutBase::clone() const +{ + auto cloned = new NestedArtboardLayout(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/nested_artboard_leaf_base.cpp b/third_party/rive/source/generated/nested_artboard_leaf_base.cpp new file mode 100644 index 0000000..d025a17 --- /dev/null +++ b/third_party/rive/source/generated/nested_artboard_leaf_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/nested_artboard_leaf_base.hpp" +#include "rive/nested_artboard_leaf.hpp" + +using namespace rive; + +Core* NestedArtboardLeafBase::clone() const +{ + auto cloned = new NestedArtboardLeaf(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/node_base.cpp b/third_party/rive/source/generated/node_base.cpp new file mode 100644 index 0000000..7f144d5 --- /dev/null +++ b/third_party/rive/source/generated/node_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/node_base.hpp" +#include "rive/node.hpp" + +using namespace rive; + +Core* NodeBase::clone() const +{ + auto cloned = new Node(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/open_url_event_base.cpp b/third_party/rive/source/generated/open_url_event_base.cpp new file mode 100644 index 0000000..6c7735d --- /dev/null +++ b/third_party/rive/source/generated/open_url_event_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/open_url_event_base.hpp" +#include "rive/open_url_event.hpp" + +using namespace rive; + +Core* OpenUrlEventBase::clone() const +{ + auto cloned = new OpenUrlEvent(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/shapes/clipping_shape_base.cpp b/third_party/rive/source/generated/shapes/clipping_shape_base.cpp new file mode 100644 index 0000000..2c28b3a --- /dev/null +++ b/third_party/rive/source/generated/shapes/clipping_shape_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/shapes/clipping_shape_base.hpp" +#include "rive/shapes/clipping_shape.hpp" + +using namespace rive; + +Core* ClippingShapeBase::clone() const +{ + auto cloned = new ClippingShape(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/shapes/contour_mesh_vertex_base.cpp b/third_party/rive/source/generated/shapes/contour_mesh_vertex_base.cpp new file mode 100644 index 0000000..8ced9fd --- /dev/null +++ b/third_party/rive/source/generated/shapes/contour_mesh_vertex_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/shapes/contour_mesh_vertex_base.hpp" +#include "rive/shapes/contour_mesh_vertex.hpp" + +using namespace rive; + +Core* ContourMeshVertexBase::clone() const +{ + auto cloned = new ContourMeshVertex(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/shapes/cubic_asymmetric_vertex_base.cpp b/third_party/rive/source/generated/shapes/cubic_asymmetric_vertex_base.cpp new file mode 100644 index 0000000..62b665a --- /dev/null +++ b/third_party/rive/source/generated/shapes/cubic_asymmetric_vertex_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/shapes/cubic_asymmetric_vertex_base.hpp" +#include "rive/shapes/cubic_asymmetric_vertex.hpp" + +using namespace rive; + +Core* CubicAsymmetricVertexBase::clone() const +{ + auto cloned = new CubicAsymmetricVertex(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/shapes/cubic_detached_vertex_base.cpp b/third_party/rive/source/generated/shapes/cubic_detached_vertex_base.cpp new file mode 100644 index 0000000..22f88ba --- /dev/null +++ b/third_party/rive/source/generated/shapes/cubic_detached_vertex_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/shapes/cubic_detached_vertex_base.hpp" +#include "rive/shapes/cubic_detached_vertex.hpp" + +using namespace rive; + +Core* CubicDetachedVertexBase::clone() const +{ + auto cloned = new CubicDetachedVertex(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/shapes/cubic_mirrored_vertex_base.cpp b/third_party/rive/source/generated/shapes/cubic_mirrored_vertex_base.cpp new file mode 100644 index 0000000..fb1731b --- /dev/null +++ b/third_party/rive/source/generated/shapes/cubic_mirrored_vertex_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/shapes/cubic_mirrored_vertex_base.hpp" +#include "rive/shapes/cubic_mirrored_vertex.hpp" + +using namespace rive; + +Core* CubicMirroredVertexBase::clone() const +{ + auto cloned = new CubicMirroredVertex(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/shapes/ellipse_base.cpp b/third_party/rive/source/generated/shapes/ellipse_base.cpp new file mode 100644 index 0000000..df160bb --- /dev/null +++ b/third_party/rive/source/generated/shapes/ellipse_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/shapes/ellipse_base.hpp" +#include "rive/shapes/ellipse.hpp" + +using namespace rive; + +Core* EllipseBase::clone() const +{ + auto cloned = new Ellipse(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/shapes/image_base.cpp b/third_party/rive/source/generated/shapes/image_base.cpp new file mode 100644 index 0000000..60bb78e --- /dev/null +++ b/third_party/rive/source/generated/shapes/image_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/shapes/image_base.hpp" +#include "rive/shapes/image.hpp" + +using namespace rive; + +Core* ImageBase::clone() const +{ + auto cloned = new Image(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/shapes/mesh_base.cpp b/third_party/rive/source/generated/shapes/mesh_base.cpp new file mode 100644 index 0000000..e30a683 --- /dev/null +++ b/third_party/rive/source/generated/shapes/mesh_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/shapes/mesh_base.hpp" +#include "rive/shapes/mesh.hpp" + +using namespace rive; + +Core* MeshBase::clone() const +{ + auto cloned = new Mesh(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/shapes/mesh_vertex_base.cpp b/third_party/rive/source/generated/shapes/mesh_vertex_base.cpp new file mode 100644 index 0000000..ff36262 --- /dev/null +++ b/third_party/rive/source/generated/shapes/mesh_vertex_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/shapes/mesh_vertex_base.hpp" +#include "rive/shapes/mesh_vertex.hpp" + +using namespace rive; + +Core* MeshVertexBase::clone() const +{ + auto cloned = new MeshVertex(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/shapes/paint/dash_base.cpp b/third_party/rive/source/generated/shapes/paint/dash_base.cpp new file mode 100644 index 0000000..81e71ac --- /dev/null +++ b/third_party/rive/source/generated/shapes/paint/dash_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/shapes/paint/dash_base.hpp" +#include "rive/shapes/paint/dash.hpp" + +using namespace rive; + +Core* DashBase::clone() const +{ + auto cloned = new Dash(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/shapes/paint/dash_path_base.cpp b/third_party/rive/source/generated/shapes/paint/dash_path_base.cpp new file mode 100644 index 0000000..8211cad --- /dev/null +++ b/third_party/rive/source/generated/shapes/paint/dash_path_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/shapes/paint/dash_path_base.hpp" +#include "rive/shapes/paint/dash_path.hpp" + +using namespace rive; + +Core* DashPathBase::clone() const +{ + auto cloned = new DashPath(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/shapes/paint/feather_base.cpp b/third_party/rive/source/generated/shapes/paint/feather_base.cpp new file mode 100644 index 0000000..f4f5f19 --- /dev/null +++ b/third_party/rive/source/generated/shapes/paint/feather_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/shapes/paint/feather_base.hpp" +#include "rive/shapes/paint/feather.hpp" + +using namespace rive; + +Core* FeatherBase::clone() const +{ + auto cloned = new Feather(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/shapes/paint/fill_base.cpp b/third_party/rive/source/generated/shapes/paint/fill_base.cpp new file mode 100644 index 0000000..1b2dbbc --- /dev/null +++ b/third_party/rive/source/generated/shapes/paint/fill_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/shapes/paint/fill_base.hpp" +#include "rive/shapes/paint/fill.hpp" + +using namespace rive; + +Core* FillBase::clone() const +{ + auto cloned = new Fill(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/shapes/paint/gradient_stop_base.cpp b/third_party/rive/source/generated/shapes/paint/gradient_stop_base.cpp new file mode 100644 index 0000000..0ff71eb --- /dev/null +++ b/third_party/rive/source/generated/shapes/paint/gradient_stop_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/shapes/paint/gradient_stop_base.hpp" +#include "rive/shapes/paint/gradient_stop.hpp" + +using namespace rive; + +Core* GradientStopBase::clone() const +{ + auto cloned = new GradientStop(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/shapes/paint/linear_gradient_base.cpp b/third_party/rive/source/generated/shapes/paint/linear_gradient_base.cpp new file mode 100644 index 0000000..ad261e7 --- /dev/null +++ b/third_party/rive/source/generated/shapes/paint/linear_gradient_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/shapes/paint/linear_gradient_base.hpp" +#include "rive/shapes/paint/linear_gradient.hpp" + +using namespace rive; + +Core* LinearGradientBase::clone() const +{ + auto cloned = new LinearGradient(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/shapes/paint/radial_gradient_base.cpp b/third_party/rive/source/generated/shapes/paint/radial_gradient_base.cpp new file mode 100644 index 0000000..79b00d6 --- /dev/null +++ b/third_party/rive/source/generated/shapes/paint/radial_gradient_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/shapes/paint/radial_gradient_base.hpp" +#include "rive/shapes/paint/radial_gradient.hpp" + +using namespace rive; + +Core* RadialGradientBase::clone() const +{ + auto cloned = new RadialGradient(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/shapes/paint/solid_color_base.cpp b/third_party/rive/source/generated/shapes/paint/solid_color_base.cpp new file mode 100644 index 0000000..df57f7f --- /dev/null +++ b/third_party/rive/source/generated/shapes/paint/solid_color_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/shapes/paint/solid_color_base.hpp" +#include "rive/shapes/paint/solid_color.hpp" + +using namespace rive; + +Core* SolidColorBase::clone() const +{ + auto cloned = new SolidColor(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/shapes/paint/stroke_base.cpp b/third_party/rive/source/generated/shapes/paint/stroke_base.cpp new file mode 100644 index 0000000..0c3acba --- /dev/null +++ b/third_party/rive/source/generated/shapes/paint/stroke_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/shapes/paint/stroke_base.hpp" +#include "rive/shapes/paint/stroke.hpp" + +using namespace rive; + +Core* StrokeBase::clone() const +{ + auto cloned = new Stroke(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/shapes/paint/trim_path_base.cpp b/third_party/rive/source/generated/shapes/paint/trim_path_base.cpp new file mode 100644 index 0000000..fb319ca --- /dev/null +++ b/third_party/rive/source/generated/shapes/paint/trim_path_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/shapes/paint/trim_path_base.hpp" +#include "rive/shapes/paint/trim_path.hpp" + +using namespace rive; + +Core* TrimPathBase::clone() const +{ + auto cloned = new TrimPath(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/shapes/points_path_base.cpp b/third_party/rive/source/generated/shapes/points_path_base.cpp new file mode 100644 index 0000000..27169a8 --- /dev/null +++ b/third_party/rive/source/generated/shapes/points_path_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/shapes/points_path_base.hpp" +#include "rive/shapes/points_path.hpp" + +using namespace rive; + +Core* PointsPathBase::clone() const +{ + auto cloned = new PointsPath(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/shapes/polygon_base.cpp b/third_party/rive/source/generated/shapes/polygon_base.cpp new file mode 100644 index 0000000..96214c5 --- /dev/null +++ b/third_party/rive/source/generated/shapes/polygon_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/shapes/polygon_base.hpp" +#include "rive/shapes/polygon.hpp" + +using namespace rive; + +Core* PolygonBase::clone() const +{ + auto cloned = new Polygon(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/shapes/rectangle_base.cpp b/third_party/rive/source/generated/shapes/rectangle_base.cpp new file mode 100644 index 0000000..47a83fe --- /dev/null +++ b/third_party/rive/source/generated/shapes/rectangle_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/shapes/rectangle_base.hpp" +#include "rive/shapes/rectangle.hpp" + +using namespace rive; + +Core* RectangleBase::clone() const +{ + auto cloned = new Rectangle(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/shapes/shape_base.cpp b/third_party/rive/source/generated/shapes/shape_base.cpp new file mode 100644 index 0000000..595afa6 --- /dev/null +++ b/third_party/rive/source/generated/shapes/shape_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/shapes/shape_base.hpp" +#include "rive/shapes/shape.hpp" + +using namespace rive; + +Core* ShapeBase::clone() const +{ + auto cloned = new Shape(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/shapes/star_base.cpp b/third_party/rive/source/generated/shapes/star_base.cpp new file mode 100644 index 0000000..3b753c2 --- /dev/null +++ b/third_party/rive/source/generated/shapes/star_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/shapes/star_base.hpp" +#include "rive/shapes/star.hpp" + +using namespace rive; + +Core* StarBase::clone() const +{ + auto cloned = new Star(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/shapes/straight_vertex_base.cpp b/third_party/rive/source/generated/shapes/straight_vertex_base.cpp new file mode 100644 index 0000000..a7c99c1 --- /dev/null +++ b/third_party/rive/source/generated/shapes/straight_vertex_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/shapes/straight_vertex_base.hpp" +#include "rive/shapes/straight_vertex.hpp" + +using namespace rive; + +Core* StraightVertexBase::clone() const +{ + auto cloned = new StraightVertex(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/shapes/triangle_base.cpp b/third_party/rive/source/generated/shapes/triangle_base.cpp new file mode 100644 index 0000000..c4f7e95 --- /dev/null +++ b/third_party/rive/source/generated/shapes/triangle_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/shapes/triangle_base.hpp" +#include "rive/shapes/triangle.hpp" + +using namespace rive; + +Core* TriangleBase::clone() const +{ + auto cloned = new Triangle(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/solo_base.cpp b/third_party/rive/source/generated/solo_base.cpp new file mode 100644 index 0000000..132eb74 --- /dev/null +++ b/third_party/rive/source/generated/solo_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/solo_base.hpp" +#include "rive/solo.hpp" + +using namespace rive; + +Core* SoloBase::clone() const +{ + auto cloned = new Solo(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/text/text_base.cpp b/third_party/rive/source/generated/text/text_base.cpp new file mode 100644 index 0000000..7c34405 --- /dev/null +++ b/third_party/rive/source/generated/text/text_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/text/text_base.hpp" +#include "rive/text/text.hpp" + +using namespace rive; + +Core* TextBase::clone() const +{ + auto cloned = new Text(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/text/text_follow_path_modifier_base.cpp b/third_party/rive/source/generated/text/text_follow_path_modifier_base.cpp new file mode 100644 index 0000000..130bc89 --- /dev/null +++ b/third_party/rive/source/generated/text/text_follow_path_modifier_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/text/text_follow_path_modifier_base.hpp" +#include "rive/text/text_follow_path_modifier.hpp" + +using namespace rive; + +Core* TextFollowPathModifierBase::clone() const +{ + auto cloned = new TextFollowPathModifier(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/text/text_input_base.cpp b/third_party/rive/source/generated/text/text_input_base.cpp new file mode 100644 index 0000000..7137c7a --- /dev/null +++ b/third_party/rive/source/generated/text/text_input_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/text/text_input_base.hpp" +#include "rive/text/text_input.hpp" + +using namespace rive; + +Core* TextInputBase::clone() const +{ + auto cloned = new TextInput(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/text/text_input_cursor_base.cpp b/third_party/rive/source/generated/text/text_input_cursor_base.cpp new file mode 100644 index 0000000..6624b53 --- /dev/null +++ b/third_party/rive/source/generated/text/text_input_cursor_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/text/text_input_cursor_base.hpp" +#include "rive/text/text_input_cursor.hpp" + +using namespace rive; + +Core* TextInputCursorBase::clone() const +{ + auto cloned = new TextInputCursor(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/text/text_input_selected_text_base.cpp b/third_party/rive/source/generated/text/text_input_selected_text_base.cpp new file mode 100644 index 0000000..2aad309 --- /dev/null +++ b/third_party/rive/source/generated/text/text_input_selected_text_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/text/text_input_selected_text_base.hpp" +#include "rive/text/text_input_selected_text.hpp" + +using namespace rive; + +Core* TextInputSelectedTextBase::clone() const +{ + auto cloned = new TextInputSelectedText(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/text/text_input_selection_base.cpp b/third_party/rive/source/generated/text/text_input_selection_base.cpp new file mode 100644 index 0000000..29424af --- /dev/null +++ b/third_party/rive/source/generated/text/text_input_selection_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/text/text_input_selection_base.hpp" +#include "rive/text/text_input_selection.hpp" + +using namespace rive; + +Core* TextInputSelectionBase::clone() const +{ + auto cloned = new TextInputSelection(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/text/text_input_text_base.cpp b/third_party/rive/source/generated/text/text_input_text_base.cpp new file mode 100644 index 0000000..48d0344 --- /dev/null +++ b/third_party/rive/source/generated/text/text_input_text_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/text/text_input_text_base.hpp" +#include "rive/text/text_input_text.hpp" + +using namespace rive; + +Core* TextInputTextBase::clone() const +{ + auto cloned = new TextInputText(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/text/text_modifier_group_base.cpp b/third_party/rive/source/generated/text/text_modifier_group_base.cpp new file mode 100644 index 0000000..cc74e27 --- /dev/null +++ b/third_party/rive/source/generated/text/text_modifier_group_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/text/text_modifier_group_base.hpp" +#include "rive/text/text_modifier_group.hpp" + +using namespace rive; + +Core* TextModifierGroupBase::clone() const +{ + auto cloned = new TextModifierGroup(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/text/text_modifier_range_base.cpp b/third_party/rive/source/generated/text/text_modifier_range_base.cpp new file mode 100644 index 0000000..c144981 --- /dev/null +++ b/third_party/rive/source/generated/text/text_modifier_range_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/text/text_modifier_range_base.hpp" +#include "rive/text/text_modifier_range.hpp" + +using namespace rive; + +Core* TextModifierRangeBase::clone() const +{ + auto cloned = new TextModifierRange(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/text/text_style_axis_base.cpp b/third_party/rive/source/generated/text/text_style_axis_base.cpp new file mode 100644 index 0000000..9f32f7f --- /dev/null +++ b/third_party/rive/source/generated/text/text_style_axis_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/text/text_style_axis_base.hpp" +#include "rive/text/text_style_axis.hpp" + +using namespace rive; + +Core* TextStyleAxisBase::clone() const +{ + auto cloned = new TextStyleAxis(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/text/text_style_base.cpp b/third_party/rive/source/generated/text/text_style_base.cpp new file mode 100644 index 0000000..4fa7bcc --- /dev/null +++ b/third_party/rive/source/generated/text/text_style_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/text/text_style_base.hpp" +#include "rive/text/text_style.hpp" + +using namespace rive; + +Core* TextStyleBase::clone() const +{ + auto cloned = new TextStyle(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/text/text_style_feature_base.cpp b/third_party/rive/source/generated/text/text_style_feature_base.cpp new file mode 100644 index 0000000..7f5f9b7 --- /dev/null +++ b/third_party/rive/source/generated/text/text_style_feature_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/text/text_style_feature_base.hpp" +#include "rive/text/text_style_feature.hpp" + +using namespace rive; + +Core* TextStyleFeatureBase::clone() const +{ + auto cloned = new TextStyleFeature(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/text/text_style_paint_base.cpp b/third_party/rive/source/generated/text/text_style_paint_base.cpp new file mode 100644 index 0000000..77a3a5a --- /dev/null +++ b/third_party/rive/source/generated/text/text_style_paint_base.cpp @@ -0,0 +1,12 @@ +#include "rive/generated/text/text_style_paint_base.hpp" +#include "rive/text/text_style_paint.hpp" +#include "rive/text/text_variation_helper.hpp" + +using namespace rive; + +Core* TextStylePaintBase::clone() const +{ + auto cloned = new TextStylePaint(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/text/text_value_run_base.cpp b/third_party/rive/source/generated/text/text_value_run_base.cpp new file mode 100644 index 0000000..732cc3b --- /dev/null +++ b/third_party/rive/source/generated/text/text_value_run_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/text/text_value_run_base.hpp" +#include "rive/text/text_value_run.hpp" + +using namespace rive; + +Core* TextValueRunBase::clone() const +{ + auto cloned = new TextValueRun(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/text/text_variation_modifier_base.cpp b/third_party/rive/source/generated/text/text_variation_modifier_base.cpp new file mode 100644 index 0000000..02a3007 --- /dev/null +++ b/third_party/rive/source/generated/text/text_variation_modifier_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/text/text_variation_modifier_base.hpp" +#include "rive/text/text_variation_modifier.hpp" + +using namespace rive; + +Core* TextVariationModifierBase::clone() const +{ + auto cloned = new TextVariationModifier(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/viewmodel/data_enum_base.cpp b/third_party/rive/source/generated/viewmodel/data_enum_base.cpp new file mode 100644 index 0000000..9ac0ef0 --- /dev/null +++ b/third_party/rive/source/generated/viewmodel/data_enum_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/viewmodel/data_enum_base.hpp" +#include "rive/viewmodel/data_enum.hpp" + +using namespace rive; + +Core* DataEnumBase::clone() const +{ + auto cloned = new DataEnum(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/viewmodel/data_enum_custom_base.cpp b/third_party/rive/source/generated/viewmodel/data_enum_custom_base.cpp new file mode 100644 index 0000000..4b065f0 --- /dev/null +++ b/third_party/rive/source/generated/viewmodel/data_enum_custom_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/viewmodel/data_enum_custom_base.hpp" +#include "rive/viewmodel/data_enum_custom.hpp" + +using namespace rive; + +Core* DataEnumCustomBase::clone() const +{ + auto cloned = new DataEnumCustom(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/viewmodel/data_enum_system_base.cpp b/third_party/rive/source/generated/viewmodel/data_enum_system_base.cpp new file mode 100644 index 0000000..f7a0949 --- /dev/null +++ b/third_party/rive/source/generated/viewmodel/data_enum_system_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/viewmodel/data_enum_system_base.hpp" +#include "rive/viewmodel/data_enum_system.hpp" + +using namespace rive; + +Core* DataEnumSystemBase::clone() const +{ + auto cloned = new DataEnumSystem(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/viewmodel/data_enum_value_base.cpp b/third_party/rive/source/generated/viewmodel/data_enum_value_base.cpp new file mode 100644 index 0000000..f695edc --- /dev/null +++ b/third_party/rive/source/generated/viewmodel/data_enum_value_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/viewmodel/data_enum_value_base.hpp" +#include "rive/viewmodel/data_enum_value.hpp" + +using namespace rive; + +Core* DataEnumValueBase::clone() const +{ + auto cloned = new DataEnumValue(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/viewmodel/viewmodel_base.cpp b/third_party/rive/source/generated/viewmodel/viewmodel_base.cpp new file mode 100644 index 0000000..87e7f7a --- /dev/null +++ b/third_party/rive/source/generated/viewmodel/viewmodel_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/viewmodel/viewmodel_base.hpp" +#include "rive/viewmodel/viewmodel.hpp" + +using namespace rive; + +Core* ViewModelBase::clone() const +{ + auto cloned = new ViewModel(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/viewmodel/viewmodel_component_base.cpp b/third_party/rive/source/generated/viewmodel/viewmodel_component_base.cpp new file mode 100644 index 0000000..706138b --- /dev/null +++ b/third_party/rive/source/generated/viewmodel/viewmodel_component_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/viewmodel/viewmodel_component_base.hpp" +#include "rive/viewmodel/viewmodel_component.hpp" + +using namespace rive; + +Core* ViewModelComponentBase::clone() const +{ + auto cloned = new ViewModelComponent(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/viewmodel/viewmodel_instance_asset_base.cpp b/third_party/rive/source/generated/viewmodel/viewmodel_instance_asset_base.cpp new file mode 100644 index 0000000..49070d1 --- /dev/null +++ b/third_party/rive/source/generated/viewmodel/viewmodel_instance_asset_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/viewmodel/viewmodel_instance_asset_base.hpp" +#include "rive/viewmodel/viewmodel_instance_asset.hpp" + +using namespace rive; + +Core* ViewModelInstanceAssetBase::clone() const +{ + auto cloned = new ViewModelInstanceAsset(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/viewmodel/viewmodel_instance_asset_image_base.cpp b/third_party/rive/source/generated/viewmodel/viewmodel_instance_asset_image_base.cpp new file mode 100644 index 0000000..1835a96 --- /dev/null +++ b/third_party/rive/source/generated/viewmodel/viewmodel_instance_asset_image_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/viewmodel/viewmodel_instance_asset_image_base.hpp" +#include "rive/viewmodel/viewmodel_instance_asset_image.hpp" + +using namespace rive; + +Core* ViewModelInstanceAssetImageBase::clone() const +{ + auto cloned = new ViewModelInstanceAssetImage(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/viewmodel/viewmodel_instance_base.cpp b/third_party/rive/source/generated/viewmodel/viewmodel_instance_base.cpp new file mode 100644 index 0000000..892eba0 --- /dev/null +++ b/third_party/rive/source/generated/viewmodel/viewmodel_instance_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/viewmodel/viewmodel_instance_base.hpp" +#include "rive/viewmodel/viewmodel_instance.hpp" + +using namespace rive; + +Core* ViewModelInstanceBase::clone() const +{ + auto cloned = new ViewModelInstance(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/viewmodel/viewmodel_instance_boolean_base.cpp b/third_party/rive/source/generated/viewmodel/viewmodel_instance_boolean_base.cpp new file mode 100644 index 0000000..641bfec --- /dev/null +++ b/third_party/rive/source/generated/viewmodel/viewmodel_instance_boolean_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/viewmodel/viewmodel_instance_boolean_base.hpp" +#include "rive/viewmodel/viewmodel_instance_boolean.hpp" + +using namespace rive; + +Core* ViewModelInstanceBooleanBase::clone() const +{ + auto cloned = new ViewModelInstanceBoolean(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/viewmodel/viewmodel_instance_color_base.cpp b/third_party/rive/source/generated/viewmodel/viewmodel_instance_color_base.cpp new file mode 100644 index 0000000..599a25d --- /dev/null +++ b/third_party/rive/source/generated/viewmodel/viewmodel_instance_color_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/viewmodel/viewmodel_instance_color_base.hpp" +#include "rive/viewmodel/viewmodel_instance_color.hpp" + +using namespace rive; + +Core* ViewModelInstanceColorBase::clone() const +{ + auto cloned = new ViewModelInstanceColor(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/viewmodel/viewmodel_instance_enum_base.cpp b/third_party/rive/source/generated/viewmodel/viewmodel_instance_enum_base.cpp new file mode 100644 index 0000000..3937d48 --- /dev/null +++ b/third_party/rive/source/generated/viewmodel/viewmodel_instance_enum_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/viewmodel/viewmodel_instance_enum_base.hpp" +#include "rive/viewmodel/viewmodel_instance_enum.hpp" + +using namespace rive; + +Core* ViewModelInstanceEnumBase::clone() const +{ + auto cloned = new ViewModelInstanceEnum(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/viewmodel/viewmodel_instance_list_base.cpp b/third_party/rive/source/generated/viewmodel/viewmodel_instance_list_base.cpp new file mode 100644 index 0000000..b73c5a6 --- /dev/null +++ b/third_party/rive/source/generated/viewmodel/viewmodel_instance_list_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/viewmodel/viewmodel_instance_list_base.hpp" +#include "rive/viewmodel/viewmodel_instance_list.hpp" + +using namespace rive; + +Core* ViewModelInstanceListBase::clone() const +{ + auto cloned = new ViewModelInstanceList(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/viewmodel/viewmodel_instance_list_item_base.cpp b/third_party/rive/source/generated/viewmodel/viewmodel_instance_list_item_base.cpp new file mode 100644 index 0000000..b327aad --- /dev/null +++ b/third_party/rive/source/generated/viewmodel/viewmodel_instance_list_item_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/viewmodel/viewmodel_instance_list_item_base.hpp" +#include "rive/viewmodel/viewmodel_instance_list_item.hpp" + +using namespace rive; + +Core* ViewModelInstanceListItemBase::clone() const +{ + auto cloned = new ViewModelInstanceListItem(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/viewmodel/viewmodel_instance_number_base.cpp b/third_party/rive/source/generated/viewmodel/viewmodel_instance_number_base.cpp new file mode 100644 index 0000000..6ac41a5 --- /dev/null +++ b/third_party/rive/source/generated/viewmodel/viewmodel_instance_number_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/viewmodel/viewmodel_instance_number_base.hpp" +#include "rive/viewmodel/viewmodel_instance_number.hpp" + +using namespace rive; + +Core* ViewModelInstanceNumberBase::clone() const +{ + auto cloned = new ViewModelInstanceNumber(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/viewmodel/viewmodel_instance_string_base.cpp b/third_party/rive/source/generated/viewmodel/viewmodel_instance_string_base.cpp new file mode 100644 index 0000000..ce48839 --- /dev/null +++ b/third_party/rive/source/generated/viewmodel/viewmodel_instance_string_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/viewmodel/viewmodel_instance_string_base.hpp" +#include "rive/viewmodel/viewmodel_instance_string.hpp" + +using namespace rive; + +Core* ViewModelInstanceStringBase::clone() const +{ + auto cloned = new ViewModelInstanceString(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/viewmodel/viewmodel_instance_symbol_list_index_base.cpp b/third_party/rive/source/generated/viewmodel/viewmodel_instance_symbol_list_index_base.cpp new file mode 100644 index 0000000..6ca252c --- /dev/null +++ b/third_party/rive/source/generated/viewmodel/viewmodel_instance_symbol_list_index_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/viewmodel/viewmodel_instance_symbol_list_index_base.hpp" +#include "rive/viewmodel/viewmodel_instance_symbol_list_index.hpp" + +using namespace rive; + +Core* ViewModelInstanceSymbolListIndexBase::clone() const +{ + auto cloned = new ViewModelInstanceSymbolListIndex(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/viewmodel/viewmodel_instance_trigger_base.cpp b/third_party/rive/source/generated/viewmodel/viewmodel_instance_trigger_base.cpp new file mode 100644 index 0000000..6d462f9 --- /dev/null +++ b/third_party/rive/source/generated/viewmodel/viewmodel_instance_trigger_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/viewmodel/viewmodel_instance_trigger_base.hpp" +#include "rive/viewmodel/viewmodel_instance_trigger.hpp" + +using namespace rive; + +Core* ViewModelInstanceTriggerBase::clone() const +{ + auto cloned = new ViewModelInstanceTrigger(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/viewmodel/viewmodel_instance_viewmodel_base.cpp b/third_party/rive/source/generated/viewmodel/viewmodel_instance_viewmodel_base.cpp new file mode 100644 index 0000000..b0854a0 --- /dev/null +++ b/third_party/rive/source/generated/viewmodel/viewmodel_instance_viewmodel_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/viewmodel/viewmodel_instance_viewmodel_base.hpp" +#include "rive/viewmodel/viewmodel_instance_viewmodel.hpp" + +using namespace rive; + +Core* ViewModelInstanceViewModelBase::clone() const +{ + auto cloned = new ViewModelInstanceViewModel(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/viewmodel/viewmodel_property_asset_base.cpp b/third_party/rive/source/generated/viewmodel/viewmodel_property_asset_base.cpp new file mode 100644 index 0000000..2233e0f --- /dev/null +++ b/third_party/rive/source/generated/viewmodel/viewmodel_property_asset_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/viewmodel/viewmodel_property_asset_base.hpp" +#include "rive/viewmodel/viewmodel_property_asset.hpp" + +using namespace rive; + +Core* ViewModelPropertyAssetBase::clone() const +{ + auto cloned = new ViewModelPropertyAsset(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/viewmodel/viewmodel_property_asset_image_base.cpp b/third_party/rive/source/generated/viewmodel/viewmodel_property_asset_image_base.cpp new file mode 100644 index 0000000..89c55db --- /dev/null +++ b/third_party/rive/source/generated/viewmodel/viewmodel_property_asset_image_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/viewmodel/viewmodel_property_asset_image_base.hpp" +#include "rive/viewmodel/viewmodel_property_asset_image.hpp" + +using namespace rive; + +Core* ViewModelPropertyAssetImageBase::clone() const +{ + auto cloned = new ViewModelPropertyAssetImage(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/viewmodel/viewmodel_property_base.cpp b/third_party/rive/source/generated/viewmodel/viewmodel_property_base.cpp new file mode 100644 index 0000000..333ffa8 --- /dev/null +++ b/third_party/rive/source/generated/viewmodel/viewmodel_property_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/viewmodel/viewmodel_property_base.hpp" +#include "rive/viewmodel/viewmodel_property.hpp" + +using namespace rive; + +Core* ViewModelPropertyBase::clone() const +{ + auto cloned = new ViewModelProperty(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/viewmodel/viewmodel_property_boolean_base.cpp b/third_party/rive/source/generated/viewmodel/viewmodel_property_boolean_base.cpp new file mode 100644 index 0000000..0371e8c --- /dev/null +++ b/third_party/rive/source/generated/viewmodel/viewmodel_property_boolean_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/viewmodel/viewmodel_property_boolean_base.hpp" +#include "rive/viewmodel/viewmodel_property_boolean.hpp" + +using namespace rive; + +Core* ViewModelPropertyBooleanBase::clone() const +{ + auto cloned = new ViewModelPropertyBoolean(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/viewmodel/viewmodel_property_color_base.cpp b/third_party/rive/source/generated/viewmodel/viewmodel_property_color_base.cpp new file mode 100644 index 0000000..6f3bf82 --- /dev/null +++ b/third_party/rive/source/generated/viewmodel/viewmodel_property_color_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/viewmodel/viewmodel_property_color_base.hpp" +#include "rive/viewmodel/viewmodel_property_color.hpp" + +using namespace rive; + +Core* ViewModelPropertyColorBase::clone() const +{ + auto cloned = new ViewModelPropertyColor(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/viewmodel/viewmodel_property_enum_base.cpp b/third_party/rive/source/generated/viewmodel/viewmodel_property_enum_base.cpp new file mode 100644 index 0000000..5f05b71 --- /dev/null +++ b/third_party/rive/source/generated/viewmodel/viewmodel_property_enum_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/viewmodel/viewmodel_property_enum_base.hpp" +#include "rive/viewmodel/viewmodel_property_enum.hpp" + +using namespace rive; + +Core* ViewModelPropertyEnumBase::clone() const +{ + auto cloned = new ViewModelPropertyEnum(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/viewmodel/viewmodel_property_enum_custom_base.cpp b/third_party/rive/source/generated/viewmodel/viewmodel_property_enum_custom_base.cpp new file mode 100644 index 0000000..d112f78 --- /dev/null +++ b/third_party/rive/source/generated/viewmodel/viewmodel_property_enum_custom_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/viewmodel/viewmodel_property_enum_custom_base.hpp" +#include "rive/viewmodel/viewmodel_property_enum_custom.hpp" + +using namespace rive; + +Core* ViewModelPropertyEnumCustomBase::clone() const +{ + auto cloned = new ViewModelPropertyEnumCustom(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/viewmodel/viewmodel_property_enum_system_base.cpp b/third_party/rive/source/generated/viewmodel/viewmodel_property_enum_system_base.cpp new file mode 100644 index 0000000..b4cd62d --- /dev/null +++ b/third_party/rive/source/generated/viewmodel/viewmodel_property_enum_system_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/viewmodel/viewmodel_property_enum_system_base.hpp" +#include "rive/viewmodel/viewmodel_property_enum_system.hpp" + +using namespace rive; + +Core* ViewModelPropertyEnumSystemBase::clone() const +{ + auto cloned = new ViewModelPropertyEnumSystem(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/viewmodel/viewmodel_property_list_base.cpp b/third_party/rive/source/generated/viewmodel/viewmodel_property_list_base.cpp new file mode 100644 index 0000000..d6a7e79 --- /dev/null +++ b/third_party/rive/source/generated/viewmodel/viewmodel_property_list_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/viewmodel/viewmodel_property_list_base.hpp" +#include "rive/viewmodel/viewmodel_property_list.hpp" + +using namespace rive; + +Core* ViewModelPropertyListBase::clone() const +{ + auto cloned = new ViewModelPropertyList(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/viewmodel/viewmodel_property_number_base.cpp b/third_party/rive/source/generated/viewmodel/viewmodel_property_number_base.cpp new file mode 100644 index 0000000..bf38820 --- /dev/null +++ b/third_party/rive/source/generated/viewmodel/viewmodel_property_number_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/viewmodel/viewmodel_property_number_base.hpp" +#include "rive/viewmodel/viewmodel_property_number.hpp" + +using namespace rive; + +Core* ViewModelPropertyNumberBase::clone() const +{ + auto cloned = new ViewModelPropertyNumber(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/viewmodel/viewmodel_property_string_base.cpp b/third_party/rive/source/generated/viewmodel/viewmodel_property_string_base.cpp new file mode 100644 index 0000000..5deac13 --- /dev/null +++ b/third_party/rive/source/generated/viewmodel/viewmodel_property_string_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/viewmodel/viewmodel_property_string_base.hpp" +#include "rive/viewmodel/viewmodel_property_string.hpp" + +using namespace rive; + +Core* ViewModelPropertyStringBase::clone() const +{ + auto cloned = new ViewModelPropertyString(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/viewmodel/viewmodel_property_symbol_list_index_base.cpp b/third_party/rive/source/generated/viewmodel/viewmodel_property_symbol_list_index_base.cpp new file mode 100644 index 0000000..0ec35d7 --- /dev/null +++ b/third_party/rive/source/generated/viewmodel/viewmodel_property_symbol_list_index_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/viewmodel/viewmodel_property_symbol_list_index_base.hpp" +#include "rive/viewmodel/viewmodel_property_symbol_list_index.hpp" + +using namespace rive; + +Core* ViewModelPropertySymbolListIndexBase::clone() const +{ + auto cloned = new ViewModelPropertySymbolListIndex(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/viewmodel/viewmodel_property_trigger_base.cpp b/third_party/rive/source/generated/viewmodel/viewmodel_property_trigger_base.cpp new file mode 100644 index 0000000..f5e4620 --- /dev/null +++ b/third_party/rive/source/generated/viewmodel/viewmodel_property_trigger_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/viewmodel/viewmodel_property_trigger_base.hpp" +#include "rive/viewmodel/viewmodel_property_trigger.hpp" + +using namespace rive; + +Core* ViewModelPropertyTriggerBase::clone() const +{ + auto cloned = new ViewModelPropertyTrigger(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/generated/viewmodel/viewmodel_property_viewmodel_base.cpp b/third_party/rive/source/generated/viewmodel/viewmodel_property_viewmodel_base.cpp new file mode 100644 index 0000000..5b57217 --- /dev/null +++ b/third_party/rive/source/generated/viewmodel/viewmodel_property_viewmodel_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/viewmodel/viewmodel_property_viewmodel_base.hpp" +#include "rive/viewmodel/viewmodel_property_viewmodel.hpp" + +using namespace rive; + +Core* ViewModelPropertyViewModelBase::clone() const +{ + auto cloned = new ViewModelPropertyViewModel(); + cloned->copy(*this); + return cloned; +} diff --git a/third_party/rive/source/hittest_command_path.cpp b/third_party/rive/source/hittest_command_path.cpp new file mode 100644 index 0000000..ff31bf7 --- /dev/null +++ b/third_party/rive/source/hittest_command_path.cpp @@ -0,0 +1,66 @@ +/* + * Copyright 2022 Rive + */ + +#include "rive/hittest_command_path.hpp" + +using namespace rive; + +HitTestCommandPath::HitTestCommandPath(const IAABB& area) : m_Area(area) +{ + m_Tester.reset(m_Area); +} + +bool HitTestCommandPath::wasHit() { return m_Tester.test(m_FillRule); } + +void HitTestCommandPath::rewind() { m_Tester.reset(m_Area); } + +void HitTestCommandPath::fillRule(FillRule value) +{ + // remember this here, and pass it to test() + m_FillRule = value; +} + +void HitTestCommandPath::addPath(CommandPath* path, const Mat2D& transform) +{ + assert(false); + // not supported +} + +RenderPath* HitTestCommandPath::renderPath() +{ + assert(false); + // not supported + return nullptr; +} + +const RenderPath* HitTestCommandPath::renderPath() const +{ + assert(false); + // not supported + return nullptr; +} + +void HitTestCommandPath::moveTo(float x, float y) +{ + m_Tester.move(m_Xform * Vec2D(x, y)); +} + +void HitTestCommandPath::lineTo(float x, float y) +{ + m_Tester.line(m_Xform * Vec2D(x, y)); +} + +void HitTestCommandPath::cubicTo(float ox, + float oy, + float ix, + float iy, + float x, + float y) +{ + m_Tester.cubic(m_Xform * Vec2D(ox, oy), + m_Xform * Vec2D(ix, iy), + m_Xform * Vec2D(x, y)); +} + +void HitTestCommandPath::close() { m_Tester.close(); } diff --git a/third_party/rive/source/importers/artboard_importer.cpp b/third_party/rive/source/importers/artboard_importer.cpp new file mode 100644 index 0000000..f90d19d --- /dev/null +++ b/third_party/rive/source/importers/artboard_importer.cpp @@ -0,0 +1,47 @@ +#include "rive/artboard.hpp" +#include "rive/importers/artboard_importer.hpp" +#include "rive/animation/linear_animation.hpp" +#include "rive/animation/state_machine.hpp" +#include "rive/data_bind/data_bind.hpp" +#include "rive/text/text_value_run.hpp" +#include "rive/event.hpp" +#include "rive/artboard.hpp" + +using namespace rive; + +ArtboardImporter::ArtboardImporter(Artboard* artboard) : m_Artboard(artboard) {} + +void ArtboardImporter::addComponent(Core* object) +{ + m_Artboard->addObject(object); +} + +void ArtboardImporter::addAnimation(LinearAnimation* animation) +{ + m_Artboard->addAnimation(animation); +} + +void ArtboardImporter::addStateMachine(StateMachine* stateMachine) +{ + m_Artboard->addStateMachine(stateMachine); +} + +void ArtboardImporter::addDataBind(DataBind* dataBind) +{ + m_Artboard->addDataBind(dataBind); +} + +StatusCode ArtboardImporter::resolve() +{ + if (!m_Artboard->validateObjects()) + { + return StatusCode::InvalidObject; + } + return m_Artboard->initialize(); +} + +bool ArtboardImporter::readNullObject() +{ + addComponent(nullptr); + return true; +} \ No newline at end of file diff --git a/third_party/rive/source/importers/backboard_importer.cpp b/third_party/rive/source/importers/backboard_importer.cpp new file mode 100644 index 0000000..6329fdf --- /dev/null +++ b/third_party/rive/source/importers/backboard_importer.cpp @@ -0,0 +1,173 @@ + +#include "rive/importers/backboard_importer.hpp" +#include "rive/artboard.hpp" +#include "rive/nested_artboard.hpp" +#include "rive/backboard.hpp" +#include "rive/file.hpp" +#include "rive/assets/file_asset_referencer.hpp" +#include "rive/assets/file_asset.hpp" +#include "rive/constraints/scrolling/scroll_physics.hpp" +#include "rive/viewmodel/viewmodel.hpp" +#include "rive/viewmodel/viewmodel_instance.hpp" +#include "rive/data_bind/converters/data_converter.hpp" +#include "rive/data_bind/converters/data_converter_group_item.hpp" +#include "rive/data_bind/converters/data_converter_range_mapper.hpp" +#include "rive/data_bind/converters/data_converter_interpolator.hpp" +#include "rive/data_bind/data_bind.hpp" +#include + +using namespace rive; + +BackboardImporter::BackboardImporter(Backboard* backboard) : + m_Backboard(backboard), m_NextArtboardId(0) +{} +void BackboardImporter::addNestedArtboard(NestedArtboard* artboard) +{ + m_NestedArtboards.push_back(artboard); +} + +void BackboardImporter::addFileAsset(FileAsset* asset) +{ + m_FileAssets.push_back(asset); + { + // EDITOR BUG 4204 + // -------------- + // Ensure assetIds are unique. Due to an editor bug: + // https://github.com/rive-app/rive/issues/4204 + std::unordered_set ids; + uint32_t nextId = 1; + for (auto fileAsset : m_FileAssets) + { + if (ids.count(fileAsset->assetId())) + { + fileAsset->assetId(nextId); + } + else + { + ids.insert(fileAsset->assetId()); + if (fileAsset->assetId() >= nextId) + { + nextId = fileAsset->assetId() + 1; + } + } + } + + // -------------- + } +} + +void BackboardImporter::addFileAssetReferencer(FileAssetReferencer* referencer) +{ + m_FileAssetReferencers.push_back(referencer); +} + +void BackboardImporter::addArtboard(Artboard* artboard) +{ + m_ArtboardLookup[m_NextArtboardId++] = artboard; +} + +void BackboardImporter::addMissingArtboard() { m_NextArtboardId++; } + +StatusCode BackboardImporter::resolve() +{ + for (auto nestedArtboard : m_NestedArtboards) + { + auto itr = m_ArtboardLookup.find(nestedArtboard->artboardId()); + if (itr != m_ArtboardLookup.end()) + { + auto artboard = itr->second; + if (artboard != nullptr) + { + nestedArtboard->nest(artboard); + } + } + } + for (auto referencer : m_FileAssetReferencers) + { + auto index = (size_t)referencer->assetId(); + if (index >= m_FileAssets.size()) + { + continue; + } + auto asset = m_FileAssets[index]; + referencer->setAsset(asset); + } + + for (auto converter : m_DataConverters) + { + if (converter->is()) + { + size_t converterId = + converter->as()->interpolatorId(); + if (converterId != -1 && converterId < m_interpolators.size()) + { + converter->as()->interpolator( + m_interpolators[converterId]); + } + } + else if (converter->is()) + { + size_t converterId = + converter->as()->interpolatorId(); + if (converterId != -1 && converterId < m_interpolators.size()) + { + converter->as()->interpolator( + m_interpolators[converterId]); + } + } + } + for (auto referencer : m_DataConverterGroupItemReferencers) + { + auto index = (size_t)referencer->converterId(); + if (index >= m_DataConverters.size() || index < 0) + { + continue; + } + // Do not clone converters at this point because some of them are + // incomplete + referencer->converter(m_DataConverters[index]); + } + for (auto referencer : m_DataConverterReferencers) + { + auto index = (size_t)referencer->converterId(); + if (index >= m_DataConverters.size() || index < 0) + { + continue; + } + referencer->converter( + m_DataConverters[index]->clone()->as()); + } + + return StatusCode::Ok; +} + +void BackboardImporter::addDataConverter(DataConverter* dataConverter) +{ + m_DataConverters.push_back(dataConverter); +} + +void BackboardImporter::addDataConverterReferencer(DataBind* dataBind) +{ + m_DataConverterReferencers.push_back(dataBind); +} + +void BackboardImporter::addDataConverterGroupItemReferencer( + DataConverterGroupItem* dataBind) +{ + m_DataConverterGroupItemReferencers.push_back(dataBind); +} + +void BackboardImporter::addInterpolator(KeyFrameInterpolator* interpolator) +{ + // Since these interpolators do not belong to an artboard, we have to + // initialize them + interpolator->initialize(); + m_interpolators.push_back(interpolator); +} + +void BackboardImporter::addPhysics(ScrollPhysics* physics) +{ + m_physics.push_back(physics); +} + +void BackboardImporter::file(File* value) { m_file = value; } \ No newline at end of file diff --git a/third_party/rive/source/importers/bindable_property_importer.cpp b/third_party/rive/source/importers/bindable_property_importer.cpp new file mode 100644 index 0000000..98addbf --- /dev/null +++ b/third_party/rive/source/importers/bindable_property_importer.cpp @@ -0,0 +1,10 @@ +#include "rive/artboard.hpp" +#include "rive/importers/bindable_property_importer.hpp" +#include "rive/data_bind/bindable_property.hpp" + +using namespace rive; + +BindablePropertyImporter::BindablePropertyImporter( + BindableProperty* bindableProperty) : + m_bindableProperty(bindableProperty) +{} \ No newline at end of file diff --git a/third_party/rive/source/importers/data_converter_formula_importer.cpp b/third_party/rive/source/importers/data_converter_formula_importer.cpp new file mode 100644 index 0000000..7657a48 --- /dev/null +++ b/third_party/rive/source/importers/data_converter_formula_importer.cpp @@ -0,0 +1,16 @@ +#include "rive/artboard.hpp" +#include "rive/importers/data_converter_formula_importer.hpp" +#include "rive/data_bind/converters/data_converter_formula.hpp" + +using namespace rive; + +DataConverterFormulaImporter::DataConverterFormulaImporter( + DataConverterFormula* formula) : + m_dataConverterFormula(formula) +{} + +StatusCode DataConverterFormulaImporter::resolve() +{ + m_dataConverterFormula->initialize(); + return StatusCode::Ok; +} \ No newline at end of file diff --git a/third_party/rive/source/importers/data_converter_group_importer.cpp b/third_party/rive/source/importers/data_converter_group_importer.cpp new file mode 100644 index 0000000..cbeb7a3 --- /dev/null +++ b/third_party/rive/source/importers/data_converter_group_importer.cpp @@ -0,0 +1,10 @@ +#include "rive/artboard.hpp" +#include "rive/importers/data_converter_group_importer.hpp" +#include "rive/data_bind/converters/data_converter.hpp" + +using namespace rive; + +DataConverterGroupImporter::DataConverterGroupImporter( + DataConverterGroup* group) : + m_dataConverterGroup(group) +{} \ No newline at end of file diff --git a/third_party/rive/source/importers/enum_importer.cpp b/third_party/rive/source/importers/enum_importer.cpp new file mode 100644 index 0000000..db980c4 --- /dev/null +++ b/third_party/rive/source/importers/enum_importer.cpp @@ -0,0 +1,14 @@ +#include "rive/importers/enum_importer.hpp" +#include "rive/viewmodel/data_enum.hpp" +#include "rive/viewmodel/data_enum_value.hpp" + +using namespace rive; + +EnumImporter::EnumImporter(DataEnum* dataEnum) : m_DataEnum(dataEnum) {} + +void EnumImporter::addValue(DataEnumValue* value) +{ + m_DataEnum->addValue(value); +} + +StatusCode EnumImporter::resolve() { return StatusCode::Ok; } \ No newline at end of file diff --git a/third_party/rive/source/importers/file_asset_importer.cpp b/third_party/rive/source/importers/file_asset_importer.cpp new file mode 100644 index 0000000..0d5d8f0 --- /dev/null +++ b/third_party/rive/source/importers/file_asset_importer.cpp @@ -0,0 +1,51 @@ +#include "rive/importers/file_asset_importer.hpp" +#include "rive/assets/file_asset_contents.hpp" +#include "rive/assets/file_asset.hpp" +#include "rive/file_asset_loader.hpp" +#include "rive/span.hpp" +#include + +using namespace rive; + +FileAssetImporter::FileAssetImporter(FileAsset* fileAsset, + rcp assetLoader, + Factory* factory) : + m_FileAsset(fileAsset), + m_FileAssetLoader(std::move(assetLoader)), + m_Factory(factory) +{} + +// if file asset contents are found when importing a rive file, store those for +// when we resolve the importer later +void FileAssetImporter::onFileAssetContents( + std::unique_ptr contents) +{ + // we should only ever be called once + assert(!m_Content); + m_Content = std::move(contents); +} + +StatusCode FileAssetImporter::resolve() +{ + Span bytes; + if (m_Content != nullptr) + { + bytes = m_Content->bytes(); + } + + // If we have a file asset loader, lets give it the opportunity to claim + // responsibility for loading the asset + if (m_FileAssetLoader != nullptr && + m_FileAssetLoader->loadContents(*m_FileAsset, bytes, m_Factory)) + { + return StatusCode::Ok; + } + // If we do not, but we have found in band contents, load those + else if (bytes.size() > 0) + { + m_FileAsset->decode(m_Content->bytes(), m_Factory); + } + + // Note that it's ok for an asset to not resolve (or to resolve async). + return StatusCode::Ok; +} diff --git a/third_party/rive/source/importers/keyed_object_importer.cpp b/third_party/rive/source/importers/keyed_object_importer.cpp new file mode 100644 index 0000000..ea4e7fa --- /dev/null +++ b/third_party/rive/source/importers/keyed_object_importer.cpp @@ -0,0 +1,16 @@ +#include "rive/importers/keyed_object_importer.hpp" +#include "rive/animation/keyed_object.hpp" +#include "rive/animation/keyed_property.hpp" +#include "rive/artboard.hpp" + +using namespace rive; + +KeyedObjectImporter::KeyedObjectImporter(KeyedObject* keyedObject) : + m_KeyedObject(keyedObject) +{} + +void KeyedObjectImporter::addKeyedProperty( + std::unique_ptr property) +{ + m_KeyedObject->addKeyedProperty(std::move(property)); +} \ No newline at end of file diff --git a/third_party/rive/source/importers/keyed_property_importer.cpp b/third_party/rive/source/importers/keyed_property_importer.cpp new file mode 100644 index 0000000..8efb275 --- /dev/null +++ b/third_party/rive/source/importers/keyed_property_importer.cpp @@ -0,0 +1,24 @@ +#include "rive/importers/keyed_property_importer.hpp" +#include "rive/animation/keyed_property.hpp" +#include "rive/animation/keyframe.hpp" +#include "rive/animation/linear_animation.hpp" + +using namespace rive; + +KeyedPropertyImporter::KeyedPropertyImporter(LinearAnimation* animation, + KeyedProperty* keyedProperty) : + m_Animation(animation), m_KeyedProperty(keyedProperty) +{} + +void KeyedPropertyImporter::addKeyFrame(std::unique_ptr keyFrame) +{ + keyFrame->computeSeconds(m_Animation->fps()); + m_KeyedProperty->addKeyFrame(std::move(keyFrame)); +} + +bool KeyedPropertyImporter::readNullObject() +{ + // We don't need to add the null keyframe as nothing references them, but we + // do need to not allow the null to propagate up. + return true; +} \ No newline at end of file diff --git a/third_party/rive/source/importers/layer_state_importer.cpp b/third_party/rive/source/importers/layer_state_importer.cpp new file mode 100644 index 0000000..d9d4237 --- /dev/null +++ b/third_party/rive/source/importers/layer_state_importer.cpp @@ -0,0 +1,49 @@ +#include "rive/importers/layer_state_importer.hpp" +#include "rive/animation/state_transition.hpp" +#include "rive/animation/layer_state.hpp" +#include "rive/animation/blend_state.hpp" +#include "rive/animation/blend_state_transition.hpp" + +using namespace rive; + +LayerStateImporter::LayerStateImporter(LayerState* state) : m_State(state) {} +void LayerStateImporter::addTransition(StateTransition* transition) +{ + m_State->addTransition(transition); +} + +bool LayerStateImporter::addBlendAnimation(BlendAnimation* animation) +{ + if (!m_State->is()) + { + return false; + } + auto blendState = m_State->as(); + + blendState->addAnimation(animation); + return true; +} + +StatusCode LayerStateImporter::resolve() +{ + if (m_State->is()) + { + auto blendState = m_State->as(); + for (auto transition : blendState->m_Transitions) + { + if (!transition->is()) + { + continue; + } + + auto blendStateTransition = transition->as(); + size_t exitId = blendStateTransition->exitBlendAnimationId(); + if (exitId < blendState->m_Animations.size()) + { + blendStateTransition->m_ExitBlendAnimation = + blendState->m_Animations[exitId]; + } + } + } + return StatusCode::Ok; +} diff --git a/third_party/rive/source/importers/linear_animation_importer.cpp b/third_party/rive/source/importers/linear_animation_importer.cpp new file mode 100644 index 0000000..f2b1fca --- /dev/null +++ b/third_party/rive/source/importers/linear_animation_importer.cpp @@ -0,0 +1,16 @@ +#include "rive/importers/linear_animation_importer.hpp" +#include "rive/animation/keyed_object.hpp" +#include "rive/animation/linear_animation.hpp" +#include "rive/artboard.hpp" + +using namespace rive; + +LinearAnimationImporter::LinearAnimationImporter(LinearAnimation* animation) : + m_Animation(animation) +{} + +void LinearAnimationImporter::addKeyedObject( + std::unique_ptr object) +{ + m_Animation->addKeyedObject(std::move(object)); +} \ No newline at end of file diff --git a/third_party/rive/source/importers/state_machine_importer.cpp b/third_party/rive/source/importers/state_machine_importer.cpp new file mode 100644 index 0000000..de29f24 --- /dev/null +++ b/third_party/rive/source/importers/state_machine_importer.cpp @@ -0,0 +1,42 @@ +#include "rive/importers/state_machine_importer.hpp" +#include "rive/animation/state_machine.hpp" +#include "rive/animation/state_machine_listener.hpp" +#include "rive/animation/state_machine_input.hpp" +#include "rive/animation/state_machine_layer.hpp" +#include "rive/data_bind/data_bind.hpp" + +using namespace rive; + +StateMachineImporter::StateMachineImporter(StateMachine* machine) : + m_StateMachine(machine) +{} + +void StateMachineImporter::addLayer(std::unique_ptr layer) +{ + m_StateMachine->addLayer(std::move(layer)); +} + +void StateMachineImporter::addInput(std::unique_ptr input) +{ + m_StateMachine->addInput(std::move(input)); +} + +void StateMachineImporter::addListener( + std::unique_ptr listener) +{ + m_StateMachine->addListener(std::move(listener)); +} + +void StateMachineImporter::addDataBind(std::unique_ptr dataBind) +{ + m_StateMachine->addDataBind(std::move(dataBind)); +} + +bool StateMachineImporter::readNullObject() +{ + // Hard assumption that we won't add new layer types... + m_StateMachine->addInput(nullptr); + return true; +} + +StatusCode StateMachineImporter::resolve() { return StatusCode::Ok; } \ No newline at end of file diff --git a/third_party/rive/source/importers/state_machine_layer_component_importer.cpp b/third_party/rive/source/importers/state_machine_layer_component_importer.cpp new file mode 100644 index 0000000..4ea47ca --- /dev/null +++ b/third_party/rive/source/importers/state_machine_layer_component_importer.cpp @@ -0,0 +1,24 @@ +#include "rive/importers/state_machine_layer_component_importer.hpp" +#include "rive/animation/state_machine_layer_component.hpp" +#include "rive/animation/state_machine_fire_event.hpp" + +using namespace rive; + +StateMachineLayerComponent::~StateMachineLayerComponent() +{ + for (auto event : m_events) + { + delete event; + } +} + +StateMachineLayerComponentImporter::StateMachineLayerComponentImporter( + StateMachineLayerComponent* component) : + m_stateMachineLayerComponent(component) +{} + +void StateMachineLayerComponentImporter::addFireEvent( + StateMachineFireEvent* fireEvent) +{ + m_stateMachineLayerComponent->m_events.push_back(fireEvent); +} \ No newline at end of file diff --git a/third_party/rive/source/importers/state_machine_layer_importer.cpp b/third_party/rive/source/importers/state_machine_layer_importer.cpp new file mode 100644 index 0000000..d578926 --- /dev/null +++ b/third_party/rive/source/importers/state_machine_layer_importer.cpp @@ -0,0 +1,61 @@ +#include "rive/importers/state_machine_layer_importer.hpp" +#include "rive/importers/artboard_importer.hpp" +#include "rive/animation/state_machine_layer.hpp" +#include "rive/animation/animation_state.hpp" +#include "rive/animation/state_transition.hpp" +#include "rive/artboard.hpp" + +using namespace rive; +StateMachineLayerImporter::StateMachineLayerImporter(StateMachineLayer* layer, + const Artboard* artboard) : + m_Layer(layer), m_Artboard(artboard) +{} +void StateMachineLayerImporter::addState(LayerState* state) +{ + m_Layer->addState(state); +} + +StatusCode StateMachineLayerImporter::resolve() +{ + + for (auto state : m_Layer->m_States) + { + if (state->is()) + { + auto animationState = state->as(); + + if (animationState->animationId() < m_Artboard->animationCount()) + { + animationState->m_Animation = + m_Artboard->animation(animationState->animationId()); + if (animationState->m_Animation == nullptr) + { + return StatusCode::MissingObject; + } + } + } + for (auto transition : state->m_Transitions) + { + if ((size_t)transition->stateToId() < m_Layer->m_States.size()) + { + transition->m_StateTo = + m_Layer->m_States[transition->stateToId()]; + } + else + { + return StatusCode::InvalidObject; + } + } + } + return StatusCode::Ok; +} + +bool StateMachineLayerImporter::readNullObject() +{ + // Add an 'empty' generic state that can be transitioned to/from but doesn't + // effectively do anything. This allows us to deal with unexpected new state + // types the runtime won't be able to understand. It'll still be able to + // make use of the state but it won't do anything visually. + addState(new LayerState()); + return true; +} diff --git a/third_party/rive/source/importers/state_machine_listener_importer.cpp b/third_party/rive/source/importers/state_machine_listener_importer.cpp new file mode 100644 index 0000000..19257be --- /dev/null +++ b/third_party/rive/source/importers/state_machine_listener_importer.cpp @@ -0,0 +1,18 @@ +#include "rive/animation/listener_action.hpp" +#include "rive/importers/state_machine_listener_importer.hpp" +#include "rive/animation/state_machine_listener.hpp" + +using namespace rive; + +StateMachineListenerImporter::StateMachineListenerImporter( + StateMachineListener* listener) : + m_StateMachineListener(listener) +{} + +void StateMachineListenerImporter::addAction( + std::unique_ptr action) +{ + m_StateMachineListener->addAction(std::move(action)); +} + +StatusCode StateMachineListenerImporter::resolve() { return StatusCode::Ok; } \ No newline at end of file diff --git a/third_party/rive/source/importers/state_transition_importer.cpp b/third_party/rive/source/importers/state_transition_importer.cpp new file mode 100644 index 0000000..beb6b45 --- /dev/null +++ b/third_party/rive/source/importers/state_transition_importer.cpp @@ -0,0 +1,15 @@ +#include "rive/importers/state_transition_importer.hpp" +#include "rive/animation/transition_condition.hpp" +#include "rive/animation/state_transition.hpp" + +using namespace rive; + +StateTransitionImporter::StateTransitionImporter(StateTransition* transition) : + m_Transition(transition) +{} +void StateTransitionImporter::addCondition(TransitionCondition* condition) +{ + m_Transition->addCondition(condition); +} + +StatusCode StateTransitionImporter::resolve() { return StatusCode::Ok; } \ No newline at end of file diff --git a/third_party/rive/source/importers/transition_viewmodel_condition_importer.cpp b/third_party/rive/source/importers/transition_viewmodel_condition_importer.cpp new file mode 100644 index 0000000..13108f1 --- /dev/null +++ b/third_party/rive/source/importers/transition_viewmodel_condition_importer.cpp @@ -0,0 +1,17 @@ +#include "rive/importers/transition_viewmodel_condition_importer.hpp" +#include "rive/animation/transition_viewmodel_condition.hpp" +#include "rive/animation/transition_comparator.hpp" +#include "rive/data_bind/data_bind.hpp" + +using namespace rive; + +TransitionViewModelConditionImporter::TransitionViewModelConditionImporter( + TransitionViewModelCondition* transitionViewModelCondition) : + m_TransitionViewModelCondition(transitionViewModelCondition) +{} + +void TransitionViewModelConditionImporter::setComparator( + TransitionComparator* comparator) +{ + m_TransitionViewModelCondition->comparator(comparator); +} \ No newline at end of file diff --git a/third_party/rive/source/importers/viewmodel_importer.cpp b/third_party/rive/source/importers/viewmodel_importer.cpp new file mode 100644 index 0000000..2ad059e --- /dev/null +++ b/third_party/rive/source/importers/viewmodel_importer.cpp @@ -0,0 +1,20 @@ +#include "rive/importers/viewmodel_importer.hpp" +#include "rive/viewmodel/viewmodel.hpp" +#include "rive/viewmodel/viewmodel_property.hpp" +#include "rive/viewmodel/viewmodel_instance.hpp" + +using namespace rive; + +ViewModelImporter::ViewModelImporter(ViewModel* viewModel) : + m_ViewModel(viewModel) +{} +void ViewModelImporter::addProperty(ViewModelProperty* property) +{ + m_ViewModel->addProperty(property); +} +void ViewModelImporter::addInstance(ViewModelInstance* value) +{ + m_ViewModel->addInstance(value); +} + +StatusCode ViewModelImporter::resolve() { return StatusCode::Ok; } \ No newline at end of file diff --git a/third_party/rive/source/importers/viewmodel_instance_importer.cpp b/third_party/rive/source/importers/viewmodel_instance_importer.cpp new file mode 100644 index 0000000..b228888 --- /dev/null +++ b/third_party/rive/source/importers/viewmodel_instance_importer.cpp @@ -0,0 +1,16 @@ +#include "rive/importers/viewmodel_instance_importer.hpp" +#include "rive/viewmodel/viewmodel_instance.hpp" +#include "rive/viewmodel/viewmodel_instance_value.hpp" + +using namespace rive; + +ViewModelInstanceImporter::ViewModelInstanceImporter( + ViewModelInstance* viewModelInstance) : + m_ViewModelInstance(viewModelInstance) +{} +void ViewModelInstanceImporter::addValue(ViewModelInstanceValue* value) +{ + m_ViewModelInstance->addValue(value); +} + +StatusCode ViewModelInstanceImporter::resolve() { return StatusCode::Ok; } \ No newline at end of file diff --git a/third_party/rive/source/importers/viewmodel_instance_list_importer.cpp b/third_party/rive/source/importers/viewmodel_instance_list_importer.cpp new file mode 100644 index 0000000..c66b5d0 --- /dev/null +++ b/third_party/rive/source/importers/viewmodel_instance_list_importer.cpp @@ -0,0 +1,16 @@ +#include "rive/importers/viewmodel_instance_list_importer.hpp" +#include "rive/viewmodel/viewmodel_instance_list.hpp" +#include "rive/viewmodel/viewmodel_instance_list_item.hpp" + +using namespace rive; + +ViewModelInstanceListImporter::ViewModelInstanceListImporter( + ViewModelInstanceList* viewModelInstanceList) : + m_ViewModelInstanceList(viewModelInstanceList) +{} +void ViewModelInstanceListImporter::addItem(ViewModelInstanceListItem* listItem) +{ + m_ViewModelInstanceList->internalAddItem(listItem); +} + +StatusCode ViewModelInstanceListImporter::resolve() { return StatusCode::Ok; } \ No newline at end of file diff --git a/third_party/rive/source/intrinsically_sizeable.cpp b/third_party/rive/source/intrinsically_sizeable.cpp new file mode 100644 index 0000000..92440a5 --- /dev/null +++ b/third_party/rive/source/intrinsically_sizeable.cpp @@ -0,0 +1,18 @@ +#include "rive/intrinsically_sizeable.hpp" +#include "rive/joystick.hpp" +#include "rive/transform_component.hpp" + +using namespace rive; + +IntrinsicallySizeable* IntrinsicallySizeable::from(Component* component) +{ + if (component->is()) + { + return component->as(); + } + else if (component->is()) + { + return component->as(); + } + return nullptr; +} \ No newline at end of file diff --git a/third_party/rive/source/joystick.cpp b/third_party/rive/source/joystick.cpp new file mode 100644 index 0000000..ea9d6e1 --- /dev/null +++ b/third_party/rive/source/joystick.cpp @@ -0,0 +1,170 @@ +#include "rive/joystick.hpp" +#include "rive/artboard.hpp" +#include "rive/transform_component.hpp" +#include "rive/animation/keyed_object.hpp" + +using namespace rive; + +StatusCode Joystick::onAddedDirty(CoreContext* context) +{ + StatusCode status = Super::onAddedDirty(context); + if (status != StatusCode::Ok) + { + return status; + } + if (handleSourceId() != Core::emptyId) + { + auto coreObject = context->resolve(handleSourceId()); + if (coreObject == nullptr || !coreObject->is()) + { + return StatusCode::MissingObject; + } + m_handleSource = static_cast(coreObject); + } + + return StatusCode::Ok; +} + +StatusCode Joystick::onAddedClean(CoreContext* context) +{ + m_xAnimation = artboard()->animation(xId()); + m_yAnimation = artboard()->animation(yId()); + + return StatusCode::Ok; +} + +void Joystick::buildDependencies() +{ + // We only need to update if we're in world space (and that is only required + // at runtime if we have a custom handle source). + if (m_handleSource != nullptr && parent() != nullptr) + { + parent()->addDependent(this); + m_handleSource->addDependent(this); + } +} + +void Joystick::update(ComponentDirt value) +{ + if (m_handleSource == nullptr) + { + return; + } + if (hasDirt(value, + ComponentDirt::WorldTransform | ComponentDirt::Transform)) + { + Mat2D world = Mat2D::fromTranslate(posX(), posY()); + if (parent() != nullptr && parent()->is()) + { + world = parent()->as()->worldTransform() * + world; + } + + if (m_worldTransform != world) + { + m_worldTransform = world; + m_inverseWorldTransform = world.invertOrIdentity(); + } + + auto pos = m_inverseWorldTransform * m_handleSource->worldTranslation(); + + auto localBounds = AABB(-width() * originX(), + -height() * originY(), + -width() * originX() + width(), + -height() * originY() + height()); + + auto local = localBounds.factorFrom(pos); + x(local.x); + y(local.y); + } +} + +void Joystick::apply(Artboard* artboard) const +{ + if (m_xAnimation != nullptr) + { + m_xAnimation->apply( + artboard, + ((isJoystickFlagged(JoystickFlags::invertX) ? -x() : x()) + 1.0f) / + 2.0f * m_xAnimation->durationSeconds()); + } + if (m_yAnimation != nullptr) + { + + m_yAnimation->apply( + artboard, + ((isJoystickFlagged(JoystickFlags::invertY) ? -y() : y()) + 1.0f) / + 2.0f * m_yAnimation->durationSeconds()); + } + for (const auto& nestedRemapAnimation : m_dependents) + { + nestedRemapAnimation->advance(0, false); + } +} + +Vec2D Joystick::measureLayout(float width, + LayoutMeasureMode widthMode, + float height, + LayoutMeasureMode heightMode) +{ + return Vec2D(std::min((widthMode == LayoutMeasureMode::undefined + ? std::numeric_limits::max() + : width), + Joystick::width()), + std::min((heightMode == LayoutMeasureMode::undefined + ? std::numeric_limits::max() + : height), + Joystick::height())); +} + +void Joystick::controlSize(Vec2D size, + LayoutScaleType widthScaleType, + LayoutScaleType heightScaleType, + LayoutDirection direction) +{ + width(size.x); + height(size.y); + posX(size.x * originX()); + posY(size.y * originY()); +} + +void Joystick::xChanged() { artboard()->addDirt(ComponentDirt::Components); } +void Joystick::yChanged() { artboard()->addDirt(ComponentDirt::Components); } +void Joystick::posXChanged() { artboard()->addDirt(ComponentDirt::Components); } +void Joystick::posYChanged() { artboard()->addDirt(ComponentDirt::Components); } +void Joystick::widthChanged() +{ + artboard()->addDirt(ComponentDirt::Components); +} +void Joystick::heightChanged() +{ + artboard()->addDirt(ComponentDirt::Components); +} + +void Joystick::addAnimationDependents(Artboard* artboard, + LinearAnimation* animation) +{ + + auto totalObjects = animation->numKeyedObjects(); + for (int i = 0; i < totalObjects; i++) + { + auto object = animation->getObject(i); + auto coreObject = artboard->resolve(object->objectId()); + if (coreObject != nullptr && coreObject->is()) + { + m_dependents.push_back(coreObject->as()); + } + } +} + +void Joystick::addDependents(Artboard* artboard) +{ + if (m_yAnimation != nullptr) + { + addAnimationDependents(artboard, m_yAnimation); + } + if (m_xAnimation != nullptr) + { + addAnimationDependents(artboard, m_xAnimation); + } +} \ No newline at end of file diff --git a/third_party/rive/source/layout.cpp b/third_party/rive/source/layout.cpp new file mode 100644 index 0000000..55d9e8f --- /dev/null +++ b/third_party/rive/source/layout.cpp @@ -0,0 +1,21 @@ +#include "rive/layout.hpp" + +using namespace rive; + +const Alignment Alignment::topLeft = Alignment(-1.0f, -1.0f); + +const Alignment Alignment::topCenter = Alignment(0.0f, -1.0f); + +const Alignment Alignment::topRight = Alignment(1.0f, -1.0f); + +const Alignment Alignment::centerLeft = Alignment(-1.0f, 0.0f); + +const Alignment Alignment::center = Alignment(0.0f, 0.0f); + +const Alignment Alignment::centerRight = Alignment(1.0f, 0.0f); + +const Alignment Alignment::bottomLeft = Alignment(-1.0f, 1.0f); + +const Alignment Alignment::bottomCenter = Alignment(0.0f, 1.0f); + +const Alignment Alignment::bottomRight = Alignment(1.0f, 1.0f); diff --git a/third_party/rive/source/layout/axis.cpp b/third_party/rive/source/layout/axis.cpp new file mode 100644 index 0000000..0161d78 --- /dev/null +++ b/third_party/rive/source/layout/axis.cpp @@ -0,0 +1,23 @@ +#include "rive/container_component.hpp" +#include "rive/layout/axis.hpp" +#include "rive/layout/n_slicer_details.hpp" + +using namespace rive; + +StatusCode Axis::onAddedDirty(CoreContext* context) +{ + StatusCode code = Super::onAddedDirty(context); + if (code != StatusCode::Ok) + { + return code; + } + + if (NSlicerDetails::from(parent()) == nullptr) + { + return StatusCode::MissingObject; + } + + return StatusCode::Ok; +} + +void Axis::offsetChanged() { NSlicerDetails::from(parent())->axisChanged(); } diff --git a/third_party/rive/source/layout/axis_x.cpp b/third_party/rive/source/layout/axis_x.cpp new file mode 100644 index 0000000..64b7bd5 --- /dev/null +++ b/third_party/rive/source/layout/axis_x.cpp @@ -0,0 +1,16 @@ +#include "rive/container_component.hpp" +#include "rive/layout/axis_x.hpp" +#include "rive/layout/n_slicer_details.hpp" + +using namespace rive; + +StatusCode AxisX::onAddedDirty(CoreContext* context) +{ + StatusCode code = Super::onAddedDirty(context); + if (code != StatusCode::Ok) + { + return code; + } + NSlicerDetails::from(parent())->addAxisX(this); + return StatusCode::Ok; +} diff --git a/third_party/rive/source/layout/axis_y.cpp b/third_party/rive/source/layout/axis_y.cpp new file mode 100644 index 0000000..7aec310 --- /dev/null +++ b/third_party/rive/source/layout/axis_y.cpp @@ -0,0 +1,17 @@ +#include "rive/container_component.hpp" +#include "rive/layout/axis_y.hpp" +#include "rive/layout/n_slicer_details.hpp" + +using namespace rive; + +StatusCode AxisY::onAddedDirty(CoreContext* context) +{ + StatusCode code = Super::onAddedDirty(context); + if (code != StatusCode::Ok) + { + return code; + } + + NSlicerDetails::from(parent())->addAxisY(this); + return StatusCode::Ok; +} diff --git a/third_party/rive/source/layout/layout_component_style.cpp b/third_party/rive/source/layout/layout_component_style.cpp new file mode 100644 index 0000000..3258f67 --- /dev/null +++ b/third_party/rive/source/layout/layout_component_style.cpp @@ -0,0 +1,438 @@ +#include "rive/animation/keyframe_interpolator.hpp" +#include "rive/core_context.hpp" +#include "rive/layout_component.hpp" +#include "rive/layout/layout_component_style.hpp" +#include + +using namespace rive; + +#ifdef WITH_RIVE_LAYOUT + +KeyFrameInterpolator* LayoutComponentStyle::interpolator() +{ + return m_interpolator; +} + +LayoutStyleInterpolation LayoutComponentStyle::interpolation() +{ + return LayoutStyleInterpolation(interpolationType()); +} + +LayoutAnimationStyle LayoutComponentStyle::animationStyle() +{ + return LayoutAnimationStyle(animationStyleType()); +} + +LayoutAlignmentType LayoutComponentStyle::alignmentType() +{ + return LayoutAlignmentType(layoutAlignmentType()); +} + +LayoutScaleType LayoutComponentStyle::widthScaleType() +{ + return LayoutScaleType(layoutWidthScaleType()); +} + +LayoutScaleType LayoutComponentStyle::heightScaleType() +{ + return LayoutScaleType(layoutHeightScaleType()); +} + +YGDisplay LayoutComponentStyle::display() { return YGDisplay(displayValue()); } + +YGPositionType LayoutComponentStyle::positionType() +{ + return YGPositionType(positionTypeValue()); +} + +YGFlexDirection LayoutComponentStyle::flexDirection() +{ + return YGFlexDirection(flexDirectionValue()); +} + +YGDirection LayoutComponentStyle::direction() +{ + return YGDirection(directionValue()); +} + +YGWrap LayoutComponentStyle::flexWrap() { return YGWrap(flexWrapValue()); } + +YGAlign LayoutComponentStyle::alignItems() +{ + return YGAlign(alignItemsValue()); +} + +YGAlign LayoutComponentStyle::alignSelf() { return YGAlign(alignSelfValue()); } + +YGAlign LayoutComponentStyle::alignContent() +{ + return YGAlign(alignContentValue()); +} + +YGJustify LayoutComponentStyle::justifyContent() +{ + return YGJustify(justifyContentValue()); +} + +YGOverflow LayoutComponentStyle::overflow() +{ + return YGOverflow(overflowValue()); +} + +bool LayoutComponentStyle::intrinsicallySized() +{ + return intrinsicallySizedValue() == 1; +} + +YGUnit LayoutComponentStyle::widthUnits() { return YGUnit(widthUnitsValue()); } + +YGUnit LayoutComponentStyle::heightUnits() +{ + return YGUnit(heightUnitsValue()); +} + +YGUnit LayoutComponentStyle::borderLeftUnits() +{ + return YGUnit(borderLeftUnitsValue()); +} + +YGUnit LayoutComponentStyle::borderRightUnits() +{ + return YGUnit(borderRightUnitsValue()); +} + +YGUnit LayoutComponentStyle::borderTopUnits() +{ + return YGUnit(borderTopUnitsValue()); +} + +YGUnit LayoutComponentStyle::borderBottomUnits() +{ + return YGUnit(borderBottomUnitsValue()); +} + +YGUnit LayoutComponentStyle::marginLeftUnits() +{ + return YGUnit(marginLeftUnitsValue()); +} + +YGUnit LayoutComponentStyle::marginRightUnits() +{ + return YGUnit(marginRightUnitsValue()); +} + +YGUnit LayoutComponentStyle::marginTopUnits() +{ + return YGUnit(marginTopUnitsValue()); +} + +YGUnit LayoutComponentStyle::marginBottomUnits() +{ + return YGUnit(marginBottomUnitsValue()); +} + +YGUnit LayoutComponentStyle::paddingLeftUnits() +{ + return YGUnit(paddingLeftUnitsValue()); +} + +YGUnit LayoutComponentStyle::paddingRightUnits() +{ + return YGUnit(paddingRightUnitsValue()); +} + +YGUnit LayoutComponentStyle::paddingTopUnits() +{ + return YGUnit(paddingTopUnitsValue()); +} + +YGUnit LayoutComponentStyle::paddingBottomUnits() +{ + return YGUnit(paddingBottomUnitsValue()); +} + +YGUnit LayoutComponentStyle::positionLeftUnits() +{ + return YGUnit(positionLeftUnitsValue()); +} + +YGUnit LayoutComponentStyle::positionRightUnits() +{ + return YGUnit(positionRightUnitsValue()); +} + +YGUnit LayoutComponentStyle::positionTopUnits() +{ + return YGUnit(positionTopUnitsValue()); +} + +YGUnit LayoutComponentStyle::positionBottomUnits() +{ + return YGUnit(positionBottomUnitsValue()); +} + +YGUnit LayoutComponentStyle::gapHorizontalUnits() +{ + return YGUnit(gapHorizontalUnitsValue()); +} + +YGUnit LayoutComponentStyle::gapVerticalUnits() +{ + return YGUnit(gapVerticalUnitsValue()); +} + +YGUnit LayoutComponentStyle::maxWidthUnits() +{ + return YGUnit(maxWidthUnitsValue()); +} + +YGUnit LayoutComponentStyle::maxHeightUnits() +{ + return YGUnit(maxHeightUnitsValue()); +} + +YGUnit LayoutComponentStyle::minWidthUnits() +{ + return YGUnit(minWidthUnitsValue()); +} + +YGUnit LayoutComponentStyle::minHeightUnits() +{ + return YGUnit(minHeightUnitsValue()); +} +YGUnit LayoutComponentStyle::flexBasisUnits() +{ + return YGUnit(flexBasisUnitsValue()); +} + +void LayoutComponentStyle::markLayoutNodeDirty() +{ + if (parent()->is()) + { + parent()->as()->markLayoutNodeDirty(); + } +} + +void LayoutComponentStyle::markLayoutStyleDirty() +{ + if (parent()->is()) + { + parent()->as()->markLayoutStyleDirty(); + } +} + +void LayoutComponentStyle::scaleTypeChanged() +{ + if (parent()->is()) + { + parent()->as()->scaleTypeChanged(); + } +} + +void LayoutComponentStyle::displayChanged() +{ + if (parent()->is()) + { + parent()->as()->displayChanged(); + } +} + +void LayoutComponentStyle::positionTypeValueChanged() +{ + if (parent()->is()) + { + parent()->as()->positionTypeChanged(); + } +} + +void LayoutComponentStyle::flexDirectionValueChanged() +{ + if (parent()->is()) + { + parent()->as()->flexDirectionChanged(); + } +} + +void LayoutComponentStyle::directionValueChanged() +{ + if (parent()->is()) + { + parent()->as()->directionChanged(); + } +} + +StatusCode LayoutComponentStyle::onAddedDirty(CoreContext* context) +{ + auto code = Super::onAddedDirty(context); + if (code != StatusCode::Ok) + { + return code; + } + + auto coreObject = context->resolve(interpolatorId()); + if (coreObject != nullptr && coreObject->is()) + { + m_interpolator = static_cast(coreObject); + } + return StatusCode::Ok; +} +#else +void LayoutComponentStyle::markLayoutNodeDirty() {} +void LayoutComponentStyle::markLayoutStyleDirty() {} +void LayoutComponentStyle::scaleTypeChanged() {} +void LayoutComponentStyle::displayChanged() {} +void LayoutComponentStyle::positionTypeValueChanged() {} +void LayoutComponentStyle::flexDirectionValueChanged() {} +void LayoutComponentStyle::directionValueChanged() {} +#endif + +void LayoutComponentStyle::interpolationTimeChanged() +{ + markLayoutStyleDirty(); +} +void LayoutComponentStyle::layoutAlignmentTypeChanged() +{ + markLayoutNodeDirty(); +} +void LayoutComponentStyle::layoutWidthScaleTypeChanged() { scaleTypeChanged(); } +void LayoutComponentStyle::layoutHeightScaleTypeChanged() +{ + scaleTypeChanged(); +} +void LayoutComponentStyle::displayValueChanged() { displayChanged(); } +void LayoutComponentStyle::overflowValueChanged() { markLayoutNodeDirty(); } +void LayoutComponentStyle::intrinsicallySizedValueChanged() +{ + markLayoutNodeDirty(); +} +void LayoutComponentStyle::alignContentValueChanged() { markLayoutNodeDirty(); } +void LayoutComponentStyle::alignItemsValueChanged() { markLayoutNodeDirty(); } +void LayoutComponentStyle::alignSelfValueChanged() { markLayoutNodeDirty(); } +void LayoutComponentStyle::justifyContentValueChanged() +{ + markLayoutNodeDirty(); +} +void LayoutComponentStyle::flexWrapValueChanged() { markLayoutNodeDirty(); } + +void LayoutComponentStyle::flexChanged() { markLayoutNodeDirty(); } +void LayoutComponentStyle::flexGrowChanged() { markLayoutNodeDirty(); } +void LayoutComponentStyle::flexShrinkChanged() { markLayoutNodeDirty(); } +void LayoutComponentStyle::flexBasisChanged() { markLayoutNodeDirty(); } +void LayoutComponentStyle::aspectRatioChanged() { markLayoutNodeDirty(); } +void LayoutComponentStyle::gapHorizontalChanged() { markLayoutNodeDirty(); } +void LayoutComponentStyle::gapVerticalChanged() { markLayoutNodeDirty(); } +void LayoutComponentStyle::maxWidthChanged() { markLayoutNodeDirty(); } +void LayoutComponentStyle::maxHeightChanged() { markLayoutNodeDirty(); } +void LayoutComponentStyle::minWidthChanged() { markLayoutNodeDirty(); } +void LayoutComponentStyle::minHeightChanged() { markLayoutNodeDirty(); } +void LayoutComponentStyle::borderLeftChanged() { markLayoutNodeDirty(); } +void LayoutComponentStyle::borderRightChanged() { markLayoutNodeDirty(); } +void LayoutComponentStyle::borderTopChanged() { markLayoutNodeDirty(); } +void LayoutComponentStyle::borderBottomChanged() { markLayoutNodeDirty(); } +void LayoutComponentStyle::marginLeftChanged() { markLayoutNodeDirty(); } +void LayoutComponentStyle::marginRightChanged() { markLayoutNodeDirty(); } +void LayoutComponentStyle::marginTopChanged() { markLayoutNodeDirty(); } +void LayoutComponentStyle::marginBottomChanged() { markLayoutNodeDirty(); } +void LayoutComponentStyle::paddingLeftChanged() { markLayoutNodeDirty(); } +void LayoutComponentStyle::paddingRightChanged() { markLayoutNodeDirty(); } +void LayoutComponentStyle::paddingTopChanged() { markLayoutNodeDirty(); } +void LayoutComponentStyle::paddingBottomChanged() { markLayoutNodeDirty(); } +void LayoutComponentStyle::positionLeftChanged() { markLayoutNodeDirty(); } +void LayoutComponentStyle::positionRightChanged() { markLayoutNodeDirty(); } +void LayoutComponentStyle::positionTopChanged() { markLayoutNodeDirty(); } +void LayoutComponentStyle::positionBottomChanged() { markLayoutNodeDirty(); } + +void LayoutComponentStyle::widthUnitsValueChanged() { markLayoutNodeDirty(); } +void LayoutComponentStyle::heightUnitsValueChanged() { markLayoutNodeDirty(); } +void LayoutComponentStyle::gapHorizontalUnitsValueChanged() +{ + markLayoutNodeDirty(); +} +void LayoutComponentStyle::gapVerticalUnitsValueChanged() +{ + markLayoutNodeDirty(); +} +void LayoutComponentStyle::maxWidthUnitsValueChanged() +{ + markLayoutNodeDirty(); +} +void LayoutComponentStyle::maxHeightUnitsValueChanged() +{ + markLayoutNodeDirty(); +} +void LayoutComponentStyle::minWidthUnitsValueChanged() +{ + markLayoutNodeDirty(); +} +void LayoutComponentStyle::minHeightUnitsValueChanged() +{ + markLayoutNodeDirty(); +} +void LayoutComponentStyle::borderLeftUnitsValueChanged() +{ + markLayoutNodeDirty(); +} +void LayoutComponentStyle::borderRightUnitsValueChanged() +{ + markLayoutNodeDirty(); +} +void LayoutComponentStyle::borderTopUnitsValueChanged() +{ + markLayoutNodeDirty(); +} +void LayoutComponentStyle::borderBottomUnitsValueChanged() +{ + markLayoutNodeDirty(); +} +void LayoutComponentStyle::marginLeftUnitsValueChanged() +{ + markLayoutNodeDirty(); +} +void LayoutComponentStyle::marginRightUnitsValueChanged() +{ + markLayoutNodeDirty(); +} +void LayoutComponentStyle::marginTopUnitsValueChanged() +{ + markLayoutNodeDirty(); +} +void LayoutComponentStyle::marginBottomUnitsValueChanged() +{ + markLayoutNodeDirty(); +} +void LayoutComponentStyle::paddingLeftUnitsValueChanged() +{ + markLayoutNodeDirty(); +} +void LayoutComponentStyle::paddingRightUnitsValueChanged() +{ + markLayoutNodeDirty(); +} +void LayoutComponentStyle::paddingTopUnitsValueChanged() +{ + markLayoutNodeDirty(); +} +void LayoutComponentStyle::paddingBottomUnitsValueChanged() +{ + markLayoutNodeDirty(); +} +void LayoutComponentStyle::positionLeftUnitsValueChanged() +{ + markLayoutNodeDirty(); +} +void LayoutComponentStyle::positionRightUnitsValueChanged() +{ + markLayoutNodeDirty(); +} +void LayoutComponentStyle::positionTopUnitsValueChanged() +{ + markLayoutNodeDirty(); +} +void LayoutComponentStyle::positionBottomUnitsValueChanged() +{ + markLayoutNodeDirty(); +} +void LayoutComponentStyle::cornerRadiusTLChanged() { markLayoutStyleDirty(); } +void LayoutComponentStyle::cornerRadiusTRChanged() { markLayoutStyleDirty(); } +void LayoutComponentStyle::cornerRadiusBLChanged() { markLayoutStyleDirty(); } +void LayoutComponentStyle::cornerRadiusBRChanged() { markLayoutStyleDirty(); } \ No newline at end of file diff --git a/third_party/rive/source/layout/layout_node_provider.cpp b/third_party/rive/source/layout/layout_node_provider.cpp new file mode 100644 index 0000000..8957bdf --- /dev/null +++ b/third_party/rive/source/layout/layout_node_provider.cpp @@ -0,0 +1,30 @@ +#include "rive/artboard_component_list.hpp" +#include "rive/component.hpp" +#include "rive/constraints/layout_constraint.hpp" +#include "rive/layout_component.hpp" +#include "rive/layout/layout_node_provider.hpp" +#include "rive/nested_artboard_layout.hpp" + +using namespace rive; + +LayoutNodeProvider* LayoutNodeProvider::from(Component* component) +{ + switch (component->coreType()) + { + case LayoutComponent::typeKey: + return component->as(); + case NestedArtboardLayout::typeKey: + return component->as(); + case ArtboardComponentListBase::typeKey: + return component->as(); + } + return nullptr; +} + +void LayoutNodeProvider::addLayoutConstraint(LayoutConstraint* constraint) +{ + assert(std::find(m_layoutConstraints.begin(), + m_layoutConstraints.end(), + constraint) == m_layoutConstraints.end()); + m_layoutConstraints.push_back(constraint); +} \ No newline at end of file diff --git a/third_party/rive/source/layout/n_sliced_node.cpp b/third_party/rive/source/layout/n_sliced_node.cpp new file mode 100644 index 0000000..e6533f5 --- /dev/null +++ b/third_party/rive/source/layout/n_sliced_node.cpp @@ -0,0 +1,164 @@ +#include "rive/layout_component.hpp" +#include "rive/layout/n_sliced_node.hpp" +#include "rive/math/math_types.hpp" +#include "rive/math/n_slicer_helpers.hpp" + +using namespace rive; + +void NSlicedNode::markPathDirtyRecursive(bool sendToLayout) +{ + // Tell all Shape descendants to re-render when the n slicer changes (e.g. + // when axis offset animates). + addDirt(ComponentDirt::NSlicer, true); + +#ifdef WITH_RIVE_LAYOUT + if (sendToLayout) + { + for (ContainerComponent* p = parent(); p != nullptr; p = p->parent()) + { + if (p->is()) + { + p->as()->markLayoutNodeDirty(); + break; + } + } + } +#endif +} + +void NSlicedNode::axisChanged() { markPathDirtyRecursive(); } +void NSlicedNode::widthChanged() { markPathDirtyRecursive(); } +void NSlicedNode::heightChanged() { markPathDirtyRecursive(); } + +void NSlicedNode::update(ComponentDirt value) +{ + Super::update(value); + + // Update whenever children axes change, or our world transform changes + // in case any dependent needs local path (we need to first map to the + // NSlicer space using world transform, then back). + if (hasDirt(value, ComponentDirt::NSlicer | ComponentDirt::WorldTransform)) + { + updateMapWorldPoint(); + } +} + +void NSlicedNode::updateMapWorldPoint() +{ + const Mat2D& world = worldTransform(); + Mat2D inverseWorld; + if (!world.invert(&inverseWorld) || initialHeight() <= 0 || + initialWidth() <= 0) + { + mapWorldPoint = [](Vec2D& v) {}; + return; + } + + Vec2D size = Vec2D(initialWidth(), initialHeight()); + Vec2D scale = scaleForNSlicer(); + + std::vector xPxStops = NSlicerHelpers::pxStops(xs(), size.x); + std::vector yPxStops = NSlicerHelpers::pxStops(ys(), size.y); + + std::vector xUVStops = NSlicerHelpers::uvStops(xs(), size.x); + std::vector yUVStops = NSlicerHelpers::uvStops(ys(), size.y); + + ScaleInfo xScaleInfo = + NSlicerHelpers::analyzeUVStops(xUVStops, size.x, std::abs(scale.x)); + ScaleInfo yScaleInfo = + NSlicerHelpers::analyzeUVStops(yUVStops, size.x, std::abs(scale.y)); + + mapWorldPoint = [this, + world, + inverseWorld, + scale, + xPxStops, + xScaleInfo, + yPxStops, + yScaleInfo](Vec2D& worldP) { + // 1. Map from world space to the effective NSlicer's space + Vec2D localP = inverseWorld * worldP; + + // 2. N-Slice it in the NSlicer's space + Vec2D slicedP = + Vec2D(scale.x == 0 ? 0.0 + : NSlicerHelpers::mapValue(xPxStops, + xScaleInfo, + std::abs(width()), + localP.x) * + std::copysign(1.0f, scale.x), + scale.y == 0 ? 0.0 + : NSlicerHelpers::mapValue(yPxStops, + yScaleInfo, + std::abs(height()), + localP.y) * + std::copysign(1.0f, scale.y)); + + // 3. Back to world space + worldP = world * slicedP; + }; +} + +void NSlicedNode::deformWorldRenderPath(RawPath& path) const +{ + NSlicerHelpers::deformWorldRenderPathWithNSlicer(*this, path); +} + +void NSlicedNode::deformLocalRenderPath(RawPath& path, + const Mat2D& world, + const Mat2D& inverseWorld) const +{ + NSlicerHelpers::deformLocalRenderPathWithNSlicer(*this, + path, + world, + inverseWorld); +} + +Vec2D NSlicedNode::deformLocalPoint(Vec2D point, + const Mat2D& worldTransform, + const Mat2D& inverseWorld) const +{ + Vec2D worldP = worldTransform * point; + Vec2D deformedWorldP = deformWorldPoint(worldP); + return inverseWorld * deformedWorldP; +} + +Vec2D NSlicedNode::deformWorldPoint(Vec2D point) const +{ + Vec2D result = point; + mapWorldPoint(result); + return result; +} + +Vec2D NSlicedNode::scaleForNSlicer() const +{ + return Vec2D(width() / initialWidth(), height() / initialHeight()); +} + +// We are telling a Layout what our size is +Vec2D NSlicedNode::measureLayout(float width, + LayoutMeasureMode widthMode, + float height, + LayoutMeasureMode heightMode) +{ + return Vec2D(std::min((widthMode == LayoutMeasureMode::undefined + ? std::numeric_limits::max() + : width), + NSlicedNode::width()), + std::min((heightMode == LayoutMeasureMode::undefined + ? std::numeric_limits::max() + : height), + NSlicedNode::height())); +} + +// We are told by a Layout to be a particular size +void NSlicedNode::controlSize(Vec2D size, + LayoutScaleType widthScaleType, + LayoutScaleType heightScaleType, + LayoutDirection direction) +{ + width(size.x); + height(size.y); + markWorldTransformDirty(); + markPathDirtyRecursive(false); +} diff --git a/third_party/rive/source/layout/n_slicer.cpp b/third_party/rive/source/layout/n_slicer.cpp new file mode 100644 index 0000000..2fcaafe --- /dev/null +++ b/third_party/rive/source/layout/n_slicer.cpp @@ -0,0 +1,56 @@ +#include "rive/layout/n_slicer.hpp" +#include "rive/layout/n_slicer_tile_mode.hpp" +#include "rive/shapes/image.hpp" +#include "rive/shapes/slice_mesh.hpp" +#include "rive/core_context.hpp" + +using namespace rive; + +NSlicer::NSlicer() { m_sliceMesh = rivestd::make_unique(this); } + +Image* NSlicer::image() +{ + if (parent()) + { + return parent()->as(); + } + return nullptr; +} + +StatusCode NSlicer::onAddedDirty(CoreContext* context) +{ + StatusCode code = Super::onAddedDirty(context); + if (code != StatusCode::Ok) + { + return code; + } + + if (!parent()->is()) + { + return StatusCode::MissingObject; + } + + parent()->as()->setMesh(m_sliceMesh.get()); + return StatusCode::Ok; +} + +void NSlicer::buildDependencies() +{ + Super::buildDependencies(); + parent()->addDependent(this); +} + +void NSlicer::axisChanged() { addDirt(ComponentDirt::NSlicer); } + +void NSlicer::update(ComponentDirt value) +{ + if (hasDirt(value, ComponentDirt::NSlicer) || + hasDirt(value, ComponentDirt::WorldTransform)) + { + if (m_sliceMesh != nullptr) + { + m_sliceMesh->update(); + } + } + Super::update(value); +} diff --git a/third_party/rive/source/layout/n_slicer_details.cpp b/third_party/rive/source/layout/n_slicer_details.cpp new file mode 100644 index 0000000..9bc0d69 --- /dev/null +++ b/third_party/rive/source/layout/n_slicer_details.cpp @@ -0,0 +1,33 @@ +#include "rive/component.hpp" +#include "rive/layout/n_sliced_node.hpp" +#include "rive/layout/n_slicer.hpp" +#include "rive/layout/n_slicer_details.hpp" +#include "rive/layout/n_slicer_tile_mode.hpp" + +using namespace rive; + +NSlicerDetails* NSlicerDetails::from(Component* component) +{ + switch (component->coreType()) + { + case NSlicer::typeKey: + return component->as(); + case NSlicedNode::typeKey: + return component->as(); + } + return nullptr; +} + +int NSlicerDetails::patchIndex(int patchX, int patchY) +{ + return patchY * (static_cast(m_xs.size()) + 1) + patchX; +} + +void NSlicerDetails::addAxisX(Axis* axis) { m_xs.push_back(axis); } + +void NSlicerDetails::addAxisY(Axis* axis) { m_ys.push_back(axis); } + +void NSlicerDetails::addTileMode(int patchIndex, NSlicerTileModeType style) +{ + m_tileModes[patchIndex] = style; +} diff --git a/third_party/rive/source/layout/n_slicer_tile_mode.cpp b/third_party/rive/source/layout/n_slicer_tile_mode.cpp new file mode 100644 index 0000000..d56335a --- /dev/null +++ b/third_party/rive/source/layout/n_slicer_tile_mode.cpp @@ -0,0 +1,23 @@ +#include "rive/container_component.hpp" +#include "rive/layout/n_slicer_tile_mode.hpp" +#include "rive/layout/n_slicer_details.hpp" + +using namespace rive; + +StatusCode NSlicerTileMode::onAddedDirty(CoreContext* context) +{ + StatusCode code = Super::onAddedDirty(context); + if (code != StatusCode::Ok) + { + return code; + } + + NSlicerDetails* container = NSlicerDetails::from(parent()); + if (container == nullptr) + { + return StatusCode::MissingObject; + } + + container->addTileMode(patchIndex(), NSlicerTileModeType(style())); + return StatusCode::Ok; +} diff --git a/third_party/rive/source/layout_component.cpp b/third_party/rive/source/layout_component.cpp new file mode 100644 index 0000000..42759fd --- /dev/null +++ b/third_party/rive/source/layout_component.cpp @@ -0,0 +1,1453 @@ +#include "rive/animation/keyframe_interpolator.hpp" +#include "rive/artboard.hpp" +#include "rive/artboard_component_list.hpp" +#include "rive/constraints/layout_constraint.hpp" +#include "rive/drawable.hpp" +#include "rive/factory.hpp" +#include "rive/intrinsically_sizeable.hpp" +#include "rive/layout_component.hpp" +#include "rive/nested_artboard_layout.hpp" +#include "rive/node.hpp" +#include "rive/math/aabb.hpp" +#include "rive/shapes/paint/fill.hpp" +#include "rive/shapes/paint/shape_paint.hpp" +#include "rive/shapes/paint/stroke.hpp" +#include "rive/shapes/rectangle.hpp" +#include "rive/nested_artboard_layout.hpp" +#include "rive/layout/layout_data.hpp" +#include "rive/layout/layout_component_style.hpp" +#ifdef WITH_RIVE_LAYOUT +#include "rive/transform_component.hpp" +#include "yoga/YGEnums.h" +#include "yoga/YGFloatOptional.h" +#endif +#include + +using namespace rive; + +#if defined(WITH_RIVE_LAYOUT) && defined(WITH_RIVE_TOOLS) && defined(DEBUG) +uint32_t LayoutData::count = 0; +#endif + +void LayoutComponent::buildDependencies() +{ + Super::buildDependencies(); + if (parent() != nullptr) + { + parent()->addDependent(this); + } + // Set the blend mode on all the shape paints. If we ever animate this + // property, we'll need to update it in the update cycle/mark dirty when the + // blend mode changes. + for (auto paint : m_ShapePaints) + { + paint->blendMode(blendMode()); + } +} + +Core* LayoutComponent::hitTest(HitInfo*, const Mat2D&) { return nullptr; } + +void LayoutComponent::update(ComponentDirt value) +{ + Super::update(value); +#ifdef WITH_RIVE_LAYOUT + if (value == ComponentDirt::Filthy) + { + // Use this to prevent layout animation on startup + interruptAnimation(); + } +#endif + if (hasDirt(value, ComponentDirt::RenderOpacity)) + { + propagateOpacity(childOpacity()); + } + if (parent() != nullptr && hasDirt(value, ComponentDirt::WorldTransform)) + { + Mat2D parentWorld = + parent()->is() + ? (parent()->as())->worldTransform() + : Mat2D(); + auto location = Vec2D(m_layout.left(), m_layout.top()); + if (parent()->is()) + { + auto art = parent()->as(); + location -= Vec2D(art->layoutWidth() * art->originX(), + art->layoutHeight() * art->originY()); + } + auto transform = Mat2D::fromTranslation(location); + m_WorldTransform = Mat2D::multiply(parentWorld, transform); + updateConstraints(); + } + if (hasDirt(value, + ComponentDirt::Path | ComponentDirt::WorldTransform | + ComponentDirt::LayoutStyle)) + { + updateRenderPath(); + } +} + +void LayoutComponent::widthOverride(float width, int unitValue, bool isRow) +{ + m_widthOverride = width; + m_widthUnitValueOverride = unitValue; + m_parentIsRow = isRow; + markLayoutNodeDirty(); +} + +void LayoutComponent::heightOverride(float height, int unitValue, bool isRow) +{ + m_heightOverride = height; + m_heightUnitValueOverride = unitValue; + m_parentIsRow = isRow; + markLayoutNodeDirty(); +} + +void LayoutComponent::parentIsRow(bool isRow) +{ + m_parentIsRow = isRow; + markLayoutNodeDirty(); +} + +void LayoutComponent::widthIntrinsicallySizeOverride(bool intrinsic) +{ + m_widthIntrinsicallySizeOverride = intrinsic; + // If we have an intrinsically sized override, set units to auto + // otherwise set to points + m_widthUnitValueOverride = intrinsic ? 3 : 1; + markLayoutNodeDirty(); +} + +void LayoutComponent::heightIntrinsicallySizeOverride(bool intrinsic) +{ + m_heightIntrinsicallySizeOverride = intrinsic; + // If we have an intrinsically sized override, set units to auto + // otherwise set to points + m_heightUnitValueOverride = intrinsic ? 3 : 1; + markLayoutNodeDirty(); +} + +void LayoutComponent::forcedWidth(float width) +{ + if (m_forcedWidth == width) + { + return; + } + m_forcedWidth = width; + markLayoutStyleDirty(); + markLayoutNodeDirty(); +} + +void LayoutComponent::forcedHeight(float height) +{ + if (m_forcedHeight == height) + { + return; + } + m_forcedHeight = height; + markLayoutStyleDirty(); + markLayoutNodeDirty(); +} + +void LayoutComponent::updateConstraints() +{ + if (m_layoutConstraints.size() > 0) + { + for (auto parentConstraint : m_layoutConstraints) + { + parentConstraint->constrainChild(this); + } + } + Super::updateConstraints(); +} + +bool LayoutComponent::overridesKeyedInterpolation(int propertyKey) +{ +#ifdef WITH_RIVE_LAYOUT + if (animates()) + { + switch (propertyKey) + { + case LayoutComponentBase::widthPropertyKey: + case LayoutComponentBase::heightPropertyKey: + return true; + default: + return false; + } + } +#endif + return false; +} + +bool LayoutComponent::isHidden() const +{ + return Super::isHidden() || isDisplayHidden(); +} + +bool LayoutComponent::isDisplayHidden() const +{ +#ifdef WITH_RIVE_LAYOUT + if (m_displayHidden || parent() == nullptr || + !parent()->is()) + { + return m_displayHidden; + } + return parent()->as()->isDisplayHidden(); +#endif + return false; +} + +void LayoutComponent::propagateCollapse(bool collapse) +{ + bool displayHidden = isDisplayHidden(); + for (Component* child : children()) + { + child->collapse(collapse || displayHidden); + } +} + +bool LayoutComponent::collapse(bool value) +{ + if (!Component::collapse(value)) + { + return false; + } + for (Component* child : children()) + { + child->collapse(value || m_displayHidden); + } + return true; +} + +#ifdef WITH_RIVE_LAYOUT + +LayoutComponent::LayoutComponent() : + m_layoutData(new LayoutData()), m_proxy(this) +{ + m_layoutData->node.getConfig()->setPointScaleFactor(0); +} + +float LayoutComponent::gapHorizontal() +{ + if (m_style == nullptr) + { + return 0; + } + return m_style->gapHorizontalUnits() == YGUnitPercent + ? (m_style->gapHorizontal() / 100.0f) * layoutWidth() + : m_style->gapHorizontal(); +} + +float LayoutComponent::gapVertical() +{ + if (m_style == nullptr) + { + return 0; + } + return m_style->gapVerticalUnits() == YGUnitPercent + ? (m_style->gapVertical() / 100.0f) * layoutHeight() + : m_style->gapVertical(); +} + +StatusCode LayoutComponent::onAddedDirty(CoreContext* context) +{ + auto code = Super::onAddedDirty(context); + if (code != StatusCode::Ok) + { + return code; + } + + auto coreStyle = context->resolve(styleId()); + if (coreStyle == nullptr || !coreStyle->is()) + { + return StatusCode::MissingObject; + } + m_style = static_cast(coreStyle); + addChild(m_style); + + return StatusCode::Ok; +} + +StatusCode LayoutComponent::onAddedClean(CoreContext* context) +{ + auto code = Super::onAddedClean(context); + if (code != StatusCode::Ok) + { + return code; + } + markLayoutStyleDirty(); + m_backgroundRect.originX(0); + m_backgroundRect.originY(0); + syncLayoutChildren(); + propagateCollapse(isCollapsed()); + return StatusCode::Ok; +} + +void LayoutComponent::drawProxy(Renderer* renderer) +{ + if (clip()) + { + renderer->save(); + renderer->clipPath(m_worldPath.renderPath(this)); + } + for (auto shapePaint : m_ShapePaints) + { + if (!shapePaint->shouldDraw()) + { + continue; + } + auto shapePaintPath = shapePaint->pickPath(this); + if (shapePaintPath == nullptr) + { + continue; + } + shapePaint->draw(renderer, shapePaintPath, worldTransform()); + } +} + +void LayoutComponent::draw(Renderer* renderer) +{ + // Restore clip before drawing stroke so we don't clip the stroke + if (clip()) + { + renderer->restore(); + } +} + +void LayoutComponent::updateRenderPath() +{ + if (isDisplayHidden()) + { + return; + } + m_backgroundRect.width(m_layout.width()); + m_backgroundRect.height(m_layout.height()); + if (style() != nullptr) + { + bool isLTR = actualDirection() != LayoutDirection::rtl; + auto linkedValue = style()->cornerRadiusTL(); + auto tl = isLTR ? style()->cornerRadiusTL() : style()->cornerRadiusTR(); + auto tr = isLTR ? style()->cornerRadiusTR() : style()->cornerRadiusTL(); + auto bl = isLTR ? style()->cornerRadiusBL() : style()->cornerRadiusBR(); + auto br = isLTR ? style()->cornerRadiusBR() : style()->cornerRadiusBL(); + m_backgroundRect.linkCornerRadius(style()->linkCornerRadius()); + m_backgroundRect.cornerRadiusTL( + style()->linkCornerRadius() ? linkedValue : tl); + m_backgroundRect.cornerRadiusTR( + style()->linkCornerRadius() ? linkedValue : tr); + m_backgroundRect.cornerRadiusBL( + style()->linkCornerRadius() ? linkedValue : bl); + m_backgroundRect.cornerRadiusBR( + style()->linkCornerRadius() ? linkedValue : br); + } + m_backgroundRect.update(ComponentDirt::Path); + + m_localPath.rewind(); + m_localPath.addPath(m_backgroundRect.rawPath()); + + m_worldPath.rewind(false, FillRule::clockwise); + m_worldPath.addPath(m_backgroundRect.rawPath(), &m_WorldTransform); + + for (auto shapePaint : m_ShapePaints) + { + if (!shapePaint->shouldDraw()) + { + continue; + } + if (shapePaint->is()) + { + shapePaint->as()->invalidateEffects(); + } + } +} + +static YGSize measureFunc(YGNode* node, + float width, + YGMeasureMode widthMode, + float height, + YGMeasureMode heightMode) +{ + Vec2D size = ((LayoutComponent*)node->getContext()) + ->measureLayout(width, + (LayoutMeasureMode)widthMode, + height, + (LayoutMeasureMode)heightMode); + + return YGSize{size.x, size.y}; +} + +Vec2D LayoutComponent::measureLayout(float width, + LayoutMeasureMode widthMode, + float height, + LayoutMeasureMode heightMode) +{ + Vec2D size = Vec2D(); + for (auto child : children()) + { + if (child->is()) + { + continue; + } + auto sizeableChild = IntrinsicallySizeable::from(child); + if (sizeableChild != nullptr) + { + Vec2D measured = sizeableChild->measureLayout(width, + widthMode, + height, + heightMode); + size = Vec2D(std::max(size.x, measured.x), + std::max(size.y, measured.y)); + } + } + return size; +} + +bool LayoutComponent::mainAxisIsRow() +{ + if (style() == nullptr) + { + return true; + } + return style()->flexDirection() == YGFlexDirectionRow || + style()->flexDirection() == YGFlexDirectionRowReverse; +} + +bool LayoutComponent::mainAxisIsColumn() +{ + if (style() == nullptr) + { + return false; + } + return style()->flexDirection() == YGFlexDirectionColumn || + style()->flexDirection() == YGFlexDirectionColumnReverse; +} + +bool LayoutComponent::isLeaf() +{ + for (auto child : children()) + { + auto layout = LayoutNodeProvider::from(child); + if (layout != nullptr) + { + return false; + } + } + return true; +} + +void* LayoutComponent::layoutNode(int index) +{ + if (m_layoutData != nullptr) + { + return static_cast(&m_layoutData->node); + } + return nullptr; +} + +void LayoutComponent::syncStyle() +{ + if (m_style == nullptr || m_layoutData == nullptr) + { + return; + } + YGNode& ygNode = m_layoutData->node; + YGStyle& ygStyle = m_layoutData->style; + if (m_style->intrinsicallySized() && isLeaf()) + { + ygNode.setContext(this); + ygNode.setMeasureFunc(measureFunc); + } + else + { + ygNode.setMeasureFunc(nullptr); + } + + auto realWidth = width(); + auto realWidthUnits = m_style->widthUnits(); + auto realWidthScaleType = m_style->widthScaleType(); + auto realHeight = height(); + auto realHeightUnits = m_style->heightUnits(); + auto realHeightScaleType = m_style->heightScaleType(); + auto parentIsRow = + layoutParent() != nullptr ? layoutParent()->mainAxisIsRow() : true; + + // If we have override width/height values, use those. + // Currently we only use these for Artboards that are part of a + // NestedArtboardLayout but perhaps there will be other use cases for + // overriding in the future? + if (canHaveOverrides()) + { + if (!std::isnan(m_widthOverride)) + { + realWidth = m_widthOverride; + } + if (!std::isnan(m_heightOverride)) + { + realHeight = m_heightOverride; + } + parentIsRow = m_parentIsRow; + + if (m_widthUnitValueOverride != -1) + { + realWidthUnits = YGUnit(m_widthUnitValueOverride); + switch (realWidthUnits) + { + case YGUnitPoint: + case YGUnitPercent: + realWidthScaleType = LayoutScaleType::fixed; + break; + case YGUnitAuto: + if (m_widthIntrinsicallySizeOverride) + { + realWidthScaleType = LayoutScaleType::hug; + } + else + { + realWidthScaleType = LayoutScaleType::fill; + } + break; + default: + break; + } + } + if (m_heightUnitValueOverride != -1) + { + realHeightUnits = YGUnit(m_heightUnitValueOverride); + switch (realHeightUnits) + { + case YGUnitPoint: + case YGUnitPercent: + realHeightScaleType = LayoutScaleType::fixed; + break; + case YGUnitAuto: + if (m_heightIntrinsicallySizeOverride) + { + realHeightScaleType = LayoutScaleType::hug; + } + else + { + realHeightScaleType = LayoutScaleType::fill; + } + break; + default: + break; + } + } + } + if (!std::isnan(m_forcedWidth)) + { + ygStyle.dimensions()[YGDimensionWidth] = + YGValue{std::max(0.0f, m_forcedWidth), YGUnitPoint}; + } + else + { + ygStyle.dimensions()[YGDimensionWidth] = + YGValue{std::max(0.0f, realWidth), realWidthUnits}; + } + if (!std::isnan(m_forcedHeight)) + { + ygStyle.dimensions()[YGDimensionHeight] = + YGValue{std::max(0.0f, m_forcedHeight), YGUnitPoint}; + } + else + { + ygStyle.dimensions()[YGDimensionHeight] = + YGValue{std::max(0.0f, realHeight), realHeightUnits}; + } + + switch (realWidthScaleType) + { + case LayoutScaleType::fixed: + if (parentIsRow) + { + ygStyle.flexGrow() = YGFloatOptional(0); + ygStyle.flexShrink() = YGFloatOptional(0); + ygStyle.flexBasis() = YGValue{m_style->flexBasis(), YGUnitAuto}; + } + else + { + ygStyle.alignSelf() = YGAlignAuto; + } + break; + case LayoutScaleType::fill: + if (parentIsRow) + { + ygStyle.flexGrow() = YGFloatOptional(fractionalWidth()); + ygStyle.flexShrink() = YGFloatOptional(fractionalWidth()); + ygStyle.flexBasis() = + YGValue{m_style->flexBasis(), m_style->flexBasisUnits()}; + } + else + { + ygStyle.alignSelf() = YGAlignStretch; + } + break; + case LayoutScaleType::hug: + if (parentIsRow) + { + ygStyle.flexGrow() = YGFloatOptional(0); + ygStyle.flexShrink() = YGFloatOptional(0); + ygStyle.flexBasis() = YGValue{m_style->flexBasis(), YGUnitAuto}; + } + else + { + ygStyle.alignSelf() = YGAlignAuto; + } + break; + default: + break; + } + + switch (realHeightScaleType) + { + case LayoutScaleType::fixed: + if (!parentIsRow) + { + ygStyle.flexGrow() = YGFloatOptional(0); + ygStyle.flexShrink() = YGFloatOptional(0); + ygStyle.flexBasis() = YGValue{m_style->flexBasis(), YGUnitAuto}; + } + else + { + ygStyle.alignSelf() = YGAlignAuto; + } + break; + case LayoutScaleType::fill: + if (!parentIsRow) + { + ygStyle.flexGrow() = YGFloatOptional(fractionalHeight()); + ygStyle.flexShrink() = YGFloatOptional(fractionalHeight()); + ygStyle.flexBasis() = + YGValue{m_style->flexBasis(), m_style->flexBasisUnits()}; + } + else + { + ygStyle.alignSelf() = YGAlignStretch; + } + break; + case LayoutScaleType::hug: + if (!parentIsRow) + { + ygStyle.flexGrow() = YGFloatOptional(0); + ygStyle.flexShrink() = YGFloatOptional(0); + ygStyle.flexBasis() = YGValue{m_style->flexBasis(), YGUnitAuto}; + } + else + { + ygStyle.alignSelf() = YGAlignAuto; + } + break; + default: + break; + } + + bool isRowForAlignment = mainAxisIsRow(); + switch (m_style->alignmentType()) + { + case LayoutAlignmentType::topLeft: + case LayoutAlignmentType::topCenter: + case LayoutAlignmentType::topRight: + if (isRowForAlignment) + { + ygStyle.alignItems() = YGAlignFlexStart; + ygStyle.alignContent() = YGAlignFlexStart; + } + else + { + ygStyle.justifyContent() = YGJustifyFlexStart; + } + break; + case LayoutAlignmentType::centerLeft: + case LayoutAlignmentType::center: + case LayoutAlignmentType::centerRight: + if (isRowForAlignment) + { + ygStyle.alignItems() = YGAlignCenter; + ygStyle.alignContent() = YGAlignCenter; + } + else + { + ygStyle.justifyContent() = YGJustifyCenter; + } + break; + case LayoutAlignmentType::bottomLeft: + case LayoutAlignmentType::bottomCenter: + case LayoutAlignmentType::bottomRight: + if (isRowForAlignment) + { + ygStyle.alignItems() = YGAlignFlexEnd; + ygStyle.alignContent() = YGAlignFlexEnd; + } + else + { + ygStyle.justifyContent() = YGJustifyFlexEnd; + } + break; + default: + break; + } + switch (m_style->alignmentType()) + { + case LayoutAlignmentType::topLeft: + case LayoutAlignmentType::centerLeft: + case LayoutAlignmentType::bottomLeft: + if (isRowForAlignment) + { + ygStyle.justifyContent() = YGJustifyFlexStart; + } + else + { + ygStyle.alignItems() = YGAlignFlexStart; + ygStyle.alignContent() = YGAlignFlexStart; + } + break; + case LayoutAlignmentType::topCenter: + case LayoutAlignmentType::center: + case LayoutAlignmentType::bottomCenter: + if (isRowForAlignment) + { + ygStyle.justifyContent() = YGJustifyCenter; + } + else + { + ygStyle.alignItems() = YGAlignCenter; + ygStyle.alignContent() = YGAlignCenter; + } + break; + case LayoutAlignmentType::topRight: + case LayoutAlignmentType::centerRight: + case LayoutAlignmentType::bottomRight: + if (isRowForAlignment) + { + ygStyle.justifyContent() = YGJustifyFlexEnd; + } + else + { + ygStyle.alignItems() = YGAlignFlexEnd; + ygStyle.alignContent() = YGAlignFlexEnd; + } + break; + case LayoutAlignmentType::spaceBetweenStart: + ygStyle.alignItems() = YGAlignFlexStart; + ygStyle.alignContent() = YGAlignFlexStart; + ygStyle.justifyContent() = YGJustifySpaceBetween; + break; + case LayoutAlignmentType::spaceBetweenCenter: + ygStyle.alignItems() = YGAlignCenter; + ygStyle.alignContent() = YGAlignCenter; + ygStyle.justifyContent() = YGJustifySpaceBetween; + break; + case LayoutAlignmentType::spaceBetweenEnd: + ygStyle.alignItems() = YGAlignFlexEnd; + ygStyle.alignContent() = YGAlignFlexEnd; + ygStyle.justifyContent() = YGJustifySpaceBetween; + break; + } + + ygStyle.minDimensions()[YGDimensionWidth] = + YGValue{m_style->minWidth(), m_style->minWidthUnits()}; + ygStyle.minDimensions()[YGDimensionHeight] = + YGValue{m_style->minHeight(), m_style->minHeightUnits()}; + ygStyle.maxDimensions()[YGDimensionWidth] = + YGValue{m_style->maxWidth(), m_style->maxWidthUnits()}; + ygStyle.maxDimensions()[YGDimensionHeight] = + YGValue{m_style->maxHeight(), m_style->maxHeightUnits()}; + ygStyle.gap()[YGGutterColumn] = + YGValue{m_style->gapHorizontal(), m_style->gapHorizontalUnits()}; + ygStyle.gap()[YGGutterRow] = + YGValue{m_style->gapVertical(), m_style->gapVerticalUnits()}; + + bool isLTR = actualDirection() != LayoutDirection::rtl; + auto startEdge = isLTR ? YGEdgeLeft : YGEdgeRight; + auto endEdge = isLTR ? YGEdgeRight : YGEdgeLeft; + ygStyle.border()[startEdge] = + YGValue{m_style->borderLeft(), m_style->borderLeftUnits()}; + ygStyle.border()[endEdge] = + YGValue{m_style->borderRight(), m_style->borderRightUnits()}; + ygStyle.border()[YGEdgeTop] = + YGValue{m_style->borderTop(), m_style->borderTopUnits()}; + ygStyle.border()[YGEdgeBottom] = + YGValue{m_style->borderBottom(), m_style->borderBottomUnits()}; + ygStyle.margin()[startEdge] = + YGValue{m_style->marginLeft(), m_style->marginLeftUnits()}; + ygStyle.margin()[endEdge] = + YGValue{m_style->marginRight(), m_style->marginRightUnits()}; + ygStyle.margin()[YGEdgeTop] = + YGValue{m_style->marginTop(), m_style->marginTopUnits()}; + ygStyle.margin()[YGEdgeBottom] = + YGValue{m_style->marginBottom(), m_style->marginBottomUnits()}; + ygStyle.padding()[startEdge] = + YGValue{m_style->paddingLeft(), m_style->paddingLeftUnits()}; + ygStyle.padding()[endEdge] = + YGValue{m_style->paddingRight(), m_style->paddingRightUnits()}; + ygStyle.padding()[YGEdgeTop] = + YGValue{m_style->paddingTop(), m_style->paddingTopUnits()}; + ygStyle.padding()[YGEdgeBottom] = + YGValue{m_style->paddingBottom(), m_style->paddingBottomUnits()}; + ygStyle.position()[startEdge] = + YGValue{m_style->positionLeft(), m_style->positionLeftUnits()}; + ygStyle.position()[endEdge] = + YGValue{m_style->positionRight(), m_style->positionRightUnits()}; + ygStyle.position()[YGEdgeTop] = + YGValue{m_style->positionTop(), m_style->positionTopUnits()}; + ygStyle.position()[YGEdgeBottom] = + YGValue{m_style->positionBottom(), m_style->positionBottomUnits()}; + + ygStyle.display() = m_style->display(); + ygStyle.positionType() = m_style->positionType(); + ygStyle.flex() = YGFloatOptional(m_style->flex()); + ygStyle.flexDirection() = m_style->flexDirection(); + ygStyle.flexWrap() = m_style->flexWrap(); + ygStyle.direction() = m_style->direction(); + + ygNode.setStyle(ygStyle); +} + +void LayoutComponent::clearLayoutChildren() +{ + YGNode& ourNode = m_layoutData->node; + YGNodeRemoveAllChildren(&ourNode); +} + +void LayoutComponent::syncLayoutChildren() +{ + YGNode& ourNode = m_layoutData->node; + YGNodeRemoveAllChildren(&ourNode); + int index = 0; + for (auto child : children()) + { + YGNode* node = nullptr; + switch (child->coreType()) + { + case LayoutComponentBase::typeKey: + node = &child->as()->m_layoutData->node; + if (node != nullptr) + { + ourNode.insertChild(node, index++); + node->setOwner(&ourNode); + ourNode.markDirtyAndPropagate(); + } + break; + case NestedArtboardLayoutBase::typeKey: + node = static_cast( + child->as()->layoutNode(0)); + if (node != nullptr) + { + ourNode.insertChild(node, index++); + node->setOwner(&ourNode); + ourNode.markDirtyAndPropagate(); + } + break; + case ArtboardComponentListBase::typeKey: + auto list = child->as(); + for (int i = 0; i < list->artboardCount(); i++) + { + node = static_cast(list->layoutNode(i)); + if (node != nullptr) + { + ourNode.insertChild(node, index++); + node->setOwner(&ourNode); + ourNode.markDirtyAndPropagate(); + } + } + break; + } + } + markLayoutNodeDirty(); +} + +void LayoutComponent::propagateSize() { propagateSizeToChildren(this); } + +void LayoutComponent::propagateSizeToChildren(ContainerComponent* component) +{ + if (isHidden()) + { + return; + } + for (auto child : component->children()) + { + if (child->is() || + child->coreType() == NodeBase::typeKey) + { + continue; + } + auto sizeableChild = IntrinsicallySizeable::from(child); + if (sizeableChild != nullptr && m_style != nullptr) + { + LayoutScaleType widthScaleType = m_style->widthScaleType(); + LayoutScaleType heightScaleType = m_style->heightScaleType(); + sizeableChild->controlSize( + Vec2D(m_layout.width(), m_layout.height()), + widthScaleType, + heightScaleType, + actualDirection()); + + if (!sizeableChild->shouldPropagateSizeToChildren()) + { + // Do not propagate to its children + continue; + } + } + if (child->is()) + { + propagateSizeToChildren(child->as()); + } + } +} + +void LayoutComponent::calculateLayout() +{ + YGNodeCalculateLayout(&m_layoutData->node, + width(), + height(), + YGDirection::YGDirectionInherit); +} + +bool LayoutComponent::styleDisplayHidden() +{ + if (m_style == nullptr) + { + return false; + } + return m_style->display() == YGDisplayNone; +} + +LayoutDirection LayoutComponent::actualDirection() +{ + if (m_style == nullptr) + { + return m_inheritedDirection; + } + switch (m_style->direction()) + { + case YGDirectionLTR: + return LayoutDirection::ltr; + case YGDirectionRTL: + return LayoutDirection::rtl; + default: + return m_inheritedDirection; + } +} + +void LayoutComponent::onDirty(ComponentDirt value) +{ + Super::onDirty(value); + if ((value & ComponentDirt::WorldTransform) == + ComponentDirt::WorldTransform && + clip()) + { + addDirt(ComponentDirt::Path); + } +} + +static Layout layoutFromYoga(const YGLayout& layout) +{ + return Layout(layout.position[YGEdgeLeft], + layout.position[YGEdgeTop], + layout.dimensions[YGDimensionWidth], + layout.dimensions[YGDimensionHeight]); +} + +static LayoutPadding layoutPaddingFromYoga(const YGLayout& layout) +{ + return LayoutPadding(layout.padding[YGEdgeLeft], + layout.padding[YGEdgeTop], + layout.padding[YGEdgeRight], + layout.padding[YGEdgeBottom]); +} + +void LayoutComponent::updateLayoutBounds(bool animate) +{ + YGNode& node = m_layoutData->node; + bool updated = node.getHasNewLayout(); + if (!updated) + { + return; + } + node.setHasNewLayout(false); + + if (m_style != nullptr && styleDisplayHidden() != m_displayHidden) + { + m_displayHidden = styleDisplayHidden(); + propagateCollapse(isCollapsed()); + } + + for (auto child : children()) + { + auto layout = LayoutNodeProvider::from(child); + if (layout != nullptr) + { + layout->updateLayoutBounds(animate); + } + } + + auto yogaLayout = node.getLayout(); + Layout newLayout = layoutFromYoga(yogaLayout); + m_layoutPadding = layoutPaddingFromYoga(yogaLayout); + + if (animate && animates()) + { + auto animationData = currentAnimationData(); + if (newLayout != animationData->to || m_forceUpdateLayoutBounds) + { + if (animationData->elapsedSeconds != 0.0f) + { + if (m_isSmoothingAnimation) + { + // we were already smoothening. + m_animationDataA.copy(m_animationDataB); + } + m_isSmoothingAnimation = true; + } + else + { + m_isSmoothingAnimation = false; + } + animationData = currentAnimationData(); + animationData->from = m_layout; + animationData->to = newLayout; + animationData->elapsedSeconds = 0.0f; + propagateSize(); + markWorldTransformDirty(); + } + } + else if (newLayout != m_layout || m_forceUpdateLayoutBounds) + { + if (m_layout.width() != newLayout.width() || + m_layout.height() != newLayout.height()) + { + // Width changed, we need to rebuild the path. + addDirt(ComponentDirt::Path); + } + m_animationDataA.to = m_layout = newLayout; + + propagateSize(); + markWorldTransformDirty(); + } + m_forceUpdateLayoutBounds = false; +} + +bool LayoutComponent::advanceComponent(float elapsedSeconds, AdvanceFlags flags) +{ + return applyInterpolation(elapsedSeconds, + (flags & AdvanceFlags::Animate) == + AdvanceFlags::Animate || + (flags & AdvanceFlags::AdvanceNested) == + AdvanceFlags::AdvanceNested); +} + +bool LayoutComponent::animates() +{ + if (m_style == nullptr) + { + return false; + } + return m_style->animationStyle() != LayoutAnimationStyle::none && + interpolation() != LayoutStyleInterpolation::hold && + interpolationTime() > 0; +} + +LayoutAnimationStyle LayoutComponent::animationStyle() +{ + if (m_style == nullptr) + { + return LayoutAnimationStyle::none; + } + return m_style->animationStyle(); +} + +KeyFrameInterpolator* LayoutComponent::interpolator() +{ + if (m_style == nullptr) + { + return nullptr; + } + switch (m_style->animationStyle()) + { + case LayoutAnimationStyle::inherit: + return m_inheritedInterpolator != nullptr ? m_inheritedInterpolator + : m_style->interpolator(); + case LayoutAnimationStyle::custom: + return m_style->interpolator(); + default: + return nullptr; + } +} + +LayoutStyleInterpolation LayoutComponent::interpolation() +{ + auto defaultInterpolation = LayoutStyleInterpolation::hold; + if (m_style == nullptr) + { + return defaultInterpolation; + } + switch (m_style->animationStyle()) + { + case LayoutAnimationStyle::inherit: + return m_inheritedInterpolation; + case LayoutAnimationStyle::custom: + return m_style->interpolation(); + default: + return defaultInterpolation; + } +} + +float LayoutComponent::interpolationTime() +{ + if (m_style == nullptr) + { + return 0; + } + switch (m_style->animationStyle()) + { + case LayoutAnimationStyle::inherit: + return m_inheritedInterpolationTime; + case LayoutAnimationStyle::custom: + return m_style->interpolationTime(); + default: + return 0; + } +} + +bool LayoutComponent::cascadeLayoutStyle( + LayoutStyleInterpolation inheritedInterpolation, + KeyFrameInterpolator* inheritedInterpolator, + float inheritedInterpolationTime, + LayoutDirection direction) +{ + bool updated = false; + if (m_style != nullptr && + m_style->animationStyle() == LayoutAnimationStyle::inherit) + { + updated = setInheritedInterpolation(inheritedInterpolation, + inheritedInterpolator, + inheritedInterpolationTime); + } + else + { + clearInheritedInterpolation(); + } + auto oldDirection = m_inheritedDirection; + if (direction == LayoutDirection::inherit || + (m_style != nullptr && m_style->direction() != YGDirectionInherit)) + { + m_inheritedDirection = LayoutDirection::inherit; + } + else + { + m_inheritedDirection = direction; + } + if (m_inheritedDirection != oldDirection) + { + markLayoutNodeDirty(true); + addDirt(ComponentDirt::Path); + updated = true; + } + for (auto child : children()) + { + if (child->is()) + { + child->as()->cascadeLayoutStyle( + interpolation(), + interpolator(), + interpolationTime(), + actualDirection()); + } + } + return updated; +} + +bool LayoutComponent::setInheritedInterpolation( + LayoutStyleInterpolation inheritedInterpolation, + KeyFrameInterpolator* inheritedInterpolator, + float inheritedInterpolationTime) +{ + if (inheritedInterpolation != m_inheritedInterpolation || + inheritedInterpolator != m_inheritedInterpolator || + inheritedInterpolationTime != m_inheritedInterpolationTime) + { + m_inheritedInterpolation = inheritedInterpolation; + m_inheritedInterpolator = inheritedInterpolator; + m_inheritedInterpolationTime = inheritedInterpolationTime; + return true; + } + return false; +} + +void LayoutComponent::clearInheritedInterpolation() +{ + m_inheritedInterpolation = LayoutStyleInterpolation::hold; + m_inheritedInterpolator = nullptr; + m_inheritedInterpolationTime = 0; +} + +LayoutAnimationData* LayoutComponent::currentAnimationData() +{ + return m_isSmoothingAnimation ? &m_animationDataB : &m_animationDataA; +} + +void LayoutAnimationData::copy(const LayoutAnimationData& source) +{ + from = source.from; + to = source.to; + elapsedSeconds = source.elapsedSeconds; +} + +bool LayoutComponent::applyInterpolation(float elapsedSeconds, bool animate) +{ + auto animationData = currentAnimationData(); + if (!animate || !animates() || m_style == nullptr || + animationData->to == m_layout) + { + return false; + } + if (m_isSmoothingAnimation) + { + float f = std::fmin(1.0f, + interpolationTime() > 0.0f + ? m_animationDataA.elapsedSeconds / + interpolationTime() + : 1.0f); + + if (interpolation() != LayoutStyleInterpolation::linear && + interpolator() != nullptr) + { + f = interpolator()->transform(f); + } + m_animationDataB.from = m_animationDataA.interpolate(f); + if (f == 1.0f) + { + m_animationDataA.copy(m_animationDataB); + m_isSmoothingAnimation = false; + } + else + { + m_animationDataA.elapsedSeconds += elapsedSeconds; + } + } + + if ((animationData = currentAnimationData())->elapsedSeconds >= + interpolationTime()) + { + Layout newLayout = animationData->to; + if (m_layout.width() != newLayout.width() || + m_layout.height() != newLayout.height()) + { + addDirt(ComponentDirt::Path); + } + m_layout = animationData->to; + + if (m_isSmoothingAnimation) + { + m_isSmoothingAnimation = false; + m_animationDataA.copy(m_animationDataB); + m_animationDataA.elapsedSeconds = m_animationDataB.elapsedSeconds = + 0.0f; + } + else + { + m_animationDataA.elapsedSeconds = 0.0f; + } + propagateSize(); + markWorldTransformDirty(); + + return false; + } + float f = + std::fmin(1.0f, + interpolationTime() > 0 + ? animationData->elapsedSeconds / interpolationTime() + : 1.0f); + if (interpolation() != LayoutStyleInterpolation::linear && + interpolator() != nullptr) + { + f = interpolator()->transform(f); + } + + auto current = animationData->interpolate(f); + if (m_layout != current) + { + bool sizeChanged = m_layout.width() != current.width() || + m_layout.height() != current.height(); + m_layout = current; + if (sizeChanged) + { + propagateSize(); + } + markWorldTransformDirty(); + } + + animationData->elapsedSeconds += elapsedSeconds; + if (f != 1) + { + // Do we really need to mark the layout node dirty!!?? + markLayoutNodeDirty(); + return true; + } + return false; +} + +void LayoutComponent::interruptAnimation() +{ + if (animates()) + { + m_layout = currentAnimationData()->to; + propagateSize(); + } +} + +void LayoutComponent::markLayoutNodeDirty(bool shouldForceUpdateLayoutBounds) +{ + if (shouldForceUpdateLayoutBounds == true) + { + m_forceUpdateLayoutBounds = shouldForceUpdateLayoutBounds; + } + m_layoutData->node.markDirtyAndPropagate(); + artboard()->markLayoutDirty(this); +} + +void LayoutComponent::markLayoutStyleDirty() +{ + clearInheritedInterpolation(); + addDirt(ComponentDirt::LayoutStyle); + if (artboard() != this) + { + artboard()->markLayoutStyleDirty(); + } +} + +void LayoutComponent::positionTypeChanged() +{ + if (m_style == nullptr) + { + return; + } + if (m_style->positionType() == YGPositionTypeAbsolute) + { + m_style->positionLeft(layoutBounds().left()); + m_style->positionTop(layoutBounds().top()); + m_style->positionRight(0); + m_style->positionBottom(0); + m_style->positionLeftUnitsValue(YGUnitPoint); + m_style->positionTopUnitsValue(YGUnitPoint); + m_style->positionRightUnitsValue(YGUnitUndefined); + m_style->positionBottomUnitsValue(YGUnitUndefined); + } + else + { + m_style->positionLeft(0); + m_style->positionTop(0); + m_style->positionRight(0); + m_style->positionBottom(0); + m_style->positionLeftUnitsValue(YGUnitUndefined); + m_style->positionTopUnitsValue(YGUnitUndefined); + m_style->positionRightUnitsValue(YGUnitUndefined); + m_style->positionBottomUnitsValue(YGUnitUndefined); + } + markLayoutNodeDirty(); +} + +void LayoutComponent::scaleTypeChanged() +{ + if (m_style == nullptr) + { + return; + } + m_style->widthUnitsValue(m_style->widthScaleType() == LayoutScaleType::fixed + ? YGUnitPoint + : YGUnitAuto); + m_style->heightUnitsValue( + m_style->heightScaleType() == LayoutScaleType::fixed ? YGUnitPoint + : YGUnitAuto); + m_style->intrinsicallySizedValue( + m_style->widthScaleType() == LayoutScaleType::hug || + m_style->heightScaleType() == LayoutScaleType::hug); + markLayoutNodeDirty(); +} + +void LayoutComponent::displayChanged() +{ + if (m_style == nullptr) + { + return; + } + markLayoutNodeDirty(); +} + +void LayoutComponent::flexDirectionChanged() +{ + markLayoutNodeDirty(); + for (Component* child : children()) + { + auto layout = LayoutNodeProvider::from(child); + if (layout != nullptr) + { + layout->markLayoutNodeDirty(); + } + } +} + +void LayoutComponent::directionChanged() +{ + markLayoutStyleDirty(); + markLayoutNodeDirty(true); +} +#else +LayoutComponent::LayoutComponent() : + m_layoutData(new LayoutData()), m_proxy(this) +{} + +float LayoutComponent::gapHorizontal() { return 0; } +float LayoutComponent::gapVertical() { return 0; } + +void LayoutComponent::drawProxy(Renderer* renderer) {} + +void LayoutComponent::draw(Renderer* renderer) {} + +void LayoutComponent::updateRenderPath() {} + +Vec2D LayoutComponent::measureLayout(float width, + LayoutMeasureMode widthMode, + float height, + LayoutMeasureMode heightMode) +{ + return Vec2D(); +} + +bool LayoutComponent::advanceComponent(float elapsedSeconds, AdvanceFlags flags) +{ + return false; +} + +void LayoutComponent::markLayoutNodeDirty(bool shouldForceUpdateLayoutBounds) {} +void LayoutComponent::markLayoutStyleDirty() {} +void LayoutComponent::onDirty(ComponentDirt value) {} +bool LayoutComponent::mainAxisIsRow() { return true; } + +bool LayoutComponent::mainAxisIsColumn() { return false; } +#endif + +LayoutComponent::~LayoutComponent() +{ + if (artboard() != nullptr) + { + artboard()->cleanLayout(this); + } +#ifdef WITH_RIVE_TOOLS + m_layoutData->unref(); +#else + delete m_layoutData; +#endif +} + +void LayoutComponent::clipChanged() { markLayoutNodeDirty(); } +void LayoutComponent::widthChanged() { markLayoutNodeDirty(); } +void LayoutComponent::heightChanged() { markLayoutNodeDirty(); } +void LayoutComponent::styleIdChanged() { markLayoutNodeDirty(); } +void LayoutComponent::fractionalWidthChanged() { markLayoutNodeDirty(); } +void LayoutComponent::fractionalHeightChanged() { markLayoutNodeDirty(); } + +ShapePaintPath* LayoutComponent::worldPath() { return &m_worldPath; } +ShapePaintPath* LayoutComponent::localPath() { return &m_localPath; } +ShapePaintPath* LayoutComponent::localClockwisePath() { return &m_localPath; } + +Component* LayoutComponent::pathBuilder() { return this; } \ No newline at end of file diff --git a/third_party/rive/source/math/aabb.cpp b/third_party/rive/source/math/aabb.cpp new file mode 100644 index 0000000..80cdc14 --- /dev/null +++ b/third_party/rive/source/math/aabb.cpp @@ -0,0 +1,91 @@ +#include "rive/math/math_types.hpp" +#include "rive/math/aabb.hpp" +#include "rive/math/simd.hpp" +#include +#include + +using namespace rive; + +AABB::AABB(Span pts) +{ + if (pts.size() == 0) + { + minX = minY = maxX = maxY = 0; + return; + } + + float L = pts[0].x, R = L, T = pts[0].y, B = T; + + for (size_t i = 1; i < pts.size(); ++i) + { + L = std::min(L, pts[i].x); + R = std::max(R, pts[i].x); + T = std::min(T, pts[i].y); + B = std::max(B, pts[i].y); + } + minX = L; + maxX = R; + minY = T; + maxY = B; +} + +static inline float graphics_roundf(float x) { return std::floor(x + 0.5f); } + +static inline int graphics_round(float x) { return (int)graphics_roundf(x); } + +IAABB AABB::round() const +{ + return { + graphics_round(left()), + graphics_round(top()), + graphics_round(right()), + graphics_round(bottom()), + }; +} + +IAABB AABB::roundOut() const +{ + float4 bounds = simd::load4f(this); + bounds.xy = simd::floor(bounds.xy); + bounds.zw = simd::ceil(bounds.zw); + return math::bit_cast(simd::cast(bounds)); +} + +void AABB::expandTo(AABB& out, const Vec2D& point) +{ + expandTo(out, point.x, point.y); +} + +void AABB::expandTo(AABB& out, float x, float y) +{ + if (x < out.minX) + { + out.minX = x; + } + if (x > out.maxX) + { + out.maxX = x; + } + if (y < out.minY) + { + out.minY = y; + } + if (y > out.maxY) + { + out.maxY = y; + } +} + +void AABB::join(AABB& out, const AABB& a, const AABB& b) +{ + out.minX = std::min(a.minX, b.minX); + out.minY = std::min(a.minY, b.minY); + out.maxX = std::max(a.maxX, b.maxX); + out.maxY = std::max(a.maxY, b.maxY); +} + +bool AABB::contains(Vec2D point) const +{ + return point.x >= left() && point.x <= right() && point.y >= top() && + point.y <= bottom(); +} diff --git a/third_party/rive/source/math/bezier_utils.cpp b/third_party/rive/source/math/bezier_utils.cpp new file mode 100644 index 0000000..1db6443 --- /dev/null +++ b/third_party/rive/source/math/bezier_utils.cpp @@ -0,0 +1,332 @@ +/* + * Copyright 2021 Google LLC. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Initial import from skia:src/core/SkGeometry.cpp + * skia:src/gpu/tessellate/Tessellation.cpp + * + * Copyright 2022 Rive + */ + +#include "rive/math/bezier_utils.hpp" + +#include "rive/math/math_types.hpp" + +namespace rive +{ +namespace math +{ +Vec2D eval_cubic_at(const Vec2D p[4], float t) +{ + float2 p0 = simd::load2f(p + 0); + float2 p1 = simd::load2f(p + 1); + float2 p2 = simd::load2f(p + 2); + float2 p3 = simd::load2f(p + 3); + float2 a = p3 + 3.f * (p1 - p2) - p0; + float2 b = 3.f * (p2 - 2.f * p1 + p0); + float2 c = 3.f * (p1 - p0); + float2 d = p0; + return math::bit_cast(((a * t + b) * t + c) * t + d); +} + +void chop_cubic_at(const Vec2D src[4], Vec2D dst[7], float t) +{ + assert(0 <= t && t <= 1); + + if (t == 1) + { + memcpy(dst, src, sizeof(Vec2D) * 4); + dst[4] = dst[5] = dst[6] = src[3]; + return; + } + + float4 p0p1 = simd::load4f(src); + float4 p1p2 = simd::load4f(src + 1); + float4 p2p3 = simd::load4f(src + 2); + float4 T = t; + + float4 ab_bc = simd::mix(p0p1, p1p2, T); + float4 bc_cd = simd::mix(p1p2, p2p3, T); + float4 abc_bcd = simd::mix(ab_bc, bc_cd, T); + float2 abcd = simd::mix(abc_bcd.xy, abc_bcd.zw, T.xy); + + simd::store(dst + 0, p0p1.xy); + simd::store(dst + 1, ab_bc.xy); + simd::store(dst + 2, abc_bcd.xy); + simd::store(dst + 3, abcd); + simd::store(dst + 4, abc_bcd.zw); + simd::store(dst + 5, bc_cd.zw); + simd::store(dst + 6, p2p3.zw); +} + +void chop_cubic_at(const Vec2D src[4], Vec2D dst[10], float t0, float t1) +{ + assert(0 <= t0 && t0 <= t1 && t1 <= 1); + + if (t1 == 1) + { + chop_cubic_at(src, dst, t0); + dst[7] = dst[8] = dst[9] = src[3]; + return; + } + + // Perform both chops in parallel using 4-lane SIMD. + float4 p00, p11, p22, p33, T; + p00 = simd::load2f(src + 0).xyxy; + p11 = simd::load2f(src + 1).xyxy; + p22 = simd::load2f(src + 2).xyxy; + p33 = simd::load2f(src + 3).xyxy; + T.xy = t0; + T.zw = t1; + + float4 ab = simd::mix(p00, p11, T); + float4 bc = simd::mix(p11, p22, T); + float4 cd = simd::mix(p22, p33, T); + float4 abc = simd::mix(ab, bc, T); + float4 bcd = simd::mix(bc, cd, T); + float4 abcd = simd::mix(abc, bcd, T); + float4 middle = simd::mix(abc, bcd, T.zwxy); + + simd::store(dst + 0, p00.xy); + simd::store(dst + 1, ab.xy); + simd::store(dst + 2, abc.xy); + simd::store(dst + 3, abcd.xy); + simd::store(dst + 4, middle); // 2 points! + // dst + 5 written above. + simd::store(dst + 6, abcd.zw); + simd::store(dst + 7, bcd.zw); + simd::store(dst + 8, cd.zw); + simd::store(dst + 9, p33.zw); +} + +void chop_cubic_at(const Vec2D src[4], + Vec2D dst[], + const float tValues[], + int tCount) +{ + assert(tValues == nullptr || + std::all_of(tValues, tValues + tCount, [](float t) { + return t >= 0 && t <= 1; + })); + assert(tValues == nullptr || std::is_sorted(tValues, tValues + tCount)); + + if (dst) + { + if (tCount == 0) + { + // nothing to chop + memcpy(dst, src, 4 * sizeof(Vec2D)); + } + else + { + int i = 0; + float lastT = 0; + for (; i < tCount - 1; i += 2) + { + // Do two chops at once. + float2 tt; + if (tValues != nullptr) + { + tt = simd::load2f(tValues + i); + tt = simd::clamp((tt - lastT) / (1 - lastT), + float2(0), + float2(1)); + lastT = tValues[i + 1]; + } + else + { + tt = float2{1, 2} / static_cast(tCount + 1 - i); + } + chop_cubic_at(src, dst, tt[0], tt[1]); + src = dst = dst + 6; + } + if (i < tCount) + { + // Chop the final cubic if there was an odd number of chops. + assert(i + 1 == tCount); + float t = tValues != nullptr ? tValues[i] : .5f; + t = simd::clamp( + math::ieee_float_divide(t - lastT, 1 - lastT), + 0, + 1) + .x; + chop_cubic_at(src, dst, t); + } + } + } +} + +float measure_angle_between_vectors(Vec2D a, Vec2D b) +{ + float cosTheta = + math::ieee_float_divide(Vec2D::dot(a, b), + sqrtf(Vec2D::dot(a, a) * Vec2D::dot(b, b))); + // Pin cosTheta such that if it is NaN (e.g., if a or b was 0), then we + // return acos(1) = 0. + cosTheta = std::max(std::min(1.f, cosTheta), -1.f); + return acosf(cosTheta); +} + +// If a chop falls within a distance of "TESS_EPSILON" from 0 or 1, throw it +// out. Tangents become unstable when we chop too close to the boundary. This +// works out because the tessellation shaders don't allow more than 2^10 +// parametric segments, and they snap the beginning and ending edges at 0 and 1. +// So if we overstep an inflection or point of 180-degree rotation by a fraction +// of a tessellation segment, it just gets snapped. +constexpr static float TESS_EPSILON = 1.f / (1 << 10); + +int find_cubic_convex_180_chops(const Vec2D pts[], float T[2], bool* areCusps) +{ + assert(pts); + assert(T); + assert(areCusps); + + // Floating-point representation of "1 - 2*TESS_EPSILON". + constexpr static uint32_t kIEEE_one_minus_2_epsilon = + (127 << 23) - 2 * (1 << (24 - 10)); + // Unfortunately we don't have a way to static_assert this, but we can + // runtime assert that the kIEEE_one_minus_2_epsilon bits are correct. + assert(math::bit_cast(kIEEE_one_minus_2_epsilon) == + 1 - 2 * TESS_EPSILON); + + float2 p0 = simd::load2f(&pts[0].x); + float2 p1 = simd::load2f(&pts[1].x); + float2 p2 = simd::load2f(&pts[2].x); + float2 p3 = simd::load2f(&pts[3].x); + CubicCoeffs coeffs(p0, p1, p2, p3); + + // Now find the cubic's inflection function. + // There are inflections where F' x F'' == 0. + // + // We formulate this as a quadratic equation: + // + // F' x F'' == aT^2 + bT + c == 0. + // + // See: + // https://www.microsoft.com/en-us/research/wp-content/uploads/2005/01/p1000-loop.pdf + // NOTE: We only need the roots, so a uniform scale factor does not affect + // the solution. + float a = simd::cross(coeffs.A, coeffs.B); + float b = simd::cross(coeffs.A, coeffs.C); + float c = simd::cross(coeffs.B, coeffs.C); + float b_over_minus_2 = -.5f * b; + float discr_over_4 = b_over_minus_2 * b_over_minus_2 - a * c; + + // If -cuspThreshold <= discr_over_4 <= cuspThreshold, it means the two + // roots are within TESS_EPSILON of one another (in parametric space). This + // is close enough for our purposes to consider them a single cusp. + float cuspThreshold = a * (TESS_EPSILON / 2); + cuspThreshold *= cuspThreshold; + + if (discr_over_4 < -cuspThreshold) + { + // The curve does not inflect or cusp. This means it might rotate more + // than 180 degrees instead. Chop were rotation == 180 deg. (This is the + // 2nd root where the tangent is parallel to tan0.) + // + // Tangent_Direction(T) x tan0 == 0 + // (AT^2 x tan0) + (2BT x tan0) + (C x tan0) == 0 + // (A x C)T^2 + (2B x C)T + (C x C) == 0 + // [[because tan0 == P1 - P0 == C]] + // bT^2 + 2cT + 0 == 0 [[because A x C == b, B x C == c]] + // T = [0, -2c/b] + // + // NOTE: if C == 0, then C != tan0. But this is fine because the curve + // is definitely convex-180 if any points are colocated, and T[0] will + // equal NaN which returns 0 chops. + *areCusps = false; + float root = math::ieee_float_divide(c, b_over_minus_2); + // Is "root" inside the range [TESS_EPSILON, 1 - TESS_EPSILON)? + if (math::bit_cast(root - TESS_EPSILON) < + kIEEE_one_minus_2_epsilon) + { + T[0] = root; + return 1; + } + return 0; + } + + *areCusps = discr_over_4 <= cuspThreshold; + if (*areCusps) + { + // The two roots are close enough that we can consider them a single + // cusp. + if (a != 0 || b_over_minus_2 != 0 || c != 0) + { + // Pick the average of both roots. + float root = math::ieee_float_divide(b_over_minus_2, a); + // Is "root" inside the range [TESS_EPSILON, 1 - TESS_EPSILON)? + if (math::bit_cast(root - TESS_EPSILON) < + kIEEE_one_minus_2_epsilon) + { + T[0] = root; + return 1; + } + *areCusps = false; + return 0; + } + + // The curve is a flat line. If the points are ordered, there are no + // inflections. + float2 base = p3 - p0; + float4 pX = {pts[0].x, pts[1].x, pts[2].x, pts[3].x}; + float4 pY = {pts[0].y, pts[1].y, pts[2].y, pts[3].y}; + float4 dotProds = pX * base.x + pY * base.y; + if (simd::all(dotProds.yzw > dotProds.xyz)) + { + // Flat line with no cusps. + *areCusps = false; + return 0; + } + + // The curve is a flat line with inflections. The standard inflection + // function doesn't detect cusps from flat lines. Find cusps by + // searching instead for points where the tangent is perpendicular to + // tan0. This will find any cusp point. + // + // dot(tan0, Tangent_Direction(T)) == 0 + // + // |T^2| + // tan0 * |A 2B C| * |T | == 0 + // |. . .| |1 | + // + float2 tan0 = simd::any(coeffs.C != 0.f) ? coeffs.C : p2 - p0; + a = simd::dot(tan0, coeffs.A); + b_over_minus_2 = -simd::dot(tan0, coeffs.B); + c = simd::dot(tan0, coeffs.C); + discr_over_4 = std::max(b_over_minus_2 * b_over_minus_2 - a * c, 0.f); + } + + // Solve our quadratic equation to find where to chop. See the quadratic + // formula from Numerical Recipes in C. + float q = sqrtf(discr_over_4); + q = copysignf(q, b_over_minus_2); + q = q + b_over_minus_2; + float2 roots = float2{q, c} / float2{a, q}; + + auto inside = (roots > TESS_EPSILON) & (roots < (1 - TESS_EPSILON)); + if (inside[0]) + { + if (inside[1] && roots[0] != roots[1]) + { + if (roots[0] > roots[1]) + { + roots = roots.yx; // Sort. + } + simd::store(T, roots); + return 2; + } + T[0] = roots[0]; + return 1; + } + if (inside[1]) + { + T[0] = roots[1]; + return 1; + } + return 0; +} +} // namespace math +} // namespace rive diff --git a/third_party/rive/source/math/bit_field_loc.cpp b/third_party/rive/source/math/bit_field_loc.cpp new file mode 100644 index 0000000..377b10a --- /dev/null +++ b/third_party/rive/source/math/bit_field_loc.cpp @@ -0,0 +1,20 @@ +#include "rive/math/bit_field_loc.hpp" +#include + +using namespace rive; + +BitFieldLoc::BitFieldLoc(uint32_t start, uint32_t end) : m_start(start) +{ + assert(end >= start); + assert(end < 32); + + m_count = end - start + 1; + m_mask = ((1 << (end - start + 1)) - 1) << start; +} + +uint32_t BitFieldLoc::read(uint32_t bits) { return (bits & m_mask) >> m_start; } + +uint32_t BitFieldLoc::write(uint32_t bits, uint32_t value) +{ + return (bits & ~m_mask) | ((value << m_start) & m_mask); +} \ No newline at end of file diff --git a/third_party/rive/source/math/contour_measure.cpp b/third_party/rive/source/math/contour_measure.cpp new file mode 100644 index 0000000..5fd2817 --- /dev/null +++ b/third_party/rive/source/math/contour_measure.cpp @@ -0,0 +1,595 @@ +/* + * Copyright 2022 Rive + */ + +#include "rive/core/type_conversions.hpp" +#include "rive/math/raw_path_utils.hpp" +#include "rive/math/contour_measure.hpp" +#include "rive/math/math_types.hpp" +#include "rive/math/wangs_formula.hpp" +#include +#include + +using namespace rive; + +enum SegmentType +{ // must fit in 2 bits + kLine, + kQuad, + kCubic, + // unused for now +}; + +/* + * Inspired by Skia's SkContourMeasure + */ + +ContourMeasure::ContourMeasure(std::vector&& segs, + std::vector&& pts, + float length, + bool isClosed) : + m_segments(std::move(segs)), + m_points(std::move(pts)), + m_length(length), + m_isClosed(isClosed) +{} + +// Return index of the segment that contains distance, +// or the last segment if distance == m_distance +size_t ContourMeasure::findSegment(float distance) const +{ + assert(m_segments.front().m_distance >= 0); + assert(m_segments.back().m_distance == m_length); + + assert(distance >= 0 && distance <= m_length); + + const Segment seg = {distance, 0, 0, 0}; + auto iter = std::lower_bound(m_segments.begin(), m_segments.end(), seg); + while (iter->m_distance == 0.0f && iter != m_segments.end()) + { + iter = std::next(iter); + } + assert(iter != m_segments.end()); + assert(iter->m_distance >= distance); + assert(iter->m_ptIndex < m_points.size()); + return iter - m_segments.begin(); +} + +static ContourMeasure::PosTan eval_quad(const Vec2D pts[], float t) +{ + assert(t >= 0 && t <= 1); + + const EvalQuad eval(pts); + + // Compute derivative as at + b + auto a = two(eval.a); + auto b = eval.b; + + return { + eval(t), + (a * t + b).normalized(), + }; +} + +static ContourMeasure::PosTan eval_cubic(const Vec2D pts[], float t) +{ + assert(t >= 0 && t <= 1); + // When t==0 and t==1, the most accurate way to find tangents is by + // differencing. + if (t == 0 || t == 1) + { + if (t == 0) + { + return {pts[0], + (pts[0] != pts[1] ? pts[1] + : pts[1] != pts[2] ? pts[2] + : pts[3]) - + pts[0] + + }; + } + else + { + return {pts[3], + pts[3] - (pts[3] != pts[2] ? pts[2] + : pts[2] != pts[1] ? pts[1] + : pts[0])}; + } + } + + const EvalCubic eval(pts); + + // Compute derivative as at^2 + bt + c; + auto a = eval.a * 3; + auto b = two(eval.b); + auto c = eval.c; + + return { + eval(t), + ((a * t + b) * t + c).normalized(), + }; +} + +void ContourMeasure::Segment::extract(RawPath* dst, const Vec2D pts[]) const +{ + pts += m_ptIndex; + switch (m_type) + { + case SegmentType::kLine: + dst->line(pts[1]); + break; + case SegmentType::kQuad: + dst->quad(pts[1], pts[2]); + break; + case SegmentType::kCubic: + dst->cubic(pts[1], pts[2], pts[3]); + break; + } +} + +void ContourMeasure::Segment::extract(RawPath* dst, + float fromT, + float toT, + const Vec2D pts[], + bool moveTo) const +{ + assert(fromT <= toT); + pts += m_ptIndex; + + Vec2D tmp[4]; + switch (m_type) + { + case SegmentType::kLine: + line_extract(pts, fromT, toT, tmp); + if (moveTo) + { + dst->move(tmp[0]); + } + dst->line(tmp[1]); + break; + case SegmentType::kQuad: + quad_extract(pts, fromT, toT, tmp); + if (moveTo) + { + dst->move(tmp[0]); + } + dst->quad(tmp[1], tmp[2]); + break; + case SegmentType::kCubic: + cubic_extract(pts, fromT, toT, tmp); + if (moveTo) + { + dst->move(tmp[0]); + } + dst->cubic(tmp[1], tmp[2], tmp[3]); + break; + } +} + +ContourMeasure::PosTan ContourMeasure::getPosTan(float distance) const +{ + // specal-case end of the contour + if (distance > m_length) + { + distance = m_length; + } + + if (distance < 0) + { + distance = 0; + } + + size_t i = this->findSegment(distance); + assert(i < m_segments.size()); + const auto seg = m_segments[i]; + const float currD = seg.m_distance; + const float prevD = i > 0 ? m_segments[i - 1].m_distance : 0; + + assert(prevD < currD); + assert(distance <= currD); + assert(distance >= prevD); + + const float relD = (distance - prevD) / (currD - prevD); + assert(relD >= 0 && relD <= 1); + + if (seg.m_type == SegmentType::kLine) + { + assert(seg.m_ptIndex + 1 < m_points.size()); + auto p0 = m_points[seg.m_ptIndex + 0]; + auto p1 = m_points[seg.m_ptIndex + 1]; + return { + Vec2D::lerp(p0, p1, relD), + (p1 - p0).normalized(), + }; + } + + float prevT = 0; + if (i > 0) + { + auto prev = m_segments[i - 1]; + if (prev.m_ptIndex == seg.m_ptIndex) + { + prevT = prev.getT(); + } + } + + const float t = lerp(prevT, seg.getT(), relD); + assert(t >= 0 && t <= 1); + + if (seg.m_type == SegmentType::kQuad) + { + assert(seg.m_ptIndex + 2 < m_points.size()); + return eval_quad(&m_points[seg.m_ptIndex], t); + } + else + { + assert(seg.m_type == SegmentType::kCubic); + assert(seg.m_ptIndex + 3 < m_points.size()); + return eval_cubic(&m_points[seg.m_ptIndex], t); + } +} + +static const ContourMeasure::Segment* next_segment_beginning( + const ContourMeasure::Segment* seg) +{ + auto startingPtIndex = seg->m_ptIndex; + do + { + seg += 1; + } while (seg->m_ptIndex == startingPtIndex); + return seg; +} + +// Compute the (interpolated) t for a distance within the index'th segment +static float compute_t(Span segs, + size_t index, + float distance) +{ + const auto seg = segs[index]; + assert(distance <= seg.m_distance); + + float prevDist = 0, prevT = 0; + if (index > 0) + { + const auto prev = segs[index - 1]; + prevDist = prev.m_distance; + if (prev.m_ptIndex == seg.m_ptIndex) + { + prevT = prev.getT(); + } + } + + assert(prevDist <= seg.m_distance); + const auto ratio = (distance - prevDist) / (seg.m_distance - prevDist); + float t = lerp(prevT, seg.getT(), ratio); + t = math::clamp(t, prevT, seg.getT()); + assert(prevT <= t && t <= seg.getT()); + return t; +} + +void ContourMeasure::getSegment(float startDist, + float endDist, + RawPath* dst, + bool startWithMove) const +{ + // sanitize the inputs + startDist = std::max(0.f, startDist); + endDist = std::min(m_length, endDist); + if (startDist >= endDist) + { + return; + } + + const auto startIndex = this->findSegment(startDist); + const auto endIndex = this->findSegment(endDist); + + const auto start = m_segments[startIndex]; + const auto end = m_segments[endIndex]; + + const auto startT = compute_t(m_segments, startIndex, startDist); + const auto endT = compute_t(m_segments, endIndex, endDist); + + if (start.m_ptIndex == end.m_ptIndex) + { + start.extract(dst, startT, endT, m_points.data(), startWithMove); + } + else + { + start.extract(dst, startT, 1, m_points.data(), startWithMove); + + // now scoop up all the segments after start, and before end + const auto* seg = next_segment_beginning(&m_segments[startIndex]); + while (seg->m_ptIndex != end.m_ptIndex) + { + seg->extract(dst, m_points.data()); + seg = next_segment_beginning(seg); + } + assert(seg->m_ptIndex == end.m_ptIndex); + + end.extract(dst, 0, endT, m_points.data(), false); + } +} + +void ContourMeasure::dump() const +{ + printf("length %g pts %zu segs %zu\n", + m_length, + m_points.size(), + m_segments.size()); + for (const auto& s : m_segments) + { + printf(" %g %d %g %d\n", s.m_distance, s.m_ptIndex, s.getT(), s.m_type); + } +} + +////////////////////////////////////////////////////////////////////////////// + +constexpr auto kMaxDot30 = ContourMeasure::kMaxDot30; + +static inline unsigned toDot30(float x) +{ + assert(x >= 0 && x < 1); + return (unsigned)(x * (1 << 30)); +} + +// These add[SegmentType]Segs routines append intermediate segments for the +// curve. They assume the caller has set the initial segment (with t == 0), so +// they only add intermediates. + +float ContourMeasureIter::addQuadSegs(ContourMeasure::Segment* segs, + const Vec2D pts[], + uint32_t segmentCount, + uint32_t ptIndex, + float distance) const +{ + const float dt = 1.f / (float)segmentCount; + const EvalQuad eval(pts); + + float t = dt; + Vec2D prev = pts[0]; + for (uint32_t i = 1; i < segmentCount; ++i) + { + auto next = eval(t); + distance += (next - prev).length(); + *segs++ = {distance, ptIndex, toDot30(t), SegmentType::kQuad}; + prev = next; + t += dt; + } + distance += (pts[2] - prev).length(); + *segs++ = {distance, ptIndex, kMaxDot30, SegmentType::kQuad}; + return distance; +} + +float ContourMeasureIter::addCubicSegs(ContourMeasure::Segment* segs, + const Vec2D pts[], + uint32_t segmentCount, + uint32_t ptIndex, + float distance) const +{ + const float dt = 1.f / (float)segmentCount; + const EvalCubic eval(pts); + + float t = dt; + Vec2D prev = pts[0]; + for (uint32_t i = 1; i < segmentCount; ++i) + { + auto next = eval(t); + distance += (next - prev).length(); + *segs++ = {distance, ptIndex, toDot30(t), SegmentType::kCubic}; + prev = next; + t += dt; + } + distance += (pts[3] - prev).length(); + *segs++ = {distance, ptIndex, kMaxDot30, SegmentType::kCubic}; + return distance; +} + +void ContourMeasureIter::rewind(const RawPath* path, float tolerance) +{ + m_iter = path->begin(); + m_end = path->end(); + m_srcPoints = path->points().data(); + + constexpr float kMinTolerance = 1.0f / 16; + m_invTolerance = 1.0f / std::max(tolerance, kMinTolerance); + + m_segmentCounts.resize(path->verbs().count()); +} + +// Can return null if either it encountered an empty contour (length == 0) +// or the iterator is exhausted. +// +rcp ContourMeasureIter::tryNext() +{ + assert(m_iter == m_end || m_iter.verb() == PathVerb::move); + + // Advance to the first line or curve. + Vec2D p0; + for (;; ++m_iter) + { + if (m_iter == m_end) + { + return nullptr; + } + switch (m_iter.verb()) + { + case PathVerb::move: + p0 = m_iter.movePt(); + RIVE_FALLTHROUGH; + case PathVerb::close: + continue; + default: + break; + } + break; + } + + // Pass 1: count segments. + uint32_t* nextSegCount = m_segmentCounts.data(); + size_t segmentCountInCurves = 0; + size_t lineCount = 0; + bool isClosed = false; + RawPath::Iter endOfContour = m_end; + for (auto it = m_iter; it != m_end; ++it) + { + // Arbirtary limit to keep our segmenting tractable. + constexpr static uint32_t kMaxSegments = 100; + switch (it.verb()) + { + case PathVerb::move: + endOfContour = it; // This move belongs to the next contour. + break; + case PathVerb::line: + if (Vec2D::distanceSquared(it.linePts()[1], it.linePts()[0]) > + 0.0f) + { + ++lineCount; + } + continue; + case PathVerb::quad: + { + assert(nextSegCount < + m_segmentCounts.data() + m_segmentCounts.size()); + uint32_t segmentCount = static_cast(ceilf( + wangs_formula::quadratic(it.quadPts(), m_invTolerance))); + segmentCount = std::min(segmentCount, kMaxSegments); + segmentCountInCurves += segmentCount; + *nextSegCount++ = segmentCount; + continue; + } + case PathVerb::cubic: + { + assert(nextSegCount < + m_segmentCounts.data() + m_segmentCounts.size()); + uint32_t segmentCount = static_cast(ceilf(ceilf( + wangs_formula::cubic(it.cubicPts(), m_invTolerance)))); + segmentCount = std::min(segmentCount, kMaxSegments); + segmentCountInCurves += segmentCount; + *nextSegCount++ = segmentCount; + continue; + } + case PathVerb::close: + if (it.ptBeforeClose() != p0) + { + ++lineCount; + } + isClosed = true; + continue; + } + break; + } + + // Pass 2: emit segments. + std::vector segs; + segs.resize(segmentCountInCurves + lineCount); + ContourMeasure::Segment* nextSeg = segs.data(); + nextSegCount = m_segmentCounts.data(); + float distance = 0; + uint32_t ptIndex = 0; + bool duplicateP0 = false; + for (auto it = m_iter; it != endOfContour; ++it) + { + switch (it.verb()) + { + case PathVerb::move: + RIVE_UNREACHABLE(); + case PathVerb::line: + if (Vec2D::distanceSquared(it.linePts()[1], it.linePts()[0]) > + 0.0f) + { + distance += (it.linePts()[1] - it.linePts()[0]).length(); + *nextSeg++ = {distance, + ptIndex, + kMaxDot30, + SegmentType::kLine}; + } + ++ptIndex; + break; + case PathVerb::quad: + { + const uint32_t n = *nextSegCount++; + if (n > 0) + { + distance = addQuadSegs(nextSeg, + it.quadPts(), + n, + ptIndex, + distance); + } + nextSeg += n; + ptIndex += 2; + break; + } + case PathVerb::cubic: + { + const uint32_t n = *nextSegCount++; + if (n > 0) + { + distance = addCubicSegs(nextSeg, + it.cubicPts(), + n, + ptIndex, + distance); + } + nextSeg += n; + ptIndex += 3; + break; + } + case PathVerb::close: + if (it.ptBeforeClose() != p0) + { + distance += (p0 - it.ptBeforeClose()).length(); + *nextSeg++ = {distance, + ptIndex, + kMaxDot30, + SegmentType::kLine}; + ++ptIndex; + duplicateP0 = true; + } + assert(isClosed); + } + } + assert(nextSeg == segs.data() + segs.size()); + + // Copy out points. + std::vector pts; + pts.reserve(1 + ptIndex); + pts.insert(pts.end(), m_iter.rawPtsPtr() - 1, endOfContour.rawPtsPtr()); + if (duplicateP0) + { + pts.push_back(p0); + } + assert(pts.size() == 1 + ptIndex); + + m_iter = endOfContour; + + if (distance > 0 && pts.size() >= 2) + { + assert(!std::isnan(distance)); + return rcp(new ContourMeasure(std::move(segs), + std::move(pts), + distance, + isClosed)); + } + + assert(distance == 0 || std::isnan(distance)); + return nullptr; +} + +rcp ContourMeasureIter::next() +{ + rcp cm; + for (;;) + { + if ((cm = this->tryNext())) + { + break; + } + if (m_iter == m_end) + { + break; + } + } + assert(!cm || !std::isnan(cm->length())); + return cm; +} diff --git a/third_party/rive/source/math/hit_test.cpp b/third_party/rive/source/math/hit_test.cpp new file mode 100644 index 0000000..a6ca01c --- /dev/null +++ b/third_party/rive/source/math/hit_test.cpp @@ -0,0 +1,471 @@ +/* + * Copyright 2022 Rive + */ + +#include "rive/math/hit_test.hpp" + +#include "rive/math/mat2d.hpp" +#include +#include +#include + +// Should we make this an option at runtime? +#define CULL_BOUNDS true + +using namespace rive; + +//static inline float graphics_roundf(float x) { return std::floor(x + 0.5f); } + +//static inline int graphics_round(float x) { return (int)graphics_roundf(x); } + +struct Point +{ + float x, y; + + Point() {} + Point(float xx, float yy) : x(xx), y(yy) {} + Point(const Vec2D& src) : x(src.x), y(src.y) {} + + Point operator+(Point v) const { return {x + v.x, y + v.y}; } + Point operator-(Point v) const { return {x - v.x, y - v.y}; } + + Point& operator+=(Point v) + { + *this = *this + v; + return *this; + } + Point& operator-=(Point v) + { + *this = *this - v; + return *this; + } + + friend Point operator*(Point v, float s) { return {v.x * s, v.y * s}; } + friend Point operator*(float s, Point v) { return {v.x * s, v.y * s}; } +}; + +//template T lerp(T a, T b, float t) { return a + (b - a) * t; } + +template T ave(T a, T b) { return lerp(a, b, 0.5f); } + +static void append_line(const float height, + Point p0, + Point p1, + float m, + int winding, + int delta[], + int iwidth) +{ + assert(winding == 1 || winding == -1); + + int top = graphics_round(p0.y); + int bottom = graphics_round(p1.y); + if (top == bottom) + { + return; + } + + assert(top < bottom); + assert(top >= 0); + assert((float)bottom <= height); + + // we add 0.5 at the end to pre-round the values + float x = p0.x + m * (top - p0.y + 0.5f) + 0.5f; + + int* row = delta + top * iwidth; + for (int y = top; y < bottom; ++y) + { + int ix = (int)std::max(x, 0.0f); + if (ix < iwidth) + { + row[ix] += winding; + } + x += m; + row += iwidth; + } +} + +static void clip_line(const float height, + Point p0, + Point p1, + int delta[], + const int iwidth) +{ + if (p0.y == p1.y) + { + return; + } + + int winding = 1; + if (p0.y > p1.y) + { + winding = -1; + std::swap(p0, p1); + } + // now we're monotonic in Y: p0 <= p1 + if (p1.y <= 0 || p0.y >= height) + { + return; + } + + const float m = (float)(p1.x - p0.x) / (p1.y - p0.y); + if (p0.y < 0) + { + p0.x += m * (0 - p0.y); + p0.y = 0; + } + if (p1.y > height) + { + p1.x += m * (height - p1.y); + p1.y = height; + } + + assert(p0.y <= p1.y); + assert(p0.y >= 0); + assert(p1.y <= height); + + append_line(height, p0, p1, m, winding, delta, iwidth); +} + +#define MAX_CURVE_SEGMENTS (1 << 8) + +static int compute_cubic_segments(Point a, Point b, Point c, Point d) +{ + Point abc = a - b - b + c; + Point bcd = b - c - c + d; + float dx = std::max(std::abs(abc.x), std::abs(bcd.x)); + float dy = std::max(std::abs(abc.y), std::abs(bcd.y)); + float dist = sqrtf(dx * dx + dy * dy); + // count = sqrt(6*dist / 8*tol) + // tol = 0.25 + // count = sqrt(3*dist) + float count = sqrtf(3 * dist); + return std::max(1, std::min((int)ceilf(count), MAX_CURVE_SEGMENTS)); +} + +// cubic a(1-t)^3 + 3bt(1-t)^2 + 3c(1-t)t^2 + dt^3 +// becomes +// At^3 + Bt^2 + Ct + D +// +struct CubicCoeff +{ + Point A, B, C, D; + + // a(1-t)^3 + 3bt(1-t)^2 + 3ct^2(1-t) + dt^3 + // a - 3at + 3at^2 - at^3 a(1 - 3t + 3t^2 - t^3) + // 3bt - 6bt^2 + 3bt^3 3b( t - 2t^2 + t^3) + // 3ct^2 - 3ct^3 3c( t^2 - t^3) + // dt^3 d( t^3) + // ... + // D + Ct + Bt^2 + At^3 + // + CubicCoeff(Point a, Point b, Point c, Point d) + { + A = (d - a) + 3.0f * (b - c); + B = 3.0f * ((c - b) + (a - b)); + C = 3.0f * (b - a); + D = a; + } + + Point eval(float t) const { return ((A * t + B) * t + C) * t + D; } +}; + +//////////////////////////////////////////// + +void HitTester::reset() { m_DW.clear(); } + +void HitTester::reset(const IAABB& clip) +{ + m_offset = Vec2D{(float)clip.left, (float)clip.top}; + m_height = (float)clip.height(); + + m_IWidth = clip.width(); + m_IHeight = clip.height(); + m_DW.resize(m_IWidth * m_IHeight); + for (size_t i = 0; i < m_DW.size(); ++i) + { + m_DW[i] = 0; + } + + m_ExpectsMove = true; +} + +void HitTester::move(Vec2D v) +{ + if (!m_ExpectsMove) + { + this->close(); + } + m_First = m_Prev = v - m_offset; + m_ExpectsMove = false; +} + +void HitTester::line(Vec2D v) +{ + assert(!m_ExpectsMove); + + v = v - m_offset; + clip_line(m_height, m_Prev, v, m_DW.data(), m_IWidth); + m_Prev = v; +} + +void HitTester::quad(Vec2D b, Vec2D c) +{ + assert(!m_ExpectsMove); + + m_Prev = c; +} + +static bool quickRejectCubic(float height, Point a, Point b, Point c, Point d) +{ + const float h = height; + return (a.y <= 0 && b.y <= 0 && c.y <= 0 && d.y <= 0) || + (a.y >= h && b.y >= h && c.y >= h && d.y >= h); +} + +struct CubicChop +{ + Vec2D storage[7]; + + CubicChop(Vec2D a, Vec2D b, Vec2D c, Vec2D d) + { + auto ab = ave(a, b); + auto bc = ave(b, c); + auto cd = ave(c, d); + auto abc = ave(ab, bc); + auto bcd = ave(bc, cd); + + storage[0] = a; + storage[1] = ab; + storage[2] = abc; + storage[3] = ave(abc, bcd); + storage[4] = bcd; + storage[5] = cd; + storage[6] = d; + } + + Vec2D operator[](unsigned index) const + { + assert(index < 7); + return storage[index]; + } +}; + +// Trial and error to pick a good value for this. +// +// Subdivision and recursion have their own cost, so at some point +// just evaluating the cubic (count) times is cheaper than continuing +// to chop. +// +// The key win is quickRejectCubic. This is how we save time over just +// evaluating the cubic up front. +// +#define MAX_LOCAL_SEGMENTS 16 + +void HitTester::recurse_cubic(Vec2D b, Vec2D c, Vec2D d, int count) +{ + if (quickRejectCubic(m_height, m_Prev, b, c, d)) + { + m_Prev = d; + return; + } + + if (count > MAX_LOCAL_SEGMENTS) + { + CubicChop chop(m_Prev, b, c, d); + const int newCount = (count + 1) >> 1; + assert(newCount < count); + this->recurse_cubic(chop[1], chop[2], chop[3], newCount); + this->recurse_cubic(chop[4], chop[5], chop[6], newCount); + } + else + { + const float dt = 1.0f / (float)count; + float t = dt; + + CubicCoeff cube(m_Prev, b, c, d); + // we don't need the first point eval(0) or the last eval(1) + Point prev = m_Prev; + for (int i = 1; i < count - 1; ++i) + { + auto next = cube.eval(t); + clip_line(m_height, prev, next, m_DW.data(), m_IWidth); + prev = next; + t += dt; + } + clip_line(m_height, prev, d, m_DW.data(), m_IWidth); + m_Prev = d; + } +} +void HitTester::cubic(Vec2D b, Vec2D c, Vec2D d) +{ + assert(!m_ExpectsMove); + + b = b - m_offset; + c = c - m_offset; + d = d - m_offset; + + if (quickRejectCubic(m_height, m_Prev, b, c, d)) + { + m_Prev = d; + return; + } + + const int count = compute_cubic_segments(m_Prev, b, c, d); + + this->recurse_cubic(b, c, d, count); +} + +void HitTester::close() +{ + assert(!m_ExpectsMove); + + clip_line(m_height, m_Prev, m_First, m_DW.data(), m_IWidth); + m_ExpectsMove = true; +} + +void HitTester::addRect(const AABB& rect, const Mat2D& xform, PathDirection dir) +{ + const Vec2D pts[] = { + xform * Vec2D{rect.left(), rect.top()}, + xform * Vec2D{rect.right(), rect.top()}, + xform * Vec2D{rect.right(), rect.bottom()}, + xform * Vec2D{rect.left(), rect.bottom()}, + }; + + move(pts[0]); + if (dir == PathDirection::clockwise) + { + line(pts[1]); + line(pts[2]); + line(pts[3]); + } + else + { + line(pts[3]); + line(pts[2]); + line(pts[1]); + } + close(); +} + +bool HitTester::test(FillRule rule) +{ + if (!m_ExpectsMove) + { + this->close(); + } + + const int mask = (rule == rive::FillRule::nonZero) ? -1 : 1; + + int nonzero = 0; + for (auto m : m_DW) + { + nonzero |= (m & mask); + } + return nonzero != 0; +} + +///////////////////////// + +static bool cross_lt(Vec2D a, Vec2D b) { return a.x * b.y < a.y * b.x; } + +bool HitTester::testMesh(Vec2D pt, Span verts, Span indices) +{ + if (verts.size() < 3) + { + return false; + } + + // Test against the bounds of the entire mesh + // Make this optional? + if (CULL_BOUNDS) + { + const auto bounds = AABB(verts); + + if (bounds.bottom() < pt.y || pt.y < bounds.top() || + bounds.right() < pt.x || pt.x < bounds.left()) + { + return false; + } + } + + for (size_t i = 0; i < indices.size(); i += 3) + { + const auto a = verts[indices[i + 0]]; + const auto b = verts[indices[i + 1]]; + const auto c = verts[indices[i + 2]]; + + auto pa = a - pt; + auto pb = b - pt; + auto pc = c - pt; + + auto ab = cross_lt(pa, pb); + auto bc = cross_lt(pb, pc); + auto ca = cross_lt(pc, pa); + + if (ab == bc && ab == ca) + { + return true; + } + } + return false; +} + +bool HitTester::testMesh(const IAABB& area, + Span verts, + Span indices) +{ + // this version can give slightly different results, so perhaps we should do + // this automatically, ... its just much faster if we do. + if (area.width() * area.height() == 1) + { + return testMesh(Vec2D((float)area.left, (float)area.top), + verts, + indices); + } + + if (verts.size() < 3) + { + return false; + } + + // Test against the bounds of the entire mesh + // Make this optional? + if (CULL_BOUNDS) + { + const auto bounds = AABB(verts); + + if (bounds.bottom() <= area.top || area.bottom <= bounds.top() || + bounds.right() <= area.left || area.right <= bounds.left()) + { + return false; + } + } + + std::vector windings(area.width() * area.height()); + const auto offset = Vec2D((float)area.left, (float)area.top); + int* deltas = windings.data(); + + for (size_t i = 0; i < indices.size(); i += 3) + { + const auto a = verts[indices[i + 0]] - offset; + const auto b = verts[indices[i + 1]] - offset; + const auto c = verts[indices[i + 2]] - offset; + + clip_line((float)area.height(), a, b, deltas, area.width()); + clip_line((float)area.height(), b, c, deltas, area.width()); + clip_line((float)area.height(), c, a, deltas, area.width()); + + int nonzero = 0; + for (auto w : windings) + { + nonzero |= w; + } + if (nonzero) + { + return true; + } + } + return false; +} diff --git a/third_party/rive/source/math/mat2d.cpp b/third_party/rive/source/math/mat2d.cpp new file mode 100644 index 0000000..b060cb9 --- /dev/null +++ b/third_party/rive/source/math/mat2d.cpp @@ -0,0 +1,245 @@ +#include "rive/math/math_types.hpp" +#include "rive/math/mat2d.hpp" +#include "rive/math/simd.hpp" +#include "rive/math/transform_components.hpp" +#include "rive/math/vec2d.hpp" +#include + +using namespace rive; + +Mat2D Mat2D::fromRotation(float rad) +{ + float s = 0, c = 1; + if (rad != 0) + { + s = sin(rad); + c = cos(rad); + } + return {c, s, -s, c, 0, 0}; +} + +Mat2D Mat2D::scale(Vec2D vec) const +{ + return { + m_buffer[0] * vec.x, + m_buffer[1] * vec.x, + m_buffer[2] * vec.y, + m_buffer[3] * vec.y, + m_buffer[4], + m_buffer[5], + }; +} + +Mat2D Mat2D::translate(Vec2D vec) const +{ + return { + m_buffer[0], + m_buffer[1], + m_buffer[2], + m_buffer[3], + m_buffer[4] + vec.x, + m_buffer[5] + vec.y, + }; +} + +Mat2D Mat2D::multiply(const Mat2D& a, const Mat2D& b) +{ + float a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5], + b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3], b4 = b[4], b5 = b[5]; + return { + a0 * b0 + a2 * b1, + a1 * b0 + a3 * b1, + a0 * b2 + a2 * b3, + a1 * b2 + a3 * b3, + a0 * b4 + a2 * b5 + a4, + a1 * b4 + a3 * b5 + a5, + }; +} + +void Mat2D::mapPoints(Vec2D dst[], const Vec2D pts[], size_t n) const +{ + size_t i = 0; + float4 scale = float2{m_buffer[0], m_buffer[3]}.xyxy; + float4 skew = simd::load2f(&m_buffer[1]).yxyx; + float4 trans = simd::load2f(&m_buffer[4]).xyxy; + if (simd::all(skew.xy == 0.f)) + { + // Scale + translate matrix. + if (n & 1) + { + float2 p = simd::load2f(pts); + p = scale.xy * p + trans.xy; + simd::store(dst, p); + ++i; + } + for (; i < n; i += 2) + { + float4 p = simd::load4f(pts + i); + p = scale * p + trans; + simd::store(dst + i, p); + } + } + else + { + // Affine matrix. + if (n & 1) + { + float2 p = simd::load2f(pts); + float2 p_ = skew.xy * p.yx + trans.xy; + p_ = scale.xy * p + p_; + simd::store(dst, p_); + ++i; + } + for (; i < n; i += 2) + { + float4 p = simd::load4f(pts + i); + float4 p_ = skew * p.yxwz + trans; + p_ = scale * p + p_; + simd::store(dst + i, p_); + } + } +} + +AABB Mat2D::mapBoundingBox(const Vec2D pts[], size_t n) const +{ + size_t i = 0; + float4 scale = float2{m_buffer[0], m_buffer[3]}.xyxy; + float4 skew = simd::load2f(&m_buffer[1]).yxyx; + float4 mins = std::numeric_limits::infinity(); + float4 maxes = -std::numeric_limits::infinity(); + if (simd::all(skew.xy == 0.f)) + { + // Scale + translate matrix. + if (n & 1) + { + float2 p = simd::load2f(pts); + p = scale.xy * p; + mins.xy = maxes.xy = p; + ++i; + } + for (; i < n; i += 2) + { + float4 p = simd::load4f(pts + i); + p = scale * p; + mins = simd::min(p, mins); + maxes = simd::max(p, maxes); + } + } + else + { + // Affine matrix. + if (n & 1) + { + float2 p = simd::load2f(pts); + float2 p_ = skew.xy * p.yx; + p_ = scale.xy * p + p_; + mins.xy = maxes.xy = p_; + ++i; + } + for (; i < n; i += 2) + { + float4 p = simd::load4f(pts + i); + float4 p_ = skew * p.yxwz; + p_ = scale * p + p_; + mins = simd::min(p_, mins); + maxes = simd::max(p_, maxes); + } + } + + float4 bbox = + simd::join(simd::min(mins.xy, mins.zw), simd::max(maxes.xy, maxes.zw)); + // Use logic that takes the "nonfinite" branch when bbox has NaN values. + // Use "b - a >= 0" instead of "a >= b" because it fails when b == a == inf. + if (!simd::all(bbox.zw - bbox.xy >= 0)) + { + // The given points were NaN or empty, or infinite. + bbox = float4(0); + } + else + { + float4 trans = simd::load2f(&m_buffer[4]).xyxy; + bbox += trans; + } + + auto aabb = math::bit_cast(bbox); + assert(aabb.width() >= 0); + assert(aabb.height() >= 0); + return aabb; +} + +AABB Mat2D::mapBoundingBox(const AABB& aabb) const +{ + Vec2D pts[4] = {{aabb.left(), aabb.top()}, + {aabb.right(), aabb.top()}, + {aabb.right(), aabb.bottom()}, + {aabb.left(), aabb.bottom()}}; + return mapBoundingBox(pts, 4); +} + +bool Mat2D::invert(Mat2D* result) const +{ + float aa = m_buffer[0], ab = m_buffer[1], ac = m_buffer[2], + ad = m_buffer[3], atx = m_buffer[4], aty = m_buffer[5]; + + float det = aa * ad - ab * ac; + if (det == 0.0f) + { + return false; + } + det = 1.0f / det; + + *result = { + ad * det, + -ab * det, + -ac * det, + aa * det, + (ac * aty - ad * atx) * det, + (ab * atx - aa * aty) * det, + }; + return true; +} + +TransformComponents Mat2D::decompose() const +{ + float m0 = m_buffer[0], m1 = m_buffer[1], m2 = m_buffer[2], + m3 = m_buffer[3]; + + float rotation = std::atan2(m1, m0); + float denom = m0 * m0 + m1 * m1; + float scaleX = std::sqrt(denom); + float scaleY = scaleX == 0.0f ? 0.0f : (m0 * m3 - m2 * m1) / scaleX; + float skewX = std::atan2(m0 * m2 + m1 * m3, denom); + + TransformComponents result; + result.x(m_buffer[4]); + result.y(m_buffer[5]); + result.scaleX(scaleX); + result.scaleY(scaleY); + result.rotation(rotation); + result.skew(skewX); + return result; +} + +Mat2D Mat2D::compose(const TransformComponents& components) +{ + auto result = Mat2D::fromRotation(components.rotation()); + result[4] = components.x(); + result[5] = components.y(); + result = result.scale(components.scale()); + + float sk = components.skew(); + if (sk != 0.0f) + { + result[2] = result[0] * sk + result[2]; + result[3] = result[1] * sk + result[3]; + } + return result; +} + +void Mat2D::scaleByValues(float sx, float sy) +{ + m_buffer[0] *= sx; + m_buffer[1] *= sx; + m_buffer[2] *= sy; + m_buffer[3] *= sy; +} diff --git a/third_party/rive/source/math/mat2d_find_max_scale.cpp b/third_party/rive/source/math/mat2d_find_max_scale.cpp new file mode 100644 index 0000000..652b21b --- /dev/null +++ b/third_party/rive/source/math/mat2d_find_max_scale.cpp @@ -0,0 +1,67 @@ +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Initial import from skia:src/core/SkMatrix.cpp + * + * Copyright 2022 Rive + */ + +#include "rive/math/mat2d.hpp" + +#include "rive/math/math_types.hpp" +#include + +static inline float sdot(float a, float b, float c, float d) +{ + return a * b + c * d; +} + +namespace rive +{ +float Mat2D::findMaxScale() const +{ + if (xy() == 0 && yx() == 0) + { + return std::max(fabsf(xx()), fabsf(yy())); + } + + // ignore the translation part of the matrix, just look at 2x2 portion. + // compute singular values, take largest or smallest abs value. + // [a b; b c] = A^T*A + float a = sdot(xx(), xx(), xy(), xy()); + float b = sdot(xx(), yx(), yy(), xy()); + float c = sdot(yx(), yx(), yy(), yy()); + // eigenvalues of A^T*A are the squared singular values of A. + // characteristic equation is det((A^T*A) - l*I) = 0 + // l^2 - (a + c)l + (ac-b^2) + // solve using quadratic equation (divisor is non-zero since l^2 has 1 coeff + // and roots are guaranteed to be pos and real). + float bSqd = b * b; + // if upper left 2x2 is orthogonal save some math + float result; + if (bSqd <= math::EPSILON * math::EPSILON) + { + result = std::max(a, c); + } + else + { + float aminusc = a - c; + float apluscdiv2 = (a + c) * .5f; + float x = sqrtf(aminusc * aminusc + 4 * bSqd) * .5f; + result = apluscdiv2 + x; + } + if (!std::isfinite(result)) + { + result = 0; + } + // Due to the floating point inaccuracy, there might be an error in a, b, c + // calculated by sdot, further deepened by subsequent arithmetic operations + // on them. Therefore, we allow and cap the nearly-zero negative values. + result = std::max(result, 0.f); + result = sqrtf(result); + return result; +} +} // namespace rive diff --git a/third_party/rive/source/math/n_slicer_helpers.cpp b/third_party/rive/source/math/n_slicer_helpers.cpp new file mode 100644 index 0000000..f7dc71c --- /dev/null +++ b/third_party/rive/source/math/n_slicer_helpers.cpp @@ -0,0 +1,158 @@ +#include "rive/artboard.hpp" +#include "rive/factory.hpp" +#include "rive/layout/axis.hpp" +#include "rive/layout/n_sliced_node.hpp" +#include "rive/math/math_types.hpp" +#include "rive/math/n_slicer_helpers.hpp" + +using namespace rive; + +std::vector NSlicerHelpers::uvStops(const std::vector& axes, + float size) +{ + std::vector uvs = {0.0}; + for (const Axis* axis : axes) + { + if (axis == nullptr) + { + continue; + } + if (axis->normalized()) + { + uvs.emplace_back(math::clamp(axis->offset(), 0, 1)); + } + else + { + uvs.emplace_back(math::clamp(axis->offset() / size, 0, 1)); + } + } + uvs.emplace_back(1.0); + std::sort(uvs.begin(), uvs.end()); + return uvs; +} + +std::vector NSlicerHelpers::pxStops(const std::vector& axes, + float size) +{ + std::vector result = {0.0}; + for (const Axis* axis : axes) + { + if (axis == nullptr) + { + continue; + } + if (axis->normalized()) + { + result.emplace_back(math::clamp(axis->offset(), 0, 1) * size); + } + else + { + result.emplace_back(math::clamp(axis->offset(), 0, size)); + } + } + result.emplace_back(size); + std::sort(result.begin(), result.end()); + return result; +} + +ScaleInfo NSlicerHelpers::analyzeUVStops(const std::vector& uvs, + float size, + float scale) +{ + assert(size >= 0 && scale >= 0); + // Find the percentage of the dimension that should be fixed / not scaled. + float fixedPct = 0.0; + int numEmptyPatch = 0; + for (int i = 0; i < (int)uvs.size() - 1; i++) + { + float range = uvs[i + 1] - uvs[i]; + if (isFixedSegment(i)) + { + fixedPct += range; + } + else + { + numEmptyPatch += (range == 0 ? 1 : 0); + } + } + + // Find the scale that the scalable segments are bearing. + // If the unscaled image is 300px, how to divide it up between scaled and + // unscaled patches. + float fixedSize = fixedPct * size; + float scalableSize = size - fixedSize; + + // Considering the image's scale, how much should the scalable patches scale + // by. And if all scalable patches were empty, how much whitespace to leave + // in those patches. + bool useScale = scalableSize != 0; + float scaleFactor = + useScale ? (size * scale - fixedSize) / scalableSize : 0; + + float fallbackSize = 0; + if (!useScale && numEmptyPatch != 0) + { + fallbackSize = (size - fixedSize / scale) / (float)numEmptyPatch; + } + + return {useScale, scaleFactor, fallbackSize}; +} + +float NSlicerHelpers::mapValue(const std::vector& stops, + const ScaleInfo& scaleInfo, + float size, + float value) +{ + if (value < (stops.front() - 0.01)) + { + return value; + } + + if (value > (stops.back() + 0.01)) + { + return value - stops.back() + size; + } + + float result = 0; + for (int i = 0; i < (int)stops.size() - 1; i++) + { + bool found = value <= stops[i + 1]; + float span = found ? value - stops[i] : stops[i + 1] - stops[i]; + if (isFixedSegment(i)) + { + result += span; + } + else + { + result += scaleInfo.useScale ? scaleInfo.scaleFactor * span : 0; + } + if (found) + { + break; + } + } + + return result; +} + +void NSlicerHelpers::deformLocalRenderPathWithNSlicer( + const NSlicedNode& nslicedNode, + RawPath& localPath, + const Mat2D& world, + const Mat2D& inverseWorld) +{ + RawPath tempWorld = localPath.transform(world); + deformWorldRenderPathWithNSlicer(nslicedNode, tempWorld); + localPath.rewind(); + localPath.addPath(tempWorld, &inverseWorld); +} + +void NSlicerHelpers::deformWorldRenderPathWithNSlicer( + const NSlicedNode& nslicedNode, + RawPath& worldPath) +{ + for (Vec2D& point : worldPath.points()) + { + nslicedNode.mapWorldPoint(point); + } +} diff --git a/third_party/rive/source/math/path_measure.cpp b/third_party/rive/source/math/path_measure.cpp new file mode 100644 index 0000000..4583d9a --- /dev/null +++ b/third_party/rive/source/math/path_measure.cpp @@ -0,0 +1,52 @@ +#include "rive/math/path_measure.hpp" + +using namespace rive; + +PathMeasure::PathMeasure() : m_length(0.0f) {} + +PathMeasure::PathMeasure(const RawPath* path, float tol) : m_length(0.0f) +{ + auto measure = ContourMeasureIter(path, tol); + for (auto contour = measure.next(); contour != nullptr; + contour = measure.next()) + { + m_length += contour->length(); + m_contours.push_back(contour); + } +} + +ContourMeasure::PosTanDistance PathMeasure::atDistance(float distance) const +{ + float currentDistance = distance; + for (auto contour : m_contours) + { + float contourLength = contour->length(); + if (currentDistance - contourLength <= 0) + { + return ContourMeasure::PosTanDistance( + contour->getPosTan(currentDistance), + distance); + } + currentDistance -= contourLength; + } + return ContourMeasure::PosTanDistance(); +} + +ContourMeasure::PosTanDistance PathMeasure::atPercentage( + float percentageDistance) const +{ + float inRangePercentage = fmodf(percentageDistance, 1.0f); + if (inRangePercentage < 0.0f) + { + inRangePercentage += 1.0f; + } + + // Mod to correct percentage (0-100%) and make sure we actually reach + // 100%. + if (percentageDistance != 0.0f && inRangePercentage == 0.0f) + { + inRangePercentage = 1.0f; + } + + return atDistance(m_length * inRangePercentage); +} diff --git a/third_party/rive/source/math/raw_path.cpp b/third_party/rive/source/math/raw_path.cpp new file mode 100644 index 0000000..3c7c46d --- /dev/null +++ b/third_party/rive/source/math/raw_path.cpp @@ -0,0 +1,775 @@ +/* + * Copyright 2022 Rive + */ + +#include "rive/math/raw_path.hpp" + +#include "rive/command_path.hpp" +#include "rive/math/simd.hpp" +#include "rive/math/wangs_formula.hpp" +#include "rive/math/bezier_utils.hpp" +#include +#include +#include + +namespace rive +{ +bool RawPath::operator==(const RawPath& o) const +{ + return m_Points == o.m_Points && m_Verbs == o.m_Verbs; +} + +AABB RawPath::bounds() const +{ + float4 mins, maxes; + size_t i; + if (m_Points.size() & 1) + { + mins = maxes = simd::load2f(&m_Points[0].x).xyxy; + i = 1; + } + else + { + mins = maxes = m_Points.empty() ? float4{0, 0, 0, 0} + : simd::load4f(&m_Points[0].x); + i = 2; + } + for (; i < m_Points.size(); i += 2) + { + float4 pts = simd::load4f(&m_Points[i].x); + mins = simd::min(mins, pts); + maxes = simd::max(maxes, pts); + } + AABB bounds; + simd::store(&bounds.minX, simd::min(mins.xy, mins.zw)); + simd::store(&bounds.maxX, simd::max(maxes.xy, maxes.zw)); + return bounds; +} + +size_t RawPath::countMoveTos() const +{ + size_t moveToCount = 0; + for (PathVerb verb : m_Verbs) + { + moveToCount += verb == PathVerb::move ? 1 : 0; + } + return moveToCount; +} + +void RawPath::injectImplicitMoveIfNeeded() +{ + if (!m_contourIsOpen) + { + move(m_Points.empty() ? Vec2D{0, 0} : m_Points[m_lastMoveIdx]); + } +} + +void RawPath::move(Vec2D a) +{ + m_contourIsOpen = true; + m_lastMoveIdx = m_Points.size(); + m_Points.push_back(a); + m_Verbs.push_back(PathVerb::move); +} + +void RawPath::line(Vec2D a) +{ + injectImplicitMoveIfNeeded(); + m_Points.push_back(a); + m_Verbs.push_back(PathVerb::line); +} + +void RawPath::quad(Vec2D a, Vec2D b) +{ + injectImplicitMoveIfNeeded(); + m_Points.push_back(a); + m_Points.push_back(b); + m_Verbs.push_back(PathVerb::quad); +} + +void RawPath::cubic(Vec2D a, Vec2D b, Vec2D c) +{ + injectImplicitMoveIfNeeded(); + m_Points.push_back(a); + m_Points.push_back(b); + m_Points.push_back(c); + m_Verbs.push_back(PathVerb::cubic); +} + +void RawPath::close() +{ + if (m_contourIsOpen) + { + m_Verbs.push_back(PathVerb::close); + m_contourIsOpen = false; + } +} + +bool RawPath::isClosed() const +{ + if (m_Verbs.size() > 0) + { + return m_Verbs[m_Verbs.size() - 1] == PathVerb::close; + } + return false; +} + +RawPath RawPath::transform(const Mat2D& m) const +{ + RawPath path; + + path.m_Verbs = m_Verbs; + + path.m_Points.resize(m_Points.size()); + m.mapPoints(path.m_Points.data(), m_Points.data(), m_Points.size()); + return path; +} + +void RawPath::transformInPlace(const Mat2D& m) +{ + m.mapPoints(m_Points.data(), m_Points.data(), m_Points.size()); +} + +void RawPath::addRect(const AABB& r, PathDirection dir) +{ + // We manually close the rectangle, in case we want to stroke + // this path. We also call close() so we get proper joins + // (and not caps). + + m_Points.reserve(5); + m_Verbs.reserve(6); + + moveTo(r.left(), r.top()); + if (dir == PathDirection::clockwise) + { + lineTo(r.right(), r.top()); + lineTo(r.right(), r.bottom()); + lineTo(r.left(), r.bottom()); + } + else + { + lineTo(r.left(), r.bottom()); + lineTo(r.right(), r.bottom()); + lineTo(r.right(), r.top()); + } + close(); +} + +void RawPath::addOval(const AABB& r, PathDirection dir) +{ + // see https://spencermortensen.com/articles/bezier-circle/ + constexpr float C = 0.5519150244935105707435627f; + // precompute clockwise unit circle, starting and ending at {1, 0} + constexpr rive::Vec2D unit[] = { + {1, 0}, + {1, C}, + {C, 1}, // quadrant 1 ( 4:30) + {0, 1}, + {-C, 1}, + {-1, C}, // quadrant 2 ( 7:30) + {-1, 0}, + {-1, -C}, + {-C, -1}, // quadrant 3 (10:30) + {0, -1}, + {C, -1}, + {1, -C}, // quadrant 4 ( 1:30) + {1, 0}, + }; + + const auto center = r.center(); + const float dx = center.x; + const float dy = center.y; + const float sx = r.width() * 0.5f; + const float sy = r.height() * 0.5f; + + auto map = [dx, dy, sx, sy](rive::Vec2D p) { + return rive::Vec2D(p.x * sx + dx, p.y * sy + dy); + }; + + m_Points.reserve(13); + m_Verbs.reserve(6); + + if (dir == PathDirection::clockwise) + { + move(map(unit[0])); + for (int i = 1; i <= 12; i += 3) + { + cubic(map(unit[i + 0]), map(unit[i + 1]), map(unit[i + 2])); + } + } + else + { + move(map(unit[12])); + for (int i = 11; i >= 0; i -= 3) + { + cubic(map(unit[i - 0]), map(unit[i - 1]), map(unit[i - 2])); + } + } + close(); +} + +void RawPath::addPoly(Span span, bool isClosed) +{ + if (span.size() == 0) + { + return; + } + + // should we permit must moveTo() or just moveTo()/close() ? + + m_Points.reserve(span.size() + isClosed); + m_Verbs.reserve(span.size() + isClosed); + + move(span[0]); + for (size_t i = 1; i < span.size(); ++i) + { + line(span[i]); + } + if (isClosed) + { + close(); + } +} + +void RawPath::addPoints(std::vector::const_iterator& ptIter, + int count, + const Mat2D* mat) +{ + while (count > 0) + { + auto point = *ptIter; + if (mat) + { + Vec2D transformedPoint = Vec2D::transformMat2D(point, *mat); + m_Points.emplace_back(transformedPoint); + } + else + { + m_Points.emplace_back(point); + } + ptIter--; + count--; + } +} + +RawPath::Iter RawPath::addPath(const RawPath& src, const Mat2D* mat) +{ + size_t initialVerbCount = m_Verbs.size(); + size_t initialPointCount = m_Points.size(); + + m_Verbs.insert(m_Verbs.end(), src.m_Verbs.cbegin(), src.m_Verbs.cend()); + + if (mat) + { + const auto oldPointCount = m_Points.size(); + m_Points.resize(oldPointCount + src.m_Points.size()); + Vec2D* dst = m_Points.data() + oldPointCount; + mat->mapPoints(dst, src.m_Points.data(), src.m_Points.size()); + } + else + { + m_Points.insert(m_Points.end(), + src.m_Points.cbegin(), + src.m_Points.cend()); + } + + // Return an iterator at the beginning of the newly added geometry. + return Iter{m_Verbs.data() + initialVerbCount, + m_Points.data() + initialPointCount}; +} + +RawPath::Iter RawPath::addPathBackwards(const RawPath& src, const Mat2D* mat) +{ + size_t initialVerbCount = m_Verbs.size(); + size_t initialPointCount = m_Points.size(); + if (!src.m_Verbs.empty()) + { + bool isClosed = src.m_Verbs.back() == PathVerb::close; + + auto reversePointIterator = src.m_Points.end() - 1; + // Move to first point + m_Verbs.emplace_back(PathVerb::move); + addPoints(reversePointIterator, 1, mat); + + auto reverseVerbIterator = src.m_Verbs.end() - 1; + if (isClosed) + { + reverseVerbIterator--; + } + + bool hasPendingMoveCommand = false; + + for (; reverseVerbIterator != src.m_Verbs.begin(); + reverseVerbIterator--) + { + PathVerb verb = *reverseVerbIterator; + // For paths that have multiple segments (like in certain font + // glyphs), we need to flip the intermediate move verbs with the + // previous close path. So we hold on to it and add it after the + // next close call. + if (verb == PathVerb::move) + { + hasPendingMoveCommand = true; + } + else + { + if (hasPendingMoveCommand && verb != PathVerb::close) + { + m_Verbs.emplace_back(PathVerb::move); + hasPendingMoveCommand = false; + } + m_Verbs.emplace_back(verb); + if (hasPendingMoveCommand && verb == PathVerb::close) + { + m_Verbs.emplace_back(PathVerb::move); + hasPendingMoveCommand = false; + } + } + switch (verb) + { + case PathVerb::cubic: + addPoints(reversePointIterator, 3, mat); + break; + case PathVerb::quad: + addPoints(reversePointIterator, 2, mat); + break; + case PathVerb::line: + case PathVerb::move: + addPoints(reversePointIterator, 1, mat); + break; + default: + break; + } + } + // This should never be the case, but if for some reason a path ends + // with a move command, we add it to the list of verbs to ensure the + // path matches with the number of points + if (hasPendingMoveCommand) + { + m_Verbs.emplace_back(PathVerb::move); + } + m_Verbs.emplace_back(PathVerb::close); + } + return Iter{m_Verbs.data() + initialVerbCount, + m_Points.data() + initialPointCount}; +} + +void RawPath::pruneEmptySegments(Iter start) +{ + auto dstVerb = + m_Verbs.begin() + + std::distance(m_Verbs.data(), start.rawVerbsPtr()); + auto dstPts = + m_Points.begin() + + std::distance(m_Points.data(), start.rawPtsPtr()); + decltype(m_Verbs)::const_iterator srcVerb = dstVerb; + decltype(m_Points)::const_iterator srcPts = dstPts; + + int ptsAdvance; + for (auto end = m_Verbs.end(); srcVerb != end; + ++srcVerb, srcPts += ptsAdvance) + { + PathVerb verb = *srcVerb; + ptsAdvance = Iter::PtsAdvanceAfterVerb(verb); + + switch (verb) + { + case PathVerb::move: + break; + case PathVerb::close: + break; + case PathVerb::cubic: + if (srcPts[2] != srcPts[1]) + { + break; + } + RIVE_FALLTHROUGH; + case PathVerb::quad: + if (srcPts[1] != srcPts[0]) + { + break; + } + RIVE_FALLTHROUGH; + case PathVerb::line: + if (srcPts[0] != srcPts[-1]) + { + break; + } + // This segment is empty! Don't keep it. + continue; + } + + if (srcVerb != dstVerb) + { + *dstVerb = verb; + std::copy(srcPts, srcPts + ptsAdvance, dstPts); + } + + ++dstVerb; + dstPts += ptsAdvance; + } + + if (dstVerb != srcVerb) + { + m_Verbs.erase(dstVerb, m_Verbs.end()); + m_Points.erase(dstPts, m_Points.end()); + } +} + +////////////////////////////////////////////////////////////////////////// +int path_verb_to_point_count(PathVerb v) +{ + static uint8_t ptCounts[] = { + 1, // move + 1, // line + 2, // quad + 2, // conic (unused) + 3, // cubic + 0, // close + }; + size_t index = (size_t)v; + assert(index < sizeof(ptCounts)); + return ptCounts[index]; +} + +void RawPath::swap(RawPath& rawPath) +{ + m_Points.swap(rawPath.m_Points); + m_Verbs.swap(rawPath.m_Verbs); +} + +void RawPath::reset() +{ + m_Points.clear(); + m_Points.shrink_to_fit(); + m_Verbs.clear(); + m_Verbs.shrink_to_fit(); + m_contourIsOpen = false; +} + +void RawPath::rewind() +{ + m_Points.clear(); + m_Verbs.clear(); + m_contourIsOpen = false; +} + +/////////////////////////////////// + +void RawPath::addTo(CommandPath* result) const +{ + for (auto iter : *this) + { + PathVerb verb = std::get<0>(iter); + const Vec2D* pts = std::get<1>(iter); + switch (verb) + { + case PathVerb::move: + result->move(pts[0]); + break; + case PathVerb::line: + result->line(pts[1]); + break; + case PathVerb::cubic: + result->cubic(pts[1], pts[2], pts[3]); + break; + case PathVerb::close: + result->close(); + break; + case PathVerb::quad: + // TODO: actually supports quads. + result->cubic(Vec2D::lerp(pts[0], pts[1], 2 / 3.f), + Vec2D::lerp(pts[2], pts[1], 2 / 3.f), + pts[2]); + } + } +} + +void RawPath::quadToCubic(float x, float y, float x1, float y1) +{ + assert(!m_Points.empty()); + if (m_Points.empty()) + { + return; + } + const Vec2D& p0 = m_Points.back(); + const Vec2D p1(x, y); + const Vec2D p2(x1, y1); + cubic(Vec2D::lerp(p0, p1, 2 / 3.f), Vec2D::lerp(p2, p1, 2 / 3.f), p2); +} + +#ifdef DEBUG +void RawPath::printCode() const +{ + fprintf(stderr, "RawPath path;\n"); + for (auto iter : *this) + { + PathVerb verb = std::get<0>(iter); + const Vec2D* pts = std::get<1>(iter); + switch (verb) + { + case PathVerb::move: + fprintf(stderr, "path.moveTo(%f, %f);\n", pts[0].x, pts[0].y); + break; + case PathVerb::line: + fprintf(stderr, "path.lineTo(%f, %f);\n", pts[1].x, pts[1].y); + break; + case PathVerb::cubic: + fprintf(stderr, + "path.cubicTo(%f, %f, %f, %f, %f, %f);\n", + pts[1].x, + pts[1].y, + pts[2].x, + pts[2].y, + pts[3].x, + pts[3].y); + break; + case PathVerb::close: + fprintf(stderr, "path.close();\n"); + break; + case PathVerb::quad: + fprintf(stderr, + "path.quadTo(%f, %f, %f, %f);\n", + pts[1].x, + pts[1].y, + pts[2].x, + pts[2].y); + } + } + fprintf(stderr, "\n"); +} +#endif +#ifdef WITH_RIVE_TOOLS +static void expandAxisBounds(AABB& bounds, int axis, float value) +{ + switch (axis) + { + case 0: + if (value < bounds.minX) + { + bounds.minX = value; + } + if (value > bounds.maxX) + { + bounds.maxX = value; + } + break; + case 1: + if (value < bounds.minY) + { + bounds.minY = value; + } + if (value > bounds.maxY) + { + bounds.maxY = value; + } + break; + default: + RIVE_UNREACHABLE(); + } +} + +// Expand our bounds to a point (in normalized T space) on the cubic. +static void expandBoundsToCubicPoint(AABB& bounds, + int axis, + float t, + float a, + float b, + float c, + float d) +{ + if (t >= 0.0f && t <= 1.0f) + { + float ti = 1.0f - t; + float pointAtT = ((ti * ti * ti) * a) + ((3.0f * ti * ti * t) * b) + + ((3.0f * ti * t * t) * c) + (t * t * t * d); + expandAxisBounds(bounds, axis, pointAtT); + } +} + +// Based on finding the extremas of the curve as described here: +// https://pomax.github.io/bezierinfo/#extremities and based on PR we provided +// to the Flutter team here: https://github.com/flutter/engine/pull/19054 and +// here: +// https://github.com/luigi-rosso/engine/blob/9ae3efd7dc6bcb9634402b4b8818d0add096c12d/lib/web_ui/lib/src/engine/surface/path.dart#L892 +static void expandCubicBoundsForAxis(AABB& bounds, + int axis, + float start, + float cp1, + float cp2, + float end) +{ + // Check start/end as cubic goes through those. + expandAxisBounds(bounds, axis, start); + expandAxisBounds(bounds, axis, end); + // Now check extremas. + + // Find the first derivative + float a = 3.0f * (cp1 - start); + float b = 3.0f * (cp2 - cp1); + float c = 3.0f * (end - cp2); + float d = a - 2.0f * b + c; + + // Solve roots for first derivative. + if (d != 0) + { + float m1 = -sqrtf(b * b - a * c); + float m2 = -a + b; + + // First root. + expandBoundsToCubicPoint(bounds, + axis, + -(m1 + m2) / d, + start, + cp1, + cp2, + end); + expandBoundsToCubicPoint(bounds, + axis, + -(-m1 + m2) / d, + start, + cp1, + cp2, + end); + } + else if (b != c && d == 0) + { + expandBoundsToCubicPoint(bounds, + axis, + (2.0f * b - c) / (2.0f * (b - c)), + start, + cp1, + cp2, + end); + } + + // Derive the first derivative to get the 2nd and use the root of + // that (linear). + float d2a = 2.0f * (b - a); + float d2b = 2.0f * (c - b); + if (d2a != b) + { + expandBoundsToCubicPoint(bounds, + axis, + d2a / (d2a - d2b), + start, + cp1, + cp2, + end); + } +} + +AABB RawPath::preciseBounds() const +{ + AABB bounds = AABB::forExpansion(); + for (auto iter : *this) + { + PathVerb verb = std::get<0>(iter); + const Vec2D* pts = std::get<1>(iter); + switch (verb) + { + case PathVerb::move: + bounds.expandTo(bounds, pts[0]); + break; + case PathVerb::line: + bounds.expandTo(bounds, pts[1]); + break; + case PathVerb::cubic: + expandCubicBoundsForAxis(bounds, + 0, + pts[0].x, + pts[1].x, + pts[2].x, + pts[3].x); + expandCubicBoundsForAxis(bounds, + 1, + pts[0].y, + pts[1].y, + pts[2].y, + pts[3].y); + break; + case PathVerb::close: + break; + case PathVerb::quad: + // Rive very rarely computes precise bounds for quadratics so we + // don't implement this specific case. We do use it in the + // editor for some cases so we still solve it as a cubic. + Vec2D pt1 = Vec2D::lerp(pts[0], pts[1], 2 / 3.f); + Vec2D pt2 = Vec2D::lerp(pts[2], pts[1], 2 / 3.f); + expandCubicBoundsForAxis(bounds, + 0, + pts[0].x, + pt1.x, + pt2.x, + pts[2].x); + expandCubicBoundsForAxis(bounds, + 1, + pts[0].y, + pt1.y, + pt2.y, + pts[2].y); + break; + } + } + return bounds; +} +#endif + +float RawPath::computeCoarseArea() const +{ + float a = 0; + Vec2D contourP0 = {0, 0}, lastPt = {0, 0}; + for (auto iter : *this) + { + PathVerb verb = std::get<0>(iter); + const Vec2D* pts = std::get<1>(iter); + switch (verb) + { + case PathVerb::move: + a += Vec2D::cross(lastPt, contourP0); + contourP0 = lastPt = pts[0]; + break; + case PathVerb::close: + break; + case PathVerb::line: + a += Vec2D::cross(lastPt, pts[1]); + lastPt = pts[1]; + break; + case PathVerb::quad: + RIVE_UNREACHABLE(); + case PathVerb::cubic: + { + // Linearize the cubic in artboard space, then add up the + // area for each segment. + float n = ceilf( + wangs_formula::cubic(pts, 1.f / kCoarseAreaTolerance)); + if (n > 1) + { + n = std::min(n, 64.f); + float4 t = float4{1, 1, 2, 2} * (1 / n); + float4 dt = t.w; + math::EvalCubic evalCubic(pts); + for (; t.x < 1; t += dt) + { + float4 p = evalCubic(t); + Vec2D lo = {p.x, p.y}; + a += Vec2D::cross(lastPt, lo); + lastPt = lo; + if (t.y < 1) + { + Vec2D hi = {p.z, p.w}; + a += Vec2D::cross(lastPt, hi); + lastPt = hi; + } + } + } + a += Vec2D::cross(lastPt, pts[3]); + lastPt = pts[3]; + break; + } + } + } + a += Vec2D::cross(lastPt, contourP0); + return a * .5f; +} +} // namespace rive diff --git a/third_party/rive/source/math/raw_path_utils.cpp b/third_party/rive/source/math/raw_path_utils.cpp new file mode 100644 index 0000000..3d11908 --- /dev/null +++ b/third_party/rive/source/math/raw_path_utils.cpp @@ -0,0 +1,118 @@ +/* + * Copyright 2022 Rive + */ + +#include "rive/math/math_types.hpp" +#include "rive/math/raw_path_utils.hpp" +#include + +// Extract subsets + +void rive::quad_subdivide(const rive::Vec2D src[3], float t, rive::Vec2D dst[5]) +{ + assert(t >= 0 && t <= 1); + auto ab = lerp(src[0], src[1], t); + auto bc = lerp(src[1], src[2], t); + dst[0] = src[0]; + dst[1] = ab; + dst[2] = lerp(ab, bc, t); + dst[3] = bc; + dst[4] = src[2]; +} + +void rive::cubic_subdivide(const rive::Vec2D src[4], + float t, + rive::Vec2D dst[7]) +{ + assert(t >= 0 && t <= 1); + auto ab = lerp(src[0], src[1], t); + auto bc = lerp(src[1], src[2], t); + auto cd = lerp(src[2], src[3], t); + auto abc = lerp(ab, bc, t); + auto bcd = lerp(bc, cd, t); + dst[0] = src[0]; + dst[1] = ab; + dst[2] = abc; + dst[3] = lerp(abc, bcd, t); + dst[4] = bcd; + dst[5] = cd; + dst[6] = src[3]; +} + +void rive::line_extract(const rive::Vec2D src[2], + float startT, + float endT, + rive::Vec2D dst[2]) +{ + assert(startT <= endT); + assert(startT >= 0 && endT <= 1); + + dst[0] = lerp(src[0], src[1], startT); + dst[1] = lerp(src[0], src[1], endT); +} + +void rive::quad_extract(const rive::Vec2D src[3], + float startT, + float endT, + rive::Vec2D dst[3]) +{ + assert(startT <= endT); + assert(startT >= 0 && endT <= 1); + + rive::Vec2D tmp[5]; + if (startT == 0 && endT == 1) + { + std::copy(src, src + 3, dst); + } + else if (startT == 0) + { + rive::quad_subdivide(src, endT, tmp); + std::copy(tmp, tmp + 3, dst); + } + else if (endT == 1) + { + rive::quad_subdivide(src, startT, tmp); + std::copy(tmp + 2, tmp + 5, dst); + } + else + { + assert(endT > 0); + rive::quad_subdivide(src, endT, tmp); + rive::Vec2D tmp2[5]; + rive::quad_subdivide(tmp, startT / endT, tmp2); + std::copy(tmp2 + 2, tmp2 + 5, dst); + } +} + +void rive::cubic_extract(const rive::Vec2D src[4], + float startT, + float endT, + rive::Vec2D dst[4]) +{ + assert(startT <= endT); + assert(startT >= 0 && endT <= 1); + + rive::Vec2D tmp[7]; + if (startT == 0 && endT == 1) + { + std::copy(src, src + 4, dst); + } + else if (startT == 0) + { + rive::cubic_subdivide(src, endT, tmp); + std::copy(tmp, tmp + 4, dst); + } + else if (endT == 1) + { + rive::cubic_subdivide(src, startT, tmp); + std::copy(tmp + 3, tmp + 7, dst); + } + else + { + assert(endT > 0); + rive::cubic_subdivide(src, endT, tmp); + rive::Vec2D tmp2[7]; + rive::cubic_subdivide(tmp, startT / endT, tmp2); + std::copy(tmp2 + 3, tmp2 + 7, dst); + } +} diff --git a/third_party/rive/source/math/rectangles_to_contour.cpp b/third_party/rive/source/math/rectangles_to_contour.cpp new file mode 100644 index 0000000..9642e63 --- /dev/null +++ b/third_party/rive/source/math/rectangles_to_contour.cpp @@ -0,0 +1,366 @@ +#include "rive/math/rectangles_to_contour.hpp" +#include + +using namespace rive; + +using RectEvent = RectanglesToContour::RectEvent; + +class SpanOffset +{ +public: + size_t start; + size_t size; + + Span toSpan(Span base) + { + return Span(base.data() + start, size); + } +}; + +// Returns SpanOffset relative to result so it can be called in succession +// (re-allocating) prior to accessing data. +static SpanOffset sortRectEvents(const std::vector& rects, + std::vector& result, + uint8_t axisA, + uint8_t axisB) +{ + size_t index = 0; + + size_t resultStart = result.size(); + + for (const AABB& rect : rects) + { + for (size_t pointIndex = 0; pointIndex < 2; pointIndex++) + { + Vec2D e = rect[pointIndex]; + RectEvent event; + event.type = (uint8_t)pointIndex; + event.index = index; + event.y = axisB == 0 ? e[axisA] : e[axisB]; + event.x = axisB == 0 ? e[axisB] : e[axisA]; + event.size = pointIndex == 0 ? rect[1][axisB] - e[axisB] + : e[axisB] - rect[0][axisB]; + result.push_back(event); + } + ++index; + } + + std::sort(result.begin() + resultStart, + result.end(), + [&](const RectEvent& a, const RectEvent& b) { + return a.getValue(axisB) < b.getValue(axisB); + }); + + std::sort(result.begin() + resultStart, + result.end(), + [&](const RectEvent& a, const RectEvent& b) { + return a.getValue(axisA) < b.getValue(axisA); + }); + + return {resultStart, result.size() - resultStart}; +} + +bool RectanglesToContour::isRectIncluded(size_t rectIndex) +{ + return (m_rectInclusionBitset[rectIndex / 8] & (1 << (rectIndex % 8))) != 0; +} + +void RectanglesToContour::markRectIncluded(size_t rectIndex, bool isIt) +{ + if (isIt) + { + m_rectInclusionBitset[rectIndex / 8] |= 1 << (rectIndex % 8); + } + else + { + m_rectInclusionBitset[rectIndex / 8] &= ~(1 << (rectIndex % 8)); + } +} + +void RectanglesToContour::subdivideRectangles() +{ + m_subdividedRects.clear(); + m_uniquePoints.clear(); + m_rectEvents.clear(); + + if (m_rects.empty()) + { + return; + } + + auto evOffset = sortRectEvents(m_rects, m_rectEvents, 0, 1); + auto ehOffset = sortRectEvents(m_rects, m_rectEvents, 1, 0); + + auto ev = evOffset.toSpan(m_rectEvents); + auto eh = ehOffset.toSpan(m_rectEvents); + + size_t inclusionByteSize = m_rects.size() / 8 + 1; + m_rectInclusionBitset.resize(inclusionByteSize); + memset(m_rectInclusionBitset.data(), 0, inclusionByteSize); + markRectIncluded(ev[0].index, true); + + int opened = 0; + float beginY = 0; + std::vector result; + + for (size_t i = 0; i < ev.size() - 1; ++i) + { + const auto& eventV = ev[i]; + markRectIncluded(eventV.index, eventV.type == 0); + const auto& next = ev[i + 1]; + float beginX = eventV.x; + float endX = next.x; + float deltaX = next.x - eventV.x; + if (deltaX == 0) + { + continue; + } + + for (size_t j = 0; j < eh.size(); ++j) + { + const auto& eventH = eh[j]; + if (isRectIncluded(eventH.index)) + { + if (eventH.type == 0) + { + ++opened; + if (opened == 1) + { + beginY = eventH.y; + } + } + else + { + --opened; + size_t n = 1; + while (j + n < eh.size() && + !isRectIncluded(eh[j + n].index)) + { + ++n; + } + const auto* next = + (j + n < eh.size()) ? &eh[j + n] : nullptr; + if (!next || (opened == 0 && next->y != eventH.y)) + { + float endY = eventH.y; + m_subdividedRects.push_back( + AABB(beginX, beginY, endX, endY)); + } + } + } + } + } +} + +void RectanglesToContour::reset() { m_rects.clear(); } + +void RectanglesToContour::addRect(const AABB& rect) +{ + if (!m_rects.empty()) + { + auto& last = m_rects.back(); + if (last.minY == rect.minY && last.maxY == rect.maxY && + last.maxX == rect.minX) + { + m_rects.pop_back(); + m_rects.emplace_back( + AABB(last.minX, last.minY, rect.maxX, last.maxY)); + return; + } + } + m_rects.push_back(rect); +} + +// Build contours and append them into contourPoints delineated by +// contourOffsets. +void extractPolygons(std::vector& contourPoints, + std::vector& contourOffsets, + EdgeMap& edgesH, + EdgeMap& edgesV) +{ + + while (!edgesH.empty()) + { + size_t contourStartOffset = contourPoints.size(); + Vec2D start = edgesH.begin()->first; + edgesH.erase(start); + + auto first = ContourPoint(start, 0); + contourPoints.push_back(first); + + while (true) + { + auto& curr = contourPoints.back(); + if (curr.dir == 0) + { + if (edgesV.find(curr.vec) != edgesV.end()) + { + auto next = edgesV[curr.vec]; + edgesV.erase(curr.vec); + contourPoints.emplace_back(next, 1); + } + else + { + break; + } + } + else + { + if (edgesH.find(curr.vec) != edgesH.end()) + { + auto next = edgesH[curr.vec]; + edgesH.erase(curr.vec); + contourPoints.emplace_back(next, 0); + } + else + { + break; + } + } + + // Remove the last point if the first and last in the contour are + // the same. + if (first == contourPoints.back()) + { + contourPoints.pop_back(); + break; + } + } + + contourOffsets.push_back(contourPoints.size()); + for (size_t index = contourStartOffset; index < contourPoints.size(); + index++) + { + Vec2D vertex = contourPoints[index].vec; + edgesH.erase(vertex); + edgesV.erase(vertex); + } + } +} + +void RectanglesToContour::computeContours() +{ + subdivideRectangles(); + for (const auto& rect : m_subdividedRects) + { + addUniquePoint(Vec2D(rect.minX, rect.minY)); + addUniquePoint(Vec2D(rect.maxX, rect.minY)); + addUniquePoint(Vec2D(rect.maxX, rect.maxY)); + addUniquePoint(Vec2D(rect.minX, rect.maxY)); + } + + m_sortedPointsX.clear(); + m_sortedPointsY.clear(); + for (auto pt : m_uniquePoints) + { + m_sortedPointsX.push_back(pt); + m_sortedPointsY.push_back(pt); + } + std::sort(m_sortedPointsX.begin(), + m_sortedPointsX.end(), + [](const Vec2D& a, const Vec2D& b) { + return a.x < b.x || (a.x == b.x && a.y < b.y); + }); + std::sort(m_sortedPointsY.begin(), + m_sortedPointsY.end(), + [](const Vec2D& a, const Vec2D& b) { + return a.y < b.y || (a.y == b.y && a.x < b.x); + }); + + // std::unordered_map isn't guaranteed to reserve memory, so this clear + // is more in prep for when we allow using allocators. We could also + // experiment with a simple linear search in a vector as usually there + // are not a lot of edges to traverse. + m_edgesH.clear(); + m_edgesV.clear(); + + size_t i = 0; + while (i < m_sortedPointsY.size()) + { + float currY = m_sortedPointsY[i].y; + while (i < m_sortedPointsY.size() && m_sortedPointsY[i].y == currY) + { + m_edgesH[m_sortedPointsY[i]] = m_sortedPointsY[i + 1]; + m_edgesH[m_sortedPointsY[i + 1]] = m_sortedPointsY[i]; + i += 2; + } + } + + i = 0; + while (i < m_sortedPointsX.size()) + { + float currX = m_sortedPointsX[i].x; + while (i < m_sortedPointsX.size() && m_sortedPointsX[i].x == currX) + { + m_edgesV[m_sortedPointsX[i]] = m_sortedPointsX[i + 1]; + m_edgesV[m_sortedPointsX[i + 1]] = m_sortedPointsX[i]; + i += 2; + } + } + + m_contourPoints.clear(); + m_contourOffsets.clear(); + extractPolygons(m_contourPoints, m_contourOffsets, m_edgesH, m_edgesV); +} + +void RectanglesToContour::addUniquePoint(const Vec2D& point) +{ + if (!m_uniquePoints.insert(point).second) + { + m_uniquePoints.erase(point); + } +} + +ContourItr& ContourItr::operator++() +{ + m_contourIndex++; + return *this; +} +Contour ContourItr::operator*() const +{ + return m_rectanglesToContour->contour(m_contourIndex); +} + +Contour RectanglesToContour::contour(size_t index) const +{ + assert(index < m_contourOffsets.size()); + size_t end = m_contourOffsets[index]; + size_t start = index == 0 ? 0 : m_contourOffsets[index - 1]; + const ContourPoint* data = m_contourPoints.data() + start; + size_t size = end - start; + return Contour(Span(data, size)); +} + +ContourPointItr& ContourPointItr::operator++() +{ + Vec2D currentPoint = m_pointIndex < m_contour.size() ? *(*this) : Vec2D(); + m_pointIndex++; + while (m_pointIndex < m_contour.size()) + { + auto nextPoint = m_contour[m_pointIndex].vec; + if (nextPoint != currentPoint) + { + break; + } + m_pointIndex++; + } + return *this; +} + +Vec2D ContourPointItr::operator*() const { return m_contour[m_pointIndex].vec; } + +bool Contour::isClockwise() const +{ + float a = 0.0f; + size_t size = m_points.size(); + if (size < 1) + { + return true; + } + for (size_t i = 1; i < size; i++) + { + a += Vec2D::cross(m_points[i - 1].vec, m_points[i].vec); + } + a += Vec2D::cross(m_points[size - 1].vec, m_points[0].vec); + return a * 0.5f >= 0; +} \ No newline at end of file diff --git a/third_party/rive/source/math/vec2d.cpp b/third_party/rive/source/math/vec2d.cpp new file mode 100644 index 0000000..e0b8233 --- /dev/null +++ b/third_party/rive/source/math/vec2d.cpp @@ -0,0 +1,25 @@ +#include "rive/math/vec2d.hpp" +#include "rive/math/mat2d.hpp" +#include + +using namespace rive; + +Vec2D Vec2D::transformDir(const Vec2D& a, const Mat2D& m) +{ + return { + m[0] * a.x + m[2] * a.y, + m[1] * a.x + m[3] * a.y, + }; +} +Vec2D Vec2D::transformMat2D(const Vec2D& a, const Mat2D& m) +{ + return {m[0] * a.x + m[2] * a.y + m[4], m[1] * a.x + m[3] * a.y + m[5]}; +} +float Vec2D::length() const { return std::sqrt(lengthSquared()); } + +Vec2D Vec2D::normalized() const +{ + auto len2 = lengthSquared(); + auto scale = len2 > 0 ? (1 / std::sqrt(len2)) : 1; + return *this * scale; +} diff --git a/third_party/rive/source/nested_artboard.cpp b/third_party/rive/source/nested_artboard.cpp new file mode 100644 index 0000000..54b874e --- /dev/null +++ b/third_party/rive/source/nested_artboard.cpp @@ -0,0 +1,391 @@ +#include "rive/nested_artboard.hpp" +#include "rive/artboard.hpp" +#include "rive/backboard.hpp" +#include "rive/importers/import_stack.hpp" +#include "rive/importers/backboard_importer.hpp" +#include "rive/nested_animation.hpp" +#include "rive/animation/nested_state_machine.hpp" +#include "rive/clip_result.hpp" +#include +#include + +using namespace rive; + +NestedArtboard::NestedArtboard() {} +NestedArtboard::~NestedArtboard() {} + +Core* NestedArtboard::clone() const +{ + NestedArtboard* nestedArtboard = + static_cast(NestedArtboardBase::clone()); + if (m_Artboard == nullptr) + { + return nestedArtboard; + } + auto ni = m_Artboard->instance(); + nestedArtboard->nest(ni.release()); + return nestedArtboard; +} + +void NestedArtboard::nest(Artboard* artboard) +{ + assert(artboard != nullptr); + + m_Artboard = artboard; + if (!m_Artboard->isInstance()) + { + // We're just marking the source artboard so we can later instance from + // it. No need to advance it or change any of its properties. + // E.g. at import time, we return here. + return; + } + m_Artboard->frameOrigin(false); + m_Artboard->opacity(renderOpacity()); + m_Artboard->volume(artboard->volume()); + m_Instance = nullptr; + if (artboard->isInstance()) + { + m_Instance.reset( + static_cast(artboard)); // take ownership + } + // This allows for swapping after initial load (after onAddedClean has + // already been called). + m_Artboard->host(this); +} + +static Mat2D makeTranslate(const Artboard* artboard) +{ + return Mat2D::fromTranslate(-artboard->originX() * artboard->width(), + -artboard->originY() * artboard->height()); +} + +void NestedArtboard::draw(Renderer* renderer) +{ + if (m_Artboard == nullptr) + { + return; + } + ClipResult clipResult = applyClip(renderer); + if (clipResult == ClipResult::noClip) + { + // We didn't clip, so make sure to save as we'll be doing some + // transformations. + renderer->save(); + } + if (clipResult != ClipResult::emptyClip) + { + renderer->transform(worldTransform()); + m_Artboard->draw(renderer); + } + renderer->restore(); +} + +Core* NestedArtboard::hitTest(HitInfo* hinfo, const Mat2D& xform) +{ + if (m_Artboard == nullptr) + { + return nullptr; + } + hinfo->mounts.push_back(this); + auto mx = xform * worldTransform() * makeTranslate(m_Artboard); + if (auto c = m_Artboard->hitTest(hinfo, mx)) + { + return c; + } + hinfo->mounts.pop_back(); + return nullptr; +} + +StatusCode NestedArtboard::import(ImportStack& importStack) +{ + auto backboardImporter = + importStack.latest(Backboard::typeKey); + if (backboardImporter == nullptr) + { + return StatusCode::MissingObject; + } + backboardImporter->addNestedArtboard(this); + + return Super::import(importStack); +} + +void NestedArtboard::addNestedAnimation(NestedAnimation* nestedAnimation) +{ + m_NestedAnimations.push_back(nestedAnimation); +} + +StatusCode NestedArtboard::onAddedClean(CoreContext* context) +{ + // N.B. The nested instance will be null here for the source artboards. + // Instances will have a nestedInstance available. This is a good thing as + // it ensures that we only instance animations in artboard instances. It + // does require that we always use an artboard instance (not just the source + // artboard) when working with nested artboards, but in general this is good + // practice for any loaded Rive file. + assert(m_Artboard == nullptr || m_Artboard == m_Instance.get()); + + if (m_Instance) + { + for (auto animation : m_NestedAnimations) + { + animation->initializeAnimation(m_Instance.get()); + } + m_Artboard->host(this); + } + return Super::onAddedClean(context); +} + +void NestedArtboard::update(ComponentDirt value) +{ + Super::update(value); + if (m_Artboard == nullptr) + { + return; + } + if (hasDirt(value, ComponentDirt::RenderOpacity)) + { + m_Artboard->opacity(renderOpacity()); + } + if (hasDirt(value, ComponentDirt::Components)) + { + // We intentionally discard whether or not this updated because by the + // end of the pass all the dirt is removed and only another advance of + // animations/statemachines can re-add it. + m_Artboard->updatePass(false); + } +} + +bool NestedArtboard::hasNestedStateMachines() const +{ + for (auto animation : m_NestedAnimations) + { + if (animation->is()) + { + return true; + } + } + return false; +} + +Span NestedArtboard::nestedAnimations() +{ + return m_NestedAnimations; +} + +NestedArtboard* NestedArtboard::nestedArtboard(std::string name) const +{ + if (m_Instance != nullptr) + { + return m_Instance->nestedArtboard(name); + } + return nullptr; +} + +NestedStateMachine* NestedArtboard::stateMachine(std::string name) const +{ + for (auto animation : m_NestedAnimations) + { + if (animation->is() && animation->name() == name) + { + return animation->as(); + } + } + return nullptr; +} + +NestedInput* NestedArtboard::input(std::string name) const +{ + return input(name, ""); +} + +NestedInput* NestedArtboard::input(std::string name, + std::string stateMachineName) const +{ + if (!stateMachineName.empty()) + { + auto nestedSM = stateMachine(stateMachineName); + if (nestedSM != nullptr) + { + return nestedSM->input(name); + } + } + else + { + for (auto animation : m_NestedAnimations) + { + if (animation->is()) + { + auto input = animation->as()->input(name); + if (input != nullptr) + { + return input; + } + } + } + } + return nullptr; +} + +bool NestedArtboard::worldToLocal(Vec2D world, Vec2D* local) +{ + assert(local != nullptr); + if (m_Artboard == nullptr) + { + return false; + } + Mat2D toMountedArtboard; + if (!worldTransform().invert(&toMountedArtboard)) + { + return false; + } + + *local = toMountedArtboard * world; + + return true; +} + +Vec2D NestedArtboard::measureLayout(float width, + LayoutMeasureMode widthMode, + float height, + LayoutMeasureMode heightMode) +{ + return Vec2D(std::min(widthMode == LayoutMeasureMode::undefined + ? std::numeric_limits::max() + : width, + m_Instance ? m_Instance->width() : 0.0f), + std::min(heightMode == LayoutMeasureMode::undefined + ? std::numeric_limits::max() + : height, + m_Instance ? m_Instance->height() : 0.0f)); +} + +void NestedArtboard::controlSize(Vec2D size, + LayoutScaleType widthScaleType, + LayoutScaleType heightScaleType, + LayoutDirection direction) +{} + +void NestedArtboard::decodeDataBindPathIds(Span value) +{ + BinaryReader reader(value); + while (!reader.reachedEnd()) + { + auto val = reader.readVarUintAs(); + m_DataBindPathIdsBuffer.push_back(val); + } +} + +void NestedArtboard::copyDataBindPathIds(const NestedArtboardBase& object) +{ + m_DataBindPathIdsBuffer = + object.as()->m_DataBindPathIdsBuffer; +} + +void NestedArtboard::internalDataContext(DataContext* value) +{ + if (artboardInstance() != nullptr) + { + artboardInstance()->internalDataContext(value, false); + for (auto& animation : m_NestedAnimations) + { + if (animation->is()) + { + animation->as()->dataContext(value); + } + } + } +} + +void NestedArtboard::clearDataContext() +{ + if (artboardInstance() != nullptr) + { + artboardInstance()->clearDataContext(); + } +} + +void NestedArtboard::populateDataBinds(std::vector* dataBinds) +{ + if (artboardInstance() != nullptr) + { + artboardInstance()->populateDataBinds(dataBinds); + } +} + +void NestedArtboard::bindViewModelInstance( + rcp viewModelInstance, + DataContext* parent) +{ + if (artboardInstance() != nullptr) + { + artboardInstance()->bindViewModelInstance(viewModelInstance, + parent, + false); + for (auto& animation : m_NestedAnimations) + { + if (animation->is()) + { + animation->as()->dataContext( + artboardInstance()->dataContext()); + } + } + } +} + +bool NestedArtboard::advanceComponent(float elapsedSeconds, AdvanceFlags flags) +{ + if (m_Artboard == nullptr || isCollapsed()) + { + return false; + } + bool keepGoing = false; + bool advanceNested = + (flags & AdvanceFlags::AdvanceNested) == AdvanceFlags::AdvanceNested; + if (advanceNested) + { + bool newFrame = + (flags & AdvanceFlags::NewFrame) == AdvanceFlags::NewFrame; + for (auto animation : m_NestedAnimations) + { + // If it is not a new frame, we only advance state machines. And we + // first validate whether their state has changed. Then and only + // then we advance the state machine. This avoids triggering dirt + // from advances that make intermediate value changes but finally + // settle in the same value + if (!newFrame) + { + if (animation->is()) + { + if (animation->as()->tryChangeState()) + { + if (animation->advance(elapsedSeconds, newFrame)) + { + keepGoing = true; + } + } + } + } + else + { + + if (animation->advance(elapsedSeconds, newFrame)) + { + keepGoing = true; + } + } + } + } + + auto advancingFlags = flags & ~AdvanceFlags::IsRoot; + if (m_Artboard->advanceInternal(elapsedSeconds, advancingFlags)) + { + keepGoing = true; + } + if (m_Artboard->hasDirt(ComponentDirt::Components)) + { + // The animation(s) caused the artboard to need an update. + addDirt(ComponentDirt::Components); + } + + return keepGoing; +} diff --git a/third_party/rive/source/nested_artboard_layout.cpp b/third_party/rive/source/nested_artboard_layout.cpp new file mode 100644 index 0000000..e9ea832 --- /dev/null +++ b/third_party/rive/source/nested_artboard_layout.cpp @@ -0,0 +1,224 @@ +#include "rive/nested_artboard_layout.hpp" +#include "rive/artboard.hpp" +#include "rive/math/aabb.hpp" +#include "rive/layout/layout_data.hpp" + +using namespace rive; + +Core* NestedArtboardLayout::clone() const +{ + NestedArtboardLayout* nestedArtboard = + static_cast(NestedArtboardLayoutBase::clone()); + if (m_Artboard == nullptr) + { + return nestedArtboard; + } + auto ni = m_Artboard->instance(); + nestedArtboard->nest(ni.release()); + return nestedArtboard; +} + +float NestedArtboardLayout::actualInstanceWidth() +{ + return instanceWidth() == -1.0f ? artboardInstance()->originalWidth() + : instanceWidth(); +} + +float NestedArtboardLayout::actualInstanceHeight() +{ + return instanceHeight() == -1.0f ? artboardInstance()->originalHeight() + : instanceHeight(); +} + +AABB NestedArtboardLayout::layoutBounds() +{ +#ifdef WITH_RIVE_LAYOUT + if (artboardInstance() != nullptr) + { + return artboardInstance()->layoutBounds(); + } +#endif + return AABB(); +} + +#ifdef WITH_RIVE_LAYOUT +void* NestedArtboardLayout::layoutNode(int index) +{ + if (artboardInstance() == nullptr) + { + return nullptr; + } + return static_cast(&artboardInstance()->takeLayoutData()->node); +} +#endif + +void NestedArtboardLayout::markHostingLayoutDirty( + ArtboardInstance* artboardInstance) +{ + if (artboard() != nullptr) + { + artboard()->markLayoutDirty(this->artboardInstance()); + } +} + +void NestedArtboardLayout::markLayoutNodeDirty( + bool shouldForceUpdateLayoutBounds) +{ + updateWidthOverride(); + updateHeightOverride(); +} + +void NestedArtboardLayout::update(ComponentDirt value) +{ + Super::update(value); + auto artboard = artboardInstance(); + if (hasDirt(value, ComponentDirt::WorldTransform) && artboard != nullptr) + { + auto layoutPosition = Vec2D(artboard->layoutX(), artboard->layoutY()); + + if (parent()->is()) + { + auto parentArtboard = parent()->as(); + auto correctedArtboardSpace = Mat2D::fromTranslation( + parentArtboard->origin() + layoutPosition); + m_WorldTransform = correctedArtboardSpace * m_WorldTransform; + } + else + { + m_WorldTransform = + Mat2D::fromTranslation(layoutPosition) * m_WorldTransform; + } + auto back = Mat2D::fromTranslation(-artboard->origin()); + m_WorldTransform = back * m_WorldTransform; + } +} + +void NestedArtboardLayout::updateConstraints() +{ + if (m_layoutConstraints.size() > 0) + { + for (auto parentConstraint : m_layoutConstraints) + { + parentConstraint->constrainChild(this); + } + } + Super::updateConstraints(); +} + +StatusCode NestedArtboardLayout::onAddedClean(CoreContext* context) +{ + StatusCode code = Super::onAddedClean(context); + if (code != StatusCode::Ok) + { + return code; + } + + updateWidthOverride(); + updateHeightOverride(); + + return StatusCode::Ok; +} + +void NestedArtboardLayout::updateLayoutBounds(bool animate) +{ +#ifdef WITH_RIVE_LAYOUT + if (artboardInstance() == nullptr) + { + return; + } + artboardInstance()->updateLayoutBounds(animate); +#endif +} + +void NestedArtboardLayout::updateWidthOverride() +{ + if (artboardInstance() == nullptr) + { + return; + } + auto isRow = parent()->is() + ? parent()->as()->mainAxisIsRow() + : true; + if (instanceWidthScaleType() == 0) // LayoutScaleType::fixed + { + // If we're set to fixed, pass the unit value (points|percent) + artboardInstance()->widthIntrinsicallySizeOverride(false); + artboardInstance()->widthOverride(actualInstanceWidth(), + instanceWidthUnitsValue(), + isRow); + } + else if (instanceWidthScaleType() == 1) // LayoutScaleType::fill + { + // If we're set to fill, pass auto + artboardInstance()->widthIntrinsicallySizeOverride(false); + artboardInstance()->widthOverride(actualInstanceWidth(), 3, isRow); + } + else if (instanceWidthScaleType() == 2) + { + artboardInstance()->widthIntrinsicallySizeOverride(true); + } + markHostingLayoutDirty(artboardInstance()); +} + +void NestedArtboardLayout::updateHeightOverride() +{ + if (artboardInstance() == nullptr) + { + return; + } + auto isRow = parent()->is() + ? parent()->as()->mainAxisIsRow() + : true; + if (instanceHeightScaleType() == 0) // LayoutScaleType::fixed + { + // If we're set to fixed, pass the unit value (points|percent) + artboardInstance()->heightIntrinsicallySizeOverride(false); + artboardInstance()->heightOverride(actualInstanceHeight(), + instanceHeightUnitsValue(), + isRow); + } + else if (instanceHeightScaleType() == 1) // LayoutScaleType::fill + { + // If we're set to fill, pass auto + artboardInstance()->heightIntrinsicallySizeOverride(false); + artboardInstance()->heightOverride(actualInstanceHeight(), 3, isRow); + } + else if (instanceWidthScaleType() == 2) + { + artboardInstance()->heightIntrinsicallySizeOverride(true); + } + markHostingLayoutDirty(artboardInstance()); +} + +void NestedArtboardLayout::instanceWidthChanged() { updateWidthOverride(); } + +void NestedArtboardLayout::instanceHeightChanged() { updateHeightOverride(); } + +void NestedArtboardLayout::instanceWidthUnitsValueChanged() +{ + updateWidthOverride(); +} + +void NestedArtboardLayout::instanceHeightUnitsValueChanged() +{ + updateHeightOverride(); +} + +void NestedArtboardLayout::instanceWidthScaleTypeChanged() +{ + updateWidthOverride(); +} + +void NestedArtboardLayout::instanceHeightScaleTypeChanged() +{ + updateHeightOverride(); +} + +bool NestedArtboardLayout::syncStyleChanges() +{ + if (m_Artboard == nullptr) + { + return false; + } + return m_Artboard->syncStyleChanges(); +} \ No newline at end of file diff --git a/third_party/rive/source/nested_artboard_leaf.cpp b/third_party/rive/source/nested_artboard_leaf.cpp new file mode 100644 index 0000000..02c1b0e --- /dev/null +++ b/third_party/rive/source/nested_artboard_leaf.cpp @@ -0,0 +1,41 @@ +#include "rive/nested_artboard_leaf.hpp" +#include "rive/renderer.hpp" +#include "rive/layout_component.hpp" +#include "rive/artboard.hpp" + +using namespace rive; + +Core* NestedArtboardLeaf::clone() const +{ + NestedArtboardLeaf* nestedArtboard = + static_cast(NestedArtboardLeafBase::clone()); + if (m_Artboard == nullptr) + { + return nestedArtboard; + } + auto ni = m_Artboard->instance(); + nestedArtboard->nest(ni.release()); + return nestedArtboard; +} + +void NestedArtboardLeaf::update(ComponentDirt value) +{ + Super::update(value); + auto artboard = artboardInstance(); + if (hasDirt(value, ComponentDirt::WorldTransform) && artboard != nullptr) + { + auto p = parent(); + + AABB bounds = p != nullptr && p->is() + ? p->as()->localBounds() + : artboard->bounds(); + + auto viewTransform = + computeAlignment((Fit)fit(), + Alignment(alignmentX(), alignmentY()), + bounds, + artboard->bounds()); + + m_WorldTransform *= viewTransform; + } +} diff --git a/third_party/rive/source/node.cpp b/third_party/rive/source/node.cpp new file mode 100644 index 0000000..8f5f635 --- /dev/null +++ b/third_party/rive/source/node.cpp @@ -0,0 +1,42 @@ +#include "rive/node.hpp" +#include "rive/world_transform_component.hpp" +#include "rive/layout_component.hpp" + +using namespace rive; + +void Node::xChanged() { markTransformDirty(); } +void Node::yChanged() { markTransformDirty(); } + +Mat2D Node::localTransform() +{ + if (m_LocalTransformNeedsRecompute) + { + m_LocalTransformNeedsRecompute = false; + if (m_ParentTransformComponent != nullptr) + { + auto parentWorld = m_ParentTransformComponent->worldTransform(); + Mat2D inverse; + + if (parentWorld.invert(&inverse)) + { + m_LocalTransform = inverse * worldTransform(); + return m_LocalTransform; + } + } + m_LocalTransform = Mat2D(); + } + return m_LocalTransform; +} + +#ifdef WITH_RIVE_LAYOUT +void Node::markLayoutNodeDirty() +{ + for (ContainerComponent* p = parent(); p != nullptr; p = p->parent()) + { + if (p->is()) + { + p->as()->markLayoutNodeDirty(); + } + } +} +#endif \ No newline at end of file diff --git a/third_party/rive/source/renderer.cpp b/third_party/rive/source/renderer.cpp new file mode 100644 index 0000000..3cab3c2 --- /dev/null +++ b/third_party/rive/source/renderer.cpp @@ -0,0 +1,219 @@ +#include "rive/math/mat2d.hpp" +#include "rive/renderer.hpp" +#include "rive/text_engine.hpp" + +using namespace rive; + +Mat2D rive::computeAlignment(Fit fit, + Alignment alignment, + const AABB& frame, + const AABB& content, + const float scaleFactor) +{ + float contentWidth = content.width(); + float contentHeight = content.height(); + float x = -content.left() - contentWidth * 0.5f - + (alignment.x() * contentWidth * 0.5f); + float y = -content.top() - contentHeight * 0.5f - + (alignment.y() * contentHeight * 0.5f); + + float scaleX = 1.0f, scaleY = 1.0f; + + switch (fit) + { + case Fit::fill: + { + scaleX = frame.width() / contentWidth; + scaleY = frame.height() / contentHeight; + break; + } + case Fit::contain: + { + float minScale = std::fmin(frame.width() / contentWidth, + frame.height() / contentHeight); + scaleX = scaleY = minScale; + break; + } + case Fit::cover: + { + float maxScale = std::fmax(frame.width() / contentWidth, + frame.height() / contentHeight); + scaleX = scaleY = maxScale; + break; + } + case Fit::fitHeight: + { + float minScale = frame.height() / contentHeight; + scaleX = scaleY = minScale; + break; + } + case Fit::fitWidth: + { + float minScale = frame.width() / contentWidth; + scaleX = scaleY = minScale; + break; + } + case Fit::layout: + { + return Mat2D::fromScale(scaleFactor, scaleFactor); + } + case Fit::none: + { + scaleX = scaleY = 1.0f; + break; + } + case Fit::scaleDown: + { + float minScale = std::fmin(frame.width() / contentWidth, + frame.height() / contentHeight); + scaleX = scaleY = minScale < 1.0f ? minScale : 1.0f; + break; + } + } + + Mat2D translation; + translation[4] = frame.left() + frame.width() * 0.5f + + (alignment.x() * frame.width() * 0.5f); + translation[5] = frame.top() + frame.height() * 0.5f + + (alignment.y() * frame.height() * 0.5f); + + return translation * Mat2D::fromScale(scaleX, scaleY) * + Mat2D::fromTranslate(x, y); +} + +void Renderer::translate(float tx, float ty) +{ + this->transform(Mat2D(1, 0, 0, 1, tx, ty)); +} + +void Renderer::scale(float sx, float sy) +{ + this->transform(Mat2D(sx, 0, 0, sy, 0, 0)); +} + +void Renderer::rotate(float radians) +{ + const float s = std::sin(radians); + const float c = std::cos(radians); + this->transform(Mat2D(c, s, -s, c, 0, 0)); +} + +RenderBuffer::RenderBuffer(RenderBufferType type, + RenderBufferFlags flags, + size_t sizeInBytes) : + m_type(type), m_flags(flags), m_sizeInBytes(sizeInBytes) +{} + +RenderBuffer::~RenderBuffer() {} + +void* RenderBuffer::map() +{ + assert(m_mapCount == 0 || + !(m_flags & RenderBufferFlags::mappedOnceAtInitialization)); + assert(m_mapCount == m_unmapCount); + RIVE_DEBUG_CODE(++m_mapCount;) + m_dirty = true; + return onMap(); +} + +void RenderBuffer::unmap() +{ + assert(m_unmapCount + 1 == m_mapCount); + RIVE_DEBUG_CODE(++m_unmapCount;) + onUnmap(); +} + +RenderShader::RenderShader() {} +RenderShader::~RenderShader() {} + +RenderPaint::RenderPaint() {} +RenderPaint::~RenderPaint() {} + +RenderImage::RenderImage(const Mat2D& uvTransform) : m_uvTransform(uvTransform) +{} +RenderImage::RenderImage() {} +RenderImage::~RenderImage() {} + +RenderPath::RenderPath() {} +RenderPath::~RenderPath() {} + +bool rive::isWhiteSpace(Unichar c) { return c <= ' ' || c == 0x2028; } + +SimpleArray Font::shapeText(Span text, + Span runs, + int textDirectionFlag) const +{ +#ifdef DEBUG + size_t count = 0; + for (const TextRun& tr : runs) + { + assert(tr.unicharCount > 0); + count += tr.unicharCount; + } + assert(count <= text.size()); +#endif + + SimpleArray paragraphs = + onShapeText(text, runs, textDirectionFlag); + bool wantWhiteSpace = false; + GlyphRun* lastRun = nullptr; + size_t reserveSize = text.size() / 4; + SimpleArrayBuilder breakBuilder(reserveSize); + for (const Paragraph& para : paragraphs) + { + for (GlyphRun& gr : para.runs) + { + if (lastRun != nullptr) + { + lastRun->breaks = std::move(breakBuilder); + // Reset the builder. + breakBuilder = SimpleArrayBuilder(reserveSize); + } + uint32_t glyphIndex = 0; + for (uint32_t offset : gr.textIndices) + { + Unichar unicode = text[offset]; + if (unicode == '\n' || unicode == 0x2028) + { + breakBuilder.add(glyphIndex); + breakBuilder.add(glyphIndex); + } + if (wantWhiteSpace == isWhiteSpace(unicode)) + { + breakBuilder.add(glyphIndex); + wantWhiteSpace = !wantWhiteSpace; + } + glyphIndex++; + } + + lastRun = &gr; + } + } + if (lastRun != nullptr) + { + if (wantWhiteSpace) + { + breakBuilder.add((uint32_t)lastRun->glyphs.size()); + } + else + { + // Consume the rest of the run. + breakBuilder.add(breakBuilder.empty() ? 0 : breakBuilder.back()); + breakBuilder.add((uint32_t)lastRun->glyphs.size()); + } + lastRun->breaks = std::move(breakBuilder); + } + +#ifdef DEBUG + for (const Paragraph& para : paragraphs) + { + for (const GlyphRun& gr : para.runs) + { + assert(gr.glyphs.size() > 0); + assert(gr.glyphs.size() == gr.textIndices.size()); + assert(gr.glyphs.size() + 1 == gr.xpos.size()); + } + } +#endif + return paragraphs; +} diff --git a/third_party/rive/source/scene.cpp b/third_party/rive/source/scene.cpp new file mode 100644 index 0000000..7efc887 --- /dev/null +++ b/third_party/rive/source/scene.cpp @@ -0,0 +1,37 @@ +#include "rive/artboard.hpp" +#include "rive/hit_result.hpp" +#include "rive/scene.hpp" +#include "rive/generated/core_registry.hpp" +using namespace rive; + +Scene::Scene(ArtboardInstance* abi) : m_artboardInstance(abi) +{ + assert(m_artboardInstance->isInstance()); +} + +float Scene::width() const { return m_artboardInstance->width(); } + +float Scene::height() const { return m_artboardInstance->height(); } + +void Scene::draw(Renderer* renderer) { m_artboardInstance->draw(renderer); } + +HitResult Scene::pointerDown(Vec2D) { return HitResult::none; } +HitResult Scene::pointerMove(Vec2D) { return HitResult::none; } +HitResult Scene::pointerUp(Vec2D) { return HitResult::none; } +HitResult Scene::pointerExit(Vec2D) { return HitResult::none; } + +size_t Scene::inputCount() const { return 0; } +SMIInput* Scene::input(size_t index) const { return nullptr; } +SMIBool* Scene::getBool(const std::string&) const { return nullptr; } +SMINumber* Scene::getNumber(const std::string&) const { return nullptr; } +SMITrigger* Scene::getTrigger(const std::string&) const { return nullptr; } +void Scene::bindViewModelInstance(rcp viewModelInstance) {} + +void Scene::reportKeyedCallback(uint32_t objectId, + uint32_t propertyKey, + float elapsedSeconds) +{ + auto coreObject = m_artboardInstance->resolve(objectId); + CallbackData data(this, elapsedSeconds); + CoreRegistry::setCallback(coreObject, propertyKey, data); +} diff --git a/third_party/rive/source/shapes/clipping_shape.cpp b/third_party/rive/source/shapes/clipping_shape.cpp new file mode 100644 index 0000000..4d029d8 --- /dev/null +++ b/third_party/rive/source/shapes/clipping_shape.cpp @@ -0,0 +1,112 @@ +#include "rive/shapes/clipping_shape.hpp" +#include "rive/artboard.hpp" +#include "rive/core_context.hpp" +#include "rive/factory.hpp" +#include "rive/node.hpp" +#include "rive/renderer.hpp" +#include "rive/shapes/path_composer.hpp" +#include "rive/shapes/shape.hpp" + +using namespace rive; + +StatusCode ClippingShape::onAddedClean(CoreContext* context) +{ + auto clippingHolder = parent(); + + auto artboard = static_cast(context); + for (auto core : artboard->objects()) + { + if (core == nullptr) + { + continue; + } + // Iterate artboard to find drawables that are parented to this clipping + // shape, they need to know they'll be clipped by this shape. + if (core->is()) + { + auto drawable = core->as(); + for (ContainerComponent* component = drawable; component != nullptr; + component = component->parent()) + { + if (component == clippingHolder) + { + drawable->addClippingShape(this); + break; + } + } + } + + // Iterate artboard to find shapes that are parented to the source, + // their paths will need to be RenderPaths in order to be used for + // clipping operations. + if (core->is()) + { + auto component = core->as(); + while (component != nullptr) + { + if (component == m_Source) + { + auto shape = core->as(); + shape->addFlags(PathFlags::world | PathFlags::clipping); + m_Shapes.push_back(shape); + break; + } + component = component->parent(); + } + } + } + + return StatusCode::Ok; +} + +StatusCode ClippingShape::onAddedDirty(CoreContext* context) +{ + StatusCode code = Super::onAddedDirty(context); + if (code != StatusCode::Ok) + { + return code; + } + auto coreObject = context->resolve(sourceId()); + if (coreObject == nullptr || !coreObject->is()) + { + return StatusCode::MissingObject; + } + + m_Source = static_cast(coreObject); + + return StatusCode::Ok; +} + +void ClippingShape::buildDependencies() +{ + for (auto shape : m_Shapes) + { + shape->pathComposer()->addDependent(this); + } +} + +void ClippingShape::update(ComponentDirt value) +{ + static Mat2D identity; + + if (hasDirt(value, + ComponentDirt::Path | ComponentDirt::WorldTransform | + ComponentDirt::NSlicer)) + { + m_path.rewind(false, (FillRule)fillRule()); + m_clipPath = nullptr; + for (auto shape : m_Shapes) + { + if (!shape->isEmpty()) + { + auto path = shape->pathComposer()->worldPath(); + if (path == nullptr) + { + continue; + } + m_path.addPath(path, &identity); + m_clipPath = &m_path; + } + } + } +} diff --git a/third_party/rive/source/shapes/cubic_asymmetric_vertex.cpp b/third_party/rive/source/shapes/cubic_asymmetric_vertex.cpp new file mode 100644 index 0000000..ca3a64f --- /dev/null +++ b/third_party/rive/source/shapes/cubic_asymmetric_vertex.cpp @@ -0,0 +1,49 @@ +#include "rive/shapes/cubic_asymmetric_vertex.hpp" +#include "rive/math/vec2d.hpp" +#include + +using namespace rive; + +static Vec2D get_point(const CubicAsymmetricVertex& v) +{ + return Vec2D(v.x(), v.y()); +} + +static Vec2D in_vector(const CubicAsymmetricVertex& v) +{ + return Vec2D(std::cos(v.rotation()) * v.inDistance(), + std::sin(v.rotation()) * v.inDistance()); +} + +static Vec2D out_vector(const CubicAsymmetricVertex& v) +{ + return Vec2D(std::cos(v.rotation()) * v.outDistance(), + std::sin(v.rotation()) * v.outDistance()); +} + +void CubicAsymmetricVertex::computeIn() +{ + m_InPoint = get_point(*this) - in_vector(*this); +} + +void CubicAsymmetricVertex::computeOut() +{ + m_OutPoint = get_point(*this) + out_vector(*this); +} + +void CubicAsymmetricVertex::rotationChanged() +{ + m_InValid = false; + m_OutValid = false; + markGeometryDirty(); +} +void CubicAsymmetricVertex::inDistanceChanged() +{ + m_InValid = false; + markGeometryDirty(); +} +void CubicAsymmetricVertex::outDistanceChanged() +{ + m_OutValid = false; + markGeometryDirty(); +} diff --git a/third_party/rive/source/shapes/cubic_detached_vertex.cpp b/third_party/rive/source/shapes/cubic_detached_vertex.cpp new file mode 100644 index 0000000..3c7e2ac --- /dev/null +++ b/third_party/rive/source/shapes/cubic_detached_vertex.cpp @@ -0,0 +1,53 @@ +#include "rive/shapes/cubic_detached_vertex.hpp" +#include "rive/math/vec2d.hpp" +#include + +using namespace rive; + +static Vec2D get_point(const CubicDetachedVertex& v) +{ + return Vec2D(v.x(), v.y()); +} + +static Vec2D in_vector(const CubicDetachedVertex& v) +{ + return Vec2D(std::cos(v.inRotation()) * v.inDistance(), + std::sin(v.inRotation()) * v.inDistance()); +} + +static Vec2D out_vector(const CubicDetachedVertex& v) +{ + return Vec2D(std::cos(v.outRotation()) * v.outDistance(), + std::sin(v.outRotation()) * v.outDistance()); +} + +void CubicDetachedVertex::computeIn() +{ + m_InPoint = get_point(*this) + in_vector(*this); +} + +void CubicDetachedVertex::computeOut() +{ + m_OutPoint = get_point(*this) + out_vector(*this); +} + +void CubicDetachedVertex::inRotationChanged() +{ + m_InValid = false; + markGeometryDirty(); +} +void CubicDetachedVertex::inDistanceChanged() +{ + m_InValid = false; + markGeometryDirty(); +} +void CubicDetachedVertex::outRotationChanged() +{ + m_OutValid = false; + markGeometryDirty(); +} +void CubicDetachedVertex::outDistanceChanged() +{ + m_OutValid = false; + markGeometryDirty(); +} diff --git a/third_party/rive/source/shapes/cubic_mirrored_vertex.cpp b/third_party/rive/source/shapes/cubic_mirrored_vertex.cpp new file mode 100644 index 0000000..9ceb4ef --- /dev/null +++ b/third_party/rive/source/shapes/cubic_mirrored_vertex.cpp @@ -0,0 +1,37 @@ +#include "rive/shapes/cubic_mirrored_vertex.hpp" +#include "rive/math/vec2d.hpp" +#include + +using namespace rive; + +static Vec2D get_point(const CubicMirroredVertex& v) +{ + return Vec2D(v.x(), v.y()); +} + +static Vec2D get_vector(const CubicMirroredVertex& v) +{ + return Vec2D(std::cos(v.rotation()) * v.distance(), + std::sin(v.rotation()) * v.distance()); +} + +void CubicMirroredVertex::computeIn() +{ + m_InPoint = get_point(*this) - get_vector(*this); +} + +void CubicMirroredVertex::computeOut() +{ + m_OutPoint = get_point(*this) + get_vector(*this); +} + +void CubicMirroredVertex::rotationChanged() +{ + m_InValid = m_OutValid = false; + markGeometryDirty(); +} +void CubicMirroredVertex::distanceChanged() +{ + m_InValid = m_OutValid = false; + markGeometryDirty(); +} diff --git a/third_party/rive/source/shapes/cubic_vertex.cpp b/third_party/rive/source/shapes/cubic_vertex.cpp new file mode 100644 index 0000000..e6c38e3 --- /dev/null +++ b/third_party/rive/source/shapes/cubic_vertex.cpp @@ -0,0 +1,90 @@ +#include "rive/shapes/cubic_vertex.hpp" +#include "rive/bones/cubic_weight.hpp" +using namespace rive; + +const Vec2D& CubicVertex::renderIn() +{ + if (hasWeight()) + { + return weight()->inTranslation(); + } + else + { + return inPoint(); + } +} + +const Vec2D& CubicVertex::renderOut() +{ + if (hasWeight()) + { + return weight()->outTranslation(); + } + else + { + return outPoint(); + } +} + +const Vec2D& CubicVertex::inPoint() +{ + if (!m_InValid) + { + computeIn(); + m_InValid = true; + } + return m_InPoint; +} + +const Vec2D& CubicVertex::outPoint() +{ + if (!m_OutValid) + { + computeOut(); + m_OutValid = true; + } + return m_OutPoint; +} + +void CubicVertex::outPoint(const Vec2D& value) +{ + m_OutPoint = value; + m_OutValid = true; +} + +void CubicVertex::inPoint(const Vec2D& value) +{ + m_InPoint = value; + m_InValid = true; +} + +void CubicVertex::xChanged() +{ + Super::xChanged(); + m_InValid = m_OutValid = false; +} +void CubicVertex::yChanged() +{ + Super::yChanged(); + m_InValid = m_OutValid = false; +} + +void CubicVertex::deform(const Mat2D& worldTransform, + const float* boneTransforms) +{ + Super::deform(worldTransform, boneTransforms); + + auto cubicWeight = weight(); + + cubicWeight->inTranslation() = Weight::deform(inPoint(), + cubicWeight->inIndices(), + cubicWeight->inValues(), + worldTransform, + boneTransforms); + + cubicWeight->outTranslation() = Weight::deform(outPoint(), + cubicWeight->outIndices(), + cubicWeight->outValues(), + worldTransform, + boneTransforms); +} diff --git a/third_party/rive/source/shapes/deformer.cpp b/third_party/rive/source/shapes/deformer.cpp new file mode 100644 index 0000000..825757e --- /dev/null +++ b/third_party/rive/source/shapes/deformer.cpp @@ -0,0 +1,25 @@ +#include "rive/layout/n_sliced_node.hpp" +#include "rive/shapes/deformer.hpp" +#include "rive/shapes/shape.hpp" + +using namespace rive; + +RenderPathDeformer* RenderPathDeformer::from(Component* component) +{ + switch (component->coreType()) + { + case NSlicedNode::typeKey: + return component->as(); + } + return nullptr; +} + +PointDeformer* PointDeformer::from(Component* component) +{ + switch (component->coreType()) + { + case NSlicedNode::typeKey: + return component->as(); + } + return nullptr; +} diff --git a/third_party/rive/source/shapes/ellipse.cpp b/third_party/rive/source/shapes/ellipse.cpp new file mode 100644 index 0000000..06489e6 --- /dev/null +++ b/third_party/rive/source/shapes/ellipse.cpp @@ -0,0 +1,47 @@ +#include "rive/shapes/ellipse.hpp" +#include "rive/component_dirt.hpp" +#include "rive/math/circle_constant.hpp" + +using namespace rive; + +Ellipse::Ellipse() +{ + addVertex(&m_Vertex1); + addVertex(&m_Vertex2); + addVertex(&m_Vertex3); + addVertex(&m_Vertex4); +} + +void Ellipse::update(ComponentDirt value) +{ + if (hasDirt(value, ComponentDirt::Path)) + { + auto radiusX = width() / 2.0f; + auto radiusY = height() / 2.0f; + + auto ox = -originX() * width() + radiusX; + auto oy = -originY() * height() + radiusY; + + m_Vertex1.x(ox); + m_Vertex1.y(oy - radiusY); + m_Vertex1.inPoint(Vec2D(ox - radiusX * circleConstant, oy - radiusY)); + m_Vertex1.outPoint(Vec2D(ox + radiusX * circleConstant, oy - radiusY)); + + m_Vertex2.x(ox + radiusX); + m_Vertex2.y(oy); + m_Vertex2.inPoint(Vec2D(ox + radiusX, oy + circleConstant * -radiusY)); + m_Vertex2.outPoint(Vec2D(ox + radiusX, oy + circleConstant * radiusY)); + + m_Vertex3.x(ox); + m_Vertex3.y(oy + radiusY); + m_Vertex3.inPoint(Vec2D(ox + radiusX * circleConstant, oy + radiusY)); + m_Vertex3.outPoint(Vec2D(ox - radiusX * circleConstant, oy + radiusY)); + + m_Vertex4.x(ox - radiusX); + m_Vertex4.y(oy); + m_Vertex4.inPoint(Vec2D(ox - radiusX, oy + radiusY * circleConstant)); + m_Vertex4.outPoint(Vec2D(ox - radiusX, oy - radiusY * circleConstant)); + } + + Super::update(value); +} \ No newline at end of file diff --git a/third_party/rive/source/shapes/image.cpp b/third_party/rive/source/shapes/image.cpp new file mode 100644 index 0000000..f2836a7 --- /dev/null +++ b/third_party/rive/source/shapes/image.cpp @@ -0,0 +1,249 @@ +#include "rive/math/hit_test.hpp" +#include "rive/shapes/image.hpp" +#include "rive/backboard.hpp" +#include "rive/importers/backboard_importer.hpp" +#include "rive/assets/file_asset.hpp" +#include "rive/assets/image_asset.hpp" +#include "rive/layout/n_slicer.hpp" +#include "rive/shapes/mesh_drawable.hpp" +#include "rive/artboard.hpp" +#include "rive/clip_result.hpp" + +using namespace rive; + +void Image::draw(Renderer* renderer) +{ + rive::ImageAsset* asset = this->imageAsset(); + if (asset == nullptr || renderOpacity() == 0.0f) + { + return; + } + + rive::RenderImage* renderImage = asset->renderImage(); + if (renderImage == nullptr) + { + return; + } + + ClipResult clipResult = applyClip(renderer); + + if (clipResult == ClipResult::noClip) + { + // We didn't clip, so make sure to save as we'll be doing some + // transformations. + renderer->save(); + } + + if (clipResult != ClipResult::emptyClip) + { + float width = (float)renderImage->width(); + float height = (float)renderImage->height(); + + // until image loading and saving is done, use default sampling for + // image assets + if (m_Mesh != nullptr) + { + m_Mesh->draw(renderer, + renderImage, + rive::ImageSampler::LinearClamp(), + blendMode(), + renderOpacity()); + } + else + { + renderer->transform(worldTransform()); + renderer->translate(-width * originX(), -height * originY()); + renderer->drawImage(renderImage, + rive::ImageSampler::LinearClamp(), + blendMode(), + renderOpacity()); + } + } + + renderer->restore(); +} + +Core* Image::hitTest(HitInfo* hinfo, const Mat2D& xform) +{ + // TODO: handle clip? + + auto renderImage = imageAsset()->renderImage(); + float width = (float)renderImage->width(); + float height = (float)renderImage->height(); + + if (m_Mesh) + { + printf("Missing mesh\n"); + // TODO: hittest mesh + } + else + { + auto mx = xform * worldTransform() * + Mat2D::fromTranslate(-width * originX(), -height * originY()); + HitTester tester(hinfo->area); + tester.addRect(AABB(0, 0, (float)width, (float)height), mx); + if (tester.test()) + { + return this; + } + } + return nullptr; +} + +StatusCode Image::import(ImportStack& importStack) +{ + auto result = registerReferencer(importStack); + if (result != StatusCode::Ok) + { + return result; + } + return Super::import(importStack); +} + +// Question: thoughts on this? it looks a bit odd to me, +// maybe there's a trick i'm missing here .. (could also implement +// getAssetId...) +uint32_t Image::assetId() { return ImageBase::assetId(); } + +void Image::setAsset(FileAsset* asset) +{ + if (asset->is()) + { + FileAssetReferencer::setAsset(asset); + + // If we have a mesh and we're in the source artboard, let's initialize + // the mesh buffers. + if (m_Mesh != nullptr && !artboard()->isInstance()) + { + m_Mesh->onAssetLoaded(imageAsset()->renderImage()); + } + updateImageScale(); + } +} + +void Image::assetUpdated() +{ + updateImageScale(); + markWorldTransformDirty(); +} + +Core* Image::clone() const +{ + Image* twin = ImageBase::clone()->as(); + if (m_fileAsset != nullptr) + { + twin->setAsset(m_fileAsset); + } + return twin; +} + +void Image::setMesh(MeshDrawable* mesh) { m_Mesh = mesh; } + +float Image::width() const +{ + rive::ImageAsset* asset = this->imageAsset(); + if (asset == nullptr) + { + return 0.0f; + } + + rive::RenderImage* renderImage = asset->renderImage(); + if (renderImage == nullptr) + { + return 0.0f; + } + return (float)renderImage->width(); +} + +float Image::height() const +{ + rive::ImageAsset* asset = this->imageAsset(); + if (asset == nullptr) + { + return 0.0f; + } + + rive::RenderImage* renderImage = asset->renderImage(); + if (renderImage == nullptr) + { + return 0.0f; + } + return (float)renderImage->height(); +} + +Vec2D Image::measureLayout(float width, + LayoutMeasureMode widthMode, + float height, + LayoutMeasureMode heightMode) +{ + float measuredWidth, measuredHeight; + switch (widthMode) + { + case LayoutMeasureMode::atMost: + measuredWidth = std::max(Image::width(), width); + break; + case LayoutMeasureMode::exactly: + measuredWidth = width; + break; + case LayoutMeasureMode::undefined: + measuredWidth = Image::width(); + break; + } + switch (heightMode) + { + case LayoutMeasureMode::atMost: + measuredHeight = std::max(Image::height(), height); + break; + case LayoutMeasureMode::exactly: + measuredHeight = height; + break; + case LayoutMeasureMode::undefined: + measuredHeight = Image::height(); + break; + } + return Vec2D(measuredWidth, measuredHeight); +} + +void Image::controlSize(Vec2D size, + LayoutScaleType widthScaleType, + LayoutScaleType heightScaleType, + LayoutDirection direction) +{ + // We store layout width/height because the image asset may not be available + // yet (referenced images) and we have defer controlling its size + if (m_layoutWidth != size.x || m_layoutHeight != size.y) + { + m_layoutWidth = size.x; + m_layoutHeight = size.y; + + updateImageScale(); + } +} + +void Image::updateImageScale() +{ + // User-created meshes are not affected by scale + if ((m_Mesh != nullptr && m_Mesh->type() == MeshType::vertex) || + imageAsset() == nullptr) + { + return; + } + auto renderImage = imageAsset()->renderImage(); + if (renderImage != nullptr && !std::isnan(m_layoutWidth) && + !std::isnan(m_layoutHeight)) + { + float newScaleX = m_layoutWidth / (float)renderImage->width(); + float newScaleY = m_layoutHeight / (float)renderImage->height(); + if (newScaleX != scaleX() || newScaleY != scaleY()) + { + scaleX(newScaleX); + scaleY(newScaleY); + addDirt(ComponentDirt::WorldTransform, false); + } + } +} + +#ifdef TESTING +#include "rive/shapes/mesh.hpp" +Mesh* Image::mesh() const { return static_cast(m_Mesh); }; +#endif diff --git a/third_party/rive/source/shapes/mesh.cpp b/third_party/rive/source/shapes/mesh.cpp new file mode 100644 index 0000000..bade491 --- /dev/null +++ b/third_party/rive/source/shapes/mesh.cpp @@ -0,0 +1,201 @@ +#include "rive/shapes/mesh.hpp" +#include "rive/shapes/image.hpp" +#include "rive/shapes/vertex.hpp" +#include "rive/shapes/mesh_vertex.hpp" +#include "rive/bones/skin.hpp" +#include "rive/artboard.hpp" +#include "rive/factory.hpp" +#include "rive/span.hpp" +#include "rive/assets/image_asset.hpp" +#include + +using namespace rive; + +/// Called whenever a vertex moves (x/y change). +void Mesh::markDrawableDirty() +{ + if (skin() != nullptr) + { + skin()->addDirt(ComponentDirt::Skin); + } + + addDirt(ComponentDirt::Vertices); +} + +void Mesh::addVertex(MeshVertex* vertex) { m_Vertices.push_back(vertex); } + +StatusCode Mesh::onAddedDirty(CoreContext* context) +{ + StatusCode result = Super::onAddedDirty(context); + if (result != StatusCode::Ok) + { + return result; + } + + if (!parent()->is()) + { + return StatusCode::MissingObject; + } + + // All good, tell the image it has a mesh. + parent()->as()->setMesh(this); + + return StatusCode::Ok; +} + +StatusCode Mesh::onAddedClean(CoreContext* context) +{ + // Make sure Core found indices in the file for this Mesh. + if (m_IndexBuffer == nullptr) + { + return StatusCode::InvalidObject; + } + + // Check the indices are all in range. We should consider having a better + // error reporting system to the implementor. + for (auto index : *m_IndexBuffer) + { + if (index >= m_Vertices.size()) + { + return StatusCode::InvalidObject; + } + } + return Super::onAddedClean(context); +} + +void Mesh::decodeTriangleIndexBytes(Span value) +{ + // decode the triangle index bytes + rcp buffer = rcp(new IndexBuffer()); + + BinaryReader reader(value); + while (!reader.reachedEnd()) + { + buffer->push_back(reader.readVarUintAs()); + } + m_IndexBuffer = buffer; +} + +void Mesh::copyTriangleIndexBytes(const MeshBase& object) +{ + m_IndexBuffer = object.as()->m_IndexBuffer; +} + +/// Called whenever a bone moves that is connected to the skin. +void Mesh::markSkinDirty() { addDirt(ComponentDirt::Vertices); } + +Core* Mesh::clone() const +{ + auto factory = artboard()->factory(); + auto clone = static_cast(MeshBase::clone()); + clone->m_VertexRenderBufferDirty = true; + clone->m_VertexRenderBuffer = + factory->makeRenderBuffer(RenderBufferType::vertex, + RenderBufferFlags::none, + m_Vertices.size() * sizeof(Vec2D)); + clone->m_UVRenderBuffer = m_UVRenderBuffer; + clone->m_IndexRenderBuffer = m_IndexRenderBuffer; + return clone; +} + +void Mesh::onAssetLoaded(RenderImage* renderImage) +{ + Mat2D uvTransform = + renderImage != nullptr ? renderImage->uvTransform() : Mat2D(); + + auto factory = artboard()->factory(); + m_VertexRenderBufferDirty = true; + m_VertexRenderBuffer = + factory->makeRenderBuffer(RenderBufferType::vertex, + RenderBufferFlags::none, + m_Vertices.size() * sizeof(Vec2D)); + + m_UVRenderBuffer = + factory->makeRenderBuffer(RenderBufferType::vertex, + RenderBufferFlags::mappedOnceAtInitialization, + m_Vertices.size() * sizeof(Vec2D)); + if (m_UVRenderBuffer) + { + float* uv = static_cast(m_UVRenderBuffer->map()); + for (auto vertex : m_Vertices) + { + Vec2D xformedUV = uvTransform * Vec2D(vertex->u(), vertex->v()); + *uv++ = xformedUV.x; + *uv++ = xformedUV.y; + } + m_UVRenderBuffer->unmap(); + } + + if (m_IndexBuffer != nullptr) + { + m_IndexRenderBuffer = factory->makeRenderBuffer( + RenderBufferType::index, + RenderBufferFlags::mappedOnceAtInitialization, + m_IndexBuffer->size() * sizeof(uint16_t)); + if (m_IndexRenderBuffer) + { + void* indexData = m_IndexRenderBuffer->map(); + memcpy(indexData, + m_IndexBuffer->data(), + m_IndexRenderBuffer->sizeInBytes()); + m_IndexRenderBuffer->unmap(); + } + } +} + +void Mesh::buildDependencies() +{ + Super::buildDependencies(); + if (skin() != nullptr) + { + skin()->addDependent(this); + } + parent()->addDependent(this); +} + +void Mesh::update(ComponentDirt value) +{ + if (hasDirt(value, ComponentDirt::Vertices)) + { + if (skin() != nullptr) + { + skin()->deform({(Vertex**)m_Vertices.data(), m_Vertices.size()}); + } + m_VertexRenderBufferDirty = true; + } + Super::update(value); +} + +void Mesh::draw(Renderer* renderer, + const RenderImage* image, + ImageSampler ImageSampler, + BlendMode blendMode, + float opacity) +{ + if (m_VertexRenderBufferDirty && m_VertexRenderBuffer != nullptr) + { + Vec2D* mappedVertices = + reinterpret_cast(m_VertexRenderBuffer->map()); + for (auto vertex : m_Vertices) + { + *mappedVertices++ = vertex->renderTranslation(); + } + m_VertexRenderBuffer->unmap(); + m_VertexRenderBufferDirty = false; + } + + if (skin() == nullptr) + { + renderer->transform( + parent()->as()->worldTransform()); + } + renderer->drawImageMesh(image, + ImageSampler, + m_VertexRenderBuffer, + m_UVRenderBuffer, + m_IndexRenderBuffer, + static_cast(m_Vertices.size()), + static_cast(m_IndexBuffer->size()), + blendMode, + opacity); +} diff --git a/third_party/rive/source/shapes/mesh_vertex.cpp b/third_party/rive/source/shapes/mesh_vertex.cpp new file mode 100644 index 0000000..72af02a --- /dev/null +++ b/third_party/rive/source/shapes/mesh_vertex.cpp @@ -0,0 +1,23 @@ +#include "rive/shapes/mesh_vertex.hpp" +#include "rive/shapes/mesh.hpp" + +using namespace rive; +void MeshVertex::markGeometryDirty() +{ + parent()->as()->markDrawableDirty(); +} + +StatusCode MeshVertex::onAddedDirty(CoreContext* context) +{ + StatusCode code = Super::onAddedDirty(context); + if (code != StatusCode::Ok) + { + return code; + } + if (!parent()->is()) + { + return StatusCode::MissingObject; + } + parent()->as()->addVertex(this); + return StatusCode::Ok; +} \ No newline at end of file diff --git a/third_party/rive/source/shapes/paint/color.cpp b/third_party/rive/source/shapes/paint/color.cpp new file mode 100644 index 0000000..7712f4e --- /dev/null +++ b/third_party/rive/source/shapes/paint/color.cpp @@ -0,0 +1,82 @@ +#include "rive/shapes/paint/color.hpp" + +#include "rive/math/simd.hpp" +#include +#include + +namespace rive +{ +unsigned int colorARGB(int a, int r, int g, int b) +{ + return (((a & 0xff) << 24) | ((r & 0xff) << 16) | ((g & 0xff) << 8) | + ((b & 0xff) << 0)) & + 0xFFFFFFFF; +} + +unsigned int colorRed(ColorInt value) { return (0x00ff0000 & value) >> 16; } + +unsigned int colorGreen(ColorInt value) { return (0x0000ff00 & value) >> 8; } + +unsigned int colorBlue(ColorInt value) { return (0x000000ff & value) >> 0; } + +unsigned int colorAlpha(ColorInt value) { return (0xff000000 & value) >> 24; } + +void UnpackColorToRGBA8(ColorInt color, uint8_t out[4]) +{ + auto rgba = simd::cast(uint4(color) >> uint4{16, 8, 0, 24}); + simd::store(out, rgba); +} + +void UnpackColorToRGBA32F(ColorInt color, float out[4]) +{ + float4 color4f = + simd::cast(color << uint4{8, 16, 24, 0} >> 24u) * (1.f / 255.f); + simd::store(out, color4f); +} + +void UnpackColorToRGBA32FPremul(ColorInt color, float out[4]) +{ + float4 premulColor4f = + simd::cast(color << uint4{8, 16, 24, 0} >> 24u) * (1.f / 255.f); + float alpha = premulColor4f.w; + premulColor4f *= float4{alpha, alpha, alpha, 1.f}; + simd::store(out, premulColor4f); +} + +float colorOpacity(ColorInt value) { return (float)colorAlpha(value) / 0xFF; } + +static uint8_t opacityToAlpha(float opacity) +{ + return (uint8_t)std::lround(255.f * + std::max(0.0f, std::min(1.0f, opacity))); +} + +ColorInt colorWithAlpha(ColorInt value, unsigned int a) +{ + return colorARGB(a, colorRed(value), colorGreen(value), colorBlue(value)); +} + +ColorInt colorWithOpacity(ColorInt value, float opacity) +{ + return colorWithAlpha(value, opacityToAlpha(opacity)); +} + +ColorInt colorModulateOpacity(ColorInt value, float opacity) +{ + return colorWithAlpha(value, opacityToAlpha(colorOpacity(value) * opacity)); +} + +static unsigned int lerp(unsigned int a, unsigned int b, float mix) +{ + return (unsigned int)std::lround( + std::max(0.0f, std::min(255.f, a * (1.0f - mix) + b * mix))); +} + +ColorInt colorLerp(ColorInt from, ColorInt to, float mix) +{ + return colorARGB(lerp(colorAlpha(from), colorAlpha(to), mix), + lerp(colorRed(from), colorRed(to), mix), + lerp(colorGreen(from), colorGreen(to), mix), + lerp(colorBlue(from), colorBlue(to), mix)); +} +} // namespace rive diff --git a/third_party/rive/source/shapes/paint/dash.cpp b/third_party/rive/source/shapes/paint/dash.cpp new file mode 100644 index 0000000..de06f39 --- /dev/null +++ b/third_party/rive/source/shapes/paint/dash.cpp @@ -0,0 +1,44 @@ +#include "rive/shapes/paint/dash.hpp" +#include "rive/shapes/paint/dash_path.hpp" + +using namespace rive; + +Dash::Dash() {} + +Dash::Dash(float value, bool percentage) +{ + length(value); + lengthIsPercentage(percentage); +} + +float Dash::normalizedLength(float contourLength) const +{ + float right = lengthIsPercentage() ? 1.0f : contourLength; + float p = fmodf(length(), right); + if (p < 0.0f) + { + p += right; + } + return lengthIsPercentage() ? p * contourLength : p; +} + +StatusCode Dash::onAddedClean(CoreContext* context) +{ + if (!parent()->is()) + { + return StatusCode::InvalidObject; + } + + return StatusCode::Ok; +} + +void Dash::lengthChanged() +{ + if (parent() == nullptr || !parent()->is()) + { + return; + } + parent()->as()->invalidateDash(); +} + +void Dash::lengthIsPercentageChanged() { lengthChanged(); } \ No newline at end of file diff --git a/third_party/rive/source/shapes/paint/dash_path.cpp b/third_party/rive/source/shapes/paint/dash_path.cpp new file mode 100644 index 0000000..ffe7444 --- /dev/null +++ b/third_party/rive/source/shapes/paint/dash_path.cpp @@ -0,0 +1,175 @@ +#include "rive/shapes/paint/dash_path.hpp" +#include "rive/shapes/paint/dash.hpp" +#include "rive/shapes/paint/stroke.hpp" +#include "rive/factory.hpp" + +using namespace rive; + +void PathDasher::invalidateSourcePath() +{ + m_contours.clear(); + invalidateDash(); +} + +void PathDasher::invalidateDash() { m_path.rewind(); } + +ShapePaintPath* PathDasher::dash(const RawPath* source, + Dash* offset, + Span dashes) +{ + if (m_path.hasRenderPath()) + { + // Previous result hasn't been invalidated, it's still good. + return &m_path; + } + + m_path.rewind(); + return applyDash(source, offset, dashes); +} +ShapePaintPath* PathDasher::applyDash(const RawPath* source, + Dash* offset, + Span dashes) +{ + if (m_contours.empty()) + { + // 0.5f / 8.0f is a value that seems to look good on dashes with small + // gaps and scaled + ContourMeasureIter iter(source, 0.0625f); + while (auto meas = iter.next()) + { + m_contours.push_back(meas); + } + } + + // Make sure dashes have some length. + bool hasValidDash = false; + for (const rcp& contour : m_contours) + { + for (auto dash : dashes) + { + if (dash->normalizedLength(contour->length()) > 0.0f) + { + hasValidDash = true; + break; + } + } + if (hasValidDash) + { + break; + } + } + if (hasValidDash) + { + int dashIndex = 0; + auto rawPath = m_path.mutableRawPath(); + for (const rcp& contour : m_contours) + { + float dashed = 0.0f; + float distance = offset->normalizedLength(contour->length()); + bool draw = true; + while (dashed < contour->length()) + { + const Dash* dash = dashes[dashIndex++ % dashes.size()]; + float dashLength = dash->normalizedLength(contour->length()); + if (dashLength > contour->length()) + { + dashLength = contour->length(); + } + float endLength = distance + dashLength; + if (endLength > contour->length()) + { + endLength -= contour->length(); + if (draw) + { + if (distance < contour->length()) + { + contour->getSegment(distance, + contour->length(), + rawPath, + true); + contour->getSegment(0.0f, + endLength, + rawPath, + !contour->isClosed()); + } + else + { + contour->getSegment(0.0f, endLength, rawPath, true); + } + } + + // Setup next step. + distance = endLength - dashLength; + } + else if (draw) + { + contour->getSegment(distance, endLength, rawPath, true); + } + distance += dashLength; + dashed += dashLength; + draw = !draw; + } + } + } + return &m_path; +} + +float PathDasher::pathLength() const +{ + float totalLength = 0.0f; + for (auto contour : m_contours) + { + totalLength += contour->length(); + } + return totalLength; +} + +StatusCode DashPath::onAddedClean(CoreContext* context) +{ + if (!parent()->is()) + { + return StatusCode::InvalidObject; + } + parent()->as()->addStrokeEffect(this); + + m_dashes.clear(); + for (auto child : children()) + { + if (child->is()) + { + m_dashes.push_back(child->as()); + } + } + return StatusCode::Ok; +} + +void DashPath::invalidateEffect() { invalidateSourcePath(); } + +void DashPath::offsetChanged() { invalidateDash(); } +void DashPath::offsetIsPercentageChanged() { invalidateDash(); } + +void DashPath::updateEffect(const ShapePaintPath* source) +{ + + if (m_path.hasRenderPath()) + { + return; + } + m_path.rewind(source->isLocal()); + + Dash dashOffset(offset(), offsetIsPercentage()); + applyDash(source->rawPath(), &dashOffset, m_dashes); +} + +ShapePaintPath* DashPath::effectPath() { return &m_path; } + +void DashPath::invalidateDash() +{ + PathDasher::invalidateDash(); + if (parent() != nullptr) + { + auto stroke = parent()->as(); + stroke->parent()->addDirt(ComponentDirt::Paint); + stroke->invalidateRendering(); + } +} \ No newline at end of file diff --git a/third_party/rive/source/shapes/paint/feather.cpp b/third_party/rive/source/shapes/paint/feather.cpp new file mode 100644 index 0000000..a3aa788 --- /dev/null +++ b/third_party/rive/source/shapes/paint/feather.cpp @@ -0,0 +1,102 @@ +#include "rive/shapes/paint/feather.hpp" +#include "rive/shapes/paint/shape_paint.hpp" +#include "rive/shapes/paint/fill.hpp" +#include "rive/shapes/shape.hpp" +#include "rive/artboard.hpp" + +#include "rive/core_context.hpp" + +using namespace rive; + +bool Feather::validate(CoreContext* context) +{ + if (!Super::validate(context)) + { + return false; + } + auto coreObject = context->resolve(parentId()); + // we know it's not nullptr from Super::validate + assert(coreObject != nullptr); + return coreObject->is(); +} + +StatusCode Feather::onAddedDirty(CoreContext* context) +{ + auto code = Super::onAddedDirty(context); + + parent()->as()->feather(this); + return code; +} + +void Feather::update(ComponentDirt value) +{ + auto shapePaint = parent()->as(); + if (hasDirt(value, ComponentDirt::Paint)) + { + auto renderPaint = shapePaint->renderPaint(); + renderPaint->feather(strength()); + } + + if (hasDirt(value, ComponentDirt::WorldTransform | ComponentDirt::Path)) + { + bool offsetInArtboard = space() == TransformSpace::world; + if (inner()) + { + auto shape = ShapePaintContainer::from(shapePaint->parent()); + + if (shape != nullptr) + { + auto transform = shape->shapeWorldTransform(); + auto path = shapePaint->pickPath(shape); + if (path == nullptr) + { + return; + } + auto bounds = path->rawPath()->bounds().pad(strength() * 1.5f); + Vec2D innerOffset(offsetX(), offsetY()); + if (offsetInArtboard) + { + Mat2D inverseTransform = transform.invertOrIdentity(); + innerOffset = + Vec2D::transformDir(innerOffset, inverseTransform); + } + m_innerPath.rewind(); + m_innerPath.addRect(bounds); + Mat2D innerOffsetTransform = + Mat2D::fromTranslation(innerOffset); + m_innerPath.addPathBackwards(*path->rawPath(), + &innerOffsetTransform); + } +#ifdef TESTING + renderCount++; +#endif + return; + } + } +} + +void Feather::buildDependencies() +{ + auto shape = parent()->as()->parent(); + if (shape == nullptr) + { + return; + } + if (shape->is()) + { + shape->as()->pathComposer()->addDependent(this); + } + else + { + shape->addDependent(this); + } +} + +void Feather::strengthChanged() +{ + addDirt(inner() ? (ComponentDirt)(ComponentDirt::Paint | + ComponentDirt::WorldTransform) + : ComponentDirt::Paint); +} +void Feather::offsetXChanged() { strengthChanged(); } +void Feather::offsetYChanged() { strengthChanged(); } \ No newline at end of file diff --git a/third_party/rive/source/shapes/paint/fill.cpp b/third_party/rive/source/shapes/paint/fill.cpp new file mode 100644 index 0000000..2bacb46 --- /dev/null +++ b/third_party/rive/source/shapes/paint/fill.cpp @@ -0,0 +1,34 @@ +#include "rive/shapes/paint/fill.hpp" +#include "rive/shapes/shape_paint_container.hpp" + +using namespace rive; + +PathFlags Fill::pathFlags() const +{ + return (FillRule)fillRule() == FillRule::clockwise + ? PathFlags::localClockwise + : PathFlags::local; +} + +RenderPaint* Fill::initRenderPaint(ShapePaintMutator* mutator) +{ + auto renderPaint = Super::initRenderPaint(mutator); + renderPaint->style(RenderPaintStyle::fill); + return renderPaint; +} + +void Fill::applyTo(RenderPaint* renderPaint, float opacityModifier) +{ + renderPaint->style(RenderPaintStyle::fill); + renderPaint->shader(nullptr); + m_PaintMutator->applyTo(renderPaint, opacityModifier); +} + +ShapePaintPath* Fill::pickPath(ShapePaintContainer* shape) const +{ + if ((FillRule)fillRule() == FillRule::clockwise) + { + return shape->localClockwisePath(); + } + return shape->localPath(); +} \ No newline at end of file diff --git a/third_party/rive/source/shapes/paint/gradient_stop.cpp b/third_party/rive/source/shapes/paint/gradient_stop.cpp new file mode 100644 index 0000000..098eea2 --- /dev/null +++ b/third_party/rive/source/shapes/paint/gradient_stop.cpp @@ -0,0 +1,29 @@ +#include "rive/shapes/paint/gradient_stop.hpp" +#include "rive/shapes/paint/linear_gradient.hpp" + +using namespace rive; + +StatusCode GradientStop::onAddedDirty(CoreContext* context) +{ + StatusCode code = Super::onAddedDirty(context); + if (code != StatusCode::Ok) + { + return code; + } + + if (!parent()->is()) + { + return StatusCode::MissingObject; + } + parent()->as()->addStop(this); + return StatusCode::Ok; +} + +void GradientStop::colorValueChanged() +{ + parent()->as()->markGradientDirty(); +} +void GradientStop::positionChanged() +{ + parent()->as()->markStopsDirty(); +} \ No newline at end of file diff --git a/third_party/rive/source/shapes/paint/linear_gradient.cpp b/third_party/rive/source/shapes/paint/linear_gradient.cpp new file mode 100644 index 0000000..5f75b4d --- /dev/null +++ b/third_party/rive/source/shapes/paint/linear_gradient.cpp @@ -0,0 +1,214 @@ +#include "rive/shapes/paint/linear_gradient.hpp" +#include "rive/math/vec2d.hpp" +#include "rive/artboard.hpp" +#include "rive/factory.hpp" +#include "rive/node.hpp" +#include "rive/renderer.hpp" +#include "rive/shapes/deformer.hpp" +#include "rive/shapes/paint/color.hpp" +#include "rive/shapes/paint/gradient_stop.hpp" +#include "rive/shapes/shape.hpp" +#include "rive/shapes/shape_paint_container.hpp" +#include "rive/shapes/paint/shape_paint.hpp" +#include + +using namespace rive; + +StatusCode LinearGradient::onAddedDirty(CoreContext* context) +{ + StatusCode code = Super::onAddedDirty(context); + if (code != StatusCode::Ok) + { + return code; + } + + return initPaintMutator(this); +} + +void LinearGradient::buildDependencies() +{ + auto p = parent(); + if (p != nullptr && p->parent() != nullptr) + { + ContainerComponent* grandParent = p->parent(); + // Parent's parent must be a shape paint container. + assert(ShapePaintContainer::from(grandParent) != nullptr); + + // We need to find the container that owns our world space transform. + // This is the first node up the chain (or none, meaning we are in world + // space). + m_shapePaintContainer = nullptr; + for (ContainerComponent* container = grandParent; container != nullptr; + container = container->parent()) + { + if (container->is()) + { + m_shapePaintContainer = container->as(); + break; + } + } + if (m_shapePaintContainer != nullptr) + { + m_shapePaintContainer->addDependent(this); + } + else + { + grandParent->addDependent(this); + } + } + updateDeformer(); +} + +void LinearGradient::updateDeformer() +{ + if (!m_shapePaintContainer) + { + return; + } + if (m_shapePaintContainer->is()) + { + if (RenderPathDeformer* deformer = + m_shapePaintContainer->as()->deformer()) + { + Component* component = deformer->asComponent(); + m_deformer = PointDeformer::from(component); + } + } +} + +void LinearGradient::addStop(GradientStop* stop) { m_stops.push_back(stop); } + +static bool stopsComparer(GradientStop* a, GradientStop* b) +{ + return a->position() < b->position(); +} + +void LinearGradient::update(ComponentDirt value) +{ + // Do the stops need to be re-ordered? + bool stopsChanged = hasDirt(value, ComponentDirt::Stops); + if (stopsChanged) + { + std::sort(m_stops.begin(), m_stops.end(), stopsComparer); + } + + // We rebuild the gradient if the gradient is dirty or we paint in world + // space and the world space transform has changed, or the local transform + // has changed. Local transform changes when a stop moves in local space. + bool rebuildGradient = + hasDirt(value, + ComponentDirt::Paint | ComponentDirt::RenderOpacity | + ComponentDirt::Transform | ComponentDirt::NSlicer) || + ( + // paints in world space + parent()->as()->isFlagged(PathFlags::world) && + // and had a world transform change + hasDirt(value, ComponentDirt::WorldTransform)); + if (rebuildGradient) + { + applyTo(renderPaint(), 1.0f); + m_flags = ShapePaintMutator::Flags::none; + const auto count = m_stops.size(); + ColorInt* colors = m_colorStorage.data(); + for (size_t i = 0; i < count; ++i) + { + auto colorValue = colors[i]; + auto opacity = colorOpacity(colorValue); + if (opacity > 0.0f) + { + m_flags |= ShapePaintMutator::Flags::visible; + } + if (opacity < 1.0f) + { + m_flags |= ShapePaintMutator::Flags::translucent; + } + } + } +} + +void LinearGradient::applyTo(RenderPaint* renderPaint, float opacityModifier) +{ + bool paintsInWorldSpace = + parent()->as()->isFlagged(PathFlags::world); + Vec2D start(startX(), startY()); + Vec2D end(endX(), endY()); + // Check if we need to update the world space gradient (if there's no + // shape container, presumably it's the artboard and we're already in + // world). + if (paintsInWorldSpace && m_shapePaintContainer != nullptr) + { + // Get the start and end of the gradient in world coordinates (world + // transform of the shape). + const Mat2D& world = m_shapePaintContainer->worldTransform(); + start = world * start; + end = world * end; + if (m_deformer) + { + start = m_deformer->deformWorldPoint(start); + end = m_deformer->deformWorldPoint(end); + } + } + else + { + if (m_deformer) + { + const Mat2D& world = m_shapePaintContainer->worldTransform(); + Mat2D inverseWorld; + if (world.invert(&inverseWorld)) + { + start = + m_deformer->deformLocalPoint(start, world, inverseWorld); + end = m_deformer->deformLocalPoint(end, world, inverseWorld); + } + } + } + + // build up the color and positions lists + const auto ro = opacity() * renderOpacity() * opacityModifier; + const auto count = m_stops.size(); + + // need some temporary storage. Allocate enough for both arrays + assert(sizeof(ColorInt) == sizeof(float)); + m_colorStorage.resize(count * 2); + ColorInt* colors = m_colorStorage.data(); + float* stops = (float*)colors + count; + + for (size_t i = 0; i < count; ++i) + { + colors[i] = colorModulateOpacity(m_stops[i]->colorValue(), ro); + stops[i] = std::max(0.0f, std::min(m_stops[i]->position(), 1.0f)); + } + + makeGradient(renderPaint, start, end, colors, stops, count); +} + +void LinearGradient::makeGradient(RenderPaint* renderPaint, + Vec2D start, + Vec2D end, + const ColorInt colors[], + const float stops[], + size_t count) const +{ + auto factory = artboard()->factory(); + renderPaint->shader(factory->makeLinearGradient(start.x, + start.y, + end.x, + end.y, + colors, + stops, + count)); +} + +void LinearGradient::markGradientDirty() { addDirt(ComponentDirt::Paint); } +void LinearGradient::markStopsDirty() +{ + addDirt(ComponentDirt::Paint | ComponentDirt::Stops); +} + +void LinearGradient::renderOpacityChanged() { markGradientDirty(); } + +void LinearGradient::startXChanged() { addDirt(ComponentDirt::Transform); } +void LinearGradient::startYChanged() { addDirt(ComponentDirt::Transform); } +void LinearGradient::endXChanged() { addDirt(ComponentDirt::Transform); } +void LinearGradient::endYChanged() { addDirt(ComponentDirt::Transform); } +void LinearGradient::opacityChanged() { markGradientDirty(); } diff --git a/third_party/rive/source/shapes/paint/radial_gradient.cpp b/third_party/rive/source/shapes/paint/radial_gradient.cpp new file mode 100644 index 0000000..4b099da --- /dev/null +++ b/third_party/rive/source/shapes/paint/radial_gradient.cpp @@ -0,0 +1,21 @@ +#include "rive/shapes/paint/radial_gradient.hpp" +#include "rive/artboard.hpp" +#include "rive/factory.hpp" + +using namespace rive; + +void RadialGradient::makeGradient(RenderPaint* renderPaint, + Vec2D start, + Vec2D end, + const ColorInt colors[], + const float stops[], + size_t count) const +{ + auto factory = artboard()->factory(); + renderPaint->shader(factory->makeRadialGradient(start.x, + start.y, + Vec2D::distance(start, end), + colors, + stops, + count)); +} diff --git a/third_party/rive/source/shapes/paint/shape_paint.cpp b/third_party/rive/source/shapes/paint/shape_paint.cpp new file mode 100644 index 0000000..d4a6c30 --- /dev/null +++ b/third_party/rive/source/shapes/paint/shape_paint.cpp @@ -0,0 +1,143 @@ +#include "rive/shapes/paint/shape_paint.hpp" +#include "rive/shapes/shape_paint_container.hpp" +#include "rive/shapes/paint/feather.hpp" +#include "rive/artboard.hpp" +#include "rive/factory.hpp" +#include "rive/shapes/paint/fill.hpp" + +using namespace rive; + +StatusCode ShapePaint::onAddedClean(CoreContext* context) +{ + auto container = ShapePaintContainer::from(parent()); + if (container == nullptr) + { + return StatusCode::MissingObject; + } + + // If the paint mutator wasn't compatible with this runtime it's possible we + // get a ShapePaint with no mutator (not children). + if (m_PaintMutator != nullptr) + { + container->addPaint(this); + } + + return StatusCode::Ok; +} + +RenderPaint* ShapePaint::initRenderPaint(ShapePaintMutator* mutator) +{ + assert(m_RenderPaint == nullptr); + m_PaintMutator = mutator; + + auto factory = mutator->component()->artboard()->factory(); + m_RenderPaint = factory->makeRenderPaint(); + return m_RenderPaint.get(); +} + +void ShapePaint::blendMode(BlendMode parentValue) +{ + assert(m_RenderPaint != nullptr); + // 127 means inherit + if (blendModeValue() == 127) + { + m_RenderPaint->blendMode(parentValue); + } + else + { + m_RenderPaint->blendMode((BlendMode)blendModeValue()); + } +} + +void ShapePaint::feather(Feather* feather) { m_feather = feather; } + +Feather* ShapePaint::feather() const { return m_feather; } + +void ShapePaint::draw(Renderer* renderer, + ShapePaintPath* shapePaintPath, + const Mat2D& transform, + bool usePathFillRule, + RenderPaint* overridePaint) +{ + ShapePaintPath* pathToDraw = shapePaintPath; + bool saved = false; + if (m_feather != nullptr) + { + bool offsetInArtboard = m_feather->space() == TransformSpace::world; + if (offsetInArtboard && !m_feather->inner()) + { + if (m_feather->offsetX() != 0 || m_feather->offsetY() != 0) + { + if (!saved) + { + saved = true; + renderer->save(); + } + renderer->translate(m_feather->offsetX(), m_feather->offsetY()); + } + } + } + if (shapePaintPath->isLocal()) + { + if (!saved) + { + saved = true; + renderer->save(); + } + renderer->transform(transform); + } + + if (m_feather != nullptr) + { + if (m_feather->inner()) + { + if (m_feather->innerPath() == nullptr) + { + return; + } + pathToDraw = m_feather->innerPath(); + if (!saved) + { + saved = true; + renderer->save(); + } + auto renderPath = shapePaintPath->renderPath(this); + if (renderPath != nullptr) + { + renderer->clipPath(renderPath); + } + } + + // If we're offseting in world space, apply the offset last. + if (m_feather->space() != TransformSpace::world && + !m_feather->inner() && + (m_feather->offsetX() != 0 || m_feather->offsetY() != 0)) + { + if (!saved) + { + saved = true; + renderer->save(); + } + renderer->translate(m_feather->offsetX(), m_feather->offsetY()); + } + } + + auto renderPath = pathToDraw->renderPath(this); + if (renderPath != nullptr) + { + // Ugh, can't we make fillRule part of the Paint? + if (!usePathFillRule && is()) + { + renderPath->fillRule((FillRule)as()->fillRule()); + } + + renderer->drawPath(renderPath, + overridePaint != nullptr ? overridePaint + : renderPaint()); + } + + if (saved) + { + renderer->restore(); + } +} \ No newline at end of file diff --git a/third_party/rive/source/shapes/paint/shape_paint_mutator.cpp b/third_party/rive/source/shapes/paint/shape_paint_mutator.cpp new file mode 100644 index 0000000..ac88602 --- /dev/null +++ b/third_party/rive/source/shapes/paint/shape_paint_mutator.cpp @@ -0,0 +1,47 @@ +#include "rive/shapes/paint/shape_paint_mutator.hpp" +#include "rive/component.hpp" +#include "rive/shapes/paint/shape_paint.hpp" + +using namespace rive; + +StatusCode ShapePaintMutator::initPaintMutator(Component* component) +{ + m_flags = Flags::translucent | Flags::visible; + auto parent = component->parent(); + m_component = component; + if (parent->is()) + { + if (parent->as()->renderPaint() != nullptr) + { + DEBUG_PRINT( + "ShapePaintMutator::initPaintMutator - ShapePaint has already " + "been asigned a mutator. Does this file have multiple solid " + "color/gradients in one single fill/stroke?"); + return StatusCode::InvalidObject; + } + // Set this object as the mutator for the shape paint and get a + // reference to the paint we'll be mutating. + m_renderPaint = parent->as()->initRenderPaint(this); + return StatusCode::Ok; + } + return StatusCode::MissingObject; +} +void ShapePaintMutator::renderOpacity(float value) +{ + if (m_renderOpacity == value) + { + return; + } + m_renderOpacity = value; + renderOpacityChanged(); +} + +bool ShapePaintMutator::isTranslucent() const +{ + return (m_flags & Flags::translucent) == Flags::translucent; +} + +bool ShapePaintMutator::isVisible() const +{ + return (m_flags & Flags::visible) == Flags::visible; +} \ No newline at end of file diff --git a/third_party/rive/source/shapes/paint/shape_paint_path.cpp b/third_party/rive/source/shapes/paint/shape_paint_path.cpp new file mode 100644 index 0000000..c23a71c --- /dev/null +++ b/third_party/rive/source/shapes/paint/shape_paint_path.cpp @@ -0,0 +1,75 @@ +#include "rive/shapes/shape_paint_path.hpp" +#include "rive/component.hpp" +#include "rive/artboard.hpp" +#include "rive/factory.hpp" + +using namespace rive; + +ShapePaintPath::ShapePaintPath(bool isLocal) : m_isLocal(isLocal) {} +ShapePaintPath::ShapePaintPath(bool isLocal, FillRule fillRule) : + m_isLocal(isLocal), m_fillRule(fillRule) +{} + +void ShapePaintPath::rewind() +{ + m_rawPath.rewind(); + m_isRenderPathDirty = true; +} + +void ShapePaintPath::addPath(const RawPath& rawPath, const Mat2D* transform) +{ + auto iter = m_rawPath.addPath(rawPath, transform); + m_rawPath.pruneEmptySegments(iter); + m_isRenderPathDirty = true; +} + +void ShapePaintPath::addPathClockwise(const RawPath& rawPath, + const Mat2D* transform) +{ + float coarseArea = rawPath.computeCoarseArea(); + if (transform != nullptr) + { + coarseArea *= transform->determinant(); + } + if (coarseArea < 0) + { + addPathBackwards(rawPath, transform); + } + else + { + addPath(rawPath, transform); + } +} + +void ShapePaintPath::addPathBackwards(const RawPath& rawPath, + const Mat2D* transform) +{ + auto iter = m_rawPath.addPathBackwards(rawPath, transform); + m_rawPath.pruneEmptySegments(iter); + m_isRenderPathDirty = true; +} + +RenderPath* ShapePaintPath::renderPath(const Component* component) +{ + assert(component != nullptr); + return renderPath(component->artboard()->factory()); +} + +RenderPath* ShapePaintPath::renderPath(Factory* factory) +{ + if (!m_renderPath) + { + m_renderPath = factory->makeEmptyRenderPath(); + m_renderPath->addRawPath(m_rawPath); + m_renderPath->fillRule(m_fillRule); + m_isRenderPathDirty = false; + } + else if (m_isRenderPathDirty) + { + m_renderPath->rewind(); + m_renderPath->addRawPath(m_rawPath); + m_isRenderPathDirty = false; + } + + return m_renderPath.get(); +} \ No newline at end of file diff --git a/third_party/rive/source/shapes/paint/solid_color.cpp b/third_party/rive/source/shapes/paint/solid_color.cpp new file mode 100644 index 0000000..da062f4 --- /dev/null +++ b/third_party/rive/source/shapes/paint/solid_color.cpp @@ -0,0 +1,49 @@ +#include "rive/shapes/paint/solid_color.hpp" +#include "rive/container_component.hpp" +#include "rive/renderer.hpp" +#include "rive/shapes/paint/color.hpp" + +using namespace rive; + +StatusCode SolidColor::onAddedDirty(CoreContext* context) +{ + StatusCode code = Super::onAddedDirty(context); + if (code != StatusCode::Ok) + { + return code; + } + if ((code = initPaintMutator(this)) == StatusCode::Ok) + { + renderOpacityChanged(); + } + + return code; +} + +void SolidColor::renderOpacityChanged() +{ + if (renderPaint() == nullptr) + { + return; + } + auto value = colorModulateOpacity(colorValue(), renderOpacity()); + renderPaint()->color(value); + auto opacity = colorOpacity(value); + m_flags = ShapePaintMutator::Flags::none; + if (opacity > 0.0f) + { + m_flags |= ShapePaintMutator::Flags::visible; + } + else if (opacity < 1.0f) + { + m_flags |= ShapePaintMutator::Flags::translucent; + } +} + +void SolidColor::applyTo(RenderPaint* renderPaint, float opacityModifier) +{ + renderPaint->color( + colorModulateOpacity(colorValue(), renderOpacity() * opacityModifier)); +} + +void SolidColor::colorValueChanged() { renderOpacityChanged(); } diff --git a/third_party/rive/source/shapes/paint/stroke.cpp b/third_party/rive/source/shapes/paint/stroke.cpp new file mode 100644 index 0000000..c502005 --- /dev/null +++ b/third_party/rive/source/shapes/paint/stroke.cpp @@ -0,0 +1,119 @@ +#include "rive/artboard.hpp" +#include "rive/shapes/paint/stroke.hpp" +#include "rive/shapes/paint/stroke_cap.hpp" +#include "rive/shapes/paint/stroke_effect.hpp" +#include "rive/shapes/paint/stroke_join.hpp" + +using namespace rive; + +PathFlags Stroke::pathFlags() const +{ + return transformAffectsStroke() ? PathFlags::local : PathFlags::world; +} +RenderPaint* Stroke::initRenderPaint(ShapePaintMutator* mutator) +{ + auto renderPaint = Super::initRenderPaint(mutator); + renderPaint->style(RenderPaintStyle::stroke); + renderPaint->thickness(thickness()); + renderPaint->cap((StrokeCap)cap()); + renderPaint->join((StrokeJoin)join()); + return renderPaint; +} + +void Stroke::update(ComponentDirt value) +{ + Super::update(value); + if (hasDirt(value, ComponentDirt::Path) && m_Effect != nullptr) + { + auto container = ShapePaintContainer::from(parent()); + auto path = pickPath(container); + m_Effect->updateEffect(path); + } +} + +void Stroke::applyTo(RenderPaint* renderPaint, float opacityModifier) +{ + renderPaint->style(RenderPaintStyle::stroke); + renderPaint->thickness(thickness()); + renderPaint->cap((StrokeCap)cap()); + renderPaint->join((StrokeJoin)join()); + renderPaint->shader(nullptr); + m_PaintMutator->applyTo(renderPaint, opacityModifier); +} + +bool Stroke::isVisible() const +{ + return Super::isVisible() && thickness() > 0.0f; +} + +void Stroke::thicknessChanged() +{ + assert(m_RenderPaint != nullptr); + m_RenderPaint->thickness(thickness()); +} + +void Stroke::capChanged() +{ + assert(m_RenderPaint != nullptr); + m_RenderPaint->cap((StrokeCap)cap()); +} + +void Stroke::joinChanged() +{ + assert(m_RenderPaint != nullptr); + m_RenderPaint->join((StrokeJoin)join()); +} + +void Stroke::addStrokeEffect(StrokeEffect* effect) { m_Effect = effect; } + +void Stroke::invalidateEffects() +{ + if (m_Effect != nullptr) + { + m_Effect->invalidateEffect(); + } + invalidateRendering(); +} + +void Stroke::invalidateRendering() +{ + assert(m_RenderPaint != nullptr); + m_RenderPaint->invalidateStroke(); + addDirt(ComponentDirt::Path); +} + +ShapePaintPath* Stroke::pickPath(ShapePaintContainer* shape) const +{ + if (transformAffectsStroke()) + { + return shape->localPath(); + } + return shape->worldPath(); +} + +void Stroke::draw(Renderer* renderer, + ShapePaintPath* shapePaintPath, + const Mat2D& transform, + bool usePathFillRule, + RenderPaint* overridePaint) +{ + if (m_Effect != nullptr) + { + shapePaintPath = m_Effect->effectPath(); + } + + Super::draw(renderer, + shapePaintPath, + transform, + usePathFillRule, + overridePaint); +} + +void Stroke::buildDependencies() +{ + auto container = ShapePaintContainer::from(parent()); + if (container != nullptr) + { + container->pathBuilder()->addDependent(this); + } +} \ No newline at end of file diff --git a/third_party/rive/source/shapes/paint/trim_path.cpp b/third_party/rive/source/shapes/paint/trim_path.cpp new file mode 100644 index 0000000..3032039 --- /dev/null +++ b/third_party/rive/source/shapes/paint/trim_path.cpp @@ -0,0 +1,219 @@ +#include "rive/shapes/paint/trim_path.hpp" +#include "rive/shapes/paint/stroke.hpp" +using namespace rive; + +StatusCode TrimPath::onAddedClean(CoreContext* context) +{ + if (!parent()->is()) + { + return StatusCode::InvalidObject; + } + + parent()->as()->addStrokeEffect(this); + + return StatusCode::Ok; +} + +void TrimPath::trimPath(const RawPath* source) +{ + auto rawPath = m_path.mutableRawPath(); + auto renderOffset = std::fmod(std::fmod(offset(), 1.0f) + 1.0f, 1.0f); + + // Build up contours if they're empty. + if (m_contours.empty()) + { + ContourMeasureIter iter(source); + while (auto meas = iter.next()) + { + m_contours.push_back(meas); + } + } + switch (mode()) + { + case TrimPathMode::sequential: + { + float totalLength = 0.0f; + for (auto contour : m_contours) + { + totalLength += contour->length(); + } + auto startLength = totalLength * (start() + renderOffset); + auto endLength = totalLength * (end() + renderOffset); + + if (endLength < startLength) + { + float swap = startLength; + startLength = endLength; + endLength = swap; + } + + if (startLength > totalLength) + { + startLength -= totalLength; + endLength -= totalLength; + } + + int i = 0, subPathCount = (int)m_contours.size(); + std::vector indices; + std::vector lengths; + while (endLength > 0) + { + auto currentContourIndex = i % subPathCount; + auto contour = m_contours[currentContourIndex]; + auto contourLength = contour->length(); + + if (startLength < contourLength) + { + indices.push_back(currentContourIndex); + lengths.push_back(startLength); + lengths.push_back(endLength); + endLength -= contourLength; + startLength = 0; + } + else + { + startLength -= contourLength; + endLength -= contourLength; + } + i++; + } + + // This is inintuitive but works. If the last segment and the first + // segment of the trim path belong to the same contour, we want to + // draw the first semgment first, then the last one and then the + // rest. This is intentional to make sure the last segment is + // connected to the first one in order to avoid a gap. A linear way + // without reordering indices is to start at index 0 and go + // backwards. For the remaining segments it's not important in what + // order they are drawn + int startingIndex = 0; + int indexCount = 0; + + int prevContourIndex = -1; + while (indexCount < indices.size()) + { + auto index = (startingIndex < 0 ? startingIndex + indices.size() + : startingIndex) % + indices.size(); + auto contourIndex = indices[index]; + auto contour = m_contours[contourIndex]; + auto contourLength = contour->length(); + auto lengthIndex = index * 2; + auto startLength = lengths[lengthIndex]; + auto endLength = lengths[lengthIndex + 1]; + // if two consecutive segments belong to the same contour, draw + // them connected. + contour->getSegment(startLength, + endLength, + rawPath, + prevContourIndex != contourIndex || + !contour->isClosed()); + // Close contours that are fully used as + // segments + if (startLength == 0.0f && + endLength - startLength >= contourLength && + contour->isClosed()) + { + rawPath->close(); + } + prevContourIndex = contourIndex; + indexCount++; + startingIndex--; + } + } + break; + + case TrimPathMode::synchronized: + { + for (auto contour : m_contours) + { + auto contourLength = contour->length(); + auto startLength = contourLength * (start() + renderOffset); + auto endLength = contourLength * (end() + renderOffset); + if (endLength < startLength) + { + auto length = startLength; + startLength = endLength; + endLength = length; + } + + if (startLength >= contourLength) + { + startLength -= contourLength; + endLength -= contourLength; + } + contour->getSegment(startLength, endLength, rawPath, true); + while (endLength > contourLength) + { + startLength = 0; + endLength -= contourLength; + contour->getSegment(startLength, + endLength, + rawPath, + !contour->isClosed()); + } + + if (start() == 0.0f && end() == 1.0f && contour->isClosed()) + { + rawPath->close(); + } + } + } + break; + default: + RIVE_UNREACHABLE(); + } +} + +void TrimPath::invalidateEffect() +{ + invalidateTrim(); + // This is usually sent when the path is changed so we need to also + // invalidate the contours, not just the trim effect. + m_contours.clear(); +} + +void TrimPath::invalidateTrim() +{ + m_path.rewind(); + if (parent() != nullptr) + { + auto stroke = parent()->as(); + stroke->parent()->addDirt(ComponentDirt::Paint); + stroke->invalidateRendering(); + } +} + +void TrimPath::startChanged() { invalidateTrim(); } +void TrimPath::endChanged() { invalidateTrim(); } +void TrimPath::offsetChanged() { invalidateTrim(); } +void TrimPath::modeValueChanged() { invalidateTrim(); } + +StatusCode TrimPath::onAddedDirty(CoreContext* context) +{ + auto code = Super::onAddedDirty(context); + if (code != StatusCode::Ok) + { + return code; + } + switch (mode()) + { + case TrimPathMode::sequential: + case TrimPathMode::synchronized: + return StatusCode::Ok; + } + return StatusCode::InvalidObject; +} + +void TrimPath::updateEffect(const ShapePaintPath* source) +{ + if (m_path.hasRenderPath()) + { + // Previous result hasn't been invalidated, it's still good. + return; + } + m_path.rewind(source->isLocal(), source->fillRule()); + trimPath(source->rawPath()); +} + +ShapePaintPath* TrimPath::effectPath() { return &m_path; } \ No newline at end of file diff --git a/third_party/rive/source/shapes/parametric_path.cpp b/third_party/rive/source/shapes/parametric_path.cpp new file mode 100644 index 0000000..363d836 --- /dev/null +++ b/third_party/rive/source/shapes/parametric_path.cpp @@ -0,0 +1,66 @@ +#include "rive/layout_component.hpp" +#include "rive/math/aabb.hpp" +#include "rive/node.hpp" +#include "rive/shapes/parametric_path.hpp" +#include "rive/shapes/shape.hpp" + +using namespace rive; + +Vec2D ParametricPath::measureLayout(float width, + LayoutMeasureMode widthMode, + float height, + LayoutMeasureMode heightMode) +{ + return Vec2D(std::min((widthMode == LayoutMeasureMode::undefined + ? std::numeric_limits::max() + : width), + ParametricPath::width()), + std::min((heightMode == LayoutMeasureMode::undefined + ? std::numeric_limits::max() + : height), + ParametricPath::height())); +} + +void ParametricPath::controlSize(Vec2D size, + LayoutScaleType widthScaleType, + LayoutScaleType heightScaleType, + LayoutDirection direction) +{ + width(size.x); + height(size.y); + markWorldTransformDirty(); + markPathDirty(false); +} + +void ParametricPath::markPathDirty(bool sendToLayout) +{ + Super::markPathDirty(); +#ifdef WITH_RIVE_LAYOUT + if (sendToLayout) + { + for (ContainerComponent* p = parent(); p != nullptr; p = p->parent()) + { + if (p->is()) + { + p->as()->markLayoutNodeDirty(); + break; + } + // If we're in a group we break out because objects in groups do + // not affect nor are affected by parent LayoutComponents + if (p->is()) + { + if (p->is() && p->as() == shape()) + { + continue; + } + break; + } + } + } +#endif +} + +void ParametricPath::widthChanged() { markPathDirty(); } +void ParametricPath::heightChanged() { markPathDirty(); } +void ParametricPath::originXChanged() { markPathDirty(); } +void ParametricPath::originYChanged() { markPathDirty(); } \ No newline at end of file diff --git a/third_party/rive/source/shapes/path.cpp b/third_party/rive/source/shapes/path.cpp new file mode 100644 index 0000000..4374917 --- /dev/null +++ b/third_party/rive/source/shapes/path.cpp @@ -0,0 +1,558 @@ +#include "rive/shapes/path.hpp" +#include "rive/renderer.hpp" +#include "rive/shapes/cubic_vertex.hpp" +#include "rive/shapes/cubic_detached_vertex.hpp" +#include "rive/shapes/deformer.hpp" +#include "rive/shapes/path_vertex.hpp" +#include "rive/shapes/shape.hpp" +#include "rive/shapes/straight_vertex.hpp" +#include "rive/math/math_types.hpp" +#include + +using namespace rive; + +/// Compute an ideal control point distance to create a curve of the given +/// radius. Based on "natural rounding" +/// https://observablehq.com/@daformat/rounding-polygon-corners +float Path::computeIdealControlPointDistance(const Vec2D& toPrev, + const Vec2D& toNext, + float radius) +{ + // Get the angle between next and prev + float angle = fabs( + std::atan2(Vec2D::cross(toPrev, toNext), Vec2D::dot(toPrev, toNext))); + + return fmin(radius, + (4.0f / 3.0f) * + std::tan(math::PI / (2.0f * ((2.0f * math::PI) / angle))) * + radius * + (angle < math::PI / 2 ? 1 + std::cos(angle) + : 2.0f - std::sin(angle))); +} + +static void rotatePoints(const Vec2D& nextPoint, + const Vec2D& prevPoint, + const Vec2D& point, + Vec2D& outPoint, + Vec2D& inPoint) +{ + // Calculate angle between original pos and new positions + auto v1 = prevPoint - nextPoint; + auto v2 = point - nextPoint; + float angle = std::atan2(Vec2D::cross(v1, v2), Vec2D::dot(v1, v2)); + { + // Rotate outPoint around prevPoint twice the angle + float s = std::sin(angle * 2); + float c = std::cos(angle * 2); + outPoint.x -= prevPoint.x; + outPoint.y -= prevPoint.y; + float xNew = outPoint.x * c - outPoint.y * s; + float yNew = outPoint.x * s + outPoint.y * c; + outPoint.x = xNew + prevPoint.x; + outPoint.y = yNew + prevPoint.y; + } + { + // Rotate inPoint around nextPoint twice the angle + float s = std::sin(-angle * 2); + float c = std::cos(-angle * 2); + inPoint.x -= nextPoint.x; + inPoint.y -= nextPoint.y; + float xNew = inPoint.x * c - inPoint.y * s; + float yNew = inPoint.x * s + inPoint.y * c; + inPoint.x = xNew + nextPoint.x; + inPoint.y = yNew + nextPoint.y; + } +} + +RenderPathDeformer* Path::deformer() const +{ + if (m_Shape != nullptr) + { + return m_Shape->deformer(); + } + return nullptr; +} + +StatusCode Path::onAddedClean(CoreContext* context) +{ + StatusCode code = Super::onAddedClean(context); + if (code != StatusCode::Ok) + { + return code; + } + + // Find the shape. + for (auto currentParent = parent(); currentParent != nullptr; + currentParent = currentParent->parent()) + { + if (currentParent->is()) + { + m_Shape = currentParent->as(); + m_Shape->addPath(this); + return StatusCode::Ok; + } + } + + return StatusCode::MissingObject; +} + +void Path::buildDependencies() { Super::buildDependencies(); } + +void Path::addVertex(PathVertex* vertex) { m_Vertices.push_back(vertex); } + +void Path::addFlags(PathFlags flags) { m_pathFlags |= flags; } +bool Path::isFlagged(PathFlags flags) const +{ + return (int)(m_pathFlags & flags) != 0x00; +} + +bool Path::canDeferPathUpdate() +{ + if (m_Shape == nullptr) + { + return false; + } + // A path cannot defer its update if the shapes requires an update. Note the + // nuance here where we track that the shape may be marked for follow path + // (meaning all child paths need to follow path). This doesn't mean the + // Shape is necessarily forced to update put the paths are, which is why we + // explicitly also check the shape's path space. + + return m_Shape->canDeferPathUpdate() && + !m_Shape->isFlagged(PathFlags::followPath) && + !isFlagged(PathFlags::followPath | PathFlags::clipping); +} + +const Mat2D& Path::pathTransform() const { return worldTransform(); } + +void Path::buildPath(RawPath& rawPath) const +{ + const bool isClosed = isPathClosed(); + const std::vector& vertices = m_Vertices; + + auto length = vertices.size(); + if (length < 2) + { + return; + } + auto firstPoint = vertices[0]; + + // Init out to translation + Vec2D out; + bool prevIsCubic; + + Vec2D start, startIn; + bool startIsCubic; + + if (firstPoint->is()) + { + auto cubic = firstPoint->as(); + startIsCubic = prevIsCubic = true; + startIn = cubic->renderIn(); + out = cubic->renderOut(); + start = cubic->renderTranslation(); + rawPath.move(start); + } + else + { + startIsCubic = prevIsCubic = false; + auto point = *firstPoint->as(); + auto radius = point.radius(); + if (radius != 0.0f) + { + auto prev = vertices[length - 1]; + + Vec2D pos = point.renderTranslation(); + + Vec2D toPrev = + (prev->is() ? prev->as()->renderOut() + : prev->renderTranslation()) - + pos; + + auto toPrevLength = toPrev.normalizeLength(); + + auto next = vertices[1]; + + Vec2D toNext = + (next->is() ? next->as()->renderIn() + : next->renderTranslation()) - + pos; + auto toNextLength = toNext.normalizeLength(); + + float renderRadius = std::min( + toPrevLength / 2.0f, + std::min(toNextLength / 2.0f, radius > 0 ? radius : -radius)); + float idealDistance = + Path::computeIdealControlPointDistance(toPrev, + toNext, + renderRadius); + + startIn = start = Vec2D::scaleAndAdd(pos, toPrev, renderRadius); + rawPath.move(startIn); + + Vec2D outPoint = + Vec2D::scaleAndAdd(pos, toPrev, renderRadius - idealDistance); + Vec2D inPoint = + Vec2D::scaleAndAdd(pos, toNext, renderRadius - idealDistance); + out = Vec2D::scaleAndAdd(pos, toNext, renderRadius); + + if (radius < 0) + { + rotatePoints(out, startIn, pos, outPoint, inPoint); + } + rawPath.cubic(outPoint, inPoint, out); + prevIsCubic = false; + } + else + { + startIn = start = out = point.renderTranslation(); + rawPath.move(out); + } + } + + for (size_t i = 1; i < length; i++) + { + auto vertex = vertices[i]; + + if (vertex->is()) + { + auto cubic = vertex->as(); + auto inPoint = cubic->renderIn(); + auto translation = cubic->renderTranslation(); + + rawPath.cubic(out, inPoint, translation); + + prevIsCubic = true; + out = cubic->renderOut(); + } + else + { + auto point = *vertex->as(); + Vec2D pos = point.renderTranslation(); + auto radius = point.radius(); + if (radius != 0.0f) + { + auto prev = vertices[i - 1]; + Vec2D toPrev = (prev->is() + ? prev->as()->renderOut() + : prev->renderTranslation()) - + pos; + auto toPrevLength = toPrev.normalizeLength(); + + auto next = vertices[(i + 1) % length]; + + Vec2D toNext = (next->is() + ? next->as()->renderIn() + : next->renderTranslation()) - + pos; + auto toNextLength = toNext.normalizeLength(); + + float renderRadius = + std::min(toPrevLength / 2.0f, + std::min(toNextLength / 2.0f, + radius > 0 ? radius : -radius)); + float idealDistance = + computeIdealControlPointDistance(toPrev, + toNext, + renderRadius); + + Vec2D translation = + Vec2D::scaleAndAdd(pos, toPrev, renderRadius); + if (prevIsCubic) + { + rawPath.cubic(out, translation, translation); + } + else + { + rawPath.line(translation); + } + + Vec2D outPoint = + Vec2D::scaleAndAdd(pos, + toPrev, + renderRadius - idealDistance); + Vec2D inPoint = + Vec2D::scaleAndAdd(pos, + toNext, + renderRadius - idealDistance); + out = Vec2D::scaleAndAdd(pos, toNext, renderRadius); + + if (radius < 0) + { + rotatePoints(out, translation, pos, outPoint, inPoint); + } + rawPath.cubic(outPoint, inPoint, out); + prevIsCubic = false; + } + else if (prevIsCubic) + { + rawPath.cubic(out, pos, pos); + + prevIsCubic = false; + out = pos; + } + else + { + out = pos; + rawPath.line(out); + } + } + } + if (isClosed) + { + if (prevIsCubic || startIsCubic) + { + rawPath.cubic(out, startIn, start); + } + else + { + rawPath.line(start); + } + rawPath.close(); + } + + RenderPathDeformer* pathDeformer = deformer(); + if (pathDeformer != nullptr) + { + Mat2D transform = pathTransform(); + Mat2D inverse = transform.invertOrIdentity(); + pathDeformer->deformLocalRenderPath(rawPath, transform, inverse); + } +} + +void Path::markPathDirty(bool sendToLayout) +{ + addDirt(ComponentDirt::Path); + if (m_Shape != nullptr) + { + m_Shape->pathChanged(); + } +} + +void Path::onDirty(ComponentDirt value) +{ + if (hasDirt(value, + ComponentDirt::WorldTransform | ComponentDirt::NSlicer) && + m_Shape != nullptr) + { + m_Shape->pathChanged(); + } + if (m_deferredPathDirt) + { + addDirt(ComponentDirt::Path); + } +} + +void Path::update(ComponentDirt value) +{ + Super::update(value); + + bool pathChanged = hasDirt(value, ComponentDirt::Path); + bool worldTransformChanged = hasDirt(value, ComponentDirt::WorldTransform); + bool deformerChanged = hasDirt(value, ComponentDirt::NSlicer); + + if (pathChanged || deformerChanged || + (deformer() != nullptr && worldTransformChanged)) + { + if (canDeferPathUpdate()) + { + m_deferredPathDirt = true; + return; + } + m_deferredPathDirt = false; + // Build path doesn't explicitly rewind because we use it to concatenate + // multiple built paths into a single command path (like the hit + // tester). + m_rawPath.rewind(); + buildPath(m_rawPath); + } + // if (hasDirt(value, ComponentDirt::WorldTransform) && m_Shape != nullptr) + // { + // // Make sure the path composer has an opportunity to rebuild the path + // // (this is why the composer depends on the shape and all its paths, + // // ascertaning it updates after both) + // m_Shape->pathChanged(); + // } +} + +void Path::isHoleChanged() { markPathDirty(); } + +bool Path::collapse(bool value) +{ + bool changed = Super::collapse(value); + if (changed && m_Shape != nullptr) + { + m_Shape->pathCollapseChanged(); + } + + return changed; +} + +#ifdef ENABLE_QUERY_FLAT_VERTICES + +class DisplayCubicVertex : public CubicVertex +{ +public: + DisplayCubicVertex(const Vec2D& in, + const Vec2D& out, + const Vec2D& translation) + + { + m_InPoint = in; + m_OutPoint = out; + m_InValid = true; + m_OutValid = true; + x(translation.x); + y(translation.y); + } + + void computeIn() override {} + void computeOut() override {} +}; + +FlattenedPath* Path::makeFlat(bool transformToParent) +{ + if (m_Vertices.empty()) + { + return nullptr; + } + + // Path transform always puts the path into world space. + auto transform = pathTransform(); + + if (transformToParent && parent()->is()) + { + // Put the transform in parent space. + auto world = parent()->as()->worldTransform(); + transform = world.invertOrIdentity() * transform; + } + + FlattenedPath* flat = new FlattenedPath(); + auto length = m_Vertices.size(); + PathVertex* previous = isPathClosed() ? m_Vertices[length - 1] : nullptr; + bool deletePrevious = false; + for (size_t i = 0; i < length; i++) + { + auto vertex = m_Vertices[i]; + + switch (vertex->coreType()) + { + case StraightVertex::typeKey: + { + auto point = *vertex->as(); + if (point.radius() > 0.0f && + (isPathClosed() || (i != 0 && i != length - 1))) + { + auto next = m_Vertices[(i + 1) % length]; + + Vec2D prevPoint = + previous->is() + ? previous->as()->renderOut() + : previous->renderTranslation(); + Vec2D nextPoint = next->is() + ? next->as()->renderIn() + : next->renderTranslation(); + + Vec2D pos = point.renderTranslation(); + + Vec2D toPrev = prevPoint - pos; + auto toPrevLength = toPrev.normalizeLength(); + + Vec2D toNext = nextPoint - pos; + auto toNextLength = toNext.normalizeLength(); + + auto renderRadius = + std::min(toPrevLength / 2.0f, + std::min(toNextLength / 2.0f, point.radius())); + float idealDistance = + computeIdealControlPointDistance(toPrev, + toNext, + renderRadius); + Vec2D translation = + Vec2D::scaleAndAdd(pos, toPrev, renderRadius); + + Vec2D out = + Vec2D::scaleAndAdd(pos, + toPrev, + renderRadius - idealDistance); + { + auto v1 = new DisplayCubicVertex(translation, + out, + translation); + flat->addVertex(v1, transform); + delete v1; + } + + translation = Vec2D::scaleAndAdd(pos, toNext, renderRadius); + + Vec2D in = Vec2D::scaleAndAdd(pos, + toNext, + renderRadius - idealDistance); + auto v2 = + new DisplayCubicVertex(in, translation, translation); + + flat->addVertex(v2, transform); + if (deletePrevious) + { + delete previous; + } + previous = v2; + deletePrevious = true; + break; + } + RIVE_FALLTHROUGH; + } + default: + if (deletePrevious) + { + delete previous; + } + previous = vertex; + deletePrevious = false; + flat->addVertex(previous, transform); + break; + } + } + if (deletePrevious) + { + delete previous; + } + return flat; +} + +void FlattenedPath::addVertex(PathVertex* vertex, const Mat2D& transform) +{ + // To make this easy and relatively clean we just transform the vertices. + // Requires the vertex to be passed in as a clone. + if (vertex->is()) + { + auto cubic = vertex->as(); + + // Cubics need to be transformed so we create a Display version which + // has set in/out values. + const auto in = transform * cubic->renderIn(); + const auto out = transform * cubic->renderOut(); + const auto translation = transform * cubic->renderTranslation(); + + auto displayCubic = new DisplayCubicVertex(in, out, translation); + m_Vertices.push_back(displayCubic); + } + else + { + auto point = new PathVertex(); + Vec2D translation = transform * vertex->renderTranslation(); + point->x(translation.x); + point->y(translation.y); + m_Vertices.push_back(point); + } +} + +FlattenedPath::~FlattenedPath() +{ + for (auto vertex : m_Vertices) + { + delete vertex; + } +} + +#endif diff --git a/third_party/rive/source/shapes/path_composer.cpp b/third_party/rive/source/shapes/path_composer.cpp new file mode 100644 index 0000000..575ad04 --- /dev/null +++ b/third_party/rive/source/shapes/path_composer.cpp @@ -0,0 +1,134 @@ +#include "rive/shapes/path_composer.hpp" +#include "rive/artboard.hpp" +#include "rive/renderer.hpp" +#include "rive/shapes/path.hpp" +#include "rive/shapes/shape.hpp" +#include "rive/factory.hpp" +#include "rive/shapes/points_path.hpp" + +using namespace rive; + +PathComposer::PathComposer(Shape* shape) : + m_shape(shape), + m_localPath(true), + m_worldPath(false), + m_localClockwisePath(true), + m_deferredPathDirt(false) +{} + +void PathComposer::buildDependencies() +{ + assert(m_shape != nullptr); + m_shape->addDependent(this); + for (auto path : m_shape->paths()) + { + path->addDependent(this); + } +} + +void PathComposer::onDirty(ComponentDirt dirt) +{ + if (m_deferredPathDirt) + { + // We'd deferred the update, let's make sure the rest of our + // dependencies update too. Constraints need to update too, stroke + // effects, etc. + m_shape->pathChanged(); + } +} + +void PathComposer::update(ComponentDirt value) +{ + if (hasDirt(value, ComponentDirt::Path | ComponentDirt::NSlicer)) + { + if (m_shape->canDeferPathUpdate()) + { + m_deferredPathDirt = true; + return; + } + m_deferredPathDirt = false; + + if (m_shape->isFlagged(PathFlags::local)) + { + m_localPath.rewind(); + auto world = m_shape->worldTransform(); + Mat2D inverseWorld = world.invertOrIdentity(); + // Get all the paths into local shape space. + for (auto path : m_shape->paths()) + { + if (!path->isHidden() && !path->isCollapsed()) + { + const auto localTransform = + inverseWorld * path->pathTransform(); + m_localPath.addPath(path->rawPath(), &localTransform); + } + } + } + if (m_shape->isFlagged(PathFlags::localClockwise)) + { + m_localClockwisePath.rewind(); + auto world = m_shape->worldTransform(); + Mat2D inverseWorld = world.invertOrIdentity(); + // Get all the paths into local shape space. + for (auto path : m_shape->paths()) + { + if (path->isHidden() || path->isCollapsed()) + { + continue; + } + const auto localTransform = + inverseWorld * path->pathTransform(); + + bool isNotClockwise = + path->is() && + (localTransform.determinant() * + (path->as()->isClockwise() ? 1.0f + : -1.0f) < + 0); + bool isHole = path->isHole(); + // Only draw backwards if values are different + if (isNotClockwise != isHole) + { + m_localClockwisePath.addPathBackwards(path->rawPath(), + &localTransform); + } + else + { + m_localClockwisePath.addPath(path->rawPath(), + &localTransform); + } + } + } + if (m_shape->isFlagged(PathFlags::world)) + { + m_worldPath.rewind(); + + for (auto path : m_shape->paths()) + { + if (!path->isHidden() && !path->isCollapsed()) + { + const Mat2D& transform = path->pathTransform(); + m_worldPath.addPath(path->rawPath(), &transform); + } + } + } + m_shape->markBoundsDirty(); + } +} + +// Instead of adding dirt and rely on the recursive behavior of the addDirt +// method, we need to explicitly add dirt to the dependents. The reason is that +// a collapsed shape will not clear its dirty path flag in the current frame +// since it is collapsed. So in a future frame if it is uncollapsed, we mark its +// path flag as dirty again, but since it was already dirty, the recursive part +// will not kick in and the dependents won't update. This scenario is not +// common, but it can happen when a solo toggles between an empty group and a +// path for example. +void PathComposer::pathCollapseChanged() +{ + addDirt(ComponentDirt::Path); + for (auto d : dependents()) + { + d->addDirt(ComponentDirt::Path, true); + } +} \ No newline at end of file diff --git a/third_party/rive/source/shapes/path_vertex.cpp b/third_party/rive/source/shapes/path_vertex.cpp new file mode 100644 index 0000000..637ec0a --- /dev/null +++ b/third_party/rive/source/shapes/path_vertex.cpp @@ -0,0 +1,30 @@ +#include "rive/shapes/path_vertex.hpp" +#include "rive/shapes/path.hpp" + +using namespace rive; + +StatusCode PathVertex::onAddedDirty(CoreContext* context) +{ + StatusCode code = Super::onAddedDirty(context); + if (code != StatusCode::Ok) + { + return code; + } + if (!parent()->is()) + { + return StatusCode::MissingObject; + } + parent()->as()->addVertex(this); + return StatusCode::Ok; +} + +void PathVertex::markGeometryDirty() +{ + if (parent() == nullptr) + { + // This is an acceptable condition as the parametric paths create points + // that are not part of the core context. + return; + } + parent()->as()->markPathDirty(); +} \ No newline at end of file diff --git a/third_party/rive/source/shapes/points_path.cpp b/third_party/rive/source/shapes/points_path.cpp new file mode 100644 index 0000000..7227b2e --- /dev/null +++ b/third_party/rive/source/shapes/points_path.cpp @@ -0,0 +1,57 @@ +#include "rive/artboard.hpp" +#include "rive/shapes/points_path.hpp" +#include "rive/shapes/vertex.hpp" +#include "rive/shapes/path_vertex.hpp" +#include "rive/shapes/shape.hpp" +#include "rive/bones/skin.hpp" +#include "rive/span.hpp" +#include "rive/shapes/shape_path_flags.hpp" + +using namespace rive; + +void PointsPath::buildDependencies() +{ + Super::buildDependencies(); + if (skin() != nullptr) + { + skin()->addDependent(this); + } +} + +const Mat2D& PointsPath::pathTransform() const +{ + if (skin() != nullptr) + { + static Mat2D identity; + return identity; + } + return worldTransform(); +} + +void PointsPath::update(ComponentDirt value) +{ + if (hasDirt(value, ComponentDirt::Path) && skin() != nullptr) + { + // Path tracks re-adding ComponentDirt::Path if we deferred due to to + // shape being invisible. + skin()->deform( + Span((Vertex**)m_Vertices.data(), m_Vertices.size())); + } + Super::update(value); +} + +void PointsPath::markPathDirty(bool sendToLayout) +{ + if (skin() != nullptr) + { + skin()->addDirt(ComponentDirt::Skin); + } + Super::markPathDirty(); +} + +void PointsPath::markSkinDirty() { markPathDirty(); } + +bool PointsPath::isClockwise() const +{ + return (pathFlags() & (int)ShapePathFlags::isCounterClockwise) == 0; +} diff --git a/third_party/rive/source/shapes/polygon.cpp b/third_party/rive/source/shapes/polygon.cpp new file mode 100644 index 0000000..6791b4e --- /dev/null +++ b/third_party/rive/source/shapes/polygon.cpp @@ -0,0 +1,55 @@ +#include "rive/shapes/polygon.hpp" +#include "rive/shapes/star.hpp" +#include "rive/shapes/straight_vertex.hpp" +#include "rive/math/math_types.hpp" +#include + +using namespace rive; + +Polygon::Polygon() {} + +Polygon::~Polygon() {} + +void Polygon::cornerRadiusChanged() { markPathDirty(); } + +void Polygon::pointsChanged() { markPathDirty(); } + +std::size_t Polygon::vertexCount() { return points(); } + +void Polygon::buildPolygon() +{ + auto halfWidth = width() / 2; + auto halfHeight = height() / 2; + + auto ox = -originX() * width() + halfWidth; + auto oy = -originY() * height() + halfHeight; + + auto angle = -math::PI / 2; + auto inc = 2 * math::PI / points(); + + for (StraightVertex& vertex : m_PolygonVertices) + { + vertex.x(ox + cos(angle) * halfWidth); + vertex.y(oy + sin(angle) * halfHeight); + vertex.radius(cornerRadius()); + angle += inc; + } +} + +void Polygon::update(ComponentDirt value) +{ + if (hasDirt(value, ComponentDirt::Path)) + { + if (m_PolygonVertices.size() != vertexCount()) + { + m_PolygonVertices.resize(vertexCount()); + m_Vertices.clear(); + for (StraightVertex& vertex : m_PolygonVertices) + { + m_Vertices.push_back(&vertex); + } + } + buildPolygon(); + } + Super::update(value); +} diff --git a/third_party/rive/source/shapes/rectangle.cpp b/third_party/rive/source/shapes/rectangle.cpp new file mode 100644 index 0000000..272718b --- /dev/null +++ b/third_party/rive/source/shapes/rectangle.cpp @@ -0,0 +1,48 @@ +#pragma once + +#include "rive/shapes/rectangle.hpp" + +using namespace rive; + +Rectangle::Rectangle() +{ + addVertex(&m_Vertex1); + addVertex(&m_Vertex2); + addVertex(&m_Vertex3); + addVertex(&m_Vertex4); +} + +void Rectangle::cornerRadiusTLChanged() { markPathDirty(); } +void Rectangle::cornerRadiusTRChanged() { markPathDirty(); } +void Rectangle::cornerRadiusBLChanged() { markPathDirty(); } +void Rectangle::cornerRadiusBRChanged() { markPathDirty(); } + +void Rectangle::update(ComponentDirt value) +{ + if (hasDirt(value, ComponentDirt::Path)) + { + auto radius = cornerRadiusTL(); + auto link = linkCornerRadius(); + + auto ox = -originX() * width(); + auto oy = -originY() * height(); + + m_Vertex1.x(ox); + m_Vertex1.y(oy); + m_Vertex1.radius(radius); + + m_Vertex2.x(ox + width()); + m_Vertex2.y(oy); + m_Vertex2.radius(link ? radius : cornerRadiusTR()); + + m_Vertex3.x(ox + width()); + m_Vertex3.y(oy + height()); + m_Vertex3.radius(link ? radius : cornerRadiusBR()); + + m_Vertex4.x(ox); + m_Vertex4.y(oy + height()); + m_Vertex4.radius(link ? radius : cornerRadiusBL()); + } + + Super::update(value); +} diff --git a/third_party/rive/source/shapes/shape.cpp b/third_party/rive/source/shapes/shape.cpp new file mode 100644 index 0000000..e42aeb9 --- /dev/null +++ b/third_party/rive/source/shapes/shape.cpp @@ -0,0 +1,399 @@ +#include "rive/constraints/constraint.hpp" +#include "rive/hittest_command_path.hpp" +#include "rive/shapes/deformer.hpp" +#include "rive/shapes/path.hpp" +#include "rive/shapes/points_path.hpp" +#include "rive/shapes/shape.hpp" +#include "rive/shapes/clipping_shape.hpp" +#include "rive/shapes/paint/blend_mode.hpp" +#include "rive/shapes/paint/shape_paint.hpp" +#include "rive/shapes/path_composer.hpp" +#include "rive/clip_result.hpp" +#include "rive/math/contour_measure.hpp" +#include "rive/math/raw_path.hpp" +#include + +using namespace rive; + +Shape::Shape() : m_PathComposer(this) {} + +void Shape::addPath(Path* path) +{ + // Make sure the path is not already in the shape. + assert(std::find(m_Paths.begin(), m_Paths.end(), path) == m_Paths.end()); + m_Paths.push_back(path); +} + +void Shape::addFlags(PathFlags flags) { m_pathFlags |= flags; } +bool Shape::isFlagged(PathFlags flags) const +{ + return (int)(pathFlags() & flags) != 0x00; +} + +bool Shape::canDeferPathUpdate() +{ + auto canDefer = + renderOpacity() == 0 && + !isFlagged(PathFlags::clipping | PathFlags::neverDeferUpdate); + if (canDefer) + { + // If we have a dependent Skin, don't defer the update + for (auto d : dependents()) + { + if (d->is() && d->as()->skin() != nullptr) + { + return false; + } + } + } + return canDefer; +} + +void Shape::update(ComponentDirt value) +{ + Super::update(value); + + if (hasDirt(value, ComponentDirt::RenderOpacity)) + { + propagateOpacity(renderOpacity()); + } +} + +bool Shape::collapse(bool value) +{ + if (!Super::collapse(value)) + { + return false; + } + m_PathComposer.collapse(value); + return true; +} + +float Shape::length() +{ + if (m_WorldLength < 0) + { + float l = 0; + for (auto path : m_Paths) + { + RawPath source = path->rawPath().transform(path->pathTransform()); + ContourMeasureIter iter(&source); + while (auto contour = iter.next()) + { + l += contour->length(); + } + } + m_WorldLength = l; + } + return m_WorldLength; +} + +void Shape::pathChanged() +{ + m_PathComposer.addDirt(ComponentDirt::Path, true); + for (auto constraint : constraints()) + { + constraint->addDirt(ComponentDirt::Path); + } + invalidateStrokeEffects(); +} + +void Shape::addToRenderPath(RenderPath* path, const Mat2D& transform) +{ + if (isFlagged(PathFlags::local)) + { + path->addPath(m_PathComposer.localPath()->renderPath(this), + transform * worldTransform()); + } + else + { + path->addPath(m_PathComposer.worldPath()->renderPath(this), transform); + } +} + +void Shape::draw(Renderer* renderer) +{ + if (renderOpacity() == 0.0f) + { + return; + } + ClipResult clipResult = applyClip(renderer); + + if (clipResult != ClipResult::emptyClip) + { + for (auto shapePaint : m_ShapePaints) + { + if (!shapePaint->isVisible()) + { + continue; + } + auto shapePaintPath = shapePaint->pickPath(this); + if (shapePaintPath == nullptr) + { + continue; + } + shapePaint->draw(renderer, shapePaintPath, worldTransform()); + } + } + + if (clipResult != ClipResult::noClip) + { + renderer->restore(); + } +} + +bool Shape::hitTestAABB(const Vec2D& position) +{ + return worldBounds().contains(position); +} + +bool Shape::hitTestHiFi(const Vec2D& position, float hitRadius) +{ + auto hitArea = AABB(position.x - hitRadius, + position.y - hitRadius, + position.x + hitRadius, + position.y + hitRadius) + .round(); + HitTestCommandPath tester(hitArea); + + for (auto path : m_Paths) + { + if (!path->isCollapsed()) + { + tester.setXform(path->pathTransform()); + path->rawPath().addTo(&tester); + } + } + return tester.wasHit(); +} + +Core* Shape::hitTest(HitInfo* hinfo, const Mat2D& xform) +{ + if (renderOpacity() == 0.0f) + { + return nullptr; + } + + // TODO: clip: + + const bool shapeIsLocal = + isFlagged(PathFlags::local | PathFlags::localClockwise); + + for (auto rit = m_ShapePaints.rbegin(); rit != m_ShapePaints.rend(); ++rit) + { + auto shapePaint = *rit; + if (shapePaint->isTranslucent()) + { + continue; + } + if (!shapePaint->isVisible()) + { + continue; + } + + auto paintIsLocal = + shapePaint->isFlagged(PathFlags::local | PathFlags::localClockwise); + + auto mx = xform; + if (paintIsLocal) + { + mx *= worldTransform(); + } + + HitTestCommandPath tester(hinfo->area); + + for (auto path : m_Paths) + { + if (shapeIsLocal) + { + tester.setXform(xform * path->pathTransform()); + } + else + { + tester.setXform(mx * path->pathTransform()); + } + path->rawPath().addTo(&tester); + } + if (tester.wasHit()) + { + return this; + } + } + return nullptr; +} + +void Shape::buildDependencies() +{ + // Make sure to propagate the call to PathComposer as it's no longer part of + // Core and owned only by the Shape. + m_PathComposer.buildDependencies(); + + Super::buildDependencies(); + + // Set the blend mode on all the shape paints. If we ever animate this + // property, we'll need to update it in the update cycle/mark dirty when the + // blend mode changes. + for (auto paint : m_ShapePaints) + { + paint->blendMode(blendMode()); + } +} + +StatusCode Shape::onAddedDirty(CoreContext* context) +{ + auto code = Super::onAddedDirty(context); + if (code != StatusCode::Ok) + { + return code; + } + // This ensures context propagates to path composer too. + return m_PathComposer.onAddedDirty(context); +} + +StatusCode Shape::onAddedClean(CoreContext* context) +{ + StatusCode code = Super::onAddedClean(context); + if (code != StatusCode::Ok) + { + return code; + } + + // Find the deformer, if any. + m_deformer = nullptr; + for (auto currentParent = parent(); currentParent != nullptr; + currentParent = currentParent->parent()) + { + RenderPathDeformer* deformer = RenderPathDeformer::from(currentParent); + if (deformer) + { + m_deformer = deformer; + return StatusCode::Ok; + } + } + + return StatusCode::Ok; +} + +bool Shape::isEmpty() +{ + for (auto path : m_Paths) + { + if (!path->isHidden() && !path->isCollapsed()) + { + return false; + } + } + return true; +} + +// Do constraints need to be marked as dirty too? From tests it doesn't seem +// they do. +void Shape::pathCollapseChanged() { m_PathComposer.pathCollapseChanged(); } + +class ComputeBoundsCommandPath : public CommandPath +{ +public: + ComputeBoundsCommandPath() {} + + AABB bounds(const Mat2D& xform) + { + m_rawPath.transformInPlace(xform); + return m_rawPath.bounds(); + } + + void rewind() override { m_rawPath.rewind(); } + void fillRule(FillRule value) override {} + void addPath(CommandPath* path, const Mat2D& transform) override + { + assert(false); + } + + void moveTo(float x, float y) override { m_rawPath.moveTo(x, y); } + void lineTo(float x, float y) override { m_rawPath.lineTo(x, y); } + void cubicTo(float ox, float oy, float ix, float iy, float x, float y) + override + { + m_rawPath.cubicTo(ox, oy, ix, iy, x, y); + } + void close() override { m_rawPath.close(); } + + RenderPath* renderPath() override + { + assert(false); + return nullptr; + } + + const RenderPath* renderPath() const override + { + assert(false); + return nullptr; + } + +private: + RawPath m_rawPath; +}; + +AABB Shape::computeWorldBounds(const Mat2D* xform) const +{ + bool first = true; + AABB computedBounds = AABB::forExpansion(); + + ComputeBoundsCommandPath boundsCalculator; + for (auto path : m_Paths) + { + if (path->isCollapsed()) + { + continue; + } + path->rawPath().addTo(&boundsCalculator); + + AABB aabb = boundsCalculator.bounds( + xform == nullptr ? path->pathTransform() + : path->pathTransform() * *xform); + + if (first) + { + first = false; + computedBounds = aabb; + } + else + { + computedBounds.expand(aabb); + } + boundsCalculator.rewind(); + } + + return computedBounds; +} + +AABB Shape::computeLocalBounds() const +{ + const Mat2D& world = worldTransform(); + Mat2D inverseWorld = world.invertOrIdentity(); + return computeWorldBounds(&inverseWorld); +} + +Vec2D Shape::measureLayout(float width, + LayoutMeasureMode widthMode, + float height, + LayoutMeasureMode heightMode) +{ + Vec2D size = Vec2D(); + for (auto path : m_Paths) + { + Vec2D measured = + path->measureLayout(width, widthMode, height, heightMode); + size = + Vec2D(std::max(size.x, measured.x), std::max(size.y, measured.y)); + } + return size; +} + +ShapePaintPath* Shape::worldPath() { return m_PathComposer.worldPath(); } +ShapePaintPath* Shape::localPath() { return m_PathComposer.localPath(); } +ShapePaintPath* Shape::localClockwisePath() +{ + return m_PathComposer.localClockwisePath(); +} + +Component* Shape::pathBuilder() { return &m_PathComposer; } \ No newline at end of file diff --git a/third_party/rive/source/shapes/shape_paint_container.cpp b/third_party/rive/source/shapes/shape_paint_container.cpp new file mode 100644 index 0000000..2d8f090 --- /dev/null +++ b/third_party/rive/source/shapes/shape_paint_container.cpp @@ -0,0 +1,75 @@ +#include "rive/shapes/shape_paint_container.hpp" +#include "rive/artboard.hpp" +#include "rive/factory.hpp" +#include "rive/component.hpp" +#include "rive/layout_component.hpp" +#include "rive/foreground_layout_drawable.hpp" +#include "rive/shapes/paint/stroke.hpp" +#include "rive/shapes/shape.hpp" +#include "rive/text/text_style_paint.hpp" +#include "rive/text/text_input_selected_text.hpp" +#include "rive/text/text_input_cursor.hpp" +#include "rive/text/text_input_selection.hpp" +#include "rive/text/text_input_text.hpp" + +using namespace rive; + +ShapePaintContainer* ShapePaintContainer::from(Component* component) +{ + switch (component->coreType()) + { + case Artboard::typeKey: + return component->as(); + case LayoutComponent::typeKey: + return component->as(); + case Shape::typeKey: + return component->as(); + case TextStylePaint::typeKey: + return component->as(); + case ForegroundLayoutDrawable::typeKey: + return component->as(); + case TextInputCursor::typeKey: + return component->as(); + case TextInputSelection::typeKey: + return component->as(); + case TextInputText::typeKey: + return component->as(); + case TextInputSelectedText::typeKey: + return component->as(); + } + return nullptr; +} + +void ShapePaintContainer::addPaint(ShapePaint* paint) +{ + m_ShapePaints.push_back(paint); +} + +PathFlags ShapePaintContainer::pathFlags() const +{ + PathFlags space = m_pathFlags; + for (auto paint : m_ShapePaints) + { + space |= paint->pathFlags(); + } + return space; +} + +void ShapePaintContainer::invalidateStrokeEffects() +{ + for (auto paint : m_ShapePaints) + { + if (paint->is()) + { + paint->as()->invalidateEffects(); + } + } +} + +void ShapePaintContainer::propagateOpacity(float opacity) +{ + for (auto shapePaint : m_ShapePaints) + { + shapePaint->renderOpacity(opacity); + } +} diff --git a/third_party/rive/source/shapes/slice_mesh.cpp b/third_party/rive/source/shapes/slice_mesh.cpp new file mode 100644 index 0000000..22e96b2 --- /dev/null +++ b/third_party/rive/source/shapes/slice_mesh.cpp @@ -0,0 +1,391 @@ +#include "rive/artboard.hpp" +#include "rive/assets/image_asset.hpp" +#include "rive/factory.hpp" +#include "rive/layout/axis.hpp" +#include "rive/layout/n_slicer.hpp" +#include "rive/layout/n_slicer_tile_mode.hpp" +#include "rive/math/math_types.hpp" +#include "rive/math/n_slicer_helpers.hpp" +#include "rive/shapes/image.hpp" +#include "rive/shapes/slice_mesh.hpp" + +using namespace rive; + +const Corner SliceMesh::patchCorners[] = { + {0, 0}, + {1, 0}, + {1, 1}, + {0, 1}, +}; + +const uint16_t SliceMesh::triangulation[] = {0, 1, 3, 1, 2, 3}; + +SliceMesh::SliceMesh(NSlicer* nslicer) : m_nslicer(nslicer) {} + +void SliceMesh::draw(Renderer* renderer, + const RenderImage* renderImage, + ImageSampler ImageSampler, + BlendMode blendMode, + float opacity) +{ + if (m_nslicer == nullptr || m_nslicer->image() == nullptr) + { + return; + } + if (!m_VertexRenderBuffer || !m_UVRenderBuffer || !m_IndexRenderBuffer) + { + return; + } + Image* image = m_nslicer->image(); + renderer->transform(image->worldTransform()); + renderer->translate(-image->width() * image->originX(), + -image->height() * image->originY()); + renderer->drawImageMesh(renderImage, + ImageSampler, + m_VertexRenderBuffer, + m_UVRenderBuffer, + m_IndexRenderBuffer, + static_cast(m_vertices.size()), + static_cast(m_indices.size()), + blendMode, + opacity); +} + +void SliceMesh::onAssetLoaded(RenderImage* renderImage) {} + +void SliceMesh::updateBuffers() +{ + auto factory = m_nslicer->artboard()->factory(); + + // 1. vertex render buffer + size_t vertexSizeInBytes = m_vertices.size() * sizeof(Vec2D); + if (m_VertexRenderBuffer != nullptr && + m_VertexRenderBuffer->sizeInBytes() != vertexSizeInBytes) + { + m_VertexRenderBuffer = nullptr; + } + + if (m_VertexRenderBuffer == nullptr && vertexSizeInBytes != 0) + { + m_VertexRenderBuffer = + factory->makeRenderBuffer(RenderBufferType::vertex, + RenderBufferFlags::none, // optimization? + vertexSizeInBytes); + } + + if (m_VertexRenderBuffer) + { + Vec2D* mappedVertices = + reinterpret_cast(m_VertexRenderBuffer->map()); + for (auto v : m_vertices) + { + *mappedVertices++ = v; + } + m_VertexRenderBuffer->unmap(); + } + + // 2. uv render buffer + size_t uvSizeInBytes = m_uvs.size() * sizeof(Vec2D); + if (m_UVRenderBuffer != nullptr && + m_UVRenderBuffer->sizeInBytes() != uvSizeInBytes) + { + m_UVRenderBuffer = nullptr; + } + + if (m_UVRenderBuffer == nullptr && uvSizeInBytes != 0) + { + m_UVRenderBuffer = factory->makeRenderBuffer(RenderBufferType::vertex, + RenderBufferFlags::none, + uvSizeInBytes); + } + + if (m_UVRenderBuffer) + { + auto renderImage = m_nslicer->image()->imageAsset()->renderImage(); + Mat2D uvTransform = + renderImage != nullptr ? renderImage->uvTransform() : Mat2D(); + + Vec2D* mappedUVs = reinterpret_cast(m_UVRenderBuffer->map()); + for (auto uv : m_uvs) + { + Vec2D xformedUV = uvTransform * uv; + *mappedUVs++ = xformedUV; + } + m_UVRenderBuffer->unmap(); + } + + // 3. index render buffer + size_t indexSizeInBytes = m_indices.size() * sizeof(uint16_t); + if (m_IndexRenderBuffer != nullptr && + m_IndexRenderBuffer->sizeInBytes() != indexSizeInBytes) + { + m_IndexRenderBuffer = nullptr; + } + + if (m_IndexRenderBuffer == nullptr && indexSizeInBytes != 0) + { + m_IndexRenderBuffer = factory->makeRenderBuffer(RenderBufferType::index, + RenderBufferFlags::none, + indexSizeInBytes); + } + + if (m_IndexRenderBuffer) + { + void* mappedIndex = m_IndexRenderBuffer->map(); + memcpy(mappedIndex, m_indices.data(), indexSizeInBytes); + m_IndexRenderBuffer->unmap(); + } +} + +std::vector SliceMesh::uvStops(AxisType forAxis) +{ + float imageSize = forAxis == AxisType::X ? m_nslicer->image()->width() + : m_nslicer->image()->height(); + float imageScale = + std::abs(forAxis == AxisType::X ? m_nslicer->image()->scaleX() + : m_nslicer->image()->scaleY()); + if (imageSize == 0 || imageScale == 0) + { + return {}; + } + + const std::vector& axes = + (forAxis == AxisType::X) ? m_nslicer->xs() : m_nslicer->ys(); + + return NSlicerHelpers::uvStops(axes, imageSize); +} + +std::vector SliceMesh::vertexStops( + const std::vector& normalizedStops, + AxisType forAxis) +{ + Image* image = m_nslicer->image(); + float imageSize = forAxis == AxisType::X ? image->width() : image->height(); + + // When doing calcualtions, we assume scale is always non-negative to keep + // everything in image space. + float imageScale = + std::abs(forAxis == AxisType::X ? image->scaleX() : image->scaleY()); + if (imageSize == 0 || imageScale == 0) + { + return {}; + } + + ScaleInfo scaleInfo = + NSlicerHelpers::analyzeUVStops(normalizedStops, imageSize, imageScale); + + std::vector vertices; + float vertex = 0.0; + float vertexInBounds = 0.0; + + for (int i = 0; i < (int)normalizedStops.size() - 1; i++) + { + vertices.emplace_back(vertexInBounds); + float segment = imageSize * + (normalizedStops[i + 1] - normalizedStops[i]) / + imageScale; + if (NSlicerHelpers::isFixedSegment(i)) + { + vertex += segment; + } + else + { + if (scaleInfo.useScale) + { + vertex += segment * scaleInfo.scaleFactor; + } + else + { + vertex += scaleInfo.fallbackSize; + } + } + vertexInBounds = math::clamp(vertex, 0, imageSize); + } + vertices.emplace_back(vertexInBounds); + return vertices; +} + +uint16_t SliceMesh::tileRepeat(std::vector& vertices, + std::vector& indices, + const std::vector& box, + uint16_t start) +{ + assert(box.size() == 4); + + const float startX = box[0].vertex.x; + const float startY = box[0].vertex.y; + const float endX = box[2].vertex.x; + const float endY = box[2].vertex.y; + + const float startU = box[0].uv.x; + const float startV = box[0].uv.y; + const float endU = box[2].uv.x; + const float endV = box[2].uv.y; + + // The size of each repeated tile in image space + Image* image = m_nslicer->image(); + float scaleX = std::abs(image->scaleX()); + float scaleY = std::abs(image->scaleY()); + + if (scaleX == 0 || scaleY == 0) + { + return 0; + } + + const float sizeX = image->width() * (endU - startU) / scaleX; + const float sizeY = image->height() * (endV - startV) / scaleY; + + if (std::abs(sizeX) < 1 || std::abs(sizeY) < 1) + { + return 0; + } + + float curX = startX; + float curY = startY; + int curV = start; + + int escape = 10000; + while (curY < endY && escape > 0) + { + escape--; + float fracY = (curY + sizeY) > endY ? (endY - curY) / sizeY : 1; + curX = startX; + while (curX < endX && escape > 0) + { + escape--; + int v0 = curV; + float fracX = (curX + sizeX) > endX ? (endX - curX) / sizeX : 1; + + std::vector curTile; + float endU1 = startU + (endU - startU) * fracX; + float endV1 = startV + (endV - startV) * fracY; + float endX1 = curX + sizeX * fracX; + float endY1 = curY + sizeY * fracY; + + // top left + SliceMeshVertex v = SliceMeshVertex(); + v.id = curV++; + v.uv = Vec2D(startU, startV); + v.vertex = Vec2D(curX, curY); + curTile.emplace_back(v); + + // top right + v = SliceMeshVertex(); + v.id = curV++; + v.uv = Vec2D(endU1, startV); + v.vertex = Vec2D(endX1, curY); + curTile.emplace_back(v); + + // bottom right + v = SliceMeshVertex(); + v.id = curV++; + v.uv = Vec2D(endU1, endV1); + v.vertex = Vec2D(endX1, endY1); + curTile.emplace_back(v); + + // bottom left + v = SliceMeshVertex(); + v.id = curV++; + v.uv = Vec2D(startU, endV1); + v.vertex = Vec2D(curX, endY1); + curTile.emplace_back(v); + + // Commit the four vertices, and the triangulation + vertices.insert(vertices.end(), curTile.begin(), curTile.end()); + for (uint16_t t : triangulation) + { + indices.emplace_back(v0 + t); + } + + curX += sizeX; + } + curY += sizeY; + } + return curV - start; +} + +void SliceMesh::calc() +{ + m_vertices = {}; + m_indices = {}; + m_uvs = {}; + + std::vector us = uvStops(AxisType::X); + std::vector vs = uvStops(AxisType::Y); + std::vector xs = vertexStops(us, AxisType::X); + std::vector ys = vertexStops(vs, AxisType::Y); + const auto& tileModes = m_nslicer->tileModes(); + + std::vector vertices; + uint16_t vertexIndex = 0; + for (int patchY = 0; patchY < (int)vs.size() - 1; patchY++) + { + for (int patchX = 0; patchX < (int)us.size() - 1; patchX++) + { + auto tileModeIt = + tileModes.find(m_nslicer->patchIndex(patchX, patchY)); + auto tileMode = tileModeIt == tileModes.end() + ? NSlicerTileModeType::STRETCH + : tileModeIt->second; + + // Do nothing if hidden + if (tileMode == NSlicerTileModeType::HIDDEN) + { + continue; + } + + const uint16_t v0 = vertexIndex; + std::vector patchVertices; + for (const Corner& corner : patchCorners) + { + int xIndex = patchX + corner.x; + int yIndex = patchY + corner.y; + + SliceMeshVertex v; + if (tileMode != NSlicerTileModeType::REPEAT) + { + v.id = vertexIndex++; + } + v.uv = Vec2D(us[xIndex], vs[yIndex]); + v.vertex = Vec2D(xs[xIndex], ys[yIndex]); + + patchVertices.emplace_back(v); + } + + if (tileMode == NSlicerTileModeType::REPEAT) + { + vertexIndex += + tileRepeat(vertices, m_indices, patchVertices, v0); + } + else + { + vertices.insert(vertices.end(), + patchVertices.begin(), + patchVertices.end()); + for (uint16_t t : triangulation) + { + m_indices.emplace_back(v0 + t); + } + } + } + } + + for (const SliceMeshVertex& v : vertices) + { + m_vertices.emplace_back(v.vertex); + m_uvs.emplace_back(v.uv); + } +} + +void SliceMesh::update() +{ + // Make sure the image is loaded + if (m_nslicer == nullptr || m_nslicer->image() == nullptr || + m_nslicer->image()->imageAsset() == nullptr) + { + return; + } + + calc(); + updateBuffers(); +} diff --git a/third_party/rive/source/shapes/star.cpp b/third_party/rive/source/shapes/star.cpp new file mode 100644 index 0000000..20723d8 --- /dev/null +++ b/third_party/rive/source/shapes/star.cpp @@ -0,0 +1,47 @@ +#include "rive/shapes/star.hpp" +#include "rive/shapes/straight_vertex.hpp" +#include "rive/math/math_types.hpp" +#include +#include + +using namespace rive; + +Star::Star() {} + +void Star::innerRadiusChanged() { markPathDirty(); } + +std::size_t Star::vertexCount() { return points() * 2; } + +void Star::buildPolygon() +{ + auto halfWidth = width() / 2; + auto halfHeight = height() / 2; + auto innerHalfWidth = width() * innerRadius() / 2; + auto innerHalfHeight = height() * innerRadius() / 2; + auto ox = -originX() * width() + halfWidth; + auto oy = -originY() * height() + halfHeight; + + std::size_t length = vertexCount(); + auto angle = -math::PI / 2; + auto inc = 2 * math::PI / length; + + for (std::size_t i = 0; i < length; i += 2) + { + { + StraightVertex& vertex = m_PolygonVertices[i]; + vertex.x(ox + cos(angle) * halfWidth); + vertex.y(oy + sin(angle) * halfHeight); + vertex.radius(cornerRadius()); + angle += inc; + } + { + StraightVertex& vertex = m_PolygonVertices[i + 1]; + vertex.x(ox + cos(angle) * innerHalfWidth); + vertex.y(oy + sin(angle) * innerHalfHeight); + vertex.radius(cornerRadius()); + angle += inc; + } + } +} + +void Star::update(ComponentDirt value) { Super::update(value); } diff --git a/third_party/rive/source/shapes/straight_vertex.cpp b/third_party/rive/source/shapes/straight_vertex.cpp new file mode 100644 index 0000000..30c30cd --- /dev/null +++ b/third_party/rive/source/shapes/straight_vertex.cpp @@ -0,0 +1,5 @@ +#include "rive/shapes/straight_vertex.hpp" + +using namespace rive; + +void StraightVertex::radiusChanged() { markGeometryDirty(); } diff --git a/third_party/rive/source/shapes/triangle.cpp b/third_party/rive/source/shapes/triangle.cpp new file mode 100644 index 0000000..6b9ca51 --- /dev/null +++ b/third_party/rive/source/shapes/triangle.cpp @@ -0,0 +1,32 @@ +#include "rive/shapes/triangle.hpp" +#include "rive/component_dirt.hpp" +#include "rive/math/circle_constant.hpp" + +using namespace rive; + +Triangle::Triangle() +{ + addVertex(&m_Vertex1); + addVertex(&m_Vertex2); + addVertex(&m_Vertex3); +} + +void Triangle::update(ComponentDirt value) +{ + if (hasDirt(value, ComponentDirt::Path)) + { + auto ox = -originX() * width(); + auto oy = -originY() * height(); + + m_Vertex1.x(ox + width() / 2); + m_Vertex1.y(oy); + + m_Vertex2.x(ox + width()); + m_Vertex2.y(oy + height()); + + m_Vertex3.x(ox); + m_Vertex3.y(oy + height()); + } + + Super::update(value); +} \ No newline at end of file diff --git a/third_party/rive/source/shapes/vertex.cpp b/third_party/rive/source/shapes/vertex.cpp new file mode 100644 index 0000000..477122d --- /dev/null +++ b/third_party/rive/source/shapes/vertex.cpp @@ -0,0 +1,24 @@ +#include "rive/shapes/vertex.hpp" + +using namespace rive; + +Vec2D Vertex::renderTranslation() +{ + if (hasWeight()) + { + return m_Weight->translation(); + } + return Vec2D(x(), y()); +} + +void Vertex::xChanged() { markGeometryDirty(); } +void Vertex::yChanged() { markGeometryDirty(); } + +void Vertex::deform(const Mat2D& worldTransform, const float* boneTransforms) +{ + m_Weight->translation() = Weight::deform(Vec2D(x(), y()), + m_Weight->indices(), + m_Weight->values(), + worldTransform, + boneTransforms); +} \ No newline at end of file diff --git a/third_party/rive/source/simple_array.cpp b/third_party/rive/source/simple_array.cpp new file mode 100644 index 0000000..095ee22 --- /dev/null +++ b/third_party/rive/source/simple_array.cpp @@ -0,0 +1,19 @@ +#ifdef TESTING +#include "rive/simple_array.hpp" +namespace rive +{ +namespace SimpleArrayTesting +{ +int mallocCount = 0; +int reallocCount = 0; +int freeCount = 0; +void resetCounters() +{ + mallocCount = 0; + reallocCount = 0; + freeCount = 0; +} +} // namespace SimpleArrayTesting +} // namespace rive + +#endif \ No newline at end of file diff --git a/third_party/rive/source/solo.cpp b/third_party/rive/source/solo.cpp new file mode 100644 index 0000000..4eb0859 --- /dev/null +++ b/third_party/rive/source/solo.cpp @@ -0,0 +1,54 @@ +#include "rive/solo.hpp" +#include "rive/constraints/constraint.hpp" +#include "rive/shapes/clipping_shape.hpp" +#include "rive/artboard.hpp" + +using namespace rive; + +void Solo::propagateCollapse(bool collapse) +{ + Core* active = + collapse ? nullptr : artboard()->resolve(activeComponentId()); + for (Component* child : children()) + { + // Some child components shouldn't be considered as part of the solo set + // as they are more aking to properties of the solo itself. For those + // components, simply pass on the collapse value of the solo itself. + if (child->is() || child->is()) + { + child->collapse(collapse); + continue; + } + + // This child is part of the solo set so only make it active if it's the + // currently marked solo object. + child->collapse(child != active); + } +} + +bool Solo::collapse(bool value) +{ + // Intentionally using Component instead of Super as we don't want to call + // collapse on the Container logic which just propagates blindly to + // children. + if (!Component::collapse(value)) + { + return false; + } + propagateCollapse(value); + return true; +} + +void Solo::activeComponentIdChanged() { propagateCollapse(isCollapsed()); } + +StatusCode Solo::onAddedClean(CoreContext* context) +{ + StatusCode code = Super::onAddedClean(context); + if (code != StatusCode::Ok) + { + return code; + } + + propagateCollapse(isCollapsed()); + return StatusCode::Ok; +} \ No newline at end of file diff --git a/third_party/rive/source/static_scene.cpp b/third_party/rive/source/static_scene.cpp new file mode 100644 index 0000000..9f8ecb5 --- /dev/null +++ b/third_party/rive/source/static_scene.cpp @@ -0,0 +1,26 @@ +#include "rive/static_scene.hpp" +#include "rive/artboard.hpp" + +using namespace rive; + +StaticScene::StaticScene(ArtboardInstance* instance) : Scene(instance) {} + +StaticScene::~StaticScene() {} + +bool StaticScene::isTranslucent() const +{ + return m_artboardInstance->isTranslucent(); +}; + +std::string StaticScene::name() const { return m_artboardInstance->name(); }; + +Loop StaticScene::loop() const { return Loop::oneShot; }; + +float StaticScene::durationSeconds() const { return 0; } + +bool StaticScene::advanceAndApply(float seconds) +{ + // We ignore the 'seconds' argument because it's not an animated scene + m_artboardInstance->advance(0); + return true; +}; \ No newline at end of file diff --git a/third_party/rive/source/text/cursor.cpp b/third_party/rive/source/text/cursor.cpp new file mode 100644 index 0000000..3ebe4f7 --- /dev/null +++ b/third_party/rive/source/text/cursor.cpp @@ -0,0 +1,360 @@ +#include "rive/text/cursor.hpp" +#ifdef WITH_RIVE_TEXT +using namespace rive; + +static uint32_t absDiffUint(uint32_t a, uint32_t b) +{ + return a > b ? a - b : b - a; +} + +static uint32_t subtractUint32(uint32_t a, uint32_t b) +{ + return a > b ? a - b : 0; +} + +CursorVisualPosition CursorPosition::visualPosition( + const FullyShapedText& shape) const +{ + const GlyphLookup& glyphLookup = shape.glyphLookup(); + const std::vector& orderedLines = shape.orderedLines(); + + uint32_t targetIndex = glyphLookup[m_codePointIndex]; + if (m_lineIndex < 0 || m_lineIndex >= orderedLines.size()) + { + return CursorVisualPosition::missing(); + } + const OrderedLine& orderedLine = orderedLines[m_lineIndex]; + + const GlyphLine& line = orderedLine.glyphLine(); + float x = line.startX; + + // Iterate each glyph and see if it's the one we're looking for. + bool haveFirstIndex = false; + uint32_t firstTextIndex = 0, lastTextIndex = 0; + for (auto glyphItr : orderedLine) + { + const GlyphRun* run = std::get<0>(glyphItr); + size_t glyphIndex = std::get<1>(glyphItr); + float advance = run->advances[glyphIndex]; + + if (advance != 0 && + targetIndex == glyphLookup[run->textIndices[glyphIndex]]) + { + x += advance * + glyphLookup.advanceFactor(m_codePointIndex, + run->dir() == TextDirection::rtl); + + const Font* font = run->font.get(); + return CursorVisualPosition( + x, + orderedLine.y() + font->ascent(run->size), + orderedLine.y() + font->descent(run->size)); + } + else + { + if (!haveFirstIndex) + { + firstTextIndex = lastTextIndex = run->textIndices[glyphIndex]; + haveFirstIndex = true; + } + else + { + lastTextIndex = run->textIndices[glyphIndex]; + } + x += advance; + } + } + + // Didn't find the glyph, we're at the end of the line. + const GlyphRun* run = orderedLine.lastRun(); + const Font* font = run->font.get(); + + return CursorVisualPosition( + absDiffUint(m_codePointIndex, firstTextIndex) < + absDiffUint(m_codePointIndex, lastTextIndex) + ? line.startX + : x, + orderedLine.y() + font->ascent(run->size), + orderedLine.y() + font->descent(run->size)); +} + +CursorPosition CursorPosition::fromTranslation(const Vec2D translation, + const FullyShapedText& shape) +{ + const std::vector& orderedLines = shape.orderedLines(); + if (orderedLines.empty()) + { + return CursorPosition::zero(); + } + + uint32_t lineIndex = 0; + uint32_t maxLine = (uint32_t)(orderedLines.size() - 1); + for (const OrderedLine& orderedLine : orderedLines) + { + if (orderedLine.bottom() < translation.y && lineIndex != maxLine) + { + lineIndex++; + continue; + } + return fromOrderedLine(orderedLine, lineIndex, translation.x, shape); + } + + return CursorPosition::zero(); +} + +CursorPosition CursorPosition::fromOrderedLine(const OrderedLine& orderedLine, + uint32_t lineIndex, + float translationX, + const FullyShapedText& shape) +{ + const GlyphLookup& glyphLookup = shape.glyphLookup(); + + float x = orderedLine.glyphLine().startX; + /// Iterate each glyph and see if it's the one we're looking for. + auto end = orderedLine.end(); + GlyphItr lastGlyphItr = orderedLine.begin(); + for (GlyphItr itr = orderedLine.begin(); itr != end; ++itr) + { + lastGlyphItr = itr; + const GlyphRun* run = itr.run(); + uint32_t glyphIndex = itr.glyphIndex(); + float advance = run->advances[glyphIndex]; + if (translationX <= x + advance) + { + float ratio = + advance == 0.0f + ? 1.0f + : std::max(0.0f, + std::min((translationX - x) / advance, 1.0f)); + uint32_t textIndex = run->textIndices[glyphIndex]; + uint32_t nextTextIndex = textIndex; + uint32_t absoluteGlyphIndex = glyphLookup[textIndex]; + while (nextTextIndex != + subtractUint32((uint32_t)glyphLookup.size(), 1) && + glyphLookup[nextTextIndex] == absoluteGlyphIndex) + { + nextTextIndex++; + } + uint32_t parts = nextTextIndex - textIndex; + uint32_t part = (uint32_t)std::round(ratio * (float)parts); + + return CursorPosition( + lineIndex, + run->dir() == TextDirection::ltr + ? textIndex + part + : (part > nextTextIndex ? 0 : nextTextIndex - part)) + .clamped(shape); + } + else + { + x += advance; + } + } + + const GlyphRun* run = lastGlyphItr.run(); + uint32_t glyphIndex = lastGlyphItr.glyphIndex(); + + uint32_t textIndex = run->textIndices[glyphIndex]; + uint32_t nextTextIndex = textIndex; + uint32_t absoluteGlyphIndex = glyphLookup[textIndex]; + while (nextTextIndex != subtractUint32((uint32_t)glyphLookup.size(), 1) && + glyphLookup[nextTextIndex] == absoluteGlyphIndex) + { + nextTextIndex++; + } + uint32_t parts = nextTextIndex - textIndex; + return CursorPosition(lineIndex, + run->dir() == TextDirection::ltr + ? textIndex + parts + : nextTextIndex - parts) + .clamped(shape); +} + +CursorPosition CursorPosition::fromLineX(uint32_t lineIndex, + float x, + const FullyShapedText& shape) +{ + const std::vector& orderedLines = shape.orderedLines(); + if (lineIndex >= orderedLines.size()) + { + return CursorPosition::zero(); + } + + return fromOrderedLine(orderedLines[lineIndex], lineIndex, x, shape); +} + +uint32_t CursorPosition::lineIndex(int32_t inc) const +{ + if (inc < 0 && (uint32_t)(-inc) > m_lineIndex) + { + return 0; + } + return m_lineIndex + inc; +} + +uint32_t CursorPosition::codePointIndex(int32_t inc) const +{ + if (inc < 0 && (uint32_t)(-inc) > m_codePointIndex) + { + return 0; + } + return m_codePointIndex + inc; +} + +CursorPosition CursorPosition::clamped(const FullyShapedText& shape) const +{ + return CursorPosition( + std::min(m_lineIndex, + subtractUint32((uint32_t)shape.orderedLines().size(), 1)), + std::min(m_codePointIndex, + subtractUint32(shape.glyphLookup().lastCodeUnitIndex(), 1))); +} + +CursorPosition CursorPosition::atIndex(uint32_t codePointIndex, + const FullyShapedText& shape) +{ + // Don't go to actual last code unit index as we always insert a zero width + // space. + // https://en.wikipedia.org/wiki/Zero-width_space + if (codePointIndex >= + subtractUint32(shape.glyphLookup().lastCodeUnitIndex(), 1)) + { + return CursorPosition( + subtractUint32((uint32_t)shape.orderedLines().size(), 1), + subtractUint32(shape.glyphLookup().lastCodeUnitIndex(), 1)); + } + + const SimpleArray& paragraphs = shape.paragraphs(); + const SimpleArray>& paragraphLines = + shape.paragraphLines(); + + uint32_t paragraphIndex = 0; + uint32_t lineIndex = 0; + for (const SimpleArray& lines : paragraphLines) + { + const Paragraph& paragraph = paragraphs[paragraphIndex++]; + for (const GlyphLine& line : lines) + { + const GlyphRun& run = paragraph.runs[line.startRunIndex]; + uint32_t smallestTextIndexInLine = + run.textIndices[line.startGlyphIndex]; + + if (smallestTextIndexInLine <= codePointIndex) + { + lineIndex++; + continue; + } + return CursorPosition(lineIndex - 1, codePointIndex).clamped(shape); + } + } + + return CursorPosition(lineIndex - 1, codePointIndex).clamped(shape); +} + +void Cursor::selectionRects(std::vector& rects, + const FullyShapedText& shape) const +{ + auto firstPosition = first().clamped(shape); + auto lastPosition = last().clamped(shape); + + uint32_t firstLine = firstPosition.lineIndex(); + uint32_t lastLine = lastPosition.lineIndex(); + uint32_t firstCodePointIndex = firstPosition.codePointIndex(); + uint32_t lastCodePointIndex = lastPosition.codePointIndex(); + + const GlyphLookup& glyphLookup = shape.glyphLookup(); + const std::vector& orderedLines = shape.orderedLines(); + for (uint32_t lineIndex = firstLine; lineIndex <= lastLine; lineIndex++) + { + const OrderedLine& orderedLine = orderedLines[lineIndex]; + const GlyphLine& glyphLine = orderedLine.glyphLine(); + float x = glyphLine.startX; + for (auto glyphItr : orderedLine) + { + const GlyphRun* run = std::get<0>(glyphItr); + size_t glyphIndex = std::get<1>(glyphItr); + float advance = run->advances[glyphIndex]; + uint32_t codePointIndex = run->textIndices[glyphIndex]; + uint32_t count = glyphLookup.count(codePointIndex); + uint32_t endCodePointIndex = codePointIndex + count; + float y = orderedLine.y(); + + // Check if this part of this glyph overlaps selection. + if (lastCodePointIndex > codePointIndex && + endCodePointIndex > firstCodePointIndex) + { + uint32_t after = + subtractUint32(firstCodePointIndex, codePointIndex); + uint32_t before = + subtractUint32(endCodePointIndex, lastCodePointIndex); + float startFactor = (float)after / (float)count; + float endFactor = (float)(count - before) / (float)count; + if (run->dir() == TextDirection::rtl) + { + startFactor = 1.0f - startFactor; + endFactor = 1.0f - endFactor; + } + + auto font = run->font; + float left = x + advance * startFactor; + float right = x + advance * endFactor; + if (left > right) + { + float swap = right; + right = left; + left = swap; + } + rects.push_back(AABB(left, + y + font->ascent(run->size), + right, + y + font->descent(run->size))); + } + x += advance; + } + } +} + +void Cursor::updateSelectionPath(ShapePaintPath& path, + const std::vector& rects, + const FullyShapedText& shape) const +{} + +bool Cursor::resolveLinePositions(const FullyShapedText& shape) +{ + bool resolved = false; + if (!m_start.hasLineIndex()) + { + m_start.resolveLine(shape); + resolved = true; + } + if (!m_end.hasLineIndex()) + { + m_end.resolveLine(shape); + resolved = true; + } + return resolved; +} + +void CursorPosition::resolveLine(const FullyShapedText& shape) +{ + const GlyphLookup& glyphLookup = shape.glyphLookup(); + const std::vector& orderedLines = shape.orderedLines(); + + uint32_t lineIndex = 0; + for (const OrderedLine& orderedLine : orderedLines) + { + if (orderedLine.containsCodePointIndex(glyphLookup, m_codePointIndex)) + { + break; + } + lineIndex++; + } + m_lineIndex = lineIndex; +} + +bool Cursor::contains(uint32_t codePointIndex) const +{ + return codePointIndex >= first().codePointIndex() && + codePointIndex < last().codePointIndex(); +} +#endif \ No newline at end of file diff --git a/third_party/rive/source/text/font_hb.cpp b/third_party/rive/source/text/font_hb.cpp new file mode 100644 index 0000000..3db80fa --- /dev/null +++ b/third_party/rive/source/text/font_hb.cpp @@ -0,0 +1,759 @@ +/* + * Copyright 2022 Rive + */ + +#include "rive/text_engine.hpp" + +#ifdef WITH_RIVE_TEXT +#include "rive/text/font_hb.hpp" + +#include "rive/factory.hpp" +#include "rive/renderer_utils.hpp" + +#include "hb.h" +#include "hb-ot.h" +#include + +extern "C" +{ +#include "SheenBidi.h" +} + +// Initialized to null. Client can set this to a callback. +rive::Font::FallbackProc rive::Font::gFallbackProc; + +bool rive::Font::gFallbackProcEnabled = true; + +rive::rcp HBFont::Decode(rive::Span span) +{ + auto blob = hb_blob_create_or_fail((const char*)span.data(), + (unsigned)span.size(), + HB_MEMORY_MODE_DUPLICATE, + nullptr, + nullptr); + if (blob) + { + auto face = hb_face_create(blob, 0); + hb_blob_destroy(blob); + if (face) + { + auto font = hb_font_create(face); + hb_face_destroy(face); + if (font) + { + return rive::rcp(new HBFont(font)); + } + } + } + return nullptr; +} + +#if defined(RIVE_NO_CORETEXT) || !defined(__APPLE__) +rive::rcp HBFont::FromSystem(void* systemFont, + bool useSystemShaper, + uint16_t weight, + uint8_t width) +{ + return nullptr; +} +#endif + +float HBFont::GetStyle(hb_font_t* font, uint32_t styleTag) +{ + return hb_style_get_value(font, (hb_style_tag_t)styleTag); +} +////////////// + +constexpr int kStdScale = 2048; +constexpr float gInvScale = 1.0f / kStdScale; + +extern "C" +{ + static void rpath_move_to(hb_draw_funcs_t*, + void* rpath, + hb_draw_state_t*, + float x, + float y, + void*) + { + ((rive::RawPath*)rpath)->moveTo(x * gInvScale, -y * gInvScale); + } + static void rpath_line_to(hb_draw_funcs_t*, + void* rpath, + hb_draw_state_t*, + float x1, + float y1, + void*) + { + ((rive::RawPath*)rpath)->lineTo(x1 * gInvScale, -y1 * gInvScale); + } + static void rpath_quad_to(hb_draw_funcs_t*, + void* rpath, + hb_draw_state_t*, + float x1, + float y1, + float x2, + float y2, + void*) + { + ((rive::RawPath*)rpath) + ->quadToCubic(x1 * gInvScale, + -y1 * gInvScale, + x2 * gInvScale, + -y2 * gInvScale); + } + static void rpath_cubic_to(hb_draw_funcs_t*, + void* rpath, + hb_draw_state_t*, + float x1, + float y1, + float x2, + float y2, + float x3, + float y3, + void*) + { + ((rive::RawPath*)rpath) + ->cubicTo(x1 * gInvScale, + -y1 * gInvScale, + x2 * gInvScale, + -y2 * gInvScale, + x3 * gInvScale, + -y3 * gInvScale); + } + static void rpath_close(hb_draw_funcs_t*, + void* rpath, + hb_draw_state_t*, + void*) + { + ((rive::RawPath*)rpath)->close(); + } +} + +static rive::Font::LineMetrics make_lmx(hb_font_t* font) +{ + // premable on font... + hb_ot_font_set_funcs(font); + hb_font_set_scale(font, kStdScale, kStdScale); + + hb_font_extents_t extents; + hb_font_get_h_extents(font, &extents); + return {-extents.ascender * gInvScale, -extents.descender * gInvScale}; +} + +HBFont::HBFont(hb_font_t* font) : HBFont(font, {}, {}, {}) {} + +HBFont::HBFont(hb_font_t* font, + std::unordered_map axisValues, + std::unordered_map featureValues, + std::vector features) : + Font(make_lmx(font)), + m_font(font), + m_features(features), + m_featureValues(featureValues), + m_axisValues(axisValues) +{ + m_drawFuncs = hb_draw_funcs_create(); + hb_draw_funcs_set_move_to_func(m_drawFuncs, + rpath_move_to, + nullptr, + nullptr); + hb_draw_funcs_set_line_to_func(m_drawFuncs, + rpath_line_to, + nullptr, + nullptr); + hb_draw_funcs_set_quadratic_to_func(m_drawFuncs, + rpath_quad_to, + nullptr, + nullptr); + hb_draw_funcs_set_cubic_to_func(m_drawFuncs, + rpath_cubic_to, + nullptr, + nullptr); + hb_draw_funcs_set_close_path_func(m_drawFuncs, + rpath_close, + nullptr, + nullptr); + hb_draw_funcs_make_immutable(m_drawFuncs); +} + +HBFont::~HBFont() +{ + hb_draw_funcs_destroy(m_drawFuncs); + hb_font_destroy(m_font); +} + +static void fillLanguageFeatures(hb_face_t* face, + hb_tag_t tag, + uint32_t scriptIndex, + uint32_t languageIndex, + std::unordered_set& features) +{ + auto featureCount = hb_ot_layout_language_get_feature_tags(face, + tag, + scriptIndex, + languageIndex, + 0, + nullptr, + nullptr); + auto featureTags = std::vector(featureCount); + hb_ot_layout_language_get_feature_tags(face, + tag, + scriptIndex, + languageIndex, + 0, + &featureCount, + featureTags.data()); + + for (auto featureTag : featureTags) + { + features.emplace(featureTag); + } +} + +static void fillFeatures(hb_face_t* face, + hb_tag_t tag, + std::unordered_set& features) +{ + auto scriptCount = + hb_ot_layout_table_get_script_tags(face, tag, 0, nullptr, nullptr); + auto scripts = std::vector(scriptCount); + hb_ot_layout_table_get_script_tags(face, + tag, + 0, + &scriptCount, + scripts.data()); + for (uint32_t i = 0; i < scriptCount; ++i) + { + auto languageCount = hb_ot_layout_script_get_language_tags(face, + tag, + i, + 0, + nullptr, + nullptr); + + if (languageCount > 0) + { + auto languages = std::vector(languageCount); + hb_ot_layout_script_get_language_tags(face, + tag, + i, + 0, + &languageCount, + languages.data()); + + for (uint32_t j = 0; j < languageCount; ++j) + { + fillLanguageFeatures(face, tag, i, j, features); + } + } + else + { + fillLanguageFeatures(face, + tag, + i, + HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX, + features); + } + } +} + +rive::SimpleArray HBFont::features() const +{ + std::unordered_set features; + auto face = hb_font_get_face(m_font); + fillFeatures(face, HB_OT_TAG_GSUB, features); + fillFeatures(face, HB_OT_TAG_GPOS, features); + + rive::SimpleArray result(features.size()); + uint32_t index = 0; + for (auto tag : features) + { + result[index++] = tag; + } + return result; +} + +rive::Font::Axis HBFont::getAxis(uint16_t index) const +{ + auto face = hb_font_get_face(m_font); + assert(index < hb_ot_var_get_axis_count(face)); + unsigned n = 1; + hb_ot_var_axis_info_t info; + hb_ot_var_get_axis_infos(face, index, &n, &info); + assert(n == 1); + return {info.tag, info.min_value, info.default_value, info.max_value}; +} + +uint16_t HBFont::getAxisCount() const +{ + auto face = hb_font_get_face(m_font); + return (uint16_t)hb_ot_var_get_axis_count(face); +} + +float HBFont::getAxisValue(uint32_t axisTag) const +{ + auto itr = m_axisValues.find(axisTag); + if (itr != m_axisValues.end()) + { + return itr->second; + } + auto face = hb_font_get_face(m_font); + + // No value specified, we're using a default. + uint32_t axisCount = hb_ot_var_get_axis_count(face); + for (uint32_t i = 0; i < axisCount; ++i) + { + hb_ot_var_axis_info_t info; + uint32_t n = 1; + hb_ot_var_get_axis_infos(face, i, &n, &info); + if (info.tag == axisTag) + { + return info.default_value; + } + } + return 0.0f; +} + +uint32_t HBFont::getFeatureValue(uint32_t featureTag) const +{ + auto itr = m_featureValues.find(featureTag); + if (itr != m_featureValues.end()) + { + return itr->second; + } + return (uint32_t)-1; +} + +uint16_t HBFont::getWeight() const +{ + uint32_t tag = HB_TAG('w', 'g', 'h', 't'); + float res = HBFont::GetStyle(m_font, tag); + return static_cast(res); +} + +bool HBFont::isItalic() const +{ + uint32_t tag = HB_TAG('i', 't', 'a', 'l'); + float res = HBFont::GetStyle(m_font, tag); + return res != 0.0; +} + +rive::rcp HBFont::withOptions( + rive::Span coords, + rive::Span features) const +{ + // Merges previous options with current ones. + std::unordered_map axisValues = m_axisValues; + for (size_t i = 0; i < coords.size(); ++i) + { + axisValues[coords[i].axis] = coords[i].value; + } + + AutoSTArray<16, hb_variation_t> vars(axisValues.size()); + size_t i = 0; + for (auto itr = axisValues.begin(); itr != axisValues.end(); itr++) + { + vars[i++] = {itr->first, itr->second}; + } + + auto font = hb_font_create_sub_font(m_font); + hb_font_set_variations(font, vars.data(), (unsigned int)vars.size()); + std::vector hbFeatures; + std::unordered_map featureValues = m_featureValues; + for (auto feature : features) + { + featureValues[feature.tag] = feature.value; + } + for (auto itr = featureValues.begin(); itr != featureValues.end(); itr++) + { + hbFeatures.push_back({itr->first, + itr->second, + HB_FEATURE_GLOBAL_START, + HB_FEATURE_GLOBAL_END}); + } + + return rive::rcp( + new HBFont(font, axisValues, featureValues, hbFeatures)); +} + +rive::RawPath HBFont::getPath(rive::GlyphID glyph) const +{ + rive::RawPath rpath; + hb_font_draw_glyph(m_font, glyph, m_drawFuncs, &rpath); + return rpath; +} + +/////////////////////////////////////////////////////////// + +static rive::GlyphRun shape_run(const rive::Unichar text[], + const rive::TextRun& tr, + unsigned textOffset) +{ + hb_buffer_t* buf = hb_buffer_create(); + hb_buffer_add_utf32(buf, text, tr.unicharCount, 0, tr.unicharCount); + + hb_buffer_set_direction(buf, + tr.level & 1 ? HB_DIRECTION_RTL : HB_DIRECTION_LTR); + hb_buffer_set_script(buf, (hb_script_t)tr.script); + hb_buffer_set_language(buf, hb_language_get_default()); + + auto hbfont = (HBFont*)tr.font.get(); + + hb_shape(hbfont->m_font, + buf, + hbfont->m_features.data(), + (unsigned int)hbfont->m_features.size()); + + unsigned int glyph_count; + hb_glyph_info_t* glyph_info = hb_buffer_get_glyph_infos(buf, &glyph_count); + hb_glyph_position_t* glyph_pos = + hb_buffer_get_glyph_positions(buf, &glyph_count); + + // todo: check for missing glyphs, and perform font-substitution + rive::GlyphRun gr(glyph_count); + gr.font = tr.font; + gr.size = tr.size; + gr.lineHeight = tr.lineHeight; + gr.letterSpacing = tr.letterSpacing; + gr.styleId = tr.styleId; + gr.level = tr.level; + + const float scale = tr.size / kStdScale; + for (unsigned int i = 0; i < glyph_count; i++) + { + unsigned int index = tr.level & 1 ? glyph_count - 1 - i : i; + gr.glyphs[i] = (uint16_t)glyph_info[index].codepoint; + gr.textIndices[i] = textOffset + glyph_info[index].cluster; + gr.advances[i] = gr.xpos[i] = + glyph_pos[index].x_advance * scale + tr.letterSpacing; + gr.offsets[i] = rive::Vec2D(glyph_pos[index].x_offset * scale, + -glyph_pos[index].y_offset * scale); + } + gr.xpos[glyph_count] = 0; // so the next run can line up snug + hb_buffer_destroy(buf); + return gr; +} + +static rive::GlyphRun extract_subset(const rive::GlyphRun& orig, + size_t start, + size_t end) +{ + auto count = end - start; + rive::GlyphRun subset( + rive::SimpleArray(&orig.glyphs[start], count), + rive::SimpleArray(&orig.textIndices[start], count), + rive::SimpleArray(&orig.advances[start], count), + rive::SimpleArray(&orig.xpos[start], count + 1), + rive::SimpleArray(&orig.offsets[start], count)); + subset.font = std::move(orig.font); + subset.size = orig.size; + subset.lineHeight = orig.lineHeight; + subset.letterSpacing = orig.letterSpacing; + subset.level = orig.level; + subset.xpos.back() = 0; // since we're now the end of a run + subset.styleId = orig.styleId; + + return subset; +} + +static void perform_fallback(rive::rcp fallbackFont, + rive::SimpleArrayBuilder& gruns, + const rive::Unichar text[], + const rive::GlyphRun& orig, + const rive::TextRun& origTextRun, + const uint32_t fallbackIndex) +{ + assert(orig.glyphs.size() > 0); + const size_t count = orig.glyphs.size(); + size_t startI = 0; + while (startI < count) + { + size_t endI = startI + 1; + if (orig.glyphs[startI] == 0) + { + while (endI < count && orig.glyphs[endI] == 0) + { + ++endI; + } + auto textStart = orig.textIndices[startI]; + auto textCount = orig.textIndices[endI - 1] - textStart + 1; + auto tr = rive::TextRun{ + fallbackFont, + orig.size, + orig.lineHeight, + origTextRun.letterSpacing, + textCount, + origTextRun.script, + orig.styleId, + orig.level, + }; + + static_cast(fallbackFont.get()) + ->shapeFallbackRun(gruns, + text, + textStart, + tr, + origTextRun, + fallbackIndex); + } + else + { + while (endI < count && orig.glyphs[endI] != 0) + { + ++endI; + } + gruns.add(extract_subset(orig, startI, endI)); + } + startI = endI; + } +} + +void HBFont::shapeFallbackRun(rive::SimpleArrayBuilder& gruns, + const rive::Unichar text[], + const unsigned textStart, + const rive::TextRun& textRun, + const rive::TextRun& originalTextRun, + const uint32_t fallbackIndex) +{ + auto gr = shape_run(&text[textStart], textRun, textStart); + auto end = gr.glyphs.end(); + auto iter = std::find(gr.glyphs.begin(), end, 0); + if (iter == end) + { + if (gr.glyphs.size() > 0) + { + gruns.add(std::move(gr)); + } + } + else + { + // found at least 1 zero in glyphs, so need to perform + // font-fallback + size_t index = iter - gr.glyphs.begin(); + rive::Unichar missing = text[gr.textIndices[index]]; + auto fallback = HBFont::gFallbackProc(missing, fallbackIndex, this); + if (fallback && fallback.get() != this) + { + perform_fallback(fallback, + gruns, + text, + gr, + originalTextRun, + fallbackIndex + 1); + } + else if (gr.glyphs.size() > 0) + { + gruns.add(std::move(gr)); + } + } +} + +rive::SimpleArray HBFont::onShapeText( + rive::Span text, + rive::Span truns, + int textDirectionFlag) const +{ + + rive::SimpleArrayBuilder paragraphs; + SBCodepointSequence codepointSequence = {SBStringEncodingUTF32, + (void*)text.data(), + text.size()}; + + hb_unicode_funcs_t* ufuncs = hb_unicode_funcs_get_default(); + + // Split runs by bidi types. + uint32_t textIndex = 0; + uint32_t runIndex = 0; + uint32_t runStartTextIndex = 0; + + SBUInteger paragraphStart = 0; + + SBAlgorithmRef bidiAlgorithm = SBAlgorithmCreate(&codepointSequence); + uint32_t unicharIndex = 0; + uint32_t runTextIndex = 0; + + SBLevel defaultLevel; + switch (textDirectionFlag) + { + case 0: + defaultLevel = 0; + break; + case 1: + defaultLevel = 1; + break; + default: + defaultLevel = SBLevelDefaultLTR; + break; + } + + while (paragraphStart < text.size()) + { + SBParagraphRef paragraph = SBAlgorithmCreateParagraph(bidiAlgorithm, + paragraphStart, + INT32_MAX, + defaultLevel); + SBUInteger paragraphLength = SBParagraphGetLength(paragraph); + // Next iteration reads the next paragraph (if any remain). + paragraphStart += paragraphLength; + const SBLevel* bidiLevels = SBParagraphGetLevelsPtr(paragraph); + SBLevel paragraphLevel = SBParagraphGetBaseLevel(paragraph); + uint32_t paragraphTextIndex = 0; + + std::vector bidiRuns; + bidiRuns.reserve(truns.size()); + + while (runIndex < truns.size()) + { + const auto& tr = truns[runIndex]; + assert(tr.unicharCount != 0); + SBLevel lastLevel = bidiLevels[paragraphTextIndex]; + auto point = text[textIndex]; + hb_script_t lastScript = hb_unicode_script(ufuncs, point); + + rive::TextRun splitRun = { + tr.font, + tr.size, + tr.lineHeight, + tr.letterSpacing, + tr.unicharCount - runTextIndex, + (uint32_t)lastScript, + tr.styleId, + (uint8_t)lastLevel, + }; + + runStartTextIndex = textIndex; + + runTextIndex++; + textIndex++; + paragraphTextIndex++; + bidiRuns.push_back(splitRun); + + while (runTextIndex < tr.unicharCount && + paragraphTextIndex < paragraphLength) + { + auto point = text[textIndex]; + hb_script_t script = + hb_unicode_general_category(ufuncs, point) == + HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK + ? HB_SCRIPT_INHERITED + : hb_unicode_script(ufuncs, point); + + switch (script) + { + case HB_SCRIPT_COMMON: + case HB_SCRIPT_INHERITED: + // Propagate last seen "real" script value. + script = lastScript; + break; + default: + break; + } + if (bidiLevels[paragraphTextIndex] != lastLevel || + script != lastScript) + { + lastScript = script; + auto& back = bidiRuns.back(); + back.unicharCount = textIndex - runStartTextIndex; + lastLevel = bidiLevels[paragraphTextIndex]; + + rive::TextRun backRun = { + back.font, + back.size, + back.lineHeight, + back.letterSpacing, + tr.unicharCount - runTextIndex, + (uint32_t)script, + back.styleId, + (uint8_t)lastLevel, + }; + runStartTextIndex = textIndex; + bidiRuns.push_back(backRun); + } + runTextIndex++; + textIndex++; + paragraphTextIndex++; + } + // Reached the end of the run? + if (runTextIndex == tr.unicharCount) + { + runIndex++; + runTextIndex = 0; + } + // We consumed the whole paragraph. + if (paragraphTextIndex == paragraphLength) + { + // Close off the last run. + auto& back = bidiRuns.back(); + back.unicharCount = textIndex - runStartTextIndex; + break; + } + } + + rive::SimpleArrayBuilder gruns(bidiRuns.size()); + + for (const auto& tr : bidiRuns) + { + auto gr = shape_run(&text[unicharIndex], tr, unicharIndex); + unicharIndex += tr.unicharCount; + + auto end = gr.glyphs.end(); + auto iter = std::find(gr.glyphs.begin(), end, 0); + if (!gFallbackProc || iter == end || !gFallbackProcEnabled) + { + if (gr.glyphs.size() > 0) + { + gruns.add(std::move(gr)); + } + } + else + { + // found at least 1 zero in glyphs, so need to perform + // font-fallback + size_t index = iter - gr.glyphs.begin(); + rive::Unichar missing = text[gr.textIndices[index]]; + // todo: consider sending more chars if that helps choose a font + auto fallback = gFallbackProc(missing, 0, this); + if (fallback) + { + perform_fallback(fallback, gruns, text.data(), gr, tr, 1); + } + else if (gr.glyphs.size() > 0) + { + // oh well, just keep the missing glyphs + gruns.add(std::move(gr)); + } + } + } + + // turn the advances we stored in xpos[] into actual x-positions + // for logical order. + float pos = 0; + for (auto& gr : gruns) + { + for (auto& xp : gr.xpos) + { + float adv = xp; + xp = pos; + pos += adv; + } + } + + paragraphs.add({ + std::move(gruns), + (uint8_t)paragraphLevel, + }); + SBParagraphRelease(paragraph); + } + + SBAlgorithmRelease(bidiAlgorithm); + return paragraphs; +} + +bool HBFont::hasGlyph(const rive::Unichar missing) const +{ + hb_codepoint_t glyph; + return hb_font_get_nominal_glyph(m_font, missing, &glyph); +} + +#endif diff --git a/third_party/rive/source/text/font_hb_apple.mm b/third_party/rive/source/text/font_hb_apple.mm new file mode 100644 index 0000000..b741ffb --- /dev/null +++ b/third_party/rive/source/text/font_hb_apple.mm @@ -0,0 +1,400 @@ +#if defined(WITH_RIVE_TEXT) && !defined(RIVE_NO_CORETEXT) + +// #if defined(TARGET_OS_IPHONE) || defined(TARGET_OS_SIMULATOR) +// #else +#include +#include +#include +#include +// #endif + +#include "rive/text_engine.hpp" +#include "rive/text/font_hb.hpp" +#include "rive/text/utf.hpp" + +#include "hb-coretext.h" +#include "hb-ot.h" + +constexpr int kStdScale = 2048; +constexpr float gInvScale = 1.0f / kStdScale; + +class CoreTextHBFont : public HBFont +{ +private: + bool m_useSystemShaper; + uint16_t m_weight; + uint8_t m_width; + +public: + CoreTextHBFont(hb_font_t* font, + bool useSystemShaper, + uint16_t weight, + uint8_t width); + + void shapeFallbackRun(rive::SimpleArrayBuilder& gruns, + const rive::Unichar text[], + const unsigned textStart, + const rive::TextRun& textRun, + const rive::TextRun& originalTextRun, + const uint32_t fallbackIndex) override; + + rive::RawPath getPath(rive::GlyphID glyph) const override; +}; + +rive::rcp HBFont::FromSystem(void* systemFont, + bool useSystemShaper, + uint16_t weight, + uint8_t width) +{ + auto ctFont = (CTFontRef)systemFont; + if (CTFontGetSize(ctFont) != kStdScale) + { + // Need the font sized at our magic scale so we can extract normalized + // path data. + ctFont = + CTFontCreateCopyWithAttributes(ctFont, kStdScale, nullptr, nullptr); + } + auto font = hb_coretext_font_create(ctFont); + if (font) + { + return rive::rcp( + new CoreTextHBFont(font, useSystemShaper, weight, width)); + } + return nullptr; +} + +template class AutoSTArray +{ + T m_storage[N]; + T* m_ptr; + const size_t m_count; + +public: + AutoSTArray(size_t n) : m_count(n) + { + m_ptr = m_storage; + if (n > N) + { + m_ptr = new T[n]; + } + } + ~AutoSTArray() + { + if (m_ptr != m_storage) + { + delete[] m_ptr; + } + } + + T* data() const { return m_ptr; } + + T& operator[](size_t index) + { + assert(index < m_count); + return m_ptr[index]; + } +}; +template class AutoCF +{ + T m_obj; + +public: + AutoCF(T obj = nullptr) : m_obj(obj) {} + AutoCF(const AutoCF& other) + { + if (other.m_obj) + { + CFRetain(other.m_obj); + } + m_obj = other.m_obj; + } + AutoCF(AutoCF&& other) + { + m_obj = other.m_obj; + other.m_obj = nullptr; + } + ~AutoCF() + { + if (m_obj) + { + CFRelease(m_obj); + } + } + + AutoCF& operator=(const AutoCF& other) + { + if (m_obj != other.m_obj) + { + if (other.m_obj) + { + CFRetain(other.m_obj); + } + if (m_obj) + { + CFRelease(m_obj); + } + m_obj = other.m_obj; + } + return *this; + } + + void reset(T obj) + { + if (obj != m_obj) + { + if (m_obj) + { + CFRelease(m_obj); + } + m_obj = obj; + } + } + + operator T() const { return m_obj; } + operator bool() const { return m_obj != nullptr; } + T get() const { return m_obj; } +}; + +struct AutoUTF16 +{ + std::vector array; + + AutoUTF16(const rive::Unichar uni[], int count) + { + array.reserve(count); + for (int i = 0; i < count; ++i) + { + uint16_t tmp[2]; + int n = rive::UTF::ToUTF16(uni[i], tmp); + + for (int i = 0; i < n; ++i) + { + array.push_back(tmp[i]); + } + } + } +}; + +static void apply_element(void* ctx, const CGPathElement* element) +{ + auto path = (rive::RawPath*)ctx; + const CGPoint* points = element->points; + + switch (element->type) + { + case kCGPathElementMoveToPoint: + path->moveTo((float)points[0].x * gInvScale, + (float)-points[0].y * gInvScale); + break; + + case kCGPathElementAddLineToPoint: + path->lineTo((float)points[0].x * gInvScale, + (float)-points[0].y * gInvScale); + break; + + case kCGPathElementAddQuadCurveToPoint: + + path->quadToCubic((float)points[0].x * gInvScale, + (float)-points[0].y * gInvScale, + (float)points[1].x * gInvScale, + (float)-points[1].y * gInvScale); + break; + + case kCGPathElementAddCurveToPoint: + + path->cubicTo((float)points[0].x * gInvScale, + (float)-points[0].y * gInvScale, + (float)points[1].x * gInvScale, + (float)-points[1].y * gInvScale, + (float)points[2].x * gInvScale, + (float)-points[2].y * gInvScale); + break; + + case kCGPathElementCloseSubpath: + path->close(); + break; + + default: + assert(false); + break; + } +} + +CoreTextHBFont::CoreTextHBFont(hb_font_t* font, + bool useSystemShaper, + uint16_t weight, + uint8_t width) : + m_useSystemShaper(useSystemShaper), + m_weight(weight), + m_width(width), + HBFont(font) +{ + hb_variation_t variation_data[2]; + variation_data[0].tag = HB_OT_TAG_VAR_AXIS_WEIGHT; + variation_data[0].value = weight; + variation_data[1].tag = HB_OT_TAG_VAR_AXIS_WIDTH; + variation_data[1].value = width; + hb_font_set_variations(font, variation_data, 2); +} + +void CoreTextHBFont::shapeFallbackRun( + rive::SimpleArrayBuilder& gruns, + const rive::Unichar text[], + const unsigned textStart, + const rive::TextRun& textRun, + const rive::TextRun& originalTextRun, + const uint32_t fallbackIndex) +{ + if (!m_useSystemShaper) + { + HBFont::shapeFallbackRun( + gruns, text, textStart, textRun, originalTextRun, fallbackIndex); + return; + } + + CTFontRef ctFont = hb_coretext_font_get_ct_font(m_font); + + AutoUTF16 utf16(&text[textStart], textRun.unicharCount); + + assert(utf16.array.size() == textRun.unicharCount); + + AutoCF string = CFStringCreateWithCharactersNoCopy( + nullptr, utf16.array.data(), utf16.array.size(), kCFAllocatorNull); + + AutoCF attr = + CFDictionaryCreateMutable(kCFAllocatorDefault, + 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + CFDictionaryAddValue(attr.get(), kCTFontAttributeName, ctFont); + + AutoCF attrString = + CFAttributedStringCreateMutable(kCFAllocatorDefault, + textRun.unicharCount); + CFAttributedStringReplaceString( + attrString.get(), CFRangeMake(0, 0), string.get()); + + AutoCF level_number = + CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &textRun.level); + AutoCF options = CFDictionaryCreate( + kCFAllocatorDefault, + (const void**)&kCTTypesetterOptionForcedEmbeddingLevel, + (const void**)&level_number, + 1, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + + AutoCF typesetter = + CTTypesetterCreateWithAttributedStringAndOptions(attrString.get(), + options.get()); + + AutoCF line = CTTypesetterCreateLine(typesetter.get(), {0, 0}); + + CFArrayRef run_array = CTLineGetGlyphRuns(line.get()); + CFIndex runCount = CFArrayGetCount(run_array); + bool isEvenLevel = textRun.level % 2 == 0; + for (CFIndex runIndex = 0; runIndex < runCount; runIndex++) + { + CTRunRef run = (CTRunRef)CFArrayGetValueAtIndex(run_array, runIndex); + + if (auto count = CTRunGetGlyphCount(run)) + { + rive::GlyphRun gr(count); + + // Because CoreText will automatically do its own font fallbacks + // we need to detect that it's trying to use a different font. + CFDictionaryRef attributes = CTRunGetAttributes(run); + CTFontRef runCtFont = static_cast( + CFDictionaryGetValue(attributes, kCTFontAttributeName)); + const float scale = textRun.size / (float)CTFontGetSize(runCtFont); + if (!CFEqual(runCtFont, ctFont)) + { + gr.font = HBFont::FromSystem( + (void*)runCtFont, true, m_weight, m_width); + } + else + { + gr.font = textRun.font; + } + gr.size = textRun.size; + gr.lineHeight = textRun.lineHeight; + gr.letterSpacing = textRun.letterSpacing; + gr.styleId = textRun.styleId; + gr.level = textRun.level; + + CTRunGetGlyphs(run, {0, count}, gr.glyphs.data()); + if (!isEvenLevel) + { + std::reverse(gr.glyphs.begin(), gr.glyphs.end()); + } + + AutoSTArray<1024, CFIndex> indices(count); + AutoSTArray<1024, CGSize> advances(count); + + CTRunGetAdvances(run, {0, count}, advances.data()); + CTRunGetStringIndices(run, {0, count}, indices.data()); + + int reverseIndex = count - 1; + for (CFIndex i = 0; i < count; ++i) + { + int glyphIndex = isEvenLevel ? i : reverseIndex; + float advance = + (float)(advances[i].width * scale) + textRun.letterSpacing; + gr.xpos[glyphIndex] = gr.advances[glyphIndex] = advance; + gr.textIndices[glyphIndex] = + textStart + indices[i]; // utf16 offsets, will fix-up later + + gr.offsets[glyphIndex] = rive::Vec2D(0.0f, 0.0f); + reverseIndex--; + } + gr.xpos[count] = 0; + + gruns.add(std::move(gr)); + } + } +} + +rive::RawPath CoreTextHBFont::getPath(rive::GlyphID glyph) const +{ + // When we use the system shaper (coretext) get the glyphs from there + // too. + if (m_useSystemShaper) + { + CTFontRef ctFont = hb_coretext_font_get_ct_font(m_font); + if (ctFont) + { + AutoCF cgPath = + CTFontCreatePathForGlyph(ctFont, glyph, nullptr); + + if (cgPath) + { + rive::RawPath rpath; + CGPathApply(cgPath.get(), &rpath, apply_element); + return rpath; + } + } + } + + rive::RawPath rpath = HBFont::getPath(glyph); + + // We didn't use the system shaper, but harfbuzz failed to extract the + // glyphs. Try getting them from the system. + if (rpath.empty() && !m_useSystemShaper) + { + CTFontRef ctFont = hb_coretext_font_get_ct_font(m_font); + if (ctFont) + { + AutoCF cgPath = + CTFontCreatePathForGlyph(ctFont, glyph, nullptr); + + if (cgPath) + { + rive::RawPath rpath; + CGPathApply(cgPath.get(), &rpath, apply_element); + return rpath; + } + } + } + return rpath; +} +#endif diff --git a/third_party/rive/source/text/fully_shaped_text.cpp b/third_party/rive/source/text/fully_shaped_text.cpp new file mode 100644 index 0000000..c532dbf --- /dev/null +++ b/third_party/rive/source/text/fully_shaped_text.cpp @@ -0,0 +1,148 @@ +#ifdef WITH_RIVE_TEXT +#include "rive/text/fully_shaped_text.hpp" +#include "rive/text/text.hpp" + +using namespace rive; + +void FullyShapedText::shape(Span text, + Span runs, + TextSizing sizing, + float maxWidth, + float maxHeight, + TextAlign alignment, + TextWrap wrap, + TextOrigin origin, + TextOverflow overflow, + float paragraphSpacing) +{ + m_paragraphs = runs[0].font->shapeText(text, runs); + m_glyphLookup.compute(text, m_paragraphs); + + m_paragraphLines = + Text::BreakLines(m_paragraphs, + sizing == TextSizing::autoWidth ? -1.0f : maxWidth, + alignment, + wrap); + m_orderedLines.clear(); + m_ellipsisRun = {}; + + // build render styles. + if (m_paragraphs.empty()) + { + m_bounds = AABB(0.0f, 0.0f, 0.0f, 0.0f); + return; + } + + // Build up ordered runs as we go. + int32_t paragraphIndex = 0; + float y = 0.0f; + float minY = 0.0f; + float measuredWidth = 0.0f; + if (origin == TextOrigin::baseline && !m_paragraphLines.empty() && + !m_paragraphLines[0].empty()) + { + y -= m_paragraphLines[0][0].baseline; + minY = y; + } + + int ellipsisLine = -1; + bool isEllipsisLineLast = false; + // Find the line to put the ellipsis on (line before the one that + // overflows). + bool wantEllipsis = + overflow == TextOverflow::ellipsis && sizing == TextSizing::fixed; + + int lastLineIndex = -1; + for (const SimpleArray& paragraphLines : m_paragraphLines) + { + const Paragraph& paragraph = m_paragraphs[paragraphIndex++]; + for (const GlyphLine& line : paragraphLines) + { + const GlyphRun& endRun = paragraph.runs[line.endRunIndex]; + const GlyphRun& startRun = paragraph.runs[line.startRunIndex]; + float width = endRun.xpos[line.endGlyphIndex] - + startRun.xpos[line.startGlyphIndex]; + if (width > measuredWidth) + { + measuredWidth = width; + } + lastLineIndex++; + if (wantEllipsis && y + line.bottom <= maxHeight) + { + ellipsisLine++; + } + } + + if (!paragraphLines.empty()) + { + y += paragraphLines.back().bottom; + } + y += paragraphSpacing; + } + if (wantEllipsis && ellipsisLine == -1) + { + // Nothing fits, just show the first line and ellipse it. + ellipsisLine = 0; + } + isEllipsisLineLast = lastLineIndex == ellipsisLine; + + int32_t lineIndex = 0; + paragraphIndex = 0; + m_bounds = + AABB(0.0f, minY, measuredWidth, std::max(minY, y - paragraphSpacing)); + + y = 0; + if (origin == TextOrigin::baseline && !m_paragraphLines.empty() && + !m_paragraphLines[0].empty()) + { + y -= m_paragraphLines[0][0].baseline; + } + paragraphIndex = 0; + + for (const SimpleArray& paragraphLines : m_paragraphLines) + { + const Paragraph& paragraph = m_paragraphs[paragraphIndex++]; + for (const GlyphLine& line : paragraphLines) + { + switch (overflow) + { + case TextOverflow::hidden: + if (sizing == TextSizing::fixed && + y + line.bottom > maxHeight) + { + return; + } + break; + case TextOverflow::clipped: + if (sizing == TextSizing::fixed && y + line.top > maxHeight) + { + return; + } + break; + default: + break; + } + + m_orderedLines.emplace_back(OrderedLine(paragraph, + line, + maxWidth, + ellipsisLine == lineIndex, + isEllipsisLineLast, + &m_ellipsisRun, + y + line.baseline)); + + if (lineIndex == ellipsisLine) + { + return; + } + lineIndex++; + } + if (!paragraphLines.empty()) + { + y += paragraphLines.back().bottom; + } + y += paragraphSpacing; + } + return; +} +#endif \ No newline at end of file diff --git a/third_party/rive/source/text/glyph_lookup.cpp b/third_party/rive/source/text/glyph_lookup.cpp new file mode 100644 index 0000000..a30f20d --- /dev/null +++ b/third_party/rive/source/text/glyph_lookup.cpp @@ -0,0 +1,88 @@ +#include "rive/text/glyph_lookup.hpp" +#include "rive/text_engine.hpp" + +using namespace rive; + +void GlyphLookup::compute(Span text, + const SimpleArray& shape) +{ + size_t codeUnitCount = text.size(); + m_glyphIndices.resize(codeUnitCount + 1); + // Build a mapping of codePoints to glyphs indices. + uint32_t glyphIndex = 0; + uint32_t lastTextIndex = 0; + for (const Paragraph& paragraph : shape) + { + for (const GlyphRun& run : paragraph.runs) + { + for (size_t i = 0; i < run.glyphs.size(); i++) + { + uint32_t textIndex = run.textIndices[i]; + for (uint32_t j = lastTextIndex; j < textIndex; j++) + { + assert(glyphIndex != 0); + m_glyphIndices[j] = glyphIndex - 1; + } + lastTextIndex = textIndex; + glyphIndex++; + } + } + } + for (size_t i = lastTextIndex; i < codeUnitCount; i++) + { + m_glyphIndices[i] = glyphIndex - 1; + } + + // Store a fake unreachable glyph at the end to allow selecting the last + // one. + m_glyphIndices[codeUnitCount] = + codeUnitCount == 0 ? 0 : m_glyphIndices[codeUnitCount - 1] + 1; +} + +uint32_t GlyphLookup::count(uint32_t index) const +{ + assert(index < (uint32_t)m_glyphIndices.size()); + + uint32_t value = m_glyphIndices[index]; + uint32_t count = 1; + uint32_t size = (uint32_t)m_glyphIndices.size(); + while (++index < size && m_glyphIndices[index] == value) + { + count++; + } + return count; +} + +float GlyphLookup::advanceFactor(int32_t codePointIndex, bool inv) const +{ + if (codePointIndex < 0 || codePointIndex >= (int32_t)m_glyphIndices.size()) + { + return 0.0f; + } + uint32_t glyphIndex = m_glyphIndices[codePointIndex]; + int32_t start = codePointIndex; + while (start > 0) + { + if (m_glyphIndices[start - 1] != glyphIndex) + { + break; + } + start--; + } + int32_t end = codePointIndex; + while (end < m_glyphIndices.size() - 1) + { + if (m_glyphIndices[end + 1] != glyphIndex) + { + break; + } + end++; + } + + float f = (codePointIndex - start) / (float)(end - start + 1); + if (inv) + { + return 1.0f - f; + } + return f; +} \ No newline at end of file diff --git a/third_party/rive/source/text/line_breaker.cpp b/third_party/rive/source/text/line_breaker.cpp new file mode 100644 index 0000000..2577ccc --- /dev/null +++ b/third_party/rive/source/text/line_breaker.cpp @@ -0,0 +1,372 @@ +/* + * Copyright 2022 Rive + */ + +#include "rive/text_engine.hpp" +#include +#include +using namespace rive; + +static bool autowidth(float width) { return width < 0.0f; } + +float GlyphLine::ComputeMaxWidth(Span lines, + Span runs) +{ + float maxLineWidth = 0.0f; + for (auto& line : lines) + { + maxLineWidth = + std::max(maxLineWidth, + runs[line.endRunIndex].xpos[line.endGlyphIndex] - + runs[line.startRunIndex].xpos[line.startGlyphIndex]); + } + return maxLineWidth; +} + +static const rive::Font::LineMetrics computeLineMetrics( + const rive::Font::LineMetrics& metrics, + float customLineHeight, + float fontSize) +{ + if (customLineHeight < 0.0f) + { + return {metrics.ascent * fontSize, metrics.descent * fontSize}; + } + float baseline = -metrics.ascent; + float height = baseline + metrics.descent; + float baselineFactor = baseline / height; + + float actualAscent = -baselineFactor * customLineHeight; + + return {actualAscent, customLineHeight + actualAscent}; +} + +void GlyphLine::ComputeLineSpacing(bool isFirstLine, + Span lines, + Span runs, + float width, + TextAlign align) +{ + bool first = isFirstLine; + float Y = 0; // top of our frame + for (auto& line : lines) + { + float asc = 0; + float realAscent = 0; + float des = 0; + float lh = 0; + for (uint32_t i = line.startRunIndex; i <= line.endRunIndex; ++i) + { + const auto& run = runs[i]; + const auto& metrics = computeLineMetrics(run.font->lineMetrics(), + run.lineHeight, + run.size); + realAscent = + std::min(realAscent, run.font->lineMetrics().ascent * run.size); + asc = std::min(asc, metrics.ascent); + des = std::max(des, metrics.descent); + if (run.lineHeight >= 0.0f) + { + lh = std::max(lh, run.lineHeight); + } + else + { + lh = std::max(lh, -asc + des); + } + } + line.top = Y; + if (first) + { + Y = -realAscent; + first = false; + } + else + { + Y -= asc; + } + line.baseline = Y; + Y += des; + line.bottom = Y; + + auto lineWidth = runs[line.endRunIndex].xpos[line.endGlyphIndex] - + runs[line.startRunIndex].xpos[line.startGlyphIndex]; + switch (align) + { + case TextAlign::right: + line.startX = width - lineWidth; + break; + case TextAlign::left: + line.startX = 0; + break; + case TextAlign::center: + line.startX = width / 2.0f - lineWidth / 2.0f; + break; + } + } +} + +struct WordMarker +{ + const GlyphRun* run; + uint32_t index; + + bool next(Span runs) + { + index += 2; + while (index >= run->breaks.size()) + { + index -= run->breaks.size(); + run++; + if (run == runs.end()) + { + return false; + } + } + return true; + } +}; + +class RunIterator +{ + Span m_runs; + const GlyphRun* m_run; + uint32_t m_index; + +public: + RunIterator(Span runs, + const GlyphRun* run, + uint32_t index) : + m_runs(runs), m_run(run), m_index(index) + {} + + bool back() + { + if (m_index == 0) + { + if (m_run == m_runs.begin()) + { + return false; + } + m_run--; + if (m_run->glyphs.size() == 0) + { + m_index = 0; + return back(); + } + else + { + m_index = m_run->glyphs.size() == 0 + ? 0 + : (uint32_t)m_run->glyphs.size() - 1; + } + } + else + { + m_index--; + } + return true; + } + + bool forward() + { + if (m_index == m_run->glyphs.size()) + { + if (m_run == m_runs.end()) + { + return false; + } + m_run++; + m_index = 0; + if (m_index == m_run->glyphs.size()) + { + return forward(); + } + } + else + { + m_index++; + } + return true; + } + + float x() const { return m_run->xpos[m_index]; } + + const GlyphRun* run() const { return m_run; } + uint32_t index() const { return m_index; } + + bool operator==(const RunIterator& o) const + { + return m_run == o.m_run && m_index == o.m_index; + } +}; + +SimpleArray GlyphLine::BreakLines(Span runs, + float width) +{ + float maxLineWidth = + autowidth(width) ? std::numeric_limits::max() : width; + + SimpleArrayBuilder lines; + + if (runs.empty()) + { + return lines; + } + + auto limit = maxLineWidth; + + bool advanceWord = false; + + // We iterate the breaks list with a WordMarker helper which is basically an + // iterator. The breaks lists contains tightly packed start/end indices per + // run. So the first valid word is at break index 0,1 (per run). Because a + // run can be created with no valid breaks, we start the word iterator at a + // negative index and attempt to move it to the first valid index (which + // could be in the Nth run in the paragraph). If that fails, we know we have + // no words to break in the entire paragraph and can early out. See how + // WordMarker::next works and notice how we also use it below in this same + // method. + WordMarker start = {runs.begin(), (uint32_t)-2}; + WordMarker end = {runs.begin(), (uint32_t)-1}; + if (!start.next(runs) || !end.next(runs)) + { + return lines; + } + + GlyphLine line = GlyphLine(); + + uint32_t breakIndex = end.run->breaks[end.index]; + const GlyphRun* breakRun = end.run; + uint32_t lastEndGlyphIndex = end.index; + uint32_t startBreakIndex = start.run->breaks[start.index]; + const GlyphRun* startBreakRun = start.run; + + float x = end.run->xpos[breakIndex]; + while (true) + { + if (advanceWord) + { + lastEndGlyphIndex = end.index; + + if (!start.next(runs)) + { + break; + } + if (!end.next(runs)) + { + break; + } + + advanceWord = false; + + breakIndex = end.run->breaks[end.index]; + breakRun = end.run; + startBreakIndex = start.run->breaks[start.index]; + startBreakRun = start.run; + x = end.run->xpos[breakIndex]; + } + + bool isForcedBreak = + breakRun == startBreakRun && breakIndex == startBreakIndex; + + if (!isForcedBreak && x > limit) + { + uint32_t startRunIndex = (uint32_t)(start.run - runs.begin()); + + // A whole word overflowed, break until we can no longer break (or + // it fits). + if (line.startRunIndex == startRunIndex && + line.startGlyphIndex == startBreakIndex) + { + bool canBreakMore = true; + while (canBreakMore && x > limit) + { + + RunIterator lineStart = + RunIterator(runs, + runs.begin() + line.startRunIndex, + line.startGlyphIndex); + RunIterator lineEnd = + RunIterator(runs, end.run, end.run->breaks[end.index]); + // Look for the next character that doesn't overflow. + while (true) + { + if (!lineEnd.back()) + { + // Hit the start of the text, can't go back. + canBreakMore = false; + break; + } + else if (lineEnd.x() <= limit) + { + if (lineStart == lineEnd && !lineEnd.forward()) + { + // Hit the start of the line and could not + // go forward to consume a single character. + // We can't break any further. + canBreakMore = false; + } + else + { + line.endRunIndex = + (uint32_t)(lineEnd.run() - runs.begin()); + line.endGlyphIndex = lineEnd.index(); + } + break; + } + } + if (canBreakMore) + { + // Add the line and push the limit out. + limit = lineEnd.x() + maxLineWidth; + if (!line.empty()) + { + lines.add(line); + } + // Setup the next line. + line = + GlyphLine((uint32_t)(lineEnd.run() - runs.begin()), + lineEnd.index()); + } + } + } + else + { + // word overflowed, knock it to a new line + auto startX = start.run->xpos[start.run->breaks[start.index]]; + limit = startX + maxLineWidth; + + if (!line.empty() || start.index - lastEndGlyphIndex > 1) + { + lines.add(line); + } + + line = GlyphLine(startRunIndex, startBreakIndex); + } + } + else + { + line.endRunIndex = (uint32_t)(end.run - runs.begin()); + line.endGlyphIndex = end.run->breaks[end.index]; + advanceWord = true; + // Forced BR. + if (isForcedBreak) + { + lines.add(line); + auto startX = + start.run->xpos[start.run->breaks[start.index] + 1]; + limit = startX + maxLineWidth; + line = GlyphLine((uint32_t)(start.run - runs.begin()), + startBreakIndex + 1); + } + } + } + + // Add the last line. + if (!line.empty()) + { + lines.add(line); + } + + return lines; +} diff --git a/third_party/rive/source/text/raw_text.cpp b/third_party/rive/source/text/raw_text.cpp new file mode 100644 index 0000000..29b74fb --- /dev/null +++ b/third_party/rive/source/text/raw_text.cpp @@ -0,0 +1,370 @@ +#ifdef WITH_RIVE_TEXT +#include "rive/text/raw_text.hpp" +#include "rive/text_engine.hpp" +#include "rive/factory.hpp" + +using namespace rive; + +RawText::RawText(Factory* factory) : m_factory(factory) {} +bool RawText::empty() const { return m_styled.empty(); } + +void RawText::append(const std::string& text, + rcp paint, + rcp font, + float size, + float lineHeight, + float letterSpacing) +{ + int styleIndex = 0; + for (RenderStyle& style : m_styles) + { + if (style.paint == paint) + { + break; + } + styleIndex++; + } + if (styleIndex == m_styles.size()) + { + m_styles.push_back({paint, true}); + } + m_styled.append(font, size, lineHeight, letterSpacing, text, styleIndex); + m_dirty = true; +} + +void RawText::clear() +{ + m_styled.clear(); + m_dirty = true; +} + +TextSizing RawText::sizing() const { return m_sizing; } + +TextOverflow RawText::overflow() const { return m_overflow; } + +TextAlign RawText::align() const { return m_align; } + +float RawText::maxWidth() const { return m_maxWidth; } + +float RawText::maxHeight() const { return m_maxHeight; } + +float RawText::paragraphSpacing() const { return m_paragraphSpacing; } + +void RawText::sizing(TextSizing value) +{ + if (m_sizing != value) + { + m_sizing = value; + m_dirty = true; + } +} + +void RawText::overflow(TextOverflow value) +{ + if (m_overflow != value) + { + m_overflow = value; + m_dirty = true; + } +} + +void RawText::align(TextAlign value) +{ + if (m_align != value) + { + m_align = value; + m_dirty = true; + } +} + +void RawText::paragraphSpacing(float value) +{ + if (m_paragraphSpacing != value) + { + m_paragraphSpacing = value; + m_dirty = true; + } +} + +void RawText::maxWidth(float value) +{ + if (m_maxWidth != value) + { + m_maxWidth = value; + m_dirty = true; + } +} + +void RawText::maxHeight(float value) +{ + if (m_maxHeight != value) + { + m_maxHeight = value; + m_dirty = true; + } +} + +void RawText::update() +{ + for (RenderStyle& style : m_styles) + { + style.path.rewind(); + style.isEmpty = true; + } + m_renderStyles.clear(); + if (m_styled.empty()) + { + return; + } + auto runs = m_styled.runs(); + + m_shape = runs[0].font->shapeText(m_styled.unichars(), runs); + m_lines = + Text::BreakLines(m_shape, + m_sizing == TextSizing::autoWidth ? -1.0f : m_maxWidth, + m_align, + m_wrap); + + m_orderedLines.clear(); + m_ellipsisRun = {}; + + // build render styles. + if (m_shape.empty()) + { + m_bounds = AABB(0.0f, 0.0f, 0.0f, 0.0f); + return; + } + + // Build up ordered runs as we go. + int paragraphIndex = 0; + float y = 0.0f; + float minY = 0.0f; + float measuredWidth = 0.0f; + if (m_origin == TextOrigin::baseline && !m_lines.empty() && + !m_lines[0].empty()) + { + y -= m_lines[0][0].baseline; + minY = y; + } + + int ellipsisLine = -1; + bool isEllipsisLineLast = false; + // Find the line to put the ellipsis on (line before the one that + // overflows). + bool wantEllipsis = + m_overflow == TextOverflow::ellipsis && m_sizing == TextSizing::fixed; + + int lastLineIndex = -1; + for (const SimpleArray& paragraphLines : m_lines) + { + const Paragraph& paragraph = m_shape[paragraphIndex++]; + for (const GlyphLine& line : paragraphLines) + { + const GlyphRun& endRun = paragraph.runs[line.endRunIndex]; + const GlyphRun& startRun = paragraph.runs[line.startRunIndex]; + float width = endRun.xpos[line.endGlyphIndex] - + startRun.xpos[line.startGlyphIndex]; + if (width > measuredWidth) + { + measuredWidth = width; + } + lastLineIndex++; + if (wantEllipsis && y + line.bottom <= m_maxHeight) + { + ellipsisLine++; + } + } + + if (!paragraphLines.empty()) + { + y += paragraphLines.back().bottom; + } + y += m_paragraphSpacing; + } + if (wantEllipsis && ellipsisLine == -1) + { + // Nothing fits, just show the first line and ellipse it. + ellipsisLine = 0; + } + isEllipsisLineLast = lastLineIndex == ellipsisLine; + + int lineIndex = 0; + paragraphIndex = 0; + switch (m_sizing) + { + case TextSizing::autoWidth: + m_bounds = AABB(0.0f, + minY, + measuredWidth, + std::max(minY, y - m_paragraphSpacing)); + break; + case TextSizing::autoHeight: + m_bounds = AABB(0.0f, + minY, + m_maxWidth, + std::max(minY, y - m_paragraphSpacing)); + break; + case TextSizing::fixed: + m_bounds = AABB(0.0f, minY, m_maxWidth, minY + m_maxHeight); + break; + } + + // Build the clip path if we want it. + if (m_overflow == TextOverflow::clipped) + { + if (m_clipRenderPath == nullptr) + { + m_clipRenderPath = m_factory->makeEmptyRenderPath(); + } + else + { + m_clipRenderPath->rewind(); + } + + m_clipRenderPath->addRect(m_bounds.minX, + m_bounds.minY, + m_bounds.width(), + m_bounds.height()); + } + else + { + m_clipRenderPath = nullptr; + } + + y = 0; + if (m_origin == TextOrigin::baseline && !m_lines.empty() && + !m_lines[0].empty()) + { + y -= m_lines[0][0].baseline; + } + paragraphIndex = 0; + + for (const SimpleArray& paragraphLines : m_lines) + { + const Paragraph& paragraph = m_shape[paragraphIndex++]; + for (const GlyphLine& line : paragraphLines) + { + switch (m_overflow) + { + case TextOverflow::hidden: + if (m_sizing == TextSizing::fixed && + y + line.bottom > m_maxHeight) + { + return; + } + break; + case TextOverflow::clipped: + if (m_sizing == TextSizing::fixed && + y + line.top > m_maxHeight) + { + return; + } + break; + default: + break; + } + + float renderY = y + line.baseline; + if (lineIndex >= m_orderedLines.size()) + { + // We need to still compute this line's ordered runs. + m_orderedLines.emplace_back( + OrderedLine(paragraph, + line, + m_maxWidth, + ellipsisLine == lineIndex, + isEllipsisLineLast, + &m_ellipsisRun, + renderY)); + } + + const OrderedLine& orderedLine = m_orderedLines[lineIndex]; + float x = line.startX; + + for (auto glyphItr : orderedLine) + { + const GlyphRun* run = std::get<0>(glyphItr); + size_t glyphIndex = std::get<1>(glyphItr); + + const Font* font = run->font.get(); + const Vec2D& offset = run->offsets[glyphIndex]; + + GlyphID glyphId = run->glyphs[glyphIndex]; + float advance = run->advances[glyphIndex]; + + RawPath path = font->getPath(glyphId); + + assert(run->styleId < m_styles.size()); + RenderStyle* style = &m_styles[run->styleId]; + assert(style != nullptr); + + Mat2D transform(run->size, + 0.0f, + 0.0f, + run->size, + x + offset.x, + renderY + offset.y); + + x += advance; + style->path.addPathClockwise(path, &transform); + + if (style->isEmpty) + { + // This was the first path added to the style, so let's mark + // it in our draw list. + style->isEmpty = false; + + m_renderStyles.push_back(style); + } + } + if (lineIndex == ellipsisLine) + { + return; + } + lineIndex++; + } + if (!paragraphLines.empty()) + { + y += paragraphLines.back().bottom; + } + y += m_paragraphSpacing; + } +} + +AABB RawText::bounds() +{ + if (m_dirty) + { + update(); + m_dirty = false; + } + return m_bounds; +} + +void RawText::render(Renderer* renderer, rcp paint) +{ + if (m_dirty) + { + update(); + m_dirty = false; + } + + if (m_overflow == TextOverflow::clipped && m_clipRenderPath) + { + renderer->save(); + renderer->clipPath(m_clipRenderPath.get()); + } + for (auto style : m_renderStyles) + { + auto renderPaint = paint ? paint.get() : style->paint.get(); + if (renderPaint != nullptr) + { + renderer->drawPath(style->path.renderPath(m_factory), renderPaint); + } + } + if (m_overflow == TextOverflow::clipped && m_clipRenderPath) + { + renderer->restore(); + } +} +#endif diff --git a/third_party/rive/source/text/raw_text_input.cpp b/third_party/rive/source/text/raw_text_input.cpp new file mode 100644 index 0000000..be6bb22 --- /dev/null +++ b/third_party/rive/source/text/raw_text_input.cpp @@ -0,0 +1,890 @@ +#ifdef WITH_RIVE_TEXT +#include "rive/text/raw_text_input.hpp" +#include "rive/text_engine.hpp" +#include "rive/factory.hpp" +#include "rive/span.hpp" + +using namespace rive; + +static const Unichar zeroWidthSpace = 8203; + +RawTextInput::RawTextInput() : + m_cursor(Cursor::atStart()), + m_textRun({nullptr, 16.0f, -1.0f, 0.0f, 0, 0, 0}), + m_cursorVisualPosition(CursorVisualPosition::missing()) +{ + m_text.push_back(zeroWidthSpace); +} + +void RawTextInput::draw(Factory* factory, + Renderer* renderer, + const Mat2D& worldTransform, + RenderPaint* textPaint, + RenderPaint* selectionPaint, + RenderPaint* cursorPaint) +{ + if (m_overflow == TextOverflow::clipped && m_clipRenderPath) + { + renderer->save(); + renderer->clipPath(m_clipRenderPath.get()); + } + + if (m_cursor.hasSelection()) + { + auto renderPath = m_selectionPath.renderPath(factory); + renderer->drawPath(renderPath, selectionPaint); + } + + auto renderPath = m_textPath.renderPath(factory); + renderer->drawPath(renderPath, textPaint); + + auto cursorRenderPath = m_cursorPath.renderPath(factory); + renderer->drawPath(cursorRenderPath, cursorPaint); + + if (m_overflow == TextOverflow::clipped && m_clipRenderPath) + { + renderer->restore(); + } +} + +void RawTextInput::backspace(int32_t direction) +{ + Cursor startingCursor = m_cursor; + int32_t offset = direction > 0 ? 0 : -1; + if (!m_cursor.isCollapsed()) + { + erase(); + captureJournalEntry(startingCursor); + return; + } + m_idealCursorX = -1.0f; + + auto index = m_cursor.first().codePointIndex(offset); + + if (index >= m_text.size() - 1) + { + return; + } + m_text.erase(m_text.begin() + index); + auto position = CursorPosition(index); + m_cursor = Cursor::collapsed(position); + flag(Flags::shapeDirty | Flags::measureDirty | Flags::selectionDirty); + captureJournalEntry(startingCursor); +} + +void RawTextInput::erase() +{ + m_idealCursorX = -1.0f; + if (m_cursor.isCollapsed()) + { + return; + } + + assert(m_cursor.first().codePointIndex() < length()); + assert(m_cursor.last().codePointIndex() <= length()); + + m_text.erase(m_text.begin() + m_cursor.first().codePointIndex(), + m_text.begin() + m_cursor.last().codePointIndex()); + auto position = CursorPosition(m_cursor.first().codePointIndex()); + m_cursor = Cursor::collapsed(position); + flag(Flags::shapeDirty | Flags::measureDirty | Flags::selectionDirty); +} + +void RawTextInput::insert(Unichar codePoint) +{ + Cursor startingCursor = m_cursor; + erase(); + + assert(m_cursor.isCollapsed()); + + m_text.insert(m_text.begin() + m_cursor.start().codePointIndex(), + codePoint); + + auto position = CursorPosition(m_cursor.first().codePointIndex(1)); + m_cursor = Cursor::collapsed(position); + captureJournalEntry(startingCursor); + flag(Flags::shapeDirty | Flags::measureDirty | Flags::selectionDirty); +} + +void RawTextInput::insert(const std::string& text) +{ + Cursor startingCursor = m_cursor; + erase(); + + uint32_t codePointIndex = m_cursor.start().codePointIndex(); + + const uint8_t* ptr = (const uint8_t*)text.c_str(); + while (*ptr) + { + Unichar codePoint = UTF::NextUTF8(&ptr); + m_text.insert(m_text.begin() + codePointIndex, codePoint); + codePointIndex++; + } + auto position = CursorPosition(codePointIndex); + m_cursor = Cursor::collapsed(position); + flag(Flags::shapeDirty | Flags::measureDirty | Flags::selectionDirty); + captureJournalEntry(startingCursor); +} + +void RawTextInput::selectionCornerRadius(float value) +{ + if (m_selectionCornerRadius == value) + { + return; + } + m_selectionCornerRadius = value; + flag(Flags::selectionDirty); +} + +void RawTextInput::fontSize(float value) +{ + if (m_textRun.size == value) + { + return; + } + m_textRun.size = value; + flag(Flags::shapeDirty | Flags::measureDirty | Flags::selectionDirty); +} + +void RawTextInput::maxWidth(float value) +{ + if (m_maxWidth == value) + { + return; + } + m_maxWidth = value; + flag(Flags::shapeDirty | Flags::measureDirty | Flags::selectionDirty); +} + +void RawTextInput::maxHeight(float value) +{ + if (m_maxHeight == value) + { + return; + } + m_maxHeight = value; + flag(Flags::shapeDirty | Flags::measureDirty | Flags::selectionDirty); +} + +void RawTextInput::sizing(TextSizing value) +{ + if (m_sizing == value) + { + return; + } + m_sizing = value; + flag(Flags::shapeDirty | Flags::measureDirty | Flags::selectionDirty); +} + +void RawTextInput::overflow(TextOverflow value) +{ + if (m_overflow == value) + { + return; + } + m_overflow = value; + flag(Flags::shapeDirty | Flags::measureDirty | Flags::selectionDirty); +} + +void RawTextInput::font(rcp value) +{ + if (m_textRun.font == value) + { + return; + } + m_textRun.font = value; + flag(Flags::shapeDirty | Flags::measureDirty | Flags::selectionDirty); +} + +void RawTextInput::computeVisualPositionFromCursor() +{ + m_cursorVisualPosition = cursorVisualPosition(m_cursor.end()); +} + +RawTextInput::Flags RawTextInput::update(Factory* factory) +{ + Flags updated = Flags::none; + if (m_textRun.font == nullptr) + { + return updated; + } + bool updateTextPath = false; + if (unflag(Flags::shapeDirty)) + { + updated |= Flags::shapeDirty; + m_textRun.unicharCount = (uint32_t)m_text.size(); + m_shape.shape(m_text, + Span(&m_textRun, 1), + m_sizing, + m_maxWidth, + m_maxHeight, + m_align, + m_wrap, + m_origin, + m_overflow, + m_paragraphSpacing); + updateTextPath = true; + } + if (unflag(Flags::selectionDirty)) + { + updated |= Flags::selectionDirty; + if (flagged(Flags::separateSelectionText)) + { + updateTextPath = true; + } + + m_cursor.resolveLinePositions(m_shape); + + computeVisualPositionFromCursor(); + + // Update the selection contours. + m_selectionRects.clear(); + m_cursor.selectionRects(m_selectionRects, m_shape); + m_selectionPath.update(m_selectionRects, m_selectionCornerRadius); + + m_cursorPath.rewind(); + float caretWidth = 1.0f; + RawPath rect; + rect.moveTo(m_cursorVisualPosition.x(), m_cursorVisualPosition.top()); + rect.lineTo(m_cursorVisualPosition.x() + caretWidth, + m_cursorVisualPosition.top()); + rect.lineTo(m_cursorVisualPosition.x() + caretWidth, + m_cursorVisualPosition.bottom()); + rect.lineTo(m_cursorVisualPosition.x(), + m_cursorVisualPosition.bottom()); + rect.close(); + + m_cursorPath.addPathClockwise(rect); + } + + if (updateTextPath) + { + buildTextPaths(factory); + } + return updated; +} + +void RawTextInput::buildTextPaths(Factory* factory) +{ + bool wantSeparate = flagged(Flags::separateSelectionText); + m_textPath.rewind(); + m_selectedTextPath.rewind(); + if (!m_shape.hasValidBounds()) + { + m_clipRenderPath = nullptr; + return; + } + + // Build the clip path if we want it. + if (m_overflow == TextOverflow::clipped) + { + if (m_clipRenderPath == nullptr) + { + m_clipRenderPath = factory->makeEmptyRenderPath(); + } + else + { + m_clipRenderPath->rewind(); + } + + const AABB& bounds = m_shape.bounds(); + m_clipRenderPath->addRect(bounds.minX, + bounds.minY, + bounds.width(), + bounds.height()); + } + else + { + m_clipRenderPath = nullptr; + } + + float y = 0; + const SimpleArray>& paragraphLines = + m_shape.paragraphLines(); + const std::vector& orderedLines = m_shape.orderedLines(); + + if (m_origin == TextOrigin::baseline && !paragraphLines.empty() && + !paragraphLines[0].empty()) + { + y -= paragraphLines[0][0].baseline; + } + int32_t lineIndex = 0; + // Only reason we don't iterate lines here is so we don't need to recompute + // shape if we just change paragraph spacing, otherwise we could store the + // computed y in each OrderedLine and just iterate those. + for (const SimpleArray& lines : paragraphLines) + { + for (const GlyphLine& line : lines) + { + if (lineIndex >= orderedLines.size()) + { + // We previously decided to clip at this number of lines (see + // fully_shaped_text.cpp). + break; + } + + const OrderedLine& orderedLine = orderedLines[lineIndex]; + float x = line.startX; + float renderY = y + line.baseline; + for (auto glyphItr : orderedLine) + { + const GlyphRun* run = std::get<0>(glyphItr); + size_t glyphIndex = std::get<1>(glyphItr); + + const Font* font = run->font.get(); + const Vec2D& offset = run->offsets[glyphIndex]; + + GlyphID glyphId = run->glyphs[glyphIndex]; + float advance = run->advances[glyphIndex]; + + RawPath rawPath = font->getPath(glyphId); + + rawPath.transformInPlace(Mat2D(run->size, + 0.0f, + 0.0f, + run->size, + x + offset.x, + renderY + offset.y)); + + x += advance; + + // m_path contains everything, so inner feather bounds can work. + if (wantSeparate && + m_cursor.contains(run->textIndices[glyphIndex])) + { + m_selectedTextPath.addPathClockwise(rawPath); + } + else + { + m_textPath.addPathClockwise(rawPath); + } + + // assert(run->styleId < m_styles.size()); + // RenderStyle* style = &m_styles[run->styleId]; + // assert(style != nullptr); + // path.addTo(style->path.get()); + + // if (style->isEmpty) + // { + // // This was the first path added to the style, so let's + // mark + // // it in our draw list. + // style->isEmpty = false; + + // m_renderStyles.push_back(style); + // } + } + lineIndex++; + } + if (!lines.empty()) + { + y += lines.back().bottom; + } + y += m_paragraphSpacing; + } +} + +AABB RawTextInput::bounds() const { return m_shape.bounds(); } + +void RawTextInput::paragraphSpacing(float value) +{ + if (m_paragraphSpacing == value) + { + return; + } + m_paragraphSpacing = value; + flag(Flags::shapeDirty | Flags::measureDirty | Flags::selectionDirty); +} + +void RawTextInput::cursor(Cursor value) +{ + if (m_cursor == value) + { + return; + } + m_cursor = value; + flag(Flags::selectionDirty); +} + +void RawTextInput::selectWord() +{ + CursorPosition searchPosition = m_cursor.start(); + Delineator classification = classify(searchPosition); + // If it's not a word, make sure point before it is not a word too. This + // accomodates for when trying to select a word by clicking on the + // right-most edge of the word. + if ((classification & Delineator::word) == Delineator::unknown) + { + CursorPosition previousPosition = searchPosition - 1; + Delineator previousClassification = classify(previousPosition); + if ((previousClassification & Delineator::word) != Delineator::unknown) + { + searchPosition = previousPosition; + classification = previousClassification; + } + } + + // Be more flexible on classification when search for a word (we don't want + // an exact match on upper/lower/underscore, we want any of the three). + if ((classification & Delineator::word) != Delineator::unknown) + { + classification = Delineator::word; + } + CursorPosition start = + findPosition(~(uint8_t)classification, searchPosition, -1); + CursorPosition end = + findPosition(~(uint8_t)classification, searchPosition, 1); + + end += 1; + + m_cursor = Cursor(start, end); + flag(Flags::selectionDirty); +} + +const OrderedLine* RawTextInput::orderedLine(CursorPosition position) const +{ + const std::vector& orderedLines = m_shape.orderedLines(); + if (position.lineIndex() >= orderedLines.size()) + { + return nullptr; + } + return &orderedLines[position.lineIndex()]; +} + +void RawTextInput::cursorHorizontal(int32_t offset, + CursorBoundary boundary, + bool select) +{ + m_idealCursorX = -1.0f; + CursorPosition end = m_cursor.end(); + + CursorPosition position = end; + switch (boundary) + { + case CursorBoundary::character: + position = + CursorPosition::atIndex(end.codePointIndex(offset), m_shape); + break; + case CursorBoundary::line: + { + auto line = orderedLine(end); + if (line != nullptr) + { + uint32_t codePointIndex = + offset < 0 + ? line->firstCodePointIndex(m_shape.glyphLookup()) + : line->lastCodePointIndex(m_shape.glyphLookup()); + position = CursorPosition(end.lineIndex(), codePointIndex); + } + break; + } + case CursorBoundary::word: + case CursorBoundary::subWord: + { + Delineator classification = + classify(position - (offset < 0 ? 1 : 0)); + + switch (classification) + { + case Delineator::whitespace: + case Delineator::underscore: + classification = find(~classification, position, offset); + break; + default: + break; + } + + switch (classification) + { + case Delineator::symbol: + classification = find(~classification, position, offset); + break; + case Delineator::lowercase: + if (boundary == CursorBoundary::subWord) + { + Delineator nonLowerCase = + find(~Delineator::lowercase, position, offset); + if (offset == -1 && + nonLowerCase == Delineator::uppercase) + { + position = position - 1; + } + } + else + { + find(~(Delineator::lowercase | Delineator::uppercase | + Delineator::underscore), + position, + offset); + } + break; + case Delineator::uppercase: + if (boundary == CursorBoundary::subWord) + { + CursorPosition startPosition = position; + Delineator nonUpper = + find(~Delineator::uppercase, position, offset); + if (offset == 1 && nonUpper == Delineator::lowercase) + { + position = position - 1; + if (position.codePointIndex() == + startPosition.codePointIndex()) + { + find(~Delineator::lowercase, position, offset); + } + } + } + else + { + find(~(Delineator::lowercase | Delineator::uppercase | + Delineator::underscore), + position, + offset); + } + break; + default: + find(~classification, position, offset); + break; + } + break; + } + default: + break; + } + + if (select) + { + m_cursor = Cursor(m_cursor.start(), position); + } + else + { + m_cursor = Cursor::collapsed(position); + } + + flag(Flags::selectionDirty); +} + +RawTextInput::Delineator RawTextInput::classify(Unichar codepoint) +{ + if (isWhiteSpace(codepoint)) + { + return Delineator::whitespace; + } + if (codepoint == 95) + { + return Delineator::underscore; + } + if (codepoint < 48 || (codepoint >= 58 && codepoint <= 64) || + (codepoint >= 91 && codepoint <= 96) || + (codepoint >= 123 && codepoint <= 127)) + { + return Delineator::symbol; + } + if (codepoint >= 65 && codepoint <= 90) + { + return Delineator::uppercase; + } + return Delineator::lowercase; +} + +RawTextInput::Delineator RawTextInput::classify(CursorPosition position) const +{ + if (empty() || position.codePointIndex() >= m_text.size() - 1) + { + return Delineator::whitespace; + } + return classify(m_text[position.codePointIndex()]); +} + +RawTextInput::Delineator RawTextInput::find(uint8_t delineatorMask, + CursorPosition& position, + int32_t direction) const +{ + Delineator lastClassification = Delineator::unknown; + while (true) + { + CursorPosition nextPosition = position + direction; + if (nextPosition.codePointIndex() == position.codePointIndex()) + { + break; + } + + position = nextPosition; + if (((lastClassification = + classify(nextPosition - (direction < 0 ? 1 : 0))) & + delineatorMask) != 0) + { + break; + } + } + return lastClassification; +} + +CursorPosition RawTextInput::findPosition(uint8_t delineatorMask, + const CursorPosition& position, + int32_t direction) const +{ + CursorPosition result = position; + while (true) + { + CursorPosition nextPosition = result + direction; + + if (nextPosition.codePointIndex() == result.codePointIndex() || + (size_t)nextPosition.codePointIndex() >= length()) + { + break; + } + + if ((classify(nextPosition) & delineatorMask) != 0) + { + break; + } + result = nextPosition; + } + return result; +} + +void RawTextInput::cursorLeft(CursorBoundary boundary, bool select) +{ + cursorHorizontal(-1, boundary, select); +} + +void RawTextInput::cursorRight(CursorBoundary boundary, bool select) +{ + cursorHorizontal(1, boundary, select); +} + +void RawTextInput::cursorUp(bool select) +{ + if (m_idealCursorX == -1.0f) + { + m_idealCursorX = m_cursorVisualPosition.x(); + } + uint32_t lineIndex = m_cursor.end().lineIndex(); + + auto position = + lineIndex == 0 ? CursorPosition::zero() + : CursorPosition::fromLineX(m_cursor.end().lineIndex(-1), + m_idealCursorX, + m_shape); + if (select) + { + m_cursor = Cursor(m_cursor.start(), position); + } + else + { + m_cursor = Cursor::collapsed(position); + } + flag(Flags::selectionDirty); +} + +void RawTextInput::cursorDown(bool select) +{ + if (m_idealCursorX == -1.0f) + { + m_idealCursorX = m_cursorVisualPosition.x(); + } + uint32_t nextLineIndex = m_cursor.end().lineIndex(1); + auto position = + m_shape.lineCount() != 0 && m_text.size() > 1 && + nextLineIndex >= m_shape.lineCount() + ? CursorPosition((uint32_t)(m_shape.lineCount() - 1), + (uint32_t)(m_text.size() - 1)) + : CursorPosition::fromLineX(nextLineIndex, m_idealCursorX, m_shape); + + if (select) + { + m_cursor = Cursor(m_cursor.start(), position); + } + else + { + m_cursor = Cursor::collapsed(position); + } + flag(Flags::selectionDirty); +} + +void RawTextInput::moveCursorTo(Vec2D translation, bool select) +{ + m_idealCursorX = -1.0f; + auto position = CursorPosition::fromTranslation(translation, m_shape); + + if (select) + { + m_cursor = Cursor(m_cursor.start(), position); + } + else + { + m_cursor = Cursor::collapsed(position); + } + flag(Flags::selectionDirty); +} + +std::string RawTextInput::text() const +{ + size_t size = m_text.size(); + if (size == 0) + { + return std::string(); + } + + auto codePoints = Span(m_text.data(), size - 1); + + std::vector buffer(UTF::CountCodePointLength(codePoints)); + uint8_t* encoded = buffer.data(); + for (auto codePoint : codePoints) + { + encoded += UTF::Encode(encoded, codePoint); + } + + std::string str; + std::move(buffer.begin(), buffer.end(), std::back_inserter(str)); + return str; +} + +void RawTextInput::setTextPrivate(std::string value) +{ + const uint8_t* ptr = (const uint8_t*)value.c_str(); + m_text.clear(); + while (*ptr) + { + Unichar codePoint = UTF::NextUTF8(&ptr); + m_text.push_back(codePoint); + } + m_text.push_back(zeroWidthSpace); +} + +void RawTextInput::text(std::string value) +{ + Cursor startingCursor = m_cursor; + setTextPrivate(value); + auto position = CursorPosition::zero(); + m_cursor = Cursor::collapsed(position); + flag(Flags::shapeDirty | Flags::measureDirty | Flags::selectionDirty); + captureJournalEntry(startingCursor); +} + +size_t RawTextInput::length() const +{ + if (empty()) + { + return 0; + } + return m_text.size() - 1; +} + +bool RawTextInput::empty() const +{ + // note that we're empty at length 1 as we have our zeroWidthSpace + return m_text.size() <= 1; +} + +void RawTextInput::captureJournalEntry(Cursor cursor) +{ + if (m_journalIndex + 1 < m_journal.size()) + { + m_journal.erase(m_journal.begin() + m_journalIndex + 1, + m_journal.end()); + } + m_journal.push_back({cursor, m_cursor, text()}); + m_journalIndex = (uint32_t)m_journal.size() - 1; +} + +void RawTextInput::undo() +{ + if (m_journalIndex == 0) + { + return; + } + const JournalEntry& entryFrom = m_journal[m_journalIndex]; + const JournalEntry& entryTo = m_journal[m_journalIndex - 1]; + setTextPrivate(entryTo.text); + m_cursor = entryFrom.cursorFrom; + + m_journalIndex -= 1; + flag(Flags::shapeDirty | Flags::measureDirty | Flags::selectionDirty); +} +void RawTextInput::redo() +{ + if (m_journal.empty() || m_journalIndex + 1 >= m_journal.size()) + { + return; + } + const JournalEntry& entryTo = m_journal[m_journalIndex + 1]; + setTextPrivate(entryTo.text); + m_cursor = entryTo.cursorTo; + m_journalIndex += 1; + flag(Flags::shapeDirty | Flags::measureDirty | Flags::selectionDirty); +} + +bool RawTextInput::flagged(RawTextInput::Flags mask) const +{ + return m_flags & mask; +} + +bool RawTextInput::unflag(RawTextInput::Flags mask) +{ + if (m_flags & mask) + { + m_flags &= ~mask; + return true; + } + + return false; +} + +void RawTextInput::flag(RawTextInput::Flags mask) { m_flags |= mask; } + +bool RawTextInput::separateSelectionText() const +{ + return flagged(Flags::separateSelectionText); +} + +void RawTextInput::separateSelectionText(bool value) +{ + if (value) + { + flag(Flags::separateSelectionText); + } + else + { + unflag(Flags::separateSelectionText); + } + flag(Flags::shapeDirty | Flags::measureDirty | Flags::selectionDirty); +} + +AABB RawTextInput::measure(float maxWidth, float maxHeight) +{ + if (m_textRun.font == nullptr) + { + return AABB(); + } + bool force = m_lastMeasureMaxWidth != maxWidth || + m_lastMeasureMaxHeight != maxHeight; + if (!m_measuringShape) + { + force = true; + m_measuringShape = rivestd::make_unique(); + } + if (unflag(Flags::measureDirty) || force) + { + m_textRun.unicharCount = (uint32_t)m_text.size(); + m_measuringShape->shape(m_text, + Span(&m_textRun, 1), + TextSizing::autoHeight, + maxWidth, + maxHeight, + m_align, + m_wrap, + m_origin, + m_overflow, + m_paragraphSpacing); + m_lastMeasureMaxWidth = maxWidth; + m_lastMeasureMaxHeight = maxHeight; +#ifdef TESTING + measureCount++; +#endif + } + return m_measuringShape->bounds(); +} + +#endif diff --git a/third_party/rive/source/text/text.cpp b/third_party/rive/source/text/text.cpp new file mode 100644 index 0000000..3f88c99 --- /dev/null +++ b/third_party/rive/source/text/text.cpp @@ -0,0 +1,999 @@ +#include "rive/text/text.hpp" +using namespace rive; +#ifdef WITH_RIVE_TEXT +#include "rive/text_engine.hpp" +#include "rive/component_dirt.hpp" +#include "rive/math/rectangles_to_contour.hpp" +#include "rive/math/transform_components.hpp" +#include "rive/text/text_style_paint.hpp" +#include "rive/text/text_value_run.hpp" +#include "rive/text/text_modifier_group.hpp" +#include "rive/shapes/paint/shape_paint.hpp" +#include "rive/artboard.hpp" +#include "rive/factory.hpp" +#include "rive/clip_result.hpp" +#include + +Vec2D Text::measureLayout(float width, + LayoutMeasureMode widthMode, + float height, + LayoutMeasureMode heightMode) +{ + return measure(Vec2D(widthMode == LayoutMeasureMode::undefined + ? std::numeric_limits::max() + : width, + heightMode == LayoutMeasureMode::undefined + ? std::numeric_limits::max() + : height)); +} + +void Text::controlSize(Vec2D size, + LayoutScaleType widthScaleType, + LayoutScaleType heightScaleType, + LayoutDirection direction) +{ + if (m_layoutWidth != size.x || m_layoutHeight != size.y || + m_layoutWidthScaleType != (uint8_t)widthScaleType || + m_layoutHeightScaleType != (uint8_t)heightScaleType || + m_layoutDirection != direction) + { + m_layoutWidth = size.x; + m_layoutHeight = size.y; + m_layoutWidthScaleType = (uint8_t)widthScaleType; + m_layoutHeightScaleType = (uint8_t)heightScaleType; + m_layoutDirection = direction; + markShapeDirty(false); + } +} + +TextSizing Text::effectiveSizing() const +{ + if (m_layoutWidthScaleType == std::numeric_limits::max() || + m_layoutWidthScaleType == (uint8_t)LayoutScaleType::hug || + m_layoutHeightScaleType == (uint8_t)LayoutScaleType::hug) + { + return sizing(); + } + return TextSizing::fixed; +} + +void Text::clearRenderStyles() +{ + for (TextStylePaint* style : m_renderStyles) + { + style->rewindPath(); + } + m_renderStyles.clear(); + + for (TextValueRun* textValueRun : m_runs) + { + textValueRun->resetHitTest(); + } +} + +TextBoundsInfo Text::computeBoundsInfo() +{ + const float paragraphSpace = paragraphSpacing(); + + // Build up ordered runs as we go. + int paragraphIndex = 0; + float y = 0.0f; + float minY = 0.0f; + float maxWidth = 0.0f; + if (textOrigin() == TextOrigin::baseline && !m_lines.empty() && + !m_lines[0].empty()) + { + y -= m_lines[0][0].baseline; + minY = y; + } + + int ellipsisLine = -1; + bool isEllipsisLineLast = false; + // Find the line to put the ellipsis on (line before the one that + // overflows). + bool wantEllipsis = overflow() == TextOverflow::ellipsis && + effectiveSizing() == TextSizing::fixed && + verticalAlign() == VerticalTextAlign::top; + + int lastLineIndex = -1; + for (const SimpleArray& paragraphLines : m_lines) + { + const Paragraph& paragraph = m_shape[paragraphIndex++]; + for (const GlyphLine& line : paragraphLines) + { + const GlyphRun& endRun = paragraph.runs[line.endRunIndex]; + const GlyphRun& startRun = paragraph.runs[line.startRunIndex]; + float width = endRun.xpos[line.endGlyphIndex] - + startRun.xpos[line.startGlyphIndex]; + if (width > maxWidth) + { + maxWidth = width; + } + lastLineIndex++; + if (wantEllipsis && y + line.bottom <= effectiveHeight()) + { + ellipsisLine++; + } + } + + if (!paragraphLines.empty()) + { + y += paragraphLines.back().bottom; + } + y += paragraphSpace; + } + auto totalHeight = y; + if (wantEllipsis && ellipsisLine == -1) + { + // Nothing fits, just show the first line and ellipse it. + ellipsisLine = 0; + } + isEllipsisLineLast = lastLineIndex == ellipsisLine; + return { + minY, + maxWidth, + totalHeight, + ellipsisLine, + isEllipsisLineLast, + }; +} + +LineIter Text::shouldDrawLine(float curY, + float totalHeight, + const GlyphLine& line) +{ + switch (overflow()) + { + case TextOverflow::hidden: + if (effectiveSizing() == TextSizing::fixed) + { + switch (verticalAlign()) + { + case VerticalTextAlign::top: + if (curY + line.bottom > effectiveHeight()) + { + return LineIter::yOutOfBounds; + } + break; + case VerticalTextAlign::middle: + if (curY + line.top < + totalHeight / 2 - effectiveHeight() / 2) + { + return LineIter::skipThisLine; + } + if (curY + line.bottom > + totalHeight / 2 + effectiveHeight() / 2) + { + return LineIter::yOutOfBounds; + } + break; + case VerticalTextAlign::bottom: + if (curY + line.top < totalHeight - effectiveHeight()) + { + return LineIter::skipThisLine; + } + break; + } + } + break; + case TextOverflow::clipped: + if (effectiveSizing() == TextSizing::fixed) + { + switch (verticalAlign()) + { + case VerticalTextAlign::top: + if (curY + line.top > effectiveHeight()) + { + return LineIter::yOutOfBounds; + } + break; + case VerticalTextAlign::middle: + if (curY + line.bottom < + totalHeight / 2 - effectiveHeight() / 2) + { + return LineIter::skipThisLine; + } + if (curY + line.top > + totalHeight / 2 + effectiveHeight() / 2) + { + return LineIter::yOutOfBounds; + } + break; + case VerticalTextAlign::bottom: + if (curY + line.bottom < + totalHeight - effectiveHeight()) + { + return LineIter::skipThisLine; + } + break; + } + } + break; + default: + break; + } + return LineIter::drawLine; +} + +void Text::buildRenderStyles() +{ + // Step 1: reset stuff + clearRenderStyles(); + + if (m_shape.empty()) + { + m_bounds = AABB(0.0f, 0.0f, 0.0f, 0.0f); + return; + } + + // Step 2: compute ellipsis information + TextBoundsInfo info = computeBoundsInfo(); + float minY = info.minY; + float maxWidth = info.maxWidth; + float totalHeight = info.totalHeight; + int ellipsisLine = info.ellipsisLine; + bool isEllipsisLineLast = info.isEllipsisLineLast; + + // Step 3: update modifiers + bool hasModifiers = haveModifiers(); + if (hasModifiers) + { + uint32_t textSize = (uint32_t)m_styledText.unichars().size(); + for (TextModifierGroup* modifierGroup : m_modifierGroups) + { + modifierGroup->computeCoverage(textSize); + modifierGroup->resetTextFollowPath(); + } + } + + // Step 4: update bounds + const float paragraphSpace = paragraphSpacing(); + switch (effectiveSizing()) + { + case TextSizing::autoWidth: + m_bounds = AABB(0.0f, + minY, + maxWidth, + std::max(minY, totalHeight - paragraphSpace)); + break; + case TextSizing::autoHeight: + m_bounds = AABB(0.0f, + minY, + effectiveWidth(), + std::max(minY, totalHeight - paragraphSpace)); + break; + case TextSizing::fixed: + m_bounds = + AABB(0.0f, minY, effectiveWidth(), minY + effectiveHeight()); + break; + } + + auto verticalAlignOffset = 0.0f; + switch (verticalAlign()) + { + case VerticalTextAlign::middle: + verticalAlignOffset = (totalHeight - m_bounds.height()) / 2; + break; + case VerticalTextAlign::bottom: + verticalAlignOffset = totalHeight - m_bounds.height(); + break; + default: + break; + } + + // Step 5: Update clip information (if we want it) + if (overflow() == TextOverflow::clipped) + { + m_clipRect.rewind(); + + AABB bounds = localBounds(); + + float minX = bounds.minX + bounds.width() * originX(); + float minY = + bounds.minY + bounds.height() * originY() + verticalAlignOffset; + m_clipRect.addRect( + AABB(minX, minY, minX + bounds.width(), minY + bounds.height())); + } + + // Step 6: add the glyphs to render paths + float curY = minY; + int lineIndex = 0; + int paragraphIndex = 0; + float minX = std::numeric_limits::max(); + + for (const SimpleArray& paragraphLines : m_lines) + { + const Paragraph& paragraph = m_shape[paragraphIndex++]; + int lineIndexInParagraph = 0; + for (const GlyphLine& line : paragraphLines) + { + LineIter lineIter = shouldDrawLine(curY, totalHeight, line); + if (lineIter == LineIter::yOutOfBounds) + { + goto skipLines; + } + else if (lineIter == LineIter::skipThisLine) + { + lineIndexInParagraph++; + lineIndex++; + continue; + } + + float renderY = curY + line.baseline; + // We need to compute this line's ordered runs. + m_orderedLines.emplace_back(OrderedLine(paragraph, + line, + effectiveWidth(), + ellipsisLine == lineIndex, + isEllipsisLineLast, + &m_ellipsisRun, + renderY)); + + float curX = line.startX; + minX = std::min(curX, minX); + for (auto glyphItr : m_orderedLines.back()) + { + const GlyphRun* run = std::get<0>(glyphItr); + size_t glyphIndex = std::get<1>(glyphItr); + + const Font* font = run->font.get(); + const Vec2D& offset = run->offsets[glyphIndex]; + + GlyphID glyphId = run->glyphs[glyphIndex]; + float advance = run->advances[glyphIndex]; + + RawPath path = font->getPath(glyphId); + + // Step 6.1: translate to the glyph's origin and scale. + Vec2D curPos(curX, renderY); + float centerX = advance / 2.0f; + TransformComponents tc; + tc.scaleX(run->size); + tc.scaleY(run->size); + tc.x(-centerX); + Mat2D pathTransform = Mat2D::compose(tc); + + // Step 6.2: apply modifiers on a font-sized glyph + float opacity = 1.0f; + if (hasModifiers) + { + uint32_t textIndex = run->textIndices[glyphIndex]; + uint32_t glyphCount = m_glyphLookup.count(textIndex); + + for (TextModifierGroup* modifierGroup : m_modifierGroups) + { + float coverage = + modifierGroup->glyphCoverage(textIndex, glyphCount); + TransformGlyphArg arg = { + curPos, + centerX, + lineIndexInParagraph, + paragraphLines, + }; + modifierGroup->transform(coverage, pathTransform, arg); + if (modifierGroup->modifiesOpacity()) + { + opacity = modifierGroup->computeOpacity(opacity, + coverage); + } + } + } + + // Step 6.3: translate back to center with offset + pathTransform = + Mat2D::fromTranslate(curPos.x + centerX + offset.x, + curPos.y + offset.y) * + pathTransform; + + path.transformInPlace(pathTransform); + + assert(run->styleId < m_runs.size()); + TextValueRun* textValueRun = m_runs[run->styleId]; + TextStylePaint* style = textValueRun->style(); + // TextValueRun::onAddedDirty botches loading if it cannot + // resolve a style, so we're confident we have a style here. + assert(style != nullptr); + + if (style->addPath(path, opacity)) + { + // This was the first path added to the style, so let's + // mark it in our draw list. + m_renderStyles.push_back(style); + style->propagateOpacity(renderOpacity()); + } + + // Bounds of the glyph + if (textValueRun->isHitTarget()) + { + Vec2D topLeft = Vec2D(curX, curY + line.top); + Vec2D bottomRight = + Vec2D(curX + advance, curY + line.bottom); + textValueRun->addHitRect(AABB(topLeft.x, + topLeft.y, + bottomRight.x, + bottomRight.y)); + } + curX += advance; + } + if (lineIndex == ellipsisLine) + { + goto skipLines; + } + lineIndexInParagraph++; + lineIndex++; + } + if (!paragraphLines.empty()) + { + curY += paragraphLines.back().bottom; + } + curY += paragraphSpacing(); + } +skipLines: + // Step 7: consider fit mode, and update local transform + auto scale = 1.0f; + auto xOffset = -m_bounds.width() * originX(); + auto yOffset = -m_bounds.height() * originY(); + if (overflow() == TextOverflow::fit) + { + auto xScale = (effectiveSizing() != TextSizing::autoWidth && + maxWidth > m_bounds.width()) + ? m_bounds.width() / maxWidth + : 1; + auto baseline = fitFromBaseline() ? m_lines[0][0].baseline : 0; + auto yScale = + (effectiveSizing() == TextSizing::fixed && + totalHeight > m_bounds.height()) + ? (m_bounds.height() - baseline) / (totalHeight - baseline) + : 1; + if (xScale != 1 || yScale != 1) + { + scale = std::max(0.0f, xScale > yScale ? yScale : xScale); + yOffset += baseline * (1 - scale); + switch (align()) + { + case TextAlign::center: + xOffset += (m_bounds.width() - maxWidth * scale) / 2 - + minX * scale; + break; + case TextAlign::right: + xOffset += + m_bounds.width() - maxWidth * scale - minX * scale; + break; + default: + break; + } + } + } + if (verticalAlign() != VerticalTextAlign::top) + { + if (effectiveSizing() == TextSizing::fixed) + { + yOffset = -m_bounds.height() * originY(); + if (verticalAlign() == VerticalTextAlign::middle) + { + yOffset += (m_bounds.height() - totalHeight * scale) / 2; + } + else if (verticalAlign() == VerticalTextAlign::bottom) + { + yOffset += m_bounds.height() - totalHeight * scale; + } + } + } + m_transform = + Mat2D::fromScaleAndTranslation(scale, scale, xOffset, yOffset); +#ifdef WITH_RIVE_LAYOUT + markLayoutNodeDirty(); +#endif + + // Step 8: cleanup + for (TextValueRun* textValueRun : m_runs) + { + if (textValueRun->isHitTarget()) + { + textValueRun->computeHitContours(); + } + } +} + +const TextStylePaint* Text::styleFromShaperId(uint16_t id) const +{ + assert(id < m_runs.size()); + return m_runs[id]->style(); +} + +void Text::draw(Renderer* renderer) +{ + ClipResult clipResult = applyClip(renderer); + if (clipResult == ClipResult::noClip) + { + // We didn't clip, so make sure to save as we'll be doing some + // transformations. + renderer->save(); + } + if (clipResult != ClipResult::emptyClip) + { + // For now we need to check both empty() and hasRenderPath() in + // ShapePaintPath because the raw path gets cleared when the render path + // is created. + if (overflow() == TextOverflow::clipped && + (!m_clipPath.empty() || m_clipPath.hasRenderPath())) + { + renderer->clipPath(m_clipPath.renderPath(this)); + } + auto worldTransform = shapeWorldTransform(); + for (auto style : m_renderStyles) + { + style->draw(renderer, worldTransform); + } + } + renderer->restore(); +} + +void Text::addRun(TextValueRun* run) { m_runs.push_back(run); } + +void Text::addModifierGroup(TextModifierGroup* group) +{ + m_modifierGroups.push_back(group); +} + +void Text::markShapeDirty() { markShapeDirty(true); } + +void Text::markShapeDirty(bool sendToLayout) +{ + addDirt(ComponentDirt::Path); + for (TextModifierGroup* group : m_modifierGroups) + { + group->clearRangeMaps(); + } + markWorldTransformDirty(); +#ifdef WITH_RIVE_LAYOUT + if (sendToLayout) + { + markLayoutNodeDirty(); + } +#endif +} + +void Text::modifierShapeDirty() { addDirt(ComponentDirt::Path); } + +void Text::markPaintDirty() { addDirt(ComponentDirt::Paint); } + +void Text::alignValueChanged() { markShapeDirty(); } + +void Text::sizingValueChanged() { markShapeDirty(); } + +void Text::overflowValueChanged() +{ + if (effectiveSizing() != TextSizing::autoWidth) + { + markShapeDirty(); + } +} + +void Text::widthChanged() +{ + if (effectiveSizing() != TextSizing::autoWidth) + { + markShapeDirty(); + } +} + +void Text::paragraphSpacingChanged() { markPaintDirty(); } + +void Text::heightChanged() +{ + if (effectiveSizing() == TextSizing::fixed) + { + markShapeDirty(); + } +} + +void StyledText::clear() +{ + m_value.clear(); + m_runs.clear(); +} + +bool StyledText::empty() const { return m_runs.empty(); } + +void StyledText::append(rcp font, + float size, + float lineHeight, + float letterSpacing, + const std::string& text, + uint16_t styleId) +{ + const uint8_t* ptr = (const uint8_t*)text.c_str(); + uint32_t n = 0; + while (*ptr) + { + m_value.push_back(UTF::NextUTF8(&ptr)); + n += 1; + } + m_runs.push_back( + {std::move(font), size, lineHeight, letterSpacing, n, 0, styleId}); +} + +bool Text::makeStyled(StyledText& styledText, bool withModifiers) const +{ + styledText.clear(); + uint16_t runIndex = 0; + for (auto valueRun : m_runs) + { + auto style = valueRun->style(); + const std::string& text = valueRun->text(); + if (style == nullptr || style->font() == nullptr || text.empty()) + { + runIndex++; + continue; + } + styledText.append(style->font(), + style->fontSize(), + style->lineHeight(), + style->letterSpacing(), + text, + runIndex++); + } + if (withModifiers) + { + for (TextModifierGroup* group : m_modifierGroups) + { + group->applyShapeModifiers(*this, styledText); + } + } + return !styledText.empty(); +} + +SimpleArray> Text::BreakLines( + const SimpleArray& paragraphs, + float width, + TextAlign align, + TextWrap wrap) +{ + bool autoWidth = width == -1.0f; + float paragraphWidth = width; + + SimpleArray> lines(paragraphs.size()); + + size_t paragraphIndex = 0; + for (auto& para : paragraphs) + { + lines[paragraphIndex] = GlyphLine::BreakLines( + para.runs, + (autoWidth || wrap == TextWrap::noWrap) ? -1.0f : width); + if (autoWidth) + { + paragraphWidth = std::max( + paragraphWidth, + GlyphLine::ComputeMaxWidth(lines[paragraphIndex], para.runs)); + } + paragraphIndex++; + } + paragraphIndex = 0; + for (auto& para : paragraphs) + { + GlyphLine::ComputeLineSpacing(paragraphIndex == 0, + lines[paragraphIndex], + para.runs, + paragraphWidth, + align); + paragraphIndex++; + } + return lines; +} + +bool Text::modifierRangesNeedShape() const +{ + for (const TextModifierGroup* modifierGroup : m_modifierGroups) + { + if (modifierGroup->needsShape()) + { + return true; + } + } + return false; +} + +void Text::onDirty(ComponentDirt value) +{ + // Sometimes a WorldTransform dirt may also affect Path + if (hasDirt(value, ComponentDirt::WorldTransform)) + { + for (TextModifierGroup* modifierGroup : m_modifierGroups) + { + modifierGroup->onTextWorldTransformDirty(); + } + } + if (hasDirt(value, ComponentDirt::Path | ComponentDirt::Paint)) + { + for (TextStylePaint* style : m_renderStyles) + { + style->invalidateStrokeEffects(); + } + } +} + +void Text::update(ComponentDirt value) +{ + Super::update(value); + + if (hasDirt(value, ComponentDirt::Path)) + { + // We have modifiers that need shaping we'll need to compute the + // coverage right before we build the actual shape. + bool precomputeModifierCoverage = modifierRangesNeedShape(); + bool parentIsLayoutNotArtboard = + parent()->is() && !parent()->is(); + if (precomputeModifierCoverage) + { + makeStyled(m_modifierStyledText, false); + auto runs = m_modifierStyledText.runs(); + m_modifierShape = + runs[0].font->shapeText(m_modifierStyledText.unichars(), runs); + m_modifierLines = + BreakLines(m_modifierShape, + (effectiveSizing() == TextSizing::autoWidth && + !parentIsLayoutNotArtboard) + ? -1.0f + : effectiveWidth(), + align(), + wrap()); + m_glyphLookup.compute(m_modifierStyledText.unichars(), + m_modifierShape); + uint32_t textSize = + (uint32_t)m_modifierStyledText.unichars().size(); + for (TextModifierGroup* group : m_modifierGroups) + { + group->computeRangeMap(m_modifierStyledText.unichars(), + m_modifierShape, + m_modifierLines, + m_glyphLookup); + group->computeCoverage(textSize); + } + } + if (makeStyled(m_styledText)) + { + auto runs = m_styledText.runs(); + m_shape = runs[0].font->shapeText(m_styledText.unichars(), runs); + + m_lines = BreakLines(m_shape, + (effectiveSizing() == TextSizing::autoWidth && + !parentIsLayoutNotArtboard) + ? -1.0f + : effectiveWidth(), + align(), + wrap()); + if (!precomputeModifierCoverage && haveModifiers()) + { + m_glyphLookup.compute(m_styledText.unichars(), m_shape); + uint32_t textSize = (uint32_t)m_styledText.unichars().size(); + for (TextModifierGroup* group : m_modifierGroups) + { + group->computeRangeMap(m_styledText.unichars(), + m_shape, + m_lines, + m_glyphLookup); + group->computeCoverage(textSize); + } + } + } + else + { + m_shape = SimpleArray(); + m_lines = SimpleArray>(); + m_glyphLookup.clear(); + } + m_orderedLines.clear(); + m_ellipsisRun = {}; + + // Immediately build render styles so dimensions get computed. + buildRenderStyles(); + } + else if (hasDirt(value, ComponentDirt::Paint)) + { + buildRenderStyles(); + } + else if (hasDirt(value, ComponentDirt::RenderOpacity)) + { + // Note that buildRenderStyles does this too, which is why we can get + // away doing this in the else. + for (TextStylePaint* style : m_renderStyles) + { + style->propagateOpacity(renderOpacity()); + } + } + + if (hasDirt(value, + ComponentDirt::WorldTransform | ComponentDirt::Path | + ComponentDirt::Paint)) + { + m_clipPath.rewind(); + m_shapeWorldTransform = m_WorldTransform * m_transform; + m_clipPath.addPath(m_clipRect, &m_shapeWorldTransform); + } +} + +Vec2D Text::measure(Vec2D maxSize) +{ + if (makeStyled(m_styledText)) + { + const float paragraphSpace = paragraphSpacing(); + auto runs = m_styledText.runs(); + auto shape = runs[0].font->shapeText(m_styledText.unichars(), runs); + auto measuringWidth = 0.0f; + switch (effectiveSizing()) + { + case TextSizing::autoHeight: + case TextSizing::fixed: + measuringWidth = width(); + break; + default: + measuringWidth = std::numeric_limits::max(); + break; + } + auto measuringWrap = maxSize.x == std::numeric_limits::max() && + effectiveSizing() != TextSizing::autoHeight + ? TextWrap::noWrap + : wrap(); + auto lines = BreakLines(shape, + std::min(maxSize.x, measuringWidth), + align(), + measuringWrap); + float y = 0; + float computedHeight = 0.0f; + float minY = 0; + int paragraphIndex = 0; + float maxWidth = 0; + + if (textOrigin() == TextOrigin::baseline && !lines.empty() && + !lines[0].empty()) + { + y -= lines[0][0].baseline; + minY = y; + } + int ellipsisLine = -1; + bool wantEllipsis = overflow() == TextOverflow::ellipsis && + sizing() == TextSizing::fixed && + verticalAlign() == VerticalTextAlign::top; + + for (const SimpleArray& paragraphLines : lines) + { + const Paragraph& paragraph = shape[paragraphIndex++]; + for (const GlyphLine& line : paragraphLines) + { + const GlyphRun& endRun = paragraph.runs[line.endRunIndex]; + const GlyphRun& startRun = paragraph.runs[line.startRunIndex]; + float width = endRun.xpos[line.endGlyphIndex] - + startRun.xpos[line.startGlyphIndex]; + if (width > maxWidth) + { + maxWidth = width; + } + if (wantEllipsis && y + line.bottom > maxSize.y) + { + if (ellipsisLine == -1) + { + // Nothing fits, just show the first line and ellipse + // it. + computedHeight = y + line.bottom; + } + goto doneMeasuring; + } + ellipsisLine++; + computedHeight = y + line.bottom; + } + if (!paragraphLines.empty()) + { + y += paragraphLines.back().bottom; + } + y += paragraphSpace; + } + doneMeasuring: + Vec2D bounds; + switch (sizing()) + { + case TextSizing::autoWidth: + bounds = Vec2D(maxWidth, std::max(minY, computedHeight)); + break; + case TextSizing::autoHeight: + bounds = Vec2D(width(), std::max(minY, computedHeight)); + break; + case TextSizing::fixed: + bounds = Vec2D(width(), minY + height()); + break; + } + return Vec2D(std::min(maxSize.x, bounds.x), + std::min(maxSize.y, bounds.y)); + } + return Vec2D(); +} + +AABB Text::localBounds() const +{ + float width = m_bounds.width(); + float height = m_bounds.height(); + return AABB::fromLTWH(m_bounds.minX - width * originX(), + m_bounds.minY - height * originY(), + width, + height); +} + +Core* Text::hitTest(HitInfo*, const Mat2D&) +{ + if (renderOpacity() == 0.0f) + { + return nullptr; + } + + return nullptr; +} + +void Text::originValueChanged() +{ + markPaintDirty(); + markWorldTransformDirty(); +} + +void Text::originXChanged() +{ + markPaintDirty(); + markWorldTransformDirty(); +} +void Text::originYChanged() +{ + markPaintDirty(); + markWorldTransformDirty(); +} + +#else +// Text disabled. +void Text::draw(Renderer* renderer) {} +Core* Text::hitTest(HitInfo*, const Mat2D&) { return nullptr; } +void Text::addRun(TextValueRun* run) {} +void Text::addModifierGroup(TextModifierGroup* group) {} +void Text::markShapeDirty(bool sendToLayout) {} +void Text::markShapeDirty() {} +void Text::update(ComponentDirt value) {} +void Text::onDirty(ComponentDirt value) {} +void Text::alignValueChanged() {} +void Text::sizingValueChanged() {} +void Text::overflowValueChanged() {} +void Text::widthChanged() {} +void Text::heightChanged() {} +void Text::markPaintDirty() {} +void Text::modifierShapeDirty() {} +bool Text::modifierRangesNeedShape() const { return false; } +const TextStylePaint* Text::styleFromShaperId(uint16_t id) const +{ + return nullptr; +} +void Text::paragraphSpacingChanged() {} +AABB Text::localBounds() const { return AABB(); } +void Text::originValueChanged() {} +void Text::originXChanged() {} +void Text::originYChanged() {} +Vec2D Text::measureLayout(float width, + LayoutMeasureMode widthMode, + float height, + LayoutMeasureMode heightMode) +{ + return Vec2D(); +} +void Text::controlSize(Vec2D size, + LayoutScaleType widthScaleType, + LayoutScaleType heightScaleType, + LayoutDirection direction) +{} +#endif + +TextAlign Text::align() const +{ + auto val = (TextAlign)alignValue(); + if (m_layoutDirection == LayoutDirection::inherit || + val == TextAlign::center) + { + return val; + } + return m_layoutDirection == LayoutDirection::ltr ? TextAlign::left + : TextAlign::right; +} \ No newline at end of file diff --git a/third_party/rive/source/text/text_engine.cpp b/third_party/rive/source/text/text_engine.cpp new file mode 100644 index 0000000..68b5852 --- /dev/null +++ b/third_party/rive/source/text/text_engine.cpp @@ -0,0 +1,310 @@ +#include "rive/text_engine.hpp" +#include "rive/text/utf.hpp" +#include "rive/text/glyph_lookup.hpp" +#ifdef WITH_RIVE_TEXT +using namespace rive; + +static void appendUnicode(std::vector& unichars, + const char text[]) +{ + const uint8_t* ptr = (const uint8_t*)text; + while (*ptr) + { + unichars.push_back(rive::UTF::NextUTF8(&ptr)); + } +} + +static void reverseRuns(const GlyphRun** runs, int count) +{ + int halfCount = count / 2; + int finalIndex = count - 1; + + for (int index = 0; index < halfCount; index++) + { + int tieIndex = finalIndex - index; + + const GlyphRun* tempRun = runs[index]; + runs[index] = runs[tieIndex]; + runs[tieIndex] = tempRun; + } +} + +OrderedLine::OrderedLine(const Paragraph& paragraph, + const GlyphLine& line, + float lineWidth, + bool wantEllipsis, + bool isEllipsisLineLast, + GlyphRun* ellipsisRun, + float y) : + m_startGlyphIndex(line.startGlyphIndex), + m_endGlyphIndex(line.endGlyphIndex), + m_glyphLine(&line), + m_y(y) +{ + std::vector logicalRuns; + const SimpleArray& glyphRuns = paragraph.runs; + + if (!wantEllipsis || !buildEllipsisRuns(logicalRuns, + paragraph, + line, + lineWidth, + isEllipsisLineLast, + ellipsisRun)) + { + for (uint32_t i = line.startRunIndex; i < line.endRunIndex + 1; i++) + { + logicalRuns.push_back(&glyphRuns[i]); + } + + if (!logicalRuns.empty()) + { + m_startLogical = logicalRuns.front(); + m_endLogical = logicalRuns.back(); + } + } + + uint8_t maxLevel = 0; + for (auto run : logicalRuns) + { + if (run->level > maxLevel) + { + maxLevel = run->level; + } + } + for (uint8_t newLevel = maxLevel; newLevel > 0; newLevel--) + { + for (int start = (int)(logicalRuns.size()) - 1; start >= 0; start--) + { + if (logicalRuns[start]->level >= newLevel) + { + int count = 1; + for (; start > 0 && logicalRuns[start - 1]->level >= newLevel; + start--) + { + count++; + } + reverseRuns(logicalRuns.data() + start, count); + } + } + } + + m_runs = std::move(logicalRuns); +} + +uint32_t OrderedLine::firstCodePointIndex(const GlyphLookup& glyphLookup) const +{ + GlyphItr index = begin(); + auto glyphIndex = index.glyphIndex(); + auto run = index.run(); + uint32_t firstCodePointIndex = run->textIndices[glyphIndex]; + if (run->dir() == TextDirection::rtl) + { + // If the final run is RTL we want to add the length of the final glyph + // to get the actual last available code unit in the line. + firstCodePointIndex += glyphLookup.count(run->textIndices[glyphIndex]); + } + // Clamp ignoring last zero width space for editing. + return std::min(firstCodePointIndex, glyphLookup.lastCodeUnitIndex() - 1); +} + +uint32_t OrderedLine::lastCodePointIndex(const GlyphLookup& glyphLookup) const +{ + GlyphItr index = begin(); + GlyphItr lastIndex = index; + + while (index != end()) + { + lastIndex = index; + ++index; + } + + auto glyphIndex = lastIndex.glyphIndex(); + auto run = lastIndex.run(); + + uint32_t lastCodePointIndex = run->textIndices[glyphIndex]; + if (run->dir() == TextDirection::ltr) + { + lastCodePointIndex += glyphLookup.count(run->textIndices[glyphIndex]); + } + // Clamp ignoring last zero width space for editing. + return std::min(lastCodePointIndex, glyphLookup.lastCodeUnitIndex() - 1); +} + +bool OrderedLine::containsCodePointIndex(const GlyphLookup& glyphLookup, + uint32_t codePointIndex) const +{ + return codePointIndex >= firstCodePointIndex(glyphLookup) && + codePointIndex <= lastCodePointIndex(glyphLookup); +} + +void GlyphItr::tryAdvanceRun() +{ + while (true) + { + auto run = *m_run; + if (m_glyphIndex == m_line->endGlyphIndex(run) && + run != m_line->lastRun()) + { + m_run++; + m_glyphIndex = m_line->startGlyphIndex(*m_run); + } + else + { + break; + } + } +} +GlyphItr& GlyphItr::operator++() +{ + auto run = *m_run; + m_glyphIndex += run->dir() == TextDirection::ltr ? 1 : -1; + tryAdvanceRun(); + return *this; +} + +bool OrderedLine::buildEllipsisRuns(std::vector& logicalRuns, + const Paragraph& paragraph, + const GlyphLine& line, + float lineWidth, + bool isEllipsisLineLast, + GlyphRun* storedEllipsisRun) +{ + float x = 0.0f; + const SimpleArray& glyphRuns = paragraph.runs; + uint32_t startGIndex = line.startGlyphIndex; + // If it's the last line we can actually early out if the whole things fits, + // so check that first with no extra shaping. + if (isEllipsisLineLast) + { + bool fits = true; + + for (uint32_t i = line.startRunIndex; i < line.endRunIndex + 1; i++) + { + const GlyphRun& run = glyphRuns[i]; + uint32_t endGIndex = i == line.endRunIndex + ? line.endGlyphIndex + : (uint32_t)run.glyphs.size(); + + for (uint32_t j = startGIndex; j != endGIndex; j++) + { + x += run.advances[j]; + if (x > lineWidth) + { + fits = false; + goto measured; + } + } + startGIndex = 0; + } + measured: + if (fits) + { + // It fits, just get the regular glyphs. + return false; + } + } + + std::vector ellipsisCodePoints; + appendUnicode(ellipsisCodePoints, "..."); + + rcp ellipsisFont = nullptr; + float ellipsisFontSize = 0.0f; + + GlyphRun ellipsisRun = {}; + float ellipsisWidth = 0.0f; + + bool ellipsisOverflowed = false; + startGIndex = line.startGlyphIndex; + x = 0.0f; + + for (uint32_t i = line.startRunIndex; i < line.endRunIndex + 1; i++) + { + const GlyphRun& run = glyphRuns[i]; + if (run.font != ellipsisFont && run.size != ellipsisFontSize) + { + // Track the latest we've checked (even if we discard it so we don't + // try to do this again for this ellipsis). + ellipsisFont = run.font; + ellipsisFontSize = run.size; + + // Get the next shape so we can check if it fits, otherwise keep + // using the last one. + TextRun ellipsisRuns[] = {{ + ellipsisFont, + ellipsisFontSize, + run.lineHeight, + run.letterSpacing, + (uint32_t)ellipsisCodePoints.size(), + 0, // default, TextRun.script + run.styleId, + }}; + auto nextEllipsisShape = + ellipsisFont->shapeText(ellipsisCodePoints, + Span(ellipsisRuns, 1)); + + // Hard assumption one run and para + const Paragraph& para = nextEllipsisShape[0]; + const GlyphRun& nextEllipsisRun = para.runs.front(); + + float nextEllipsisWidth = 0; + for (size_t j = 0; j < nextEllipsisRun.glyphs.size(); j++) + { + nextEllipsisWidth += nextEllipsisRun.advances[j]; + } + + if (ellipsisRun.font == nullptr || + x + nextEllipsisWidth <= lineWidth) + { + // This ellipsis still fits, go ahead and use it. Otherwise + // stick with the old one. + ellipsisWidth = nextEllipsisWidth; + ellipsisRun = std::move(para.runs.front()); + } + } + + uint32_t endGIndex = i == line.endRunIndex + ? line.endGlyphIndex + : (uint32_t)run.glyphs.size(); + for (uint32_t j = startGIndex; j != endGIndex; j++) + { + float advance = run.advances[j]; + if (x + advance + ellipsisWidth > lineWidth) + { + m_endGlyphIndex = j; + ellipsisOverflowed = true; + break; + } + x += advance; + } + startGIndex = 0; + logicalRuns.push_back(&run); + m_endLogical = &run; + + if (ellipsisOverflowed && ellipsisRun.font != nullptr) + { + *storedEllipsisRun = std::move(ellipsisRun); + logicalRuns.push_back(storedEllipsisRun); + break; + } + } + + // There was enough space for it, so let's add the ellipsis (if we didn't + // already). Note that we already checked if this is the last line and found + // that the whole text didn't fit. + if (!ellipsisOverflowed && ellipsisRun.font != nullptr) + { + *storedEllipsisRun = std::move(ellipsisRun); + logicalRuns.push_back(storedEllipsisRun); + } + m_startLogical = storedEllipsisRun == logicalRuns.front() + ? nullptr + : logicalRuns.front(); + return true; +} + +float OrderedLine::bottom() const +{ + return m_y - m_glyphLine->baseline + m_glyphLine->bottom; +} + +#endif \ No newline at end of file diff --git a/third_party/rive/source/text/text_follow_path_modifier.cpp b/third_party/rive/source/text/text_follow_path_modifier.cpp new file mode 100644 index 0000000..e7440e8 --- /dev/null +++ b/third_party/rive/source/text/text_follow_path_modifier.cpp @@ -0,0 +1,206 @@ +#include "rive/core_context.hpp" +#include "rive/math/math_types.hpp" +#include "rive/shapes/path.hpp" +#include "rive/shapes/shape.hpp" +#include "rive/text/text.hpp" +#include "rive/text/text_follow_path_modifier.hpp" +#include "rive/text/text_modifier_group.hpp" +#include "rive/transform_component.hpp" + +using namespace rive; + +// Path -> this -> text +void TextFollowPathModifier::buildDependencies() +{ + if (m_Target != nullptr && m_Target->is()) + { + Shape* shape = static_cast(m_Target); + shape->pathComposer()->addDependent(this); + } + + else if (m_Target != nullptr && m_Target->is()) + { + Path* path = static_cast(m_Target); + path->addDependent(this); + } + + Text* text = textComponent(); + if (text != nullptr) + { + addDependent(text); + } +} + +StatusCode TextFollowPathModifier::onAddedClean(CoreContext* context) +{ + if (m_Target != nullptr) + { + if (m_Target->is()) + { + Shape* shape = static_cast(m_Target); + shape->addFlags(PathFlags::followPath); + } + else if (m_Target->is()) + { + Path* path = static_cast(m_Target); + path->addFlags(PathFlags::followPath); + } + } + return Super::onAddedClean(context); +} + +void TextFollowPathModifier::update(ComponentDirt value) +{ + std::vector paths; + if (m_Target != nullptr && m_Target->is()) + { + auto shape = m_Target->as(); + for (auto path : shape->paths()) + { + paths.push_back(path); + } + } + else if (m_Target != nullptr && m_Target->is()) + { + paths.push_back(m_Target->as()); + } + + m_worldPath.rewind(); + for (auto path : paths) + { + m_worldPath.addPath(path->rawPath(), &path->pathTransform()); + } +} + +void TextFollowPathModifier::radialChanged() { modifierShapeDirty(); } +void TextFollowPathModifier::orientChanged() { modifierShapeDirty(); } +void TextFollowPathModifier::startChanged() { modifierShapeDirty(); } +void TextFollowPathModifier::endChanged() { modifierShapeDirty(); } +void TextFollowPathModifier::offsetChanged() { modifierShapeDirty(); } +void TextFollowPathModifier::strengthChanged() { modifierShapeDirty(); } +void TextFollowPathModifier::modifierShapeDirty() +{ + Text* text = textComponent(); + if (text != nullptr) + { + text->modifierShapeDirty(); + } +} + +void TextFollowPathModifier::reset(const Mat2D* inverseText) +{ + if (m_Target == nullptr) + { + m_pathMeasure = PathMeasure(); + return; + } + m_localPath.rewind(); + m_localPath.addPath(m_worldPath, inverseText); + m_pathMeasure = PathMeasure(&m_localPath, 0.1f); +} + +TransformComponents TextFollowPathModifier::transformGlyph( + const TransformComponents& cur, + const TransformGlyphArg& arg) +{ + float pathLength = m_pathMeasure.length(); + if (pathLength == 0) + { + return cur; + } + + const auto& paragraphLines = arg.paragraphLines; + int lineIndexInParagraph = arg.lineIndexInParagraph; + + Vec2D positionOnPath = arg.originPosition + arg.offset; + + // endPct >= startPct + float startPct = math::clamp(std::min(start(), end()), 0.0, 1.0); + float endPct = math::clamp(std::max(start(), end()), 0.0, 1.0); + bool canWrap = m_localPath.isClosed() && (endPct - startPct) == 1.0; + float validLength = (endPct - startPct) * pathLength; + + // 0%-100% + auto offsetPct = std::fmod(std::fmod(offset(), 1.0f) + 1.0f, 1.0f); + + // 0%-200% + startPct += offsetPct; + endPct += offsetPct; + + Vec2D position, tangent; + + // Render along the tangent if overflowing on either ends + if ((!canWrap && positionOnPath.x < 0) || startPct == endPct) + { + auto result = m_pathMeasure.atPercentage(startPct); + tangent = result.tan; + tangent = tangent.normalized(); + Vec2D zeroPosition = result.pos; + float extra = -positionOnPath.x; + position = Vec2D(zeroPosition.x - tangent.x * extra, + zeroPosition.y - tangent.y * extra); + } + else if (!canWrap && positionOnPath.x > validLength) + { + auto result = m_pathMeasure.atPercentage(endPct); + tangent = result.tan; + tangent = tangent.normalized(); + Vec2D termPosition = result.pos; + float extra = positionOnPath.x - validLength; + position = Vec2D(termPosition.x + tangent.x * extra, + termPosition.y + tangent.y * extra); + } + else + { + // Closed path, or in the range of the path. + // Use the percentage API to wrap around + auto result = m_pathMeasure.atPercentage(startPct + + positionOnPath.x / pathLength); + position = result.pos; + tangent = result.tan; + tangent = tangent.normalized(); + } + + // Find out the baseline to sit on + float lastBaseline = 0; + float curBaseline = 0; + auto validLine = [&](int i) -> bool { + return i >= 0 && i < paragraphLines.size(); + }; + int lastLineIndex = lineIndexInParagraph - 1; + if (validLine(lastLineIndex)) + { + lastBaseline = paragraphLines[lastLineIndex].baseline; + } + if (validLine(lineIndexInParagraph)) + { + curBaseline = paragraphLines[lineIndexInParagraph].baseline; + } + + // We assume the glyph would have been rendered on the + // current line's baseline. + Vec2D translation; + if (radial()) + { + float verticalSpacing = positionOnPath.y - curBaseline; + Vec2D perpendicular(-tangent.y, tangent.x); + translation = Vec2D(position.x + verticalSpacing * perpendicular.x, + position.y + verticalSpacing * perpendicular.y); + } + else + { + translation = + Vec2D(position.x, + positionOnPath.y - curBaseline + position.y + lastBaseline); + } + + float rotation = orient() ? std::atan2(tangent.y, tangent.x) : 0; + + TransformComponents tc; + float t = math::clamp(strength(), 0.0, 1.0); + float ti = 1.0f - t; + tc.x(translation.x * t + cur.x() * ti); + tc.y(translation.y * t + cur.y() * ti); + tc.rotation(rotation * t + cur.rotation() * ti); + return tc; +} diff --git a/third_party/rive/source/text/text_input.cpp b/third_party/rive/source/text/text_input.cpp new file mode 100644 index 0000000..789485e --- /dev/null +++ b/third_party/rive/source/text/text_input.cpp @@ -0,0 +1,112 @@ +#include "rive/text/text_input.hpp" +#include "rive/text/text_style.hpp" +#include "rive/text/text_input_drawable.hpp" +#include "rive/math/mat2d.hpp" +#include "rive/artboard.hpp" +#include "rive/factory.hpp" + +using namespace rive; + +void TextInput::draw(Renderer* renderer) {} + +Core* TextInput::hitTest(HitInfo*, const Mat2D&) { return nullptr; } + +void TextInput::textChanged() +{ +#ifdef WITH_RIVE_TEXT + m_rawTextInput.text(m_Text); +#endif +} +void TextInput::selectionRadiusChanged() {} + +void TextInput::markPaintDirty() { addDirt(ComponentDirt::Paint); } + +void TextInput::markShapeDirty() { addDirt(ComponentDirt::TextShape); } + +AABB TextInput::localBounds() const +{ +#ifdef WITH_RIVE_TEXT + return m_rawTextInput.bounds(); +#else + return AABB(); +#endif +} + +StatusCode TextInput::onAddedClean(CoreContext* context) +{ + Super::onAddedClean(context); + + m_textStyle = children().first(); + +#ifdef WITH_RIVE_TEXT + if (m_textStyle != nullptr && m_textStyle->font() != nullptr) + { + m_rawTextInput.font(m_textStyle->font()); + } + m_rawTextInput.text(m_Text); +#endif + return m_textStyle == nullptr ? StatusCode::MissingObject : StatusCode::Ok; +} + +void TextInput::update(ComponentDirt value) +{ + Super::update(value); +#ifdef WITH_RIVE_TEXT + if (hasDirt(value, ComponentDirt::Paint | ComponentDirt::TextShape)) + { + Factory* factory = artboard()->factory(); + RawTextInput::Flags changed = m_rawTextInput.update(factory); + if ((changed & RawTextInput::Flags::shapeDirty) != 0) + { + m_worldBounds = + worldTransform().mapBoundingBox(m_rawTextInput.bounds()); + +#ifdef WITH_RIVE_LAYOUT + if (m_rawTextInput.sizing() == TextSizing::autoHeight) + { + markLayoutNodeDirty(); + } +#endif + } + if ((changed & RawTextInput::Flags::selectionDirty) != 0) + { + for (auto child : children()) + { + child->invalidateStrokeEffects(); + } + } + } +#endif +} + +Vec2D TextInput::measureLayout(float width, + LayoutMeasureMode widthMode, + float height, + LayoutMeasureMode heightMode) +{ +#ifdef WITH_RIVE_TEXT + AABB bounds = + m_rawTextInput.measure(widthMode == LayoutMeasureMode::undefined + ? std::numeric_limits::max() + : width, + heightMode == LayoutMeasureMode::undefined + ? std::numeric_limits::max() + : height); + return bounds.size(); +#else + return Vec2D(); +#endif +} + +void TextInput::controlSize(Vec2D size, + LayoutScaleType widthScaleType, + LayoutScaleType heightScaleType, + LayoutDirection direction) +{ +#ifdef WITH_RIVE_TEXT + m_rawTextInput.maxWidth(size.x); + m_rawTextInput.sizing(TextSizing::autoHeight); + + addDirt(ComponentDirt::TextShape); +#endif +} \ No newline at end of file diff --git a/third_party/rive/source/text/text_input_cursor.cpp b/third_party/rive/source/text/text_input_cursor.cpp new file mode 100644 index 0000000..89144a0 --- /dev/null +++ b/third_party/rive/source/text/text_input_cursor.cpp @@ -0,0 +1,16 @@ +#include "rive/text/text_input_cursor.hpp" +#include "rive/math/mat2d.hpp" +#include "rive/text/text_input.hpp" + +using namespace rive; + +Core* TextInputCursor::hitTest(HitInfo*, const Mat2D&) { return nullptr; } + +ShapePaintPath* TextInputCursor::localClockwisePath() +{ +#ifdef WITH_RIVE_TEXT + return textInput()->rawTextInput()->cursorPath(); +#else + return nullptr; +#endif +} \ No newline at end of file diff --git a/third_party/rive/source/text/text_input_drawable.cpp b/third_party/rive/source/text/text_input_drawable.cpp new file mode 100644 index 0000000..0d23472 --- /dev/null +++ b/third_party/rive/source/text/text_input_drawable.cpp @@ -0,0 +1,64 @@ +#include "rive/text/text_input_drawable.hpp" +#include "rive/text/text_input.hpp" +#include "rive/shapes/paint/shape_paint.hpp" + +using namespace rive; + +TextInput* TextInputDrawable::textInput() const +{ + return parent()->as(); +} + +ShapePaintPath* TextInputDrawable::worldPath() +{ + RIVE_UNREACHABLE(); + return nullptr; +} + +StatusCode TextInputDrawable::onAddedClean(CoreContext* context) +{ + if (!parent()->is()) + { + return StatusCode::InvalidObject; + } + + return StatusCode::Ok; +} + +const Mat2D& TextInputDrawable::shapeWorldTransform() const +{ + return worldTransform(); +} + +void TextInputDrawable::draw(Renderer* renderer) +{ + if (renderOpacity() == 0.0f) + { + return; + } + ClipResult clipResult = applyClip(renderer); + + if (clipResult != ClipResult::emptyClip) + { + for (auto shapePaint : m_ShapePaints) + { + if (!shapePaint->isVisible()) + { + continue; + } + auto shapePaintPath = shapePaint->pickPath(this); + if (shapePaintPath == nullptr) + { + continue; + } + shapePaint->draw(renderer, + shapePaintPath, + textInput()->worldTransform()); + } + } + + if (clipResult != ClipResult::noClip) + { + renderer->restore(); + } +} \ No newline at end of file diff --git a/third_party/rive/source/text/text_input_selected_text.cpp b/third_party/rive/source/text/text_input_selected_text.cpp new file mode 100644 index 0000000..766e98f --- /dev/null +++ b/third_party/rive/source/text/text_input_selected_text.cpp @@ -0,0 +1,16 @@ +#include "rive/text/text_input_selected_text.hpp" +#include "rive/math/mat2d.hpp" +#include "rive/text/text_input.hpp" + +using namespace rive; + +Core* TextInputSelectedText::hitTest(HitInfo*, const Mat2D&) { return nullptr; } + +ShapePaintPath* TextInputSelectedText::localClockwisePath() +{ +#ifdef WITH_RIVE_TEXT + return textInput()->rawTextInput()->selectedTextPath(); +#else + return nullptr; +#endif +} \ No newline at end of file diff --git a/third_party/rive/source/text/text_input_selection.cpp b/third_party/rive/source/text/text_input_selection.cpp new file mode 100644 index 0000000..9e4d288 --- /dev/null +++ b/third_party/rive/source/text/text_input_selection.cpp @@ -0,0 +1,16 @@ +#include "rive/text/text_input_selection.hpp" +#include "rive/math/mat2d.hpp" +#include "rive/text/text_input.hpp" + +using namespace rive; + +Core* TextInputSelection::hitTest(HitInfo*, const Mat2D&) { return nullptr; } + +ShapePaintPath* TextInputSelection::localClockwisePath() +{ +#ifdef WITH_RIVE_TEXT + return textInput()->rawTextInput()->selectionPath(); +#else + return nullptr; +#endif +} \ No newline at end of file diff --git a/third_party/rive/source/text/text_input_text.cpp b/third_party/rive/source/text/text_input_text.cpp new file mode 100644 index 0000000..b134f50 --- /dev/null +++ b/third_party/rive/source/text/text_input_text.cpp @@ -0,0 +1,16 @@ +#include "rive/text/text_input_text.hpp" +#include "rive/math/mat2d.hpp" +#include "rive/text/text_input.hpp" + +using namespace rive; + +Core* TextInputText::hitTest(HitInfo*, const Mat2D&) { return nullptr; } + +ShapePaintPath* TextInputText::localClockwisePath() +{ +#ifdef WITH_RIVE_TEXT + return textInput()->rawTextInput()->textPath(); +#else + return nullptr; +#endif +} \ No newline at end of file diff --git a/third_party/rive/source/text/text_interface.cpp b/third_party/rive/source/text/text_interface.cpp new file mode 100644 index 0000000..4a7a58e --- /dev/null +++ b/third_party/rive/source/text/text_interface.cpp @@ -0,0 +1,23 @@ +#include "rive/text/text_interface.hpp" +#include "rive/text/text_input.hpp" +#include "rive/text/text.hpp" + +using namespace rive; + +TextInterface* TextInterface::from(Core* component) +{ + if (component == nullptr) + { + return nullptr; + } + switch (component->coreType()) + { + case Text::typeKey: + return component->as(); + break; + case TextInput::typeKey: + return component->as(); + break; + } + return nullptr; +} \ No newline at end of file diff --git a/third_party/rive/source/text/text_modifier.cpp b/third_party/rive/source/text/text_modifier.cpp new file mode 100644 index 0000000..3583c8e --- /dev/null +++ b/third_party/rive/source/text/text_modifier.cpp @@ -0,0 +1,22 @@ +#include "rive/text/text.hpp" +#include "rive/text/text_modifier.hpp" +#include "rive/text/text_modifier_group.hpp" + +using namespace rive; + +StatusCode TextModifier::onAddedDirty(CoreContext* context) +{ + StatusCode code = Super::onAddedDirty(context); + if (code != StatusCode::Ok) + { + return code; + } + + if (parent() != nullptr && parent()->is()) + { + parent()->as()->addModifier(this); + return StatusCode::Ok; + } + + return StatusCode::MissingObject; +} \ No newline at end of file diff --git a/third_party/rive/source/text/text_modifier_group.cpp b/third_party/rive/source/text/text_modifier_group.cpp new file mode 100644 index 0000000..86ad525 --- /dev/null +++ b/third_party/rive/source/text/text_modifier_group.cpp @@ -0,0 +1,413 @@ +#include "rive/text/text.hpp" +#include "rive/text/text_modifier_group.hpp" +#include "rive/text/text_follow_path_modifier.hpp" +#include "rive/text/text_shape_modifier.hpp" +#include "rive/text/text_modifier_range.hpp" +#include "rive/text/glyph_lookup.hpp" +#include "rive/text/text_style_paint.hpp" +#include "rive/artboard.hpp" +#include + +using namespace rive; + +Text* TextModifierGroup::textComponent() const +{ + if (parent() != nullptr && parent()->is()) + { + return parent()->as(); + } + return nullptr; +} + +StatusCode TextModifierGroup::onAddedDirty(CoreContext* context) +{ + StatusCode code = Super::onAddedDirty(context); + if (code != StatusCode::Ok) + { + return code; + } + + if (parent() != nullptr && parent()->is()) + { + parent()->as()->addModifierGroup(this); + return StatusCode::Ok; + } + + return StatusCode::MissingObject; +} + +void TextModifierGroup::addModifierRange(TextModifierRange* range) +{ + m_ranges.push_back(range); +} + +void TextModifierGroup::addModifier(TextModifier* modifier) +{ + m_modifiers.push_back(modifier); + if (modifier->is()) + { + m_shapeModifiers.push_back(modifier->as()); + } + if (modifier->is()) + { + m_followPathModifiers.push_back(modifier->as()); + } +} + +void TextModifierGroup::rangeTypeChanged() +{ + parent()->as()->modifierShapeDirty(); + addDirt(ComponentDirt::TextCoverage); +} + +void TextModifierGroup::shapeModifierChanged() +{ + parent()->as()->markShapeDirty(); +} + +void TextModifierGroup::rangeChanged() +{ + /// Marking shape dirty should only be done if this modifer group changes + /// shaping properties (for now we're just testing and we're hardcoding a + /// shaping change). + if (!m_shapeModifiers.empty()) + { + parent()->as()->modifierShapeDirty(); + } + else + { + parent()->as()->markPaintDirty(); + } + addDirt(ComponentDirt::TextCoverage); +} + +/// Clear any cached selector range maps so they can be recomputed after next +/// shaping. +void TextModifierGroup::clearRangeMaps() +{ + for (TextModifierRange* range : m_ranges) + { + range->clearRangeMap(); + } + addDirt(ComponentDirt::TextCoverage); +} + +void TextModifierGroup::computeRangeMap( + Span text, + const SimpleArray& shape, + const SimpleArray>& lines, + const GlyphLookup& glyphLookup) +{ + for (TextModifierRange* range : m_ranges) + { + range->computeRange(text, shape, lines, glyphLookup); + } +} + +void TextModifierGroup::computeCoverage(uint32_t textSize) +{ + if (!hasDirt(ComponentDirt::TextCoverage)) + { + return; + } + + // Because we're not dependent on anything we need to reset our dirt + // ourselves. We're not in the DAG so we'll never get reset. + m_Dirt = ComponentDirt::None; + + // When the text re-shapes, we udpate our coverage values. + m_coverage.resize(textSize); + std::fill(m_coverage.begin(), m_coverage.end(), 0); + for (TextModifierRange* range : m_ranges) + { + range->computeCoverage(m_coverage); + } +} + +float TextModifierGroup::glyphCoverage(uint32_t textIndex, + uint32_t codePointCount) +{ + assert(codePointCount >= 1); + float c = coverage(textIndex); + + for (uint32_t i = 1; i < codePointCount; i++) + { + c += coverage(textIndex + i); + } + return c /= (float)codePointCount; +} + +void TextModifierGroup::onTextWorldTransformDirty() +{ + bool followsPath = !m_followPathModifiers.empty(); + if (followsPath) + { + textComponent()->addDirt(ComponentDirt::Path); + } +} + +void TextModifierGroup::resetTextFollowPath() +{ + Text* text = textComponent(); + Mat2D inverseText; + if (text == nullptr || !text->worldTransform().invert(&inverseText)) + { + return; + } + for (TextFollowPathModifier* modifier : m_followPathModifiers) + { + modifier->reset(&inverseText); + } +} + +void TextModifierGroup::transform(float amount, + Mat2D& ctm, + TransformGlyphArg& arg) +{ + bool followsPath = !m_followPathModifiers.empty(); + if (amount == 0.0f || (!modifiesTransform() && !followsPath)) + { + return; + } + + TransformComponents parts; + + if (followsPath) + { + TransformComponents tc; + tc.x(arg.originPosition.x); + tc.y(arg.originPosition.y); + if (modifiesTranslation()) + { + arg.offset = {x(), y()}; + } + + for (TextFollowPathModifier* modifier : m_followPathModifiers) + { + tc = modifier->transformGlyph(tc, arg); + } + Vec2D posDiff = tc.translation() - arg.originPosition; + + // Commit the effect of the follow path modifiers to parts + parts.rotation(parts.rotation() + tc.rotation() * amount); + parts.x(posDiff.x * amount); + parts.y(posDiff.y * amount); + } + else if (modifiesTranslation()) + { + parts.x(x() * amount); + parts.y(y() * amount); + } + + if (modifiesScale()) + { + float iamount = 1.0f - amount; + parts.scaleX(iamount + scaleX() * amount); + parts.scaleY(iamount + scaleY() * amount); + } + + if (modifiesRotation()) + { + parts.rotation(parts.rotation() + rotation() * amount); + } + + Mat2D transform = Mat2D::compose(parts); + + bool doesModifyOrigin = modifiesOrigin(); + if (doesModifyOrigin) + { + ctm[4] += originX(); + ctm[5] += originY(); + } + ctm = transform * ctm; + if (doesModifyOrigin) + { + ctm[4] -= originX(); + ctm[5] -= originY(); + } +} + +float TextModifierGroup::computeOpacity(float current, float t) const +{ + if ((modifierFlags() & (uint32_t)TextModifierFlags::invertOpacity) != 0) + { + return current * (1.0f - t) + opacity() * t; + } + else + { + return current * opacity() * t; + } +} + +void TextModifierGroup::modifierFlagsChanged() +{ + parent()->as()->markPaintDirty(); +} +void TextModifierGroup::originXChanged() +{ + parent()->as()->markPaintDirty(); +} +void TextModifierGroup::originYChanged() +{ + parent()->as()->markPaintDirty(); +} +void TextModifierGroup::opacityChanged() +{ + parent()->as()->markPaintDirty(); +} +void TextModifierGroup::xChanged() { parent()->as()->markPaintDirty(); } +void TextModifierGroup::yChanged() { parent()->as()->markPaintDirty(); } +void TextModifierGroup::rotationChanged() +{ + parent()->as()->markPaintDirty(); +} +void TextModifierGroup::scaleXChanged() +{ + parent()->as()->markPaintDirty(); +} +void TextModifierGroup::scaleYChanged() +{ + parent()->as()->markPaintDirty(); +} + +static TextRun copyRun(const TextRun& source, uint32_t unicharCount) +{ + return { + source.font, + source.size, + source.lineHeight, + source.letterSpacing, + unicharCount, + source.script, + source.styleId, + source.level, + }; +} + +TextRun TextModifierGroup::modifyShape(const Text& text, + TextRun run, + float strength) +{ + const TextStylePaint* style = text.styleFromShaperId(run.styleId); + if (style == nullptr || style->font() == nullptr) + { + return run; + } + + Font* font = style->font().get(); + + std::unordered_map variations; + float fontSize = run.size; + for (TextShapeModifier* shapeModifier : m_shapeModifiers) + { + fontSize = shapeModifier->modify(font, variations, fontSize, strength); + } + + if (!variations.empty()) + { + m_variationCoords.clear(); + for (auto itr = variations.begin(); itr != variations.end(); itr++) + { + m_variationCoords.push_back({itr->first, itr->second}); + } + m_variableFont = font->makeAtCoords(m_variationCoords); + return { + m_variableFont, + run.size, + run.lineHeight, + run.letterSpacing, + run.unicharCount, + run.script, + run.styleId, + run.level, + }; + } + else + { + m_variableFont = nullptr; + } + return run; +} + +void TextModifierGroup::applyShapeModifiers(const Text& text, + StyledText& styledText) +{ + if (m_shapeModifiers.empty()) + { + return; + } + m_nextTextRuns.clear(); + m_nextTextRuns.reserve(styledText.runs().size()); + + uint32_t index = 0; + float lastCoverage = std::numeric_limits::max(); + uint32_t extractRunIndex = 0; + + for (const TextRun& run : styledText.runs()) + { + // Split the run into sub-runs as necessary based on equal coverage + // values. + uint32_t end = index + run.unicharCount; + + auto coverageSize = m_coverage.size(); + while (index < end && index < coverageSize) + { + float coverage = m_coverage[index]; + if (coverage != lastCoverage) + { + if (index - extractRunIndex != 0) + { + // Add new run from extractRunStart to index (exclusive) + if (lastCoverage == 0.0f) + { + m_nextTextRuns.push_back( + copyRun(run, index - extractRunIndex)); + } + else + { + m_nextTextRuns.push_back( + modifyShape(text, + copyRun(run, index - extractRunIndex), + lastCoverage)); + } + } + lastCoverage = coverage; + extractRunIndex = index; + } + index++; + } + + assert(extractRunIndex != end); + // Add new run from extractRunStart to index (exclusive) + if (lastCoverage == 0.0f) + { + m_nextTextRuns.push_back(copyRun(run, end - extractRunIndex)); + } + else + { + m_nextTextRuns.push_back( + modifyShape(text, + copyRun(run, end - extractRunIndex), + lastCoverage)); + } + extractRunIndex = end; + } + styledText.swapRuns(m_nextTextRuns); + // return nextTextRuns; +} + +bool TextModifierGroup::needsShape() const +{ + if (!m_shapeModifiers.empty()) + { + return true; + } + for (const TextModifierRange* range : m_ranges) + { + if (range->needsShape()) + { + return true; + } + } + return false; +} \ No newline at end of file diff --git a/third_party/rive/source/text/text_modifier_range.cpp b/third_party/rive/source/text/text_modifier_range.cpp new file mode 100644 index 0000000..f9f8646 --- /dev/null +++ b/third_party/rive/source/text/text_modifier_range.cpp @@ -0,0 +1,386 @@ +#include "rive/text/text.hpp" +#include "rive/text/text_modifier_range.hpp" +#include "rive/text/text_modifier_group.hpp" +#include "rive/text/text_value_run.hpp" +#include "rive/text/glyph_lookup.hpp" +#include "rive/animation/cubic_interpolator_component.hpp" +#include "rive/core_context.hpp" + +using namespace rive; + +StatusCode TextModifierRange::onAddedDirty(CoreContext* context) +{ + StatusCode code = Super::onAddedDirty(context); + if (code != StatusCode::Ok) + { + return code; + } + + if (runId() != Core::emptyId) + { + auto coreObject = context->resolve(runId()); + if (coreObject == nullptr || !coreObject->is()) + { + return StatusCode::MissingObject; + } + m_run = static_cast(coreObject); + } + + if (parent() != nullptr && parent()->is()) + { + parent()->as()->addModifierRange(this); + return StatusCode::Ok; + } + + return StatusCode::MissingObject; +} + +void TextModifierRange::addChild(Component* component) +{ + Super::addChild(component); + if (component->is()) + { + // mark this as the cubic interpolator. + m_interpolator = component->as(); + } +} + +void TextModifierRange::clearRangeMap() { m_rangeMapper.clear(); } + +void TextModifierRange::computeRange( + Span text, + const SimpleArray& shape, + const SimpleArray>& lines, + const GlyphLookup& glyphLookup) +{ + // Check if the range mapper is still valid. + if (!m_rangeMapper.empty()) + { + return; + } + uint32_t start = 0; + uint32_t end = (uint32_t)text.size(); + if (m_run != nullptr) + { + start = m_run->offset(); + end = start + m_run->length(); + } + switch (units()) + { + case TextRangeUnits::charactersExcludingSpaces: + m_rangeMapper.fromCharacters(text, start, end, glyphLookup, true); + break; + case TextRangeUnits::words: + m_rangeMapper.fromWords(text, start, end); + break; + case TextRangeUnits::lines: + m_rangeMapper + .fromLines(text, start, end, shape, lines, glyphLookup); + break; + default: + m_rangeMapper.fromCharacters(text, start, end, glyphLookup); + break; + } +} + +float TextModifierRange::coverageAt(float t) +{ + float c = 0.0f; + if (m_indexTo >= m_indexFrom) + { + if (t < m_indexFrom || t > m_indexTo) + { + c = 0.0f; + } + else if (t < m_indexFalloffFrom) + { + float range = std::max(0.0f, m_indexFalloffFrom - m_indexFrom); + c = range == 0.0f ? 1.0f : std::max(0.0f, t - m_indexFrom) / range; + if (m_interpolator != nullptr) + { + c = m_interpolator->transform(c); + } + } + else if (t > m_indexFalloffTo) + { + float range = std::max(0.0f, m_indexTo - m_indexFalloffTo); + c = range == 0.0f + ? 1.0f + : 1.0f - std::min(1.0f, (t - m_indexFalloffTo) / range); + if (m_interpolator != nullptr) + { + c = m_interpolator->transform(c); + } + } + else + { + c = 1.0f; + } + } + return c; +} + +void TextModifierRange::computeCoverage(Span coverage) +{ + if (m_rangeMapper.empty()) + { + return; + } + + // Compute range mapped coverage. + uint32_t count = m_rangeMapper.unitCount(); + switch (type()) + { + case TextRangeType::unitIndex: + m_indexFrom = offsetModifyFrom(); + m_indexTo = offsetModifyTo(); + m_indexFalloffFrom = offsetFalloffFrom(); + m_indexFalloffTo = offsetFalloffTo(); + break; + case TextRangeType::percentage: + m_indexFrom = count * offsetModifyFrom(); + m_indexTo = count * offsetModifyTo(); + m_indexFalloffFrom = count * offsetFalloffFrom(); + m_indexFalloffTo = count * offsetFalloffTo(); + break; + } + + TextRangeMode rangeMode = mode(); + for (uint32_t unitIndex = 0; unitIndex < count; unitIndex++) + { + uint32_t unitLength = (uint32_t)m_rangeMapper.unitLength(unitIndex); + uint32_t characterIndex = m_rangeMapper.unitCharacterIndex(unitIndex); + float c = strength() * coverageAt(unitIndex + 0.5f); + for (uint32_t i = 0; i < unitLength; i++) + { + assert((characterIndex + i) < (uint32_t)coverage.size()); + float current = coverage[characterIndex + i]; + switch (rangeMode) + { + case TextRangeMode::add: + current += c; + break; + case TextRangeMode::subtract: + current -= c; + break; + case TextRangeMode::max: + current = std::max(current, c); + break; + case TextRangeMode::min: + current = std::min(current, c); + break; + case TextRangeMode::multiply: + current *= c; + break; + case TextRangeMode::difference: + current = std::abs(current - c); + break; + } + coverage[characterIndex + i] = + clamp() ? std::max(0.0f, std::min(1.0f, current)) : current; + } + + // Set space between units coverage to 0. + if (unitIndex + 1 < m_rangeMapper.unitCharacterIndexCount()) + { + uint32_t nextCharacterIndex = + m_rangeMapper.unitCharacterIndex(unitIndex + 1); + for (uint32_t i = characterIndex + unitLength; + i < nextCharacterIndex; + i++) + { + coverage[i] = 0; + } + } + } +} + +void TextModifierRange::modifyFromChanged() +{ + parent()->as()->rangeChanged(); +} +void TextModifierRange::modifyToChanged() +{ + parent()->as()->rangeChanged(); +} +void TextModifierRange::strengthChanged() +{ + parent()->as()->rangeChanged(); +} +void TextModifierRange::unitsValueChanged() +{ + parent()->as()->rangeTypeChanged(); +} +void TextModifierRange::typeValueChanged() +{ + parent()->as()->rangeChanged(); +} +void TextModifierRange::modeValueChanged() +{ + parent()->as()->rangeChanged(); +} +void TextModifierRange::clampChanged() +{ + parent()->as()->rangeChanged(); +} +void TextModifierRange::falloffFromChanged() +{ + parent()->as()->rangeChanged(); +} +void TextModifierRange::falloffToChanged() +{ + parent()->as()->rangeChanged(); +} +void TextModifierRange::offsetChanged() +{ + parent()->as()->rangeChanged(); +} + +bool TextModifierRange::needsShape() const +{ + return units() == TextRangeUnits::lines; +} + +void RangeMapper::clear() +{ + m_unitCharacterIndices.clear(); + m_unitLengths.clear(); +} + +float RangeMapper::unitToCharacterRange(float word) const +{ + if (m_unitCharacterIndices.empty()) + { + return 0.0f; + } + float clampedUnit = std::min(std::max(word, 0.0f), + (float)(m_unitCharacterIndices.size() - 1)); + size_t intUnit = (size_t)clampedUnit; + float characters = (float)m_unitCharacterIndices[intUnit]; + if (intUnit < m_unitLengths.size()) + { + float fraction = clampedUnit - intUnit; + characters += m_unitLengths[intUnit] * fraction; + } + return characters; +} + +void RangeMapper::addRange(uint32_t indexFrom, + uint32_t indexTo, + uint32_t startOffset, + uint32_t endOffset) +{ + if (indexTo > startOffset && endOffset > indexFrom) + { + uint32_t actualStart = std::max(startOffset, indexFrom); + uint32_t actualEnd = std::min(endOffset, indexTo); + if (actualEnd > actualStart) + { + m_unitCharacterIndices.push_back(actualStart); + m_unitLengths.push_back(actualEnd - actualStart); + } + } +} + +void RangeMapper::fromWords(Span text, + uint32_t start, + uint32_t end) +{ + if (text.empty()) + { + return; + } + + bool wantWhiteSpace = false; + uint32_t characterCount = 0; + uint32_t index = 0; + uint32_t indexFrom = 0; + for (Unichar unit : text) + { + if (wantWhiteSpace == isWhiteSpace(unit)) + { + if (!wantWhiteSpace) + { + indexFrom = index; + } + else + { + addRange(indexFrom, indexFrom + characterCount, start, end); + + characterCount = 0; + } + wantWhiteSpace = !wantWhiteSpace; + } + if (wantWhiteSpace) + { + characterCount++; + } + index++; + } + if (characterCount > 0) + { + addRange(indexFrom, indexFrom + characterCount, start, end); + } + m_unitCharacterIndices.push_back(end); +} + +void RangeMapper::fromCharacters(Span text, + uint32_t start, + uint32_t end, + const GlyphLookup& glyphLookup, + bool withoutSpaces) +{ + if (text.empty()) + { + return; + } + for (uint32_t i = start; i < end;) + { + Unichar unit = text[i]; + if (withoutSpaces && isWhiteSpace(unit)) + { + i++; + continue; + } + // Don't break ligated glyphs. + uint32_t codePoints = glyphLookup.count(i); + m_unitCharacterIndices.push_back(i); + m_unitLengths.push_back(codePoints); + i += codePoints; + } + + m_unitCharacterIndices.push_back(end); +} + +void RangeMapper::fromLines(Span text, + uint32_t start, + uint32_t end, + const SimpleArray& shape, + const SimpleArray>& lines, + const GlyphLookup& glyphLookup) +{ + if (text.empty()) + { + return; + } + uint32_t paragraphIndex = 0; + for (const SimpleArray& paragraphLines : lines) + { + const Paragraph& paragraph = shape[paragraphIndex++]; + const SimpleArray& glyphRuns = paragraph.runs; + for (const GlyphLine& line : paragraphLines) + { + const GlyphRun& rf = glyphRuns[line.startRunIndex]; + uint32_t indexFrom = rf.textIndices[line.startGlyphIndex]; + + const GlyphRun& rt = glyphRuns[line.endRunIndex]; + uint32_t endGlyphIndex = + line.endGlyphIndex == 0 ? 0 : line.endGlyphIndex - 1; + uint32_t indexTo = rt.textIndices[endGlyphIndex]; + indexTo += glyphLookup.count(indexTo); + + addRange(indexFrom, indexTo, start, end); + } + } + m_unitCharacterIndices.push_back(end); +} diff --git a/third_party/rive/source/text/text_selection_path.cpp b/third_party/rive/source/text/text_selection_path.cpp new file mode 100644 index 0000000..981ef6d --- /dev/null +++ b/third_party/rive/source/text/text_selection_path.cpp @@ -0,0 +1,141 @@ +#ifdef WITH_RIVE_TEXT +#include "rive/text/text_selection_path.hpp" +#include "rive/text/text.hpp" +#include "rive/shapes/path.hpp" + +using namespace rive; + +void TextSelectionPath::update(Span rects, float cornerRadius) +{ + rewind(); + m_rectanglesToContour.reset(); + for (const AABB& rect : rects) + { + m_rectanglesToContour.addRect(rect); + } + m_rectanglesToContour.computeContours(); + + RawPath& rawPath = *mutableRawPath(); + for (auto contour : m_rectanglesToContour) + { + addRoundedPath(contour, cornerRadius, rawPath); + } +} + +void TextSelectionPath::addRoundedPath(const Contour& contour, + float radius, + RawPath& rawPath) +{ + bool isClockwise = contour.isClockwise(); + size_t length = contour.size(); + if (length < 2) + { + return; + } + + Vec2D firstPoint = contour.point(0, !isClockwise); + Vec2D point = firstPoint; + + if (radius > 0.0f) + { + Vec2D prev = contour.point(length - 1, !isClockwise); + Vec2D pos = point; + + Vec2D toPrev = prev - pos; + float toPrevLength = toPrev.length(); + toPrev.x /= toPrevLength; + toPrev.y /= toPrevLength; + + Vec2D next = contour.point(1, !isClockwise); + + Vec2D toNext = next - pos; + float toNextLength = toNext.length(); + toNext.x /= toNextLength; + toNext.y /= toNextLength; + + float renderRadius = std::min(toPrevLength / 2.0f, + std::min(toNextLength / 2.0f, radius)); + float idealDistance = + Path::computeIdealControlPointDistance(toPrev, + toNext, + renderRadius); + + Vec2D translation = Vec2D::scaleAndAdd(pos, toPrev, renderRadius); + rawPath.moveTo(translation.x, translation.y); + + Vec2D outPoint = + Vec2D::scaleAndAdd(pos, toPrev, renderRadius - idealDistance); + + Vec2D inPoint = + Vec2D::scaleAndAdd(pos, toNext, renderRadius - idealDistance); + + Vec2D posNext = Vec2D::scaleAndAdd(pos, toNext, renderRadius); + rawPath.cubicTo(outPoint.x, + outPoint.y, + inPoint.x, + inPoint.y, + posNext.x, + posNext.y); + } + else + { + rawPath.moveTo(point.x, point.y); + } + + for (size_t i = 1; i < length; i++) + { + Vec2D point = contour.point(i, !isClockwise); + + if (radius > 0.0f) + { + Vec2D prev = contour.point(i - 1, !isClockwise); + + Vec2D pos = point; + Vec2D toPrev = prev - pos; + + float toPrevLength = toPrev.length(); + toPrev.x /= toPrevLength; + toPrev.y /= toPrevLength; + + Vec2D next = contour.point((i + 1) % length, !isClockwise); + + Vec2D toNext = next - pos; + float toNextLength = toNext.length(); + toNext.x /= toNextLength; + toNext.y /= toNextLength; + + float renderRadius = + std::min(toPrevLength / 2.0f, + std::min(toNextLength / 2.0f, radius)); + + float idealDistance = + Path::computeIdealControlPointDistance(toPrev, + toNext, + renderRadius); + + Vec2D translation = Vec2D::scaleAndAdd(pos, toPrev, renderRadius); + + rawPath.lineTo(translation.x, translation.y); + + Vec2D outPoint = + Vec2D::scaleAndAdd(pos, toPrev, renderRadius - idealDistance); + + Vec2D inPoint = + Vec2D::scaleAndAdd(pos, toNext, renderRadius - idealDistance); + + Vec2D posNext = Vec2D::scaleAndAdd(pos, toNext, renderRadius); + rawPath.cubicTo(outPoint.x, + outPoint.y, + inPoint.x, + inPoint.y, + posNext.x, + posNext.y); + } + else + { + rawPath.lineTo(point.x, point.y); + } + } + rawPath.close(); +} +#endif \ No newline at end of file diff --git a/third_party/rive/source/text/text_style.cpp b/third_party/rive/source/text/text_style.cpp new file mode 100644 index 0000000..0624de1 --- /dev/null +++ b/third_party/rive/source/text/text_style.cpp @@ -0,0 +1,159 @@ +#include "rive/text/text_style.hpp" +#include "rive/text/text_style_axis.hpp" +#include "rive/text/text_style_feature.hpp" +#include "rive/text/text_variation_helper.hpp" +#include "rive/renderer.hpp" +#include "rive/shapes/paint/shape_paint.hpp" +#include "rive/backboard.hpp" +#include "rive/importers/backboard_importer.hpp" +#include "rive/text/text.hpp" +#include "rive/artboard.hpp" + +using namespace rive; + +// satisfy unique_ptr +TextStyle::TextStyle() = default; + +void TextStyle::addVariation(TextStyleAxis* axis) +{ + m_variations.push_back(axis); +} + +void TextStyle::addFeature(TextStyleFeature* feature) +{ + m_styleFeatures.push_back(feature); +} + +void TextStyle::onDirty(ComponentDirt dirt) +{ + if ((dirt & ComponentDirt::TextShape) == ComponentDirt::TextShape) + { + m_text->markShapeDirty(); + if (m_variationHelper != nullptr) + { + m_variationHelper->addDirt(ComponentDirt::TextShape); + } + } +} + +StatusCode TextStyle::onAddedClean(CoreContext* context) +{ + // We know this is good because we validated it during validate(). + m_text = TextInterface::from(parent()); + + auto code = Super::onAddedClean(context); + if (code != StatusCode::Ok) + { + return code; + } + // This ensures context propagates to variation helper too. + if (!m_variations.empty() || !m_styleFeatures.empty()) + { + m_variationHelper = rivestd::make_unique(this); + } + if (m_variationHelper != nullptr) + { + if ((code = m_variationHelper->onAddedDirty(context)) != StatusCode::Ok) + { + return code; + } + if ((code = m_variationHelper->onAddedClean(context)) != StatusCode::Ok) + { + return code; + } + } + return StatusCode::Ok; +} + +const rcp TextStyle::font() const +{ + if (m_variableFont != nullptr) + { + return m_variableFont; + } + + auto asset = fontAsset(); + return asset == nullptr ? nullptr : asset->font(); +} + +void TextStyle::updateVariableFont() +{ + auto asset = fontAsset(); + rcp baseFont = asset == nullptr ? nullptr : asset->font(); + if (baseFont == nullptr) + { + // Not ready yet. + return; + } + if (!m_variations.empty() || !m_styleFeatures.empty()) + { + m_coords.clear(); + for (TextStyleAxis* axis : m_variations) + { + m_coords.push_back({axis->tag(), axis->axisValue()}); + } + m_features.clear(); + for (TextStyleFeature* styleFeature : m_styleFeatures) + { + m_features.push_back( + {styleFeature->tag(), styleFeature->featureValue()}); + } + m_variableFont = baseFont->withOptions(m_coords, m_features); + } + else + { + m_variableFont = nullptr; + } +} + +void TextStyle::buildDependencies() +{ + if (m_variationHelper != nullptr) + { + m_variationHelper->buildDependencies(); + } + parent()->addDependent(this); + Super::buildDependencies(); +} + +uint32_t TextStyle::assetId() { return this->fontAssetId(); } + +void TextStyle::setAsset(FileAsset* asset) +{ + if (asset->is()) + { + FileAssetReferencer::setAsset(asset); + } +} + +StatusCode TextStyle::import(ImportStack& importStack) +{ + auto result = registerReferencer(importStack); + if (result != StatusCode::Ok) + { + return result; + } + return Super::import(importStack); +} + +void TextStyle::fontSizeChanged() { m_text->markShapeDirty(); } + +void TextStyle::lineHeightChanged() { m_text->markShapeDirty(); } + +void TextStyle::letterSpacingChanged() { m_text->markShapeDirty(); } + +Core* TextStyle::clone() const +{ + TextStyle* twin = TextStyleBase::clone()->as(); + if (m_fileAsset != nullptr) + { + twin->setAsset(m_fileAsset); + } + + return twin; +} + +bool TextStyle::validate(CoreContext* context) +{ + return TextInterface::from(context->resolve(parentId())) != nullptr; +} \ No newline at end of file diff --git a/third_party/rive/source/text/text_style_axis.cpp b/third_party/rive/source/text/text_style_axis.cpp new file mode 100644 index 0000000..11d1e2e --- /dev/null +++ b/third_party/rive/source/text/text_style_axis.cpp @@ -0,0 +1,30 @@ +#include "rive/text/text_style_axis.hpp" +#include "rive/text/text_style.hpp" +#include "rive/container_component.hpp" + +using namespace rive; + +StatusCode TextStyleAxis::onAddedDirty(CoreContext* context) +{ + StatusCode code = Super::onAddedDirty(context); + if (code == StatusCode::Ok) + { + if (!parent()->is()) + { + return StatusCode::InvalidObject; + } + auto style = parent()->as(); + style->addVariation(this); + } + return code; +} + +void TextStyleAxis::tagChanged() +{ + parent()->addDirt(ComponentDirt::TextShape); +} + +void TextStyleAxis::axisValueChanged() +{ + parent()->addDirt(ComponentDirt::TextShape); +} \ No newline at end of file diff --git a/third_party/rive/source/text/text_style_feature.cpp b/third_party/rive/source/text/text_style_feature.cpp new file mode 100644 index 0000000..31410a5 --- /dev/null +++ b/third_party/rive/source/text/text_style_feature.cpp @@ -0,0 +1,20 @@ +#include "rive/text/text_style_feature.hpp" +#include "rive/text/text_style.hpp" +#include "rive/container_component.hpp" + +using namespace rive; + +StatusCode TextStyleFeature::onAddedDirty(CoreContext* context) +{ + StatusCode code = Super::onAddedDirty(context); + if (code == StatusCode::Ok) + { + if (!parent()->is()) + { + return StatusCode::InvalidObject; + } + auto style = parent()->as(); + style->addFeature(this); + } + return code; +} \ No newline at end of file diff --git a/third_party/rive/source/text/text_style_paint.cpp b/third_party/rive/source/text/text_style_paint.cpp new file mode 100644 index 0000000..d7f210d --- /dev/null +++ b/third_party/rive/source/text/text_style_paint.cpp @@ -0,0 +1,117 @@ +#include "rive/text/text_style_paint.hpp" +#include "rive/text/text.hpp" +#include "rive/text/text_variation_helper.hpp" +#include "rive/shapes/paint/shape_paint.hpp" +#include "rive/shapes/paint/feather.hpp" +#include "rive/artboard.hpp" +#include "rive/factory.hpp" + +using namespace rive; + +TextStylePaint::TextStylePaint() : m_path(true, FillRule::clockwise) {} + +void TextStylePaint::rewindPath() +{ + m_path.rewind(); + m_hasContents = false; + m_opacityPaths.clear(); +} + +bool TextStylePaint::addPath(const RawPath& rawPath, float opacity) +{ + bool hadContents = m_hasContents; + m_hasContents = true; + if (opacity > 0.0f) + { + + // m_path contains everything, so inner feather bounds can work. + m_path.addPathClockwise(rawPath); + + // Bucket by opacity + auto itr = m_opacityPaths.find(opacity); + ShapePaintPath* shapePaintPath = nullptr; + if (itr != m_opacityPaths.end()) + { + ShapePaintPath& path = itr->second; + shapePaintPath = &path; + } + else + { + m_opacityPaths[opacity] = ShapePaintPath(true, FillRule::clockwise); + shapePaintPath = &m_opacityPaths.at(opacity); + } + shapePaintPath->addPathClockwise(rawPath); + } + + return !hadContents; +} + +void TextStylePaint::draw(Renderer* renderer, const Mat2D& worldTransform) +{ + for (auto shapePaint : m_ShapePaints) + { + if (!shapePaint->shouldDraw()) + { + continue; + } + shapePaint->blendMode(parent()->as()->blendMode()); + + // For blend modes to work, opaque paths render first + auto itr = m_opacityPaths.find(1.0f); + if (itr != m_opacityPaths.end()) + { + ShapePaintPath& path = itr->second; + shapePaint->draw(renderer, &path, worldTransform, true); + } + + if (m_paintPool.size() < m_opacityPaths.size()) + { + m_paintPool.reserve(m_opacityPaths.size()); + Factory* factory = artboard()->factory(); + while (m_paintPool.size() < m_opacityPaths.size()) + { + m_paintPool.emplace_back(factory->makeRenderPaint()); + } + } + + uint32_t paintIndex = 0; + for (itr = m_opacityPaths.begin(); itr != m_opacityPaths.end(); itr++) + { + // Don't render opaque paths twice + if (itr->first == 1.0f) + { + continue; + } + RenderPaint* renderPaint = m_paintPool[paintIndex++].get(); + shapePaint->applyTo(renderPaint, itr->first); + if (auto feather = shapePaint->feather()) + { + renderPaint->feather(feather->strength()); + } + ShapePaintPath& path = itr->second; + shapePaint->draw(renderer, + &path, + worldTransform, + true, + renderPaint); + } + } +} + +const Mat2D& TextStylePaint::shapeWorldTransform() const +{ + return parent()->as()->shapeWorldTransform(); +} + +Component* TextStylePaint::pathBuilder() { return parent(); } + +Core* TextStylePaint::clone() const +{ + TextStylePaint* twin = TextStylePaintBase::clone()->as(); + if (m_fileAsset != nullptr) + { + twin->setAsset(m_fileAsset); + } + + return twin; +} diff --git a/third_party/rive/source/text/text_target_modifier.cpp b/third_party/rive/source/text/text_target_modifier.cpp new file mode 100644 index 0000000..cf14a6e --- /dev/null +++ b/third_party/rive/source/text/text_target_modifier.cpp @@ -0,0 +1,30 @@ +#include "rive/core_context.hpp" +#include "rive/text/text.hpp" +#include "rive/text/text_modifier_group.hpp" +#include "rive/text/text_target_modifier.hpp" +#include "rive/transform_component.hpp" + +using namespace rive; + +StatusCode TextTargetModifier::onAddedDirty(CoreContext* context) +{ + StatusCode code = Super::onAddedDirty(context); + if (code != StatusCode::Ok) + { + return code; + } + + auto coreObject = context->resolve(targetId()); + m_Target = static_cast(coreObject); + + return StatusCode::Ok; +} + +Text* TextTargetModifier::textComponent() const +{ + if (parent() != nullptr && parent()->is()) + { + return parent()->as()->textComponent(); + } + return nullptr; +} diff --git a/third_party/rive/source/text/text_value_run.cpp b/third_party/rive/source/text/text_value_run.cpp new file mode 100644 index 0000000..39f2b5e --- /dev/null +++ b/third_party/rive/source/text/text_value_run.cpp @@ -0,0 +1,191 @@ +#include "rive/core_context.hpp" +#include "rive/text/text.hpp" +#include "rive/text/text_style_paint.hpp" +#include "rive/text/text_value_run.hpp" +#include "rive/artboard.hpp" +#include "rive/hittest_command_path.hpp" +#include "rive/importers/artboard_importer.hpp" + +using namespace rive; + +void TextValueRun::textChanged() +{ + m_length = -1; + parent()->as()->markShapeDirty(); +} + +Text* TextValueRun::textComponent() const { return parent()->as(); } + +StatusCode TextValueRun::onAddedClean(CoreContext* context) +{ + StatusCode code = Super::onAddedClean(context); + if (code != StatusCode::Ok) + { + return code; + } + + if (parent() != nullptr && parent()->is()) + { + parent()->as()->addRun(this); + return StatusCode::Ok; + } + + return StatusCode::MissingObject; +} + +StatusCode TextValueRun::onAddedDirty(CoreContext* context) +{ + StatusCode code = Super::onAddedDirty(context); + if (code != StatusCode::Ok) + { + return code; + } + auto coreObject = context->resolve(styleId()); + if (coreObject == nullptr || !coreObject->is()) + { + return StatusCode::MissingObject; + } + + m_style = static_cast(coreObject); + + return StatusCode::Ok; +} + +void TextValueRun::styleIdChanged() +{ + auto coreObject = artboard()->resolve(styleId()); + if (coreObject != nullptr && coreObject->is()) + { + m_style = static_cast(coreObject); + parent()->as()->markShapeDirty(); + } +} + +uint32_t TextValueRun::offset() const +{ +#ifdef WITH_RIVE_TEXT + Text* text = parent()->as(); + uint32_t offset = 0; + + for (TextValueRun* run : text->runs()) + { + if (run == this) + { + break; + } + offset += run->length(); + } + return offset; +#else + return 0; +#endif +} + +bool TextValueRun::canHitTest() const +{ + return (m_isHitTarget && textComponent() != nullptr && + !m_localBounds.isEmptyOrNaN()); +} + +void TextValueRun::resetHitTest() +{ + m_glyphHitRects.clear(); + m_localBounds = AABB::forExpansion(); +} + +void TextValueRun::addHitRect(const AABB& rect) +{ + AABB::expandTo(m_localBounds, rect.min()); + AABB::expandTo(m_localBounds, rect.max()); + m_glyphHitRects.push_back(rect); +} + +void TextValueRun::computeHitContours() +{ + if (!m_rectanglesToContour) + { + m_rectanglesToContour = rivestd::make_unique(); + } + else + { + m_rectanglesToContour->reset(); + } + for (const AABB& rect : m_glyphHitRects) + { + m_rectanglesToContour->addRect(rect); + } + m_rectanglesToContour->computeContours(); +} + +bool TextValueRun::hitTestAABB(const Vec2D& position) +{ + if (!canHitTest()) + { + return false; + } + + if (textComponent()->overflow() != TextOverflow::visible) + { + Mat2D inverseWorld; + if (!textComponent()->worldTransform().invert(&inverseWorld)) + { + return false; + } + + if (!textComponent()->localBounds().contains(inverseWorld * position)) + { + return false; + } + } + + Mat2D inverseWorld; + Mat2D worldTransform = + textComponent()->worldTransform() * textComponent()->m_transform; + if (worldTransform.invert(&inverseWorld)) + { + auto localWorld = inverseWorld * position; + return m_localBounds.contains(localWorld); + } + + return false; +} + +bool TextValueRun::hitTestHiFi(const Vec2D& position, float hitRadius) +{ + if (!canHitTest()) + { + return false; + } + + auto hitArea = AABB(position.x - hitRadius, + position.y - hitRadius, + position.x + hitRadius, + position.y + hitRadius) + .round(); + HitTestCommandPath tester(hitArea); + tester.setXform(textComponent()->worldTransform() * + textComponent()->m_transform); + + assert(m_rectanglesToContour != nullptr); + for (auto contour : *m_rectanglesToContour) + { + assert(contour.begin() != contour.end()); + auto pointItr = contour.begin(); + auto end = contour.end(); + + Vec2D firstPoint = *pointItr; + tester.moveTo(firstPoint.x, firstPoint.y); + + while (++pointItr != end) + { + Vec2D point = *pointItr; + tester.lineTo(point.x, point.y); + } + + tester.close(); + } + + return tester.wasHit(); +} + +void TextValueRun::isHitTarget(bool value) { m_isHitTarget = value; } \ No newline at end of file diff --git a/third_party/rive/source/text/text_variation_helper.cpp b/third_party/rive/source/text/text_variation_helper.cpp new file mode 100644 index 0000000..231e63d --- /dev/null +++ b/third_party/rive/source/text/text_variation_helper.cpp @@ -0,0 +1,17 @@ +#include "rive/text/text_variation_helper.hpp" +#include "rive/text/text_style.hpp" +#include "rive/artboard.hpp" + +using namespace rive; + +void TextVariationHelper::buildDependencies() +{ + auto text = m_textStyle->parent(); + text->artboard()->addDependent(this); + addDependent(text); +} + +void TextVariationHelper::update(ComponentDirt value) +{ + m_textStyle->updateVariableFont(); +} \ No newline at end of file diff --git a/third_party/rive/source/text/text_variation_modifier.cpp b/third_party/rive/source/text/text_variation_modifier.cpp new file mode 100644 index 0000000..b7753d5 --- /dev/null +++ b/third_party/rive/source/text/text_variation_modifier.cpp @@ -0,0 +1,24 @@ +#include "rive/text/text_variation_modifier.hpp" +#include "rive/text/text_modifier_group.hpp" +#include "rive/text_engine.hpp" + +using namespace rive; + +float TextVariationModifier::modify( + Font* font, + std::unordered_map& variations, + float fontSize, + float strength) const +{ + auto itr = variations.find(axisTag()); + + float fromValue = + itr != variations.end() ? itr->second : font->getAxisValue(axisTag()); + variations[axisTag()] = fromValue * (1 - strength) + axisValue() * strength; + return fontSize; +} + +void TextVariationModifier::axisValueChanged() +{ + parent()->as()->shapeModifierChanged(); +} \ No newline at end of file diff --git a/third_party/rive/source/text/utf.cpp b/third_party/rive/source/text/utf.cpp new file mode 100644 index 0000000..ceec00e --- /dev/null +++ b/third_party/rive/source/text/utf.cpp @@ -0,0 +1,124 @@ +#include "rive/text/utf.hpp" +#include "rive/core/type_conversions.hpp" + +using namespace rive; + +int UTF::CountUTF8Length(const uint8_t utf8[]) +{ + unsigned lead = *utf8; + assert(lead != 0xFF); + assert((lead & 0xC0) != 0x80); // 10xxxxxx is not a legal lead byte + if ((lead & 0x80) == 0) + { + return 1; + } + int n = 1; + lead <<= 1; + while (lead & 0x80) + { + n += 1; + lead <<= 1; + } + assert(n >= 1 && n <= 4); + return n; +} + +// Return the unichar pointed to by the utf8 pointer, and then +// update the pointer to point to the next sequence. +Unichar UTF::NextUTF8(const uint8_t** utf8Ptr) +{ + const uint8_t* text = *utf8Ptr; + + uint32_t c = 0; + int n = CountUTF8Length(text); + assert(n >= 1 && n <= 4); + + unsigned first = *text++; + if (n == 1) + { + c = first; + } + else + { + c = first & ((unsigned)0xFF >> n); + --n; + do + { + c = (c << 6) | (*text++ & 0x3F); + } while (--n); + } + *utf8Ptr = text; // update the pointer + return c; +} + +int UTF::ToUTF16(Unichar uni, uint16_t utf16[]) +{ + if (uni > 0xFFFF) + { + utf16[0] = castTo((0xD800 - 64) | (uni >> 10)); + utf16[1] = castTo(0xDC00 | (uni & 0x3FF)); + return 2; + } + utf16[0] = castTo(uni); + return 1; +} + +uint32_t UTF::CountCodePointLength(Span codepoints) +{ + uint32_t length = 0; + for (auto codepoint : codepoints) + { + if (codepoint <= 0x7F) + { + length += 1; + } + else if (codepoint <= 0x07FF) + { + length += 2; + } + else if (codepoint <= 0xFFFF) + { + length += 3; + } + else if (codepoint <= 0x10FFFF) + { + length += 4; + } + } + return length; +} + +uint32_t UTF::Encode(uint8_t* output, Unichar codepoint) +{ + if (codepoint <= 0x7F) + { + output[0] = (uint8_t)codepoint; + return 1; + } + else if (codepoint <= 0x07FF) + { + output[0] = (uint8_t)(((codepoint >> 6) & 0x1F) | 0xC0); + output[1] = (uint8_t)(((codepoint >> 0) & 0x3F) | 0x80); + return 2; + } + else if (codepoint <= 0xFFFF) + { + output[0] = (uint8_t)(((codepoint >> 12) & 0x0F) | 0xE0); + output[1] = (uint8_t)(((codepoint >> 6) & 0x3F) | 0x80); + output[2] = (uint8_t)(((codepoint >> 0) & 0x3F) | 0x80); + return 3; + } + else if (codepoint <= 0x10FFFF) + { + output[0] = (uint8_t)(((codepoint >> 18) & 0x07) | 0xF0); + output[1] = (uint8_t)(((codepoint >> 12) & 0x3F) | 0x80); + output[2] = (uint8_t)(((codepoint >> 6) & 0x3F) | 0x80); + output[3] = (uint8_t)(((codepoint >> 0) & 0x3F) | 0x80); + return 4; + } + else + { + // error + return 0; + } +} \ No newline at end of file diff --git a/third_party/rive/source/transform_component.cpp b/third_party/rive/source/transform_component.cpp new file mode 100644 index 0000000..4dff878 --- /dev/null +++ b/third_party/rive/source/transform_component.cpp @@ -0,0 +1,126 @@ +#include "rive/transform_component.hpp" +#include "rive/world_transform_component.hpp" +#include "rive/shapes/clipping_shape.hpp" +#include "rive/math/vec2d.hpp" +#include "rive/constraints/constraint.hpp" + +using namespace rive; + +StatusCode TransformComponent::onAddedClean(CoreContext* context) +{ + m_ParentTransformComponent = + parent() != nullptr && parent()->is() + ? parent()->as() + : nullptr; + return StatusCode::Ok; +} + +bool TransformComponent::collapse(bool value) +{ + if (!Super::collapse(value)) + { + return false; + } + for (auto d : dependents()) + { + if (d->is()) + { + auto dependent = d->as(); + dependent->markDirtyIfConstrained(); + } + } + return true; +} + +// If the component has any constraints applied we mark it as dirty +// because one of its constraining targets has changed its collapse +// status. +void TransformComponent::markDirtyIfConstrained() +{ + if (m_Constraints.size() > 0) + { + addDirt(ComponentDirt::WorldTransform, true); + } +} + +void TransformComponent::buildDependencies() +{ + if (parent() != nullptr) + { + parent()->addDependent(this); + } +} + +void TransformComponent::markTransformDirty() +{ + if (!addDirt(ComponentDirt::Transform)) + { + return; + } + markWorldTransformDirty(); +} + +void TransformComponent::updateTransform() +{ + m_Transform = Mat2D::fromRotation(rotation()); + m_Transform[4] = x(); + m_Transform[5] = y(); + m_Transform.scaleByValues(scaleX(), scaleY()); +} + +AABB TransformComponent::localBounds() const { return AABB(); } + +void TransformComponent::updateWorldTransform() +{ + if (m_ParentTransformComponent != nullptr) + { + m_WorldTransform = + m_ParentTransformComponent->m_WorldTransform * m_Transform; + } + else + { + m_WorldTransform = m_Transform; + } + updateConstraints(); +} + +void TransformComponent::updateConstraints() +{ + for (auto constraint : m_Constraints) + { + constraint->constrain(this); + } +} + +void TransformComponent::update(ComponentDirt value) +{ + if (hasDirt(value, ComponentDirt::Transform)) + { + updateTransform(); + } + if (hasDirt(value, ComponentDirt::WorldTransform)) + { + updateWorldTransform(); + } + if (hasDirt(value, ComponentDirt::RenderOpacity)) + { + m_RenderOpacity = opacity(); + if (m_ParentTransformComponent != nullptr) + { + m_RenderOpacity *= m_ParentTransformComponent->childOpacity(); + } + } +} + +const Mat2D& TransformComponent::transform() const { return m_Transform; } + +Mat2D& TransformComponent::mutableTransform() { return m_Transform; } + +void TransformComponent::rotationChanged() { markTransformDirty(); } +void TransformComponent::scaleXChanged() { markTransformDirty(); } +void TransformComponent::scaleYChanged() { markTransformDirty(); } + +void TransformComponent::addConstraint(Constraint* constraint) +{ + m_Constraints.push_back(constraint); +} diff --git a/third_party/rive/source/viewmodel/data_enum.cpp b/third_party/rive/source/viewmodel/data_enum.cpp new file mode 100644 index 0000000..e8ed0eb --- /dev/null +++ b/third_party/rive/source/viewmodel/data_enum.cpp @@ -0,0 +1,96 @@ +#include +#include +#include + +#include "rive/viewmodel/data_enum.hpp" +#include "rive/viewmodel/data_enum_value.hpp" +#include "rive/viewmodel/viewmodel_property.hpp" +#include "rive/backboard.hpp" +#include "rive/importers/backboard_importer.hpp" + +using namespace rive; + +DataEnum::~DataEnum() +{ + for (auto& enumValue : m_Values) + { + delete enumValue; + } +} + +void DataEnum::addValue(DataEnumValue* value) { m_Values.push_back(value); } + +std::string DataEnum::value(std::string key) +{ + for (auto enumValue : m_Values) + { + if (enumValue->key() == key) + { + if (enumValue->value() != "") + { + return enumValue->value(); + } + return enumValue->key(); + }; + } + return ""; +} + +std::string DataEnum::value(uint32_t index) +{ + if (index < m_Values.size()) + { + if (m_Values[index]->value() != "") + { + return m_Values[index]->value(); + } + return m_Values[index]->key(); + } + return ""; +} + +bool DataEnum::value(std::string key, std::string value) +{ + for (auto enumValue : m_Values) + { + if (enumValue->key() == key) + { + enumValue->value(value); + return true; + }; + } + return false; +} + +bool DataEnum::value(uint32_t index, std::string value) +{ + if (index < m_Values.size()) + { + m_Values[index]->value(value); + return true; + } + return false; +} + +int DataEnum::valueIndex(std::string key) +{ + int index = 0; + for (auto enumValue : m_Values) + { + if (enumValue->key() == key) + { + return index; + }; + index++; + } + return -1; +} + +int DataEnum::valueIndex(uint32_t index) +{ + if (index < m_Values.size()) + { + return index; + } + return -1; +} \ No newline at end of file diff --git a/third_party/rive/source/viewmodel/data_enum_value.cpp b/third_party/rive/source/viewmodel/data_enum_value.cpp new file mode 100644 index 0000000..133037b --- /dev/null +++ b/third_party/rive/source/viewmodel/data_enum_value.cpp @@ -0,0 +1,23 @@ +#include +#include +#include + +#include "rive/viewmodel/data_enum.hpp" +#include "rive/viewmodel/data_enum_custom.hpp" +#include "rive/viewmodel/data_enum_value.hpp" +#include "rive/importers/enum_importer.hpp" + +using namespace rive; + +StatusCode DataEnumValue::import(ImportStack& importStack) +{ + auto enumImporter = + importStack.latest(DataEnumCustom::typeKey); + if (enumImporter == nullptr) + { + return StatusCode::MissingObject; + } + + enumImporter->addValue(this); + return Super::import(importStack); +} \ No newline at end of file diff --git a/third_party/rive/source/viewmodel/runtime/viewmodel_instance_asset_image_runtime.cpp b/third_party/rive/source/viewmodel/runtime/viewmodel_instance_asset_image_runtime.cpp new file mode 100644 index 0000000..aba5679 --- /dev/null +++ b/third_party/rive/source/viewmodel/runtime/viewmodel_instance_asset_image_runtime.cpp @@ -0,0 +1,11 @@ + +#include "rive/viewmodel/runtime/viewmodel_instance_asset_image_runtime.hpp" + +// Default namespace for Rive Cpp code +using namespace rive; + +void ViewModelInstanceAssetImageRuntime::value(RenderImage* renderImage) +{ + m_viewModelInstanceValue->as()->value( + renderImage); +} diff --git a/third_party/rive/source/viewmodel/runtime/viewmodel_instance_boolean_runtime.cpp b/third_party/rive/source/viewmodel/runtime/viewmodel_instance_boolean_runtime.cpp new file mode 100644 index 0000000..d60ab20 --- /dev/null +++ b/third_party/rive/source/viewmodel/runtime/viewmodel_instance_boolean_runtime.cpp @@ -0,0 +1,17 @@ + +#include "rive/viewmodel/runtime/viewmodel_instance_boolean_runtime.hpp" + +// Default namespace for Rive Cpp code +using namespace rive; + +bool ViewModelInstanceBooleanRuntime::value() const +{ + return m_viewModelInstanceValue->as() + ->propertyValue(); +} + +void ViewModelInstanceBooleanRuntime::value(bool val) +{ + m_viewModelInstanceValue->as()->propertyValue( + val); +} diff --git a/third_party/rive/source/viewmodel/runtime/viewmodel_instance_color_runtime.cpp b/third_party/rive/source/viewmodel/runtime/viewmodel_instance_color_runtime.cpp new file mode 100644 index 0000000..76b4506 --- /dev/null +++ b/third_party/rive/source/viewmodel/runtime/viewmodel_instance_color_runtime.cpp @@ -0,0 +1,41 @@ + +#include "rive/viewmodel/runtime/viewmodel_instance_color_runtime.hpp" + +// Default namespace for Rive Cpp code +using namespace rive; + +int ViewModelInstanceColorRuntime::value() const +{ + return m_viewModelInstanceValue->as() + ->propertyValue(); +} + +void ViewModelInstanceColorRuntime::value(int val) +{ + m_viewModelInstanceValue->as()->propertyValue(val); +} + +void ViewModelInstanceColorRuntime::rgb(int r, int g, int b) +{ + auto val = + m_viewModelInstanceValue->as()->propertyValue(); + int alpha = (val & 0xFF000000) >> 24; + argb(alpha, r, g, b); +} + +void ViewModelInstanceColorRuntime::alpha(int a) +{ + auto color = + m_viewModelInstanceValue->as()->propertyValue(); + int r = (color >> 16) & 0xFF; + int g = (color >> 8) & 0xFF; + int b = color & 0xFF; + argb(a, r, g, b); +} + +void ViewModelInstanceColorRuntime::argb(int a, int r, int g, int b) +{ + auto color = (a << 24) | (r << 16) | (g << 8) | b; + m_viewModelInstanceValue->as()->propertyValue( + color); +} diff --git a/third_party/rive/source/viewmodel/runtime/viewmodel_instance_enum_runtime.cpp b/third_party/rive/source/viewmodel/runtime/viewmodel_instance_enum_runtime.cpp new file mode 100644 index 0000000..5e95fed --- /dev/null +++ b/third_party/rive/source/viewmodel/runtime/viewmodel_instance_enum_runtime.cpp @@ -0,0 +1,63 @@ + +#include "rive/viewmodel/runtime/viewmodel_instance_enum_runtime.hpp" +#include "rive/viewmodel/viewmodel_property_enum.hpp" + +// Default namespace for Rive Cpp code +using namespace rive; + +std::vector ViewModelInstanceEnumRuntime::dataValues() const +{ + auto enumProperty = m_viewModelInstanceValue->viewModelProperty() + ->as(); + auto dataEnum = enumProperty->dataEnum(); + return dataEnum->values(); +} + +std::string ViewModelInstanceEnumRuntime::value() const +{ + auto values = dataValues(); + uint32_t index = + m_viewModelInstanceValue->as()->propertyValue(); + if (index < values.size()) + { + return values[index]->key(); + } + return ""; +} + +void ViewModelInstanceEnumRuntime::value(std::string val) +{ + m_viewModelInstanceValue->as()->value(val); +} + +uint32_t ViewModelInstanceEnumRuntime::valueIndex() const +{ + auto values = dataValues(); + uint32_t index = + m_viewModelInstanceValue->as()->propertyValue(); + if (index < values.size()) + { + return index; + } + return 0; +} + +void ViewModelInstanceEnumRuntime::valueIndex(uint32_t index) +{ + auto values = dataValues(); + if (index < values.size()) + { + m_viewModelInstanceValue->as()->value( + values[index]->key()); + } +} + +std::vector ViewModelInstanceEnumRuntime::values() const +{ + std::vector stringValues; + for (auto value : dataValues()) + { + stringValues.push_back(value->key()); + } + return stringValues; +} \ No newline at end of file diff --git a/third_party/rive/source/viewmodel/runtime/viewmodel_instance_list_runtime.cpp b/third_party/rive/source/viewmodel/runtime/viewmodel_instance_list_runtime.cpp new file mode 100644 index 0000000..6cb96ca --- /dev/null +++ b/third_party/rive/source/viewmodel/runtime/viewmodel_instance_list_runtime.cpp @@ -0,0 +1,110 @@ + +#include "rive/viewmodel/runtime/viewmodel_instance_list_runtime.hpp" +#include "rive/viewmodel/viewmodel_instance_list_item.hpp" +#include "rive/viewmodel/runtime/viewmodel_instance_runtime.hpp" + +// Default namespace for Rive Cpp code +using namespace rive; + +ViewModelInstanceListRuntime::~ViewModelInstanceListRuntime() +{ + for (auto& list : m_itemsMap) + { + list.first->unref(); + list.second->unref(); + } +} + +ViewModelInstanceRuntime* ViewModelInstanceListRuntime::instanceAt(int index) +{ + auto listItems = + m_viewModelInstanceValue->as()->listItems(); + if (index > listItems.size() || index < 0) + { + return nullptr; + } + auto listItem = listItems[index]; + if (listItem->viewModelInstance() == nullptr) + { + return nullptr; + } + auto it = m_itemsMap.find(listItem); + if (it != m_itemsMap.end()) + { + return it->second; + } + auto instanceRuntime = + new ViewModelInstanceRuntime(listItem->viewModelInstance()); + m_itemsMap[listItem] = instanceRuntime; + return instanceRuntime; +} + +void ViewModelInstanceListRuntime::addInstance( + ViewModelInstanceRuntime* instanceRuntime) +{ + instanceRuntime->ref(); + auto listItem = new ViewModelInstanceListItem(); + listItem->viewModelInstance(instanceRuntime->instance()); + auto list = m_viewModelInstanceValue->as(); + m_itemsMap[listItem] = instanceRuntime; + list->addItem(listItem); +} + +void ViewModelInstanceListRuntime::removeInstance( + ViewModelInstanceRuntime* instanceRuntime) +{ + auto instanceList = m_viewModelInstanceValue->as(); + auto listItems = instanceList->listItems(); + // The same instance might be present multiple times in the list + std::vector itemsToRemove; + for (auto& item : listItems) + { + if (item->viewModelInstance().get() == + instanceRuntime->instance().get()) + { + itemsToRemove.push_back(item); + } + } + for (auto& item : itemsToRemove) + { + auto it = m_itemsMap.find(item); + if (it != m_itemsMap.end()) + { + it->first->unref(); + it->second->unref(); + } + instanceList->removeItem(item); + } +} + +void ViewModelInstanceListRuntime::removeInstanceAt(int index) +{ + auto instanceList = m_viewModelInstanceValue->as(); + auto listItems = instanceList->listItems(); + std::vector itemsToRemove; + if (index >= 0 && index < listItems.size()) + { + auto listItem = listItems[index]; + instanceList->removeItem(listItem); + + auto it = m_itemsMap.find(listItem); + if (it != m_itemsMap.end()) + { + it->first->unref(); + it->second->unref(); + } + } +} + +void ViewModelInstanceListRuntime::swap(uint32_t a, uint32_t b) +{ + auto instanceList = m_viewModelInstanceValue->as(); + instanceList->swap(a, b); +} + +size_t ViewModelInstanceListRuntime::size() const +{ + auto listItems = + m_viewModelInstanceValue->as()->listItems(); + return listItems.size(); +} diff --git a/third_party/rive/source/viewmodel/runtime/viewmodel_instance_number_runtime.cpp b/third_party/rive/source/viewmodel/runtime/viewmodel_instance_number_runtime.cpp new file mode 100644 index 0000000..a67c751 --- /dev/null +++ b/third_party/rive/source/viewmodel/runtime/viewmodel_instance_number_runtime.cpp @@ -0,0 +1,16 @@ + +#include "rive/viewmodel/runtime/viewmodel_instance_number_runtime.hpp" + +// Default namespace for Rive Cpp code +using namespace rive; + +float ViewModelInstanceNumberRuntime::value() const +{ + return m_viewModelInstanceValue->as() + ->propertyValue(); +} + +void ViewModelInstanceNumberRuntime::value(float val) +{ + m_viewModelInstanceValue->as()->propertyValue(val); +} diff --git a/third_party/rive/source/viewmodel/runtime/viewmodel_instance_runtime.cpp b/third_party/rive/source/viewmodel/runtime/viewmodel_instance_runtime.cpp new file mode 100644 index 0000000..21f33d3 --- /dev/null +++ b/third_party/rive/source/viewmodel/runtime/viewmodel_instance_runtime.cpp @@ -0,0 +1,352 @@ +#include "rive/viewmodel/runtime/viewmodel_instance_runtime.hpp" +#include "rive/viewmodel/viewmodel.hpp" +#include "rive/viewmodel/viewmodel_instance_number.hpp" +#include "rive/viewmodel/viewmodel_instance_viewmodel.hpp" +#include "rive/viewmodel/runtime/viewmodel_instance_value_runtime.hpp" +#include "rive/viewmodel/runtime/viewmodel_instance_number_runtime.hpp" +#include "rive/viewmodel/runtime/viewmodel_instance_string_runtime.hpp" +#include "rive/viewmodel/runtime/viewmodel_instance_boolean_runtime.hpp" +#include "rive/viewmodel/runtime/viewmodel_instance_color_runtime.hpp" +#include "rive/viewmodel/runtime/viewmodel_instance_enum_runtime.hpp" +#include "rive/viewmodel/runtime/viewmodel_instance_trigger_runtime.hpp" +#include "rive/viewmodel/runtime/viewmodel_instance_list_runtime.hpp" +#include "rive/viewmodel/viewmodel_property_string.hpp" +#include "rive/viewmodel/viewmodel_property_number.hpp" +#include "rive/viewmodel/viewmodel_property_boolean.hpp" +#include "rive/viewmodel/viewmodel_property_color.hpp" +#include "rive/viewmodel/viewmodel_property_list.hpp" +#include "rive/viewmodel/viewmodel_property_enum.hpp" +#include "rive/viewmodel/viewmodel_property_enum_custom.hpp" +#include "rive/viewmodel/viewmodel_property_enum_system.hpp" +#include "rive/viewmodel/viewmodel_property_trigger.hpp" +#include "rive/viewmodel/viewmodel_property_viewmodel.hpp" +#include "rive/viewmodel/runtime/viewmodel_runtime.hpp" + +// Default namespace for Rive Cpp code +using namespace rive; + +ViewModelInstanceRuntime::ViewModelInstanceRuntime( + rcp instance) : + m_viewModelInstance(instance) +{} + +ViewModelInstanceRuntime::~ViewModelInstanceRuntime() +{ + for (auto& it : m_properties) + { + delete it.second; + } +} + +const std::string& ViewModelInstanceRuntime::name() const +{ + return m_viewModelInstance->name(); +} + +size_t ViewModelInstanceRuntime::propertyCount() const +{ + return m_viewModelInstance->propertyValues().size(); +} + +ViewModelInstanceRuntime* ViewModelInstanceRuntime::viewModelInstanceAtPath( + const std::string& path) const +{ + std::string delimiter = "/"; + size_t firstDelim = path.find(delimiter); + std::string viewModelInstanceName = + firstDelim == std::string::npos ? path : path.substr(0, firstDelim); + std::string restOfPath = firstDelim == std::string::npos + ? "" + : path.substr(firstDelim + 1, path.size()); + + if (!viewModelInstanceName.empty()) + { + auto instance = instanceRuntime(viewModelInstanceName); + if (instance != nullptr) + { + if (restOfPath.empty()) + { + return instance.get(); + } + else + { + return instance->viewModelInstanceAtPath(restOfPath); + } + } + } + return nullptr; +} + +ViewModelInstanceValueRuntime* ViewModelInstanceRuntime::property( + const std::string& path) const +{ + if (path.empty()) + { + return nullptr; + } + const auto propertyName = getPropertyNameFromPath(path); + auto viewModelInstanceRuntime = viewModelInstanceFromFullPath(path); + if (viewModelInstanceRuntime != nullptr) + { + auto properties = viewModelInstanceRuntime->properties(); + for (auto p : properties) + { + if (p.name == propertyName) + { + switch (p.type) + { + case DataType::string: + return viewModelInstanceRuntime->propertyString( + propertyName); + case DataType::number: + return viewModelInstanceRuntime->propertyNumber( + propertyName); + case DataType::boolean: + return viewModelInstanceRuntime->propertyBoolean( + propertyName); + default: + break; + } + } + } + } + return nullptr; +} + +std::string ViewModelInstanceRuntime::getPropertyNameFromPath( + const std::string& path) const +{ + if (!path.empty()) + { + std::string delimiter = "/"; + auto propertyNameDelimiter = path.rfind(delimiter); + return propertyNameDelimiter == std::string::npos + ? path + : path.substr(propertyNameDelimiter + 1); + } + return ""; +} + +const ViewModelInstanceRuntime* ViewModelInstanceRuntime:: + viewModelInstanceFromFullPath(const std::string& path) const +{ + std::string delimiter = "/"; + auto propertyNameDelimiter = path.rfind(delimiter); + if (propertyNameDelimiter != std::string::npos) + { + return viewModelInstanceAtPath(path.substr(0, propertyNameDelimiter)); + } + return this; +} + +ViewModelInstanceNumberRuntime* ViewModelInstanceRuntime::propertyNumber( + const std::string& path) const +{ + const auto propertyName = getPropertyNameFromPath(path); + auto viewModelInstance = viewModelInstanceFromFullPath(path); + if (viewModelInstance != nullptr) + { + + return viewModelInstance + ->getPropertyInstance(propertyName); + } + return nullptr; +} + +ViewModelInstanceBooleanRuntime* ViewModelInstanceRuntime::propertyBoolean( + const std::string& path) const +{ + const auto propertyName = getPropertyNameFromPath(path); + auto viewModelInstance = viewModelInstanceFromFullPath(path); + if (viewModelInstance != nullptr) + { + + return viewModelInstance + ->getPropertyInstance( + propertyName); + } + return nullptr; +} + +ViewModelInstanceStringRuntime* ViewModelInstanceRuntime::propertyString( + const std::string& path) const +{ + const auto propertyName = getPropertyNameFromPath(path); + auto viewModelInstance = viewModelInstanceFromFullPath(path); + if (viewModelInstance != nullptr) + { + + return viewModelInstance + ->getPropertyInstance(propertyName); + } + return nullptr; +} + +ViewModelInstanceColorRuntime* ViewModelInstanceRuntime::propertyColor( + const std::string& path) const +{ + const auto propertyName = getPropertyNameFromPath(path); + auto viewModelInstance = viewModelInstanceFromFullPath(path); + if (viewModelInstance != nullptr) + { + + return viewModelInstance + ->getPropertyInstance(propertyName); + } + return nullptr; +} + +ViewModelInstanceTriggerRuntime* ViewModelInstanceRuntime::propertyTrigger( + const std::string& path) const +{ + const auto propertyName = getPropertyNameFromPath(path); + auto viewModelInstance = viewModelInstanceFromFullPath(path); + if (viewModelInstance != nullptr) + { + + return viewModelInstance + ->getPropertyInstance( + propertyName); + } + return nullptr; +} + +ViewModelInstanceEnumRuntime* ViewModelInstanceRuntime::propertyEnum( + const std::string& path) const +{ + const auto propertyName = getPropertyNameFromPath(path); + auto viewModelInstance = viewModelInstanceFromFullPath(path); + if (viewModelInstance != nullptr) + { + + return viewModelInstance + ->getPropertyInstance(propertyName); + } + return nullptr; +} + +ViewModelInstanceListRuntime* ViewModelInstanceRuntime::propertyList( + const std::string& path) const +{ + const auto propertyName = getPropertyNameFromPath(path); + auto viewModelInstance = viewModelInstanceFromFullPath(path); + if (viewModelInstance != nullptr) + { + + return viewModelInstance + ->getPropertyInstance(propertyName); + } + return nullptr; +} + +rcp ViewModelInstanceRuntime::viewModelInstanceProperty( + const std::string& name) const +{ + auto viewModelInstanceValue = m_viewModelInstance->propertyValue(name); + if (viewModelInstanceValue != nullptr && + viewModelInstanceValue->is()) + { + return viewModelInstanceValue->as() + ->referenceViewModelInstance(); + } + return nullptr; +} + +rcp ViewModelInstanceRuntime::instanceRuntime( + const std::string& name) const +{ + auto itr = m_viewModelInstances.find(name); + if (itr != m_viewModelInstances.end()) + { + return static_cast>(itr->second); + } + auto viewModelInstance = viewModelInstanceProperty(name); + if (viewModelInstance != nullptr) + { + auto viewModelInstanceRef = rcp( + new ViewModelInstanceRuntime(viewModelInstance)); + m_viewModelInstances[name] = viewModelInstanceRef; + return viewModelInstanceRef; + } + return nullptr; +} + +ViewModelInstanceRuntime* ViewModelInstanceRuntime::propertyViewModel( + const std::string& path) const +{ + const auto propertyName = getPropertyNameFromPath(path); + auto viewModelInstance = viewModelInstanceFromFullPath(path); + if (viewModelInstance != nullptr) + { + return viewModelInstance->instanceRuntime(propertyName).get(); + } + return nullptr; +} + +ViewModelInstanceAssetImageRuntime* ViewModelInstanceRuntime::propertyImage( + const std::string& path) const +{ + const auto propertyName = getPropertyNameFromPath(path); + auto viewModelInstance = viewModelInstanceFromFullPath(path); + if (viewModelInstance != nullptr) + { + + return viewModelInstance + ->getPropertyInstance( + propertyName); + } + return nullptr; +} + +bool ViewModelInstanceRuntime::replaceViewModel( + const std::string& path, + ViewModelInstanceRuntime* value) const +{ + const auto propertyName = getPropertyNameFromPath(path); + auto viewModelInstance = viewModelInstanceFromFullPath(path); + if (viewModelInstance != nullptr) + { + return viewModelInstance->replaceViewModelByName(propertyName, value); + } + return false; +} + +bool ViewModelInstanceRuntime::replaceViewModelByName( + const std::string& name, + ViewModelInstanceRuntime* value) const +{ + if (m_viewModelInstance->replaceViewModelByName(name, value->instance())) + { + bool isStored = false; + for (const auto& rcpInstance : m_viewModelInstances) + { + if (rcpInstance.second.get() == value) + { + isStored = true; + break; + } + } + if (!isStored) + { + value->ref(); + m_viewModelInstances[name] = rcp(value); + } + return true; + } + return false; +} + +std::vector ViewModelInstanceRuntime::properties() const +{ + std::vector props; + auto properties = m_viewModelInstance->viewModel()->properties(); + return ViewModelRuntime::buildPropertiesData(properties); +} \ No newline at end of file diff --git a/third_party/rive/source/viewmodel/runtime/viewmodel_instance_string_runtime.cpp b/third_party/rive/source/viewmodel/runtime/viewmodel_instance_string_runtime.cpp new file mode 100644 index 0000000..4cff402 --- /dev/null +++ b/third_party/rive/source/viewmodel/runtime/viewmodel_instance_string_runtime.cpp @@ -0,0 +1,16 @@ + +#include "rive/viewmodel/runtime/viewmodel_instance_string_runtime.hpp" + +// Default namespace for Rive Cpp code +using namespace rive; + +const std::string& ViewModelInstanceStringRuntime::value() const +{ + return m_viewModelInstanceValue->as() + ->propertyValue(); +} + +void ViewModelInstanceStringRuntime::value(std::string val) +{ + m_viewModelInstanceValue->as()->propertyValue(val); +} diff --git a/third_party/rive/source/viewmodel/runtime/viewmodel_instance_trigger_runtime.cpp b/third_party/rive/source/viewmodel/runtime/viewmodel_instance_trigger_runtime.cpp new file mode 100644 index 0000000..be7a1bb --- /dev/null +++ b/third_party/rive/source/viewmodel/runtime/viewmodel_instance_trigger_runtime.cpp @@ -0,0 +1,10 @@ + +#include "rive/viewmodel/runtime/viewmodel_instance_trigger_runtime.hpp" + +// Default namespace for Rive Cpp code +using namespace rive; + +void ViewModelInstanceTriggerRuntime::trigger() +{ + return m_viewModelInstanceValue->as()->trigger(); +} \ No newline at end of file diff --git a/third_party/rive/source/viewmodel/runtime/viewmodel_instance_value_runtime.cpp b/third_party/rive/source/viewmodel/runtime/viewmodel_instance_value_runtime.cpp new file mode 100644 index 0000000..b4f9115 --- /dev/null +++ b/third_party/rive/source/viewmodel/runtime/viewmodel_instance_value_runtime.cpp @@ -0,0 +1,47 @@ + +#include "rive/viewmodel/runtime/viewmodel_instance_value_runtime.hpp" +#include "rive/viewmodel/viewmodel.hpp" +#include "rive/viewmodel/viewmodel_instance_number.hpp" + +// Default namespace for Rive Cpp code +using namespace rive; + +ViewModelInstanceValueRuntime::~ViewModelInstanceValueRuntime() +{ + if (m_viewModelInstanceValue != nullptr) + { + m_viewModelInstanceValue->removeDependent(this); + m_viewModelInstanceValue->unref(); + m_viewModelInstanceValue = nullptr; + } +} + +ViewModelInstanceValueRuntime::ViewModelInstanceValueRuntime( + ViewModelInstanceValue* instanceValue) : + m_viewModelInstanceValue(instanceValue) +{ + instanceValue->ref(); + instanceValue->addDependent(this); +} + +void ViewModelInstanceValueRuntime::addDirt(ComponentDirt dirt, bool recurse) +{ + m_hasChanged = true; +} + +void ViewModelInstanceValueRuntime::clearChanges() { m_hasChanged = false; } + +bool ViewModelInstanceValueRuntime::flushChanges() +{ + if (m_hasChanged) + { + m_hasChanged = false; + return true; + } + return false; +} + +const std::string& ViewModelInstanceValueRuntime::name() const +{ + return m_viewModelInstanceValue->name(); +} diff --git a/third_party/rive/source/viewmodel/runtime/viewmodel_runtime.cpp b/third_party/rive/source/viewmodel/runtime/viewmodel_runtime.cpp new file mode 100644 index 0000000..f99869d --- /dev/null +++ b/third_party/rive/source/viewmodel/runtime/viewmodel_runtime.cpp @@ -0,0 +1,172 @@ + +#include "rive/viewmodel/runtime/viewmodel_runtime.hpp" +#include "rive/viewmodel/viewmodel.hpp" +#include "rive/viewmodel/viewmodel_property_string.hpp" +#include "rive/viewmodel/viewmodel_property_number.hpp" +#include "rive/viewmodel/viewmodel_property_boolean.hpp" +#include "rive/viewmodel/viewmodel_property_color.hpp" +#include "rive/viewmodel/viewmodel_property_list.hpp" +#include "rive/viewmodel/viewmodel_property_enum.hpp" +#include "rive/viewmodel/viewmodel_property_enum_custom.hpp" +#include "rive/viewmodel/viewmodel_property_enum_system.hpp" +#include "rive/viewmodel/viewmodel_property_trigger.hpp" +#include "rive/viewmodel/viewmodel_property_viewmodel.hpp" +#include "rive/file.hpp" +#include "rive/refcnt.hpp" + +// Default namespace for Rive Cpp code +using namespace rive; + +ViewModelRuntime::ViewModelRuntime(ViewModel* viewModel, const File* file) : + m_viewModel(viewModel), m_file(file) +{} + +size_t ViewModelRuntime::instanceCount() const +{ + return m_viewModel->instanceCount(); +} + +size_t ViewModelRuntime::propertyCount() const +{ + return m_viewModel->properties().size(); +} + +const std::string& ViewModelRuntime::name() const +{ + return m_viewModel->name(); +} + +std::vector ViewModelRuntime::buildPropertiesData( + std::vector& properties) +{ + std::vector props; + for (auto property : properties) + { + DataType type = DataType::none; + switch (property->coreType()) + { + case ViewModelPropertyString::typeKey: + type = DataType::string; + break; + case ViewModelPropertyNumber::typeKey: + type = DataType::number; + break; + case ViewModelPropertyBoolean::typeKey: + type = DataType::boolean; + break; + case ViewModelPropertyColor::typeKey: + type = DataType::color; + break; + case ViewModelPropertyList::typeKey: + type = DataType::list; + break; + case ViewModelPropertyEnum::typeKey: + case ViewModelPropertyEnumCustomBase::typeKey: + case ViewModelPropertyEnumSystemBase::typeKey: + type = DataType::enumType; + break; + case ViewModelPropertyTrigger::typeKey: + type = DataType::trigger; + break; + case ViewModelPropertyViewModelBase::typeKey: + type = DataType::viewModel; + break; + default: + break; + } + props.push_back({type, property->name()}); + } + return props; +} + +std::vector ViewModelRuntime::properties() +{ + auto props = m_viewModel->properties(); + return buildPropertiesData(props); +} + +std::vector ViewModelRuntime::instanceNames() const +{ + auto instances = m_viewModel->instances(); + std::vector names; + for (auto instance : instances) + { + names.push_back(instance->name()); + } + return names; +} + +ViewModelInstanceRuntime* ViewModelRuntime::createInstanceFromIndex( + const size_t index) const +{ + auto viewModelInstance = m_viewModel->instance(index); + if (viewModelInstance != nullptr) + { + auto copy = rcp( + viewModelInstance->clone()->as()); + m_file->completeViewModelInstance(copy); + return createRuntimeInstance(copy); + } + else + { + fprintf( + stderr, + "Could not find View Model Instance. Index %zu is out of range.\n", + index); + } + return nullptr; +} + +ViewModelInstanceRuntime* ViewModelRuntime::createInstanceFromName( + const std::string& name) const +{ + auto viewModelInstance = m_viewModel->instance(name); + if (viewModelInstance != nullptr) + { + auto copy = rcp( + viewModelInstance->clone()->as()); + m_file->completeViewModelInstance(copy); + return createRuntimeInstance(copy); + } + else + { + fprintf(stderr, + "Could not find View Model Instance named %s. Was it marked to " + "export " + "with the file?\n", + name.c_str()); + } + return nullptr; +} + +ViewModelInstanceRuntime* ViewModelRuntime::createDefaultInstance() const +{ + auto viewModelInstance = + m_file->createDefaultViewModelInstance(m_viewModel); + if (viewModelInstance != nullptr) + { + return createRuntimeInstance(viewModelInstance); + } + fprintf(stderr, + "Default instance not found. Creating empty instance instead.\n"); + return createInstance(); +} + +ViewModelInstanceRuntime* ViewModelRuntime::createInstance() const +{ + auto instance = m_file->createViewModelInstance(m_viewModel); + return createRuntimeInstance(instance); +} + +ViewModelInstanceRuntime* ViewModelRuntime::createRuntimeInstance( + rcp instance) const +{ + if (instance != nullptr) + { + auto viewModelInstanceRuntime = rcp( + new ViewModelInstanceRuntime(instance)); + m_viewModelInstanceRuntimes.push_back(viewModelInstanceRuntime); + return viewModelInstanceRuntime.get(); + } + return nullptr; +} \ No newline at end of file diff --git a/third_party/rive/source/viewmodel/viewmodel.cpp b/third_party/rive/source/viewmodel/viewmodel.cpp new file mode 100644 index 0000000..792d6e4 --- /dev/null +++ b/third_party/rive/source/viewmodel/viewmodel.cpp @@ -0,0 +1,83 @@ +#include +#include +#include + +#include "rive/viewmodel/viewmodel.hpp" +#include "rive/viewmodel/viewmodel_property.hpp" +#include "rive/backboard.hpp" +#include "rive/importers/backboard_importer.hpp" + +using namespace rive; + +ViewModel::~ViewModel() +{ + for (auto& property : m_Properties) + { + delete property; + } +} + +void ViewModel::addProperty(ViewModelProperty* property) +{ + m_Properties.push_back(property); +} + +ViewModelProperty* ViewModel::property(size_t index) +{ + if (index < m_Properties.size()) + { + return m_Properties[index]; + } + return nullptr; +} + +ViewModelProperty* ViewModel::property(const std::string& name) +{ + for (auto property : m_Properties) + { + if (property->name() == name) + { + return property; + } + } + return nullptr; +} + +void ViewModel::addInstance(ViewModelInstance* value) +{ + m_Instances.push_back(value); + value->viewModel(this); +} + +ViewModelInstance* ViewModel::defaultInstance() +{ + if (m_Instances.size() > 0) + { + + return m_Instances[0]; + } + return nullptr; +} + +ViewModelInstance* ViewModel::instance(size_t index) +{ + if (index < m_Instances.size()) + { + return m_Instances[index]; + } + return nullptr; +} + +ViewModelInstance* ViewModel::instance(const std::string& name) +{ + for (auto instance : m_Instances) + { + if (instance->name() == name) + { + return instance; + } + } + return nullptr; +} + +size_t ViewModel::instanceCount() const { return m_Instances.size(); } \ No newline at end of file diff --git a/third_party/rive/source/viewmodel/viewmodel_instance.cpp b/third_party/rive/source/viewmodel/viewmodel_instance.cpp new file mode 100644 index 0000000..95b3398 --- /dev/null +++ b/third_party/rive/source/viewmodel/viewmodel_instance.cpp @@ -0,0 +1,191 @@ +#include +#include +#include + +#include "rive/viewmodel/viewmodel_instance.hpp" +#include "rive/viewmodel/viewmodel.hpp" +#include "rive/viewmodel/viewmodel_instance_value.hpp" +#include "rive/viewmodel/viewmodel_instance_viewmodel.hpp" +#include "rive/importers/viewmodel_importer.hpp" +#include "rive/viewmodel/viewmodel_property_viewmodel.hpp" +#include "rive/core_context.hpp" +#include "rive/refcnt.hpp" + +using namespace rive; + +ViewModelInstance::~ViewModelInstance() +{ + for (auto& value : m_PropertyValues) + { + value->unref(); + } + m_PropertyValues.clear(); + if (m_ViewModel != nullptr) + { + m_ViewModel->unref(); + } +} + +void ViewModelInstance::addValue(ViewModelInstanceValue* value) +{ + m_PropertyValues.push_back(value); +} + +ViewModelInstanceValue* ViewModelInstance::propertyValue(const uint32_t id) +{ + for (auto value : m_PropertyValues) + { + if (value->viewModelPropertyId() == id) + { + return value; + } + } + return nullptr; +} + +bool ViewModelInstance::replaceViewModelByName(const std::string& name, + rcp value) +{ + auto viewModelProperty = viewModel()->property(name); + if (viewModelProperty != nullptr) + { + for (auto propertyValue : m_PropertyValues) + { + if (propertyValue->viewModelProperty() == viewModelProperty) + { + if (value->viewModelId() == + viewModelProperty->as() + ->viewModelReferenceId()) + { + propertyValue->as() + ->referenceViewModelInstance(value); + return true; + } + break; + } + } + } + return false; +} + +ViewModelInstanceValue* ViewModelInstance::propertyValue( + const std::string& name) +{ + auto viewModelProperty = viewModel()->property(name); + if (viewModelProperty != nullptr) + { + for (auto value : m_PropertyValues) + { + if (value->viewModelProperty() == viewModelProperty) + { + return value; + } + } + } + return nullptr; +} + +void ViewModelInstance::viewModel(ViewModel* value) +{ + if (m_ViewModel != nullptr) + { + m_ViewModel->unref(); + } + value->ref(); + m_ViewModel = value; +} + +ViewModel* ViewModelInstance::viewModel() const { return m_ViewModel; } + +void ViewModelInstance::onComponentDirty(Component* component) {} + +void ViewModelInstance::setAsRoot(rcp instance) +{ + setRoot(instance); +} + +void ViewModelInstance::setRoot(rcp value) +{ + for (auto propertyValue : m_PropertyValues) + { + propertyValue->setRoot(value); + } +} + +std::vector ViewModelInstance::propertyValues() +{ + return m_PropertyValues; +} + +Core* ViewModelInstance::clone() const +{ + auto cloned = new ViewModelInstance(); + cloned->copy(*this); + for (auto propertyValue : m_PropertyValues) + { + auto clonedValue = propertyValue->clone()->as(); + cloned->addValue(clonedValue); + } + cloned->viewModel(viewModel()); + return cloned; +} + +StatusCode ViewModelInstance::import(ImportStack& importStack) +{ + auto viewModelImporter = + importStack.latest(ViewModel::typeKey); + if (viewModelImporter == nullptr) + { + return StatusCode::MissingObject; + } + + viewModelImporter->addInstance(this); + return StatusCode::Ok; +} + +ViewModelInstanceValue* ViewModelInstance::propertyFromPath( + std::vector* path, + size_t index) +{ + if (index < path->size()) + { + auto propertyId = (*path)[index]; + auto property = propertyValue(propertyId); + if (property != nullptr) + { + if (index == path->size() - 1) + { + return property; + } + if (property->is()) + { + auto propertyViewModel = + property->as(); + auto viewModelInstance = + propertyViewModel->referenceViewModelInstance(); + return viewModelInstance->propertyFromPath(path, index + 1); + } + } + } + return nullptr; +} + +void ViewModelInstance::advanced() +{ + for (auto value : m_PropertyValues) + { + value->advanced(); + } +} + +ViewModelInstanceValue* ViewModelInstance::symbol(int coreType) +{ + for (auto& value : m_PropertyValues) + { + if (value->coreType() == coreType) + { + return value; + } + } + return nullptr; +} \ No newline at end of file diff --git a/third_party/rive/source/viewmodel/viewmodel_instance_asset.cpp b/third_party/rive/source/viewmodel/viewmodel_instance_asset.cpp new file mode 100644 index 0000000..4f577c1 --- /dev/null +++ b/third_party/rive/source/viewmodel/viewmodel_instance_asset.cpp @@ -0,0 +1,28 @@ +#include +#include +#include + +#include "rive/viewmodel/viewmodel_instance_asset.hpp" +#include "rive/viewmodel/viewmodel_instance.hpp" +#include "rive/importers/backboard_importer.hpp" +#include "rive/backboard.hpp" +#include "rive/component_dirt.hpp" +#include "rive/refcnt.hpp" + +using namespace rive; + +StatusCode ViewModelInstanceAsset::import(ImportStack& importStack) +{ + auto backboardImporter = + importStack.latest(Backboard::typeKey); + if (backboardImporter == nullptr) + { + return StatusCode::MissingObject; + } + auto assets = backboardImporter->assets(); + for (const auto& asset : *assets) + { + m_assets.push_back(asset); + } + return Super::import(importStack); +} \ No newline at end of file diff --git a/third_party/rive/source/viewmodel/viewmodel_instance_asset_image.cpp b/third_party/rive/source/viewmodel/viewmodel_instance_asset_image.cpp new file mode 100644 index 0000000..768c098 --- /dev/null +++ b/third_party/rive/source/viewmodel/viewmodel_instance_asset_image.cpp @@ -0,0 +1,43 @@ +#include +#include +#include + +#include "rive/viewmodel/viewmodel_instance_asset_image.hpp" +#include "rive/component_dirt.hpp" +#include "rive/refcnt.hpp" + +using namespace rive; + +void ViewModelInstanceAssetImage::propertyValueChanged() +{ + addDirt(ComponentDirt::Bindings); +#ifdef WITH_RIVE_TOOLS + if (m_changedCallback != nullptr) + { + m_changedCallback(this, propertyValue()); + } +#endif +} + +void ViewModelInstanceAssetImage::value(RenderImage* image) +{ + if (m_imageAsset.renderImage() == image || image == nullptr) + { + return; + } + propertyValue(-1); + image->ref(); + m_imageAsset.renderImage(rcp(image)); + addDirt(ComponentDirt::Bindings); +} + +Core* ViewModelInstanceAssetImage::clone() const +{ + auto cloned = new ViewModelInstanceAssetImage(); + cloned->copy(*this); + for (const auto& asset : assets()) + { + cloned->addAsset(asset); + } + return cloned; +} \ No newline at end of file diff --git a/third_party/rive/source/viewmodel/viewmodel_instance_boolean.cpp b/third_party/rive/source/viewmodel/viewmodel_instance_boolean.cpp new file mode 100644 index 0000000..72b85f3 --- /dev/null +++ b/third_party/rive/source/viewmodel/viewmodel_instance_boolean.cpp @@ -0,0 +1,19 @@ +#include +#include +#include + +#include "rive/viewmodel/viewmodel_instance_boolean.hpp" +#include "rive/component_dirt.hpp" + +using namespace rive; + +void ViewModelInstanceBoolean::propertyValueChanged() +{ + addDirt(ComponentDirt::Bindings); +#ifdef WITH_RIVE_TOOLS + if (m_changedCallback != nullptr) + { + m_changedCallback(this, propertyValue()); + } +#endif +} \ No newline at end of file diff --git a/third_party/rive/source/viewmodel/viewmodel_instance_color.cpp b/third_party/rive/source/viewmodel/viewmodel_instance_color.cpp new file mode 100644 index 0000000..468f6d0 --- /dev/null +++ b/third_party/rive/source/viewmodel/viewmodel_instance_color.cpp @@ -0,0 +1,19 @@ +#include +#include +#include + +#include "rive/viewmodel/viewmodel_instance_color.hpp" +#include "rive/component_dirt.hpp" + +using namespace rive; + +void ViewModelInstanceColor::propertyValueChanged() +{ + addDirt(ComponentDirt::Bindings); +#ifdef WITH_RIVE_TOOLS + if (m_changedCallback != nullptr) + { + m_changedCallback(this, propertyValue()); + } +#endif +} \ No newline at end of file diff --git a/third_party/rive/source/viewmodel/viewmodel_instance_enum.cpp b/third_party/rive/source/viewmodel/viewmodel_instance_enum.cpp new file mode 100644 index 0000000..7c0728d --- /dev/null +++ b/third_party/rive/source/viewmodel/viewmodel_instance_enum.cpp @@ -0,0 +1,43 @@ +#include +#include +#include + +#include "rive/viewmodel/viewmodel_instance_enum.hpp" +#include "rive/viewmodel/viewmodel_property_enum.hpp" +#include "rive/component_dirt.hpp" + +using namespace rive; + +void ViewModelInstanceEnum::propertyValueChanged() +{ + addDirt(ComponentDirt::Bindings); +#ifdef WITH_RIVE_TOOLS + if (m_changedCallback != nullptr) + { + m_changedCallback(this, propertyValue()); + } +#endif +} + +bool ViewModelInstanceEnum::value(std::string name) +{ + auto enumProperty = viewModelProperty()->as(); + int index = enumProperty->valueIndex(name); + if (index != -1) + { + propertyValue(index); + return true; + } + return false; +} + +bool ViewModelInstanceEnum::value(uint32_t index) +{ + auto enumProperty = viewModelProperty()->as(); + if (enumProperty->valueIndex(index) != -1) + { + propertyValue(index); + return true; + } + return false; +} \ No newline at end of file diff --git a/third_party/rive/source/viewmodel/viewmodel_instance_list.cpp b/third_party/rive/source/viewmodel/viewmodel_instance_list.cpp new file mode 100644 index 0000000..fd792db --- /dev/null +++ b/third_party/rive/source/viewmodel/viewmodel_instance_list.cpp @@ -0,0 +1,99 @@ +#include +#include +#include + +#include "rive/viewmodel/viewmodel_instance_list.hpp" +#include "rive/viewmodel/viewmodel_instance_list_item.hpp" +#include "rive/component_dirt.hpp" + +using namespace rive; + +ViewModelInstanceList::~ViewModelInstanceList() +{ + for (auto item : m_ListItems) + { + item->unref(); + } +} + +void ViewModelInstanceList::propertyValueChanged() +{ + addDirt(ComponentDirt::Bindings); +} + +void ViewModelInstanceList::addItem(ViewModelInstanceListItem* item) +{ + item->ref(); + m_ListItems.push_back(item); + propertyValueChanged(); +} + +void ViewModelInstanceList::internalAddItem(ViewModelInstanceListItem* item) +{ + // For ViewModelInstanceListItems that are built as a core object + // we skip the ref since core has already reffed it + m_ListItems.push_back(item); +} + +void ViewModelInstanceList::insertItem(int index, + ViewModelInstanceListItem* item) +{ + // TODO: @hernan decide if we want to return a boolean + if (index < m_ListItems.size()) + { + item->ref(); + m_ListItems.insert(m_ListItems.begin() + index, item); + propertyValueChanged(); + } +} + +void ViewModelInstanceList::removeItem(int index) +{ + // TODO: @hernan decide if we want to return a boolean + if (index >= 0 && index < m_ListItems.size()) + { + auto listItem = m_ListItems[index]; + m_ListItems.erase(m_ListItems.begin() + index); + listItem->unref(); + propertyValueChanged(); + } +} + +void ViewModelInstanceList::removeItem(ViewModelInstanceListItem* listItem) +{ + auto noSpaceEnd = + std::remove(m_ListItems.begin(), m_ListItems.end(), listItem); + m_ListItems.erase(noSpaceEnd, m_ListItems.end()); + propertyValueChanged(); +} + +ViewModelInstanceListItem* ViewModelInstanceList::item(uint32_t index) +{ + if (index < m_ListItems.size()) + { + return m_ListItems[index]; + } + return nullptr; +} + +void ViewModelInstanceList::swap(uint32_t index1, uint32_t index2) +{ + if (index1 < m_ListItems.size() && index2 < m_ListItems.size()) + { + std::iter_swap(m_ListItems.begin() + index1, + m_ListItems.begin() + index2); + propertyValueChanged(); + } +} + +Core* ViewModelInstanceList::clone() const +{ + auto cloned = new ViewModelInstanceList(); + cloned->copy(*this); + for (auto property : m_ListItems) + { + auto clonedValue = property->clone()->as(); + cloned->internalAddItem(clonedValue); + } + return cloned; +} \ No newline at end of file diff --git a/third_party/rive/source/viewmodel/viewmodel_instance_list_item.cpp b/third_party/rive/source/viewmodel/viewmodel_instance_list_item.cpp new file mode 100644 index 0000000..715f9c2 --- /dev/null +++ b/third_party/rive/source/viewmodel/viewmodel_instance_list_item.cpp @@ -0,0 +1,23 @@ +#include +#include +#include + +#include "rive/viewmodel/viewmodel_instance_list.hpp" +#include "rive/viewmodel/viewmodel_instance_list_item.hpp" +#include "rive/importers/viewmodel_instance_list_importer.hpp" + +using namespace rive; + +StatusCode ViewModelInstanceListItem::import(ImportStack& importStack) +{ + auto viewModelInstanceList = + importStack.latest( + ViewModelInstanceList::typeKey); + if (viewModelInstanceList == nullptr) + { + return StatusCode::MissingObject; + } + viewModelInstanceList->addItem(this); + + return Super::import(importStack); +} \ No newline at end of file diff --git a/third_party/rive/source/viewmodel/viewmodel_instance_number.cpp b/third_party/rive/source/viewmodel/viewmodel_instance_number.cpp new file mode 100644 index 0000000..cbd5e09 --- /dev/null +++ b/third_party/rive/source/viewmodel/viewmodel_instance_number.cpp @@ -0,0 +1,19 @@ +#include +#include +#include + +#include "rive/viewmodel/viewmodel_instance_number.hpp" +#include "rive/component_dirt.hpp" + +using namespace rive; + +void ViewModelInstanceNumber::propertyValueChanged() +{ + addDirt(ComponentDirt::Bindings); +#ifdef WITH_RIVE_TOOLS + if (m_changedCallback != nullptr) + { + m_changedCallback(this, propertyValue()); + } +#endif +} \ No newline at end of file diff --git a/third_party/rive/source/viewmodel/viewmodel_instance_string.cpp b/third_party/rive/source/viewmodel/viewmodel_instance_string.cpp new file mode 100644 index 0000000..58505eb --- /dev/null +++ b/third_party/rive/source/viewmodel/viewmodel_instance_string.cpp @@ -0,0 +1,19 @@ +#include +#include +#include + +#include "rive/viewmodel/viewmodel_instance_string.hpp" +#include "rive/component_dirt.hpp" + +using namespace rive; + +void ViewModelInstanceString::propertyValueChanged() +{ + addDirt(ComponentDirt::Bindings); +#ifdef WITH_RIVE_TOOLS + if (m_changedCallback != nullptr) + { + m_changedCallback(this, propertyValue().c_str()); + } +#endif +} \ No newline at end of file diff --git a/third_party/rive/source/viewmodel/viewmodel_instance_symbol_list_index.cpp b/third_party/rive/source/viewmodel/viewmodel_instance_symbol_list_index.cpp new file mode 100644 index 0000000..db43f2d --- /dev/null +++ b/third_party/rive/source/viewmodel/viewmodel_instance_symbol_list_index.cpp @@ -0,0 +1,19 @@ +#include +#include +#include + +#include "rive/viewmodel/viewmodel_instance_symbol_list_index.hpp" +#include "rive/component_dirt.hpp" + +using namespace rive; + +void ViewModelInstanceSymbolListIndex::propertyValueChanged() +{ + addDirt(ComponentDirt::Bindings); +#ifdef WITH_RIVE_TOOLS + if (m_changedCallback != nullptr) + { + m_changedCallback(this, propertyValue()); + } +#endif +} \ No newline at end of file diff --git a/third_party/rive/source/viewmodel/viewmodel_instance_trigger.cpp b/third_party/rive/source/viewmodel/viewmodel_instance_trigger.cpp new file mode 100644 index 0000000..9f50c0f --- /dev/null +++ b/third_party/rive/source/viewmodel/viewmodel_instance_trigger.cpp @@ -0,0 +1,25 @@ +#include +#include +#include + +#include "rive/viewmodel/viewmodel_instance_trigger.hpp" +#include "rive/component_dirt.hpp" + +using namespace rive; + +void ViewModelInstanceTrigger::propertyValueChanged() +{ + addDirt(ComponentDirt::Bindings); +#ifdef WITH_RIVE_TOOLS + if (m_changedCallback != nullptr) + { + m_changedCallback(this, propertyValue()); + } +#endif +} + +void ViewModelInstanceTrigger::advanced() +{ + propertyValue(0); + m_usedLayers.clear(); +} \ No newline at end of file diff --git a/third_party/rive/source/viewmodel/viewmodel_instance_value.cpp b/third_party/rive/source/viewmodel/viewmodel_instance_value.cpp new file mode 100644 index 0000000..074db35 --- /dev/null +++ b/third_party/rive/source/viewmodel/viewmodel_instance_value.cpp @@ -0,0 +1,65 @@ +#include +#include +#include + +#include "rive/viewmodel/viewmodel_instance.hpp" +#include "rive/viewmodel/viewmodel_instance_value.hpp" +#include "rive/importers/viewmodel_instance_importer.hpp" +#include "rive/data_bind/data_bind.hpp" +#include "rive/refcnt.hpp" + +using namespace rive; + +StatusCode ViewModelInstanceValue::import(ImportStack& importStack) +{ + auto viewModelInstanceImporter = + importStack.latest( + ViewModelInstance::typeKey); + if (viewModelInstanceImporter == nullptr) + { + return StatusCode::MissingObject; + } + viewModelInstanceImporter->addValue(this); + + return Super::import(importStack); +} + +void ViewModelInstanceValue::viewModelProperty(ViewModelProperty* value) +{ + m_ViewModelProperty = value; +} +ViewModelProperty* ViewModelInstanceValue::viewModelProperty() +{ + return m_ViewModelProperty; +} + +void ViewModelInstanceValue::addDependent(Dirtyable* value) +{ + m_DependencyHelper.addDependent(value); +} + +void ViewModelInstanceValue::removeDependent(Dirtyable* value) +{ + m_DependencyHelper.removeDependent(value); +} + +void ViewModelInstanceValue::addDirt(ComponentDirt value) +{ + m_DependencyHelper.addDirt(value); +} + +void ViewModelInstanceValue::setRoot(rcp viewModelInstance) +{ + m_DependencyHelper.dependecyRoot(&viewModelInstance); +} + +std::string ViewModelInstanceValue::defaultName = ""; + +const std::string& ViewModelInstanceValue::name() const +{ + if (m_ViewModelProperty != nullptr) + { + return m_ViewModelProperty->constName(); + }; + return defaultName; +} \ No newline at end of file diff --git a/third_party/rive/source/viewmodel/viewmodel_instance_viewmodel.cpp b/third_party/rive/source/viewmodel/viewmodel_instance_viewmodel.cpp new file mode 100644 index 0000000..a5fac96 --- /dev/null +++ b/third_party/rive/source/viewmodel/viewmodel_instance_viewmodel.cpp @@ -0,0 +1,23 @@ +#include +#include +#include + +#include "rive/viewmodel/viewmodel_instance_viewmodel.hpp" + +using namespace rive; + +ViewModelInstanceViewModel::~ViewModelInstanceViewModel() {} + +void ViewModelInstanceViewModel::setRoot(rcp value) +{ + Super::setRoot(value); + m_referenceViewModelInstance->setRoot(value); +} + +void ViewModelInstanceViewModel::advanced() +{ + if (m_referenceViewModelInstance != nullptr) + { + m_referenceViewModelInstance->advanced(); + } +} \ No newline at end of file diff --git a/third_party/rive/source/viewmodel/viewmodel_property.cpp b/third_party/rive/source/viewmodel/viewmodel_property.cpp new file mode 100644 index 0000000..a23f6d5 --- /dev/null +++ b/third_party/rive/source/viewmodel/viewmodel_property.cpp @@ -0,0 +1,18 @@ +#include "rive/viewmodel/viewmodel_property.hpp" +#include "rive/importers/viewmodel_importer.hpp" +#include "rive/viewmodel/viewmodel.hpp" + +using namespace rive; + +StatusCode ViewModelProperty::import(ImportStack& importStack) +{ + auto viewModelImporter = + importStack.latest(ViewModel::typeKey); + if (viewModelImporter == nullptr) + { + return StatusCode::MissingObject; + } + + viewModelImporter->addProperty(this); + return Super::import(importStack); +} diff --git a/third_party/rive/source/viewmodel/viewmodel_property_enum.cpp b/third_party/rive/source/viewmodel/viewmodel_property_enum.cpp new file mode 100644 index 0000000..e0477cf --- /dev/null +++ b/third_party/rive/source/viewmodel/viewmodel_property_enum.cpp @@ -0,0 +1,72 @@ +#include "rive/viewmodel/viewmodel_property_enum.hpp" + +using namespace rive; + +void ViewModelPropertyEnum::dataEnum(DataEnum* value) +{ + value->ref(); + m_DataEnum = rcp(value); +} + +DataEnum* ViewModelPropertyEnum::dataEnum() +{ + if (m_DataEnum == nullptr) + { + return nullptr; + } + return m_DataEnum.get(); +} + +std::string ViewModelPropertyEnum::value(std::string name) +{ + if (dataEnum() != nullptr) + { + return dataEnum()->value(name); + } + return ""; +} + +std::string ViewModelPropertyEnum::value(uint32_t index) +{ + if (dataEnum() != nullptr) + { + return dataEnum()->value(index); + } + return ""; +} + +bool ViewModelPropertyEnum::value(std::string name, std::string value) +{ + if (dataEnum() != nullptr) + { + return dataEnum()->value(name, value); + } + return false; +} + +bool ViewModelPropertyEnum::value(uint32_t index, std::string value) +{ + if (dataEnum() != nullptr) + { + return dataEnum()->value(index, value); + } + return false; +} + +int ViewModelPropertyEnum::valueIndex(std::string name) +{ + if (dataEnum() != nullptr) + { + return dataEnum()->valueIndex(name); + } + return -1; +} + +int ViewModelPropertyEnum::valueIndex(uint32_t index) +{ + if (dataEnum() != nullptr) + { + return dataEnum()->valueIndex(index); + } + return -1; +} \ No newline at end of file diff --git a/third_party/rive/source/viewmodel/viewmodel_property_enum_system.cpp b/third_party/rive/source/viewmodel/viewmodel_property_enum_system.cpp new file mode 100644 index 0000000..075f2b6 --- /dev/null +++ b/third_party/rive/source/viewmodel/viewmodel_property_enum_system.cpp @@ -0,0 +1,5 @@ +#include "rive/viewmodel/viewmodel_property_enum_system.hpp" + +using namespace rive; + +DataEnum ViewModelPropertyEnumSystem::m_systemDataEnum; \ No newline at end of file diff --git a/third_party/rive/source/world_transform_component.cpp b/third_party/rive/source/world_transform_component.cpp new file mode 100644 index 0000000..4c308b5 --- /dev/null +++ b/third_party/rive/source/world_transform_component.cpp @@ -0,0 +1,28 @@ +#include "rive/transform_component.hpp" +#include "rive/shapes/clipping_shape.hpp" +#include "rive/math/vec2d.hpp" +#include "rive/constraints/constraint.hpp" + +using namespace rive; + +float WorldTransformComponent::childOpacity() { return opacity(); } + +void WorldTransformComponent::markWorldTransformDirty() +{ + addDirt(ComponentDirt::WorldTransform, true); +} + +const Mat2D& WorldTransformComponent::worldTransform() const +{ + return m_WorldTransform; +} + +Mat2D& WorldTransformComponent::mutableWorldTransform() +{ + return m_WorldTransform; +} + +void WorldTransformComponent::opacityChanged() +{ + addDirt(ComponentDirt::RenderOpacity, true); +} diff --git a/third_party/rive_decoders/include/rive/decoders/bitmap_decoder.hpp b/third_party/rive_decoders/include/rive/decoders/bitmap_decoder.hpp new file mode 100644 index 0000000..3feb42e --- /dev/null +++ b/third_party/rive_decoders/include/rive/decoders/bitmap_decoder.hpp @@ -0,0 +1,80 @@ +/* + * Copyright 2023 Rive + */ + +#ifndef _RIVE_BITMAP_DECODER_HPP_ +#define _RIVE_BITMAP_DECODER_HPP_ + +#include +#include + +namespace rive { + +/// Bitmap will always take ownership of the bytes it is constructed with. +class Bitmap +{ +public: + enum class PixelFormat : uint8_t + { + RGB, + RGBA, + RGBAPremul, + }; + + Bitmap(uint32_t width, + uint32_t height, + PixelFormat pixelFormat, + std::unique_ptr bytes); + + Bitmap(uint32_t width, + uint32_t height, + PixelFormat pixelFormat, + const uint8_t* bytes); + +private: + uint32_t m_Width; + uint32_t m_Height; + PixelFormat m_PixelFormat; + std::unique_ptr m_Bytes; + +public: + uint32_t width() const { return m_Width; } + uint32_t height() const { return m_Height; } + PixelFormat pixelFormat() const { return m_PixelFormat; } + const uint8_t* bytes() const { return m_Bytes.get(); } + std::unique_ptr detachBytes() + { + return std::move(m_Bytes); + } + + enum class ImageType + { + png, + jpeg, + webp, + }; + + using BitmapDecoder = std::unique_ptr (*)(const uint8_t bytes[], + size_t byteCount); + + struct ImageFormat + { + const char* name; + ImageType type; + std::vector fingerprint; + BitmapDecoder decodeImage; + }; + + static const ImageFormat* RecognizeImageFormat(const uint8_t bytes[], + size_t byteCount); + + static std::unique_ptr decode(const uint8_t bytes[], + size_t byteCount); + + // Change the pixel format (note this will resize bytes). + void pixelFormat(PixelFormat format); +}; + +} // namespace rive + +#endif diff --git a/third_party/rive_decoders/rive_decoders.cpp b/third_party/rive_decoders/rive_decoders.cpp new file mode 100644 index 0000000..0665054 --- /dev/null +++ b/third_party/rive_decoders/rive_decoders.cpp @@ -0,0 +1,37 @@ +/* + ============================================================================== + + This file is part of the YUP library. + Copyright (c) 2024 - kunitoki@gmail.com + + YUP is an open source library subject to open-source licensing. + + The code included in this file is provided under the terms of the ISC license + http://www.isc.org/downloads/software-support-policy/isc-license. Permission + to use, copy, modify, and/or distribute this software for any purpose with or + without fee is hereby granted provided that the above copyright notice and + this permission notice appear in all copies. + + YUP IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +#include "rive_decoders.h" + +#include "source/bitmap_decoder.cpp" +#include "source/bitmap_decoder_thirdparty.cpp" + +#if RIVE_JPEG +#include "source/decode_jpeg.cpp" +#endif + +#if RIVE_PNG +#include "source/decode_png.cpp" +#endif + +#if RIVE_WEBP +#include "source/decode_webp.cpp" +#endif diff --git a/third_party/rive_decoders/rive_decoders.h b/third_party/rive_decoders/rive_decoders.h new file mode 100644 index 0000000..e84acfa --- /dev/null +++ b/third_party/rive_decoders/rive_decoders.h @@ -0,0 +1,54 @@ +/* + ============================================================================== + + This file is part of the YUP library. + Copyright (c) 2024 - kunitoki@gmail.com + + YUP is an open source library subject to open-source licensing. + + The code included in this file is provided under the terms of the ISC license + http://www.isc.org/downloads/software-support-policy/isc-license. Permission + to use, copy, modify, and/or distribute this software for any purpose with or + without fee is hereby granted provided that the above copyright notice and + this permission notice appear in all copies. + + YUP IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +/* + ============================================================================== + + BEGIN_YUP_MODULE_DECLARATION + + ID: rive_decoders + vendor: rive + version: 1.0 + name: Rive Decoders. + description: The Rive Decoders is a companion library for ratser image decoding. + website: https://github.com/rive-app/rive-runtime + license: MIT + + searchpaths: include + appleFrameworks: ImageIO + enableARC: 1 + + END_YUP_MODULE_DECLARATION + + ============================================================================== +*/ + +#pragma once + +#if YUP_MODULE_AVAILABLE_libpng +#define RIVE_PNG 1 +#endif + +#if YUP_MODULE_AVAILABLE_libwebp +#define RIVE_WEBP 1 +#endif + +#include "include/rive/decoders/bitmap_decoder.hpp" diff --git a/third_party/rive_decoders/rive_decoders.mm b/third_party/rive_decoders/rive_decoders.mm new file mode 100644 index 0000000..493ef3a --- /dev/null +++ b/third_party/rive_decoders/rive_decoders.mm @@ -0,0 +1,22 @@ +/* + ============================================================================== + + This file is part of the YUP library. + Copyright (c) 2024 - kunitoki@gmail.com + + YUP is an open source library subject to open-source licensing. + + The code included in this file is provided under the terms of the ISC license + http://www.isc.org/downloads/software-support-policy/isc-license. Permission + to use, copy, modify, and/or distribute this software for any purpose with or + without fee is hereby granted provided that the above copyright notice and + this permission notice appear in all copies. + + YUP IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +#include "rive_decoders.cpp" diff --git a/third_party/rive_decoders/source/bitmap_decoder.cpp b/third_party/rive_decoders/source/bitmap_decoder.cpp new file mode 100644 index 0000000..979b2e5 --- /dev/null +++ b/third_party/rive_decoders/source/bitmap_decoder.cpp @@ -0,0 +1,108 @@ +/* + * Copyright 2023 Rive + */ + +#include "rive/decoders/bitmap_decoder.hpp" +#include "rive/rive_types.hpp" +#include "rive/math/simd.hpp" +#include +#include + +namespace rive { + +Bitmap::Bitmap(uint32_t width, + uint32_t height, + PixelFormat pixelFormat, + std::unique_ptr bytes) : + m_Width(width), + m_Height(height), + m_PixelFormat(pixelFormat), + m_Bytes(std::move(bytes)) +{} + +Bitmap::Bitmap(uint32_t width, + uint32_t height, + PixelFormat pixelFormat, + const uint8_t* bytes) : + Bitmap(width, height, pixelFormat, std::unique_ptr(bytes)) +{} + +static size_t bytes_per_pixel(Bitmap::PixelFormat format) +{ + switch (format) + { + case Bitmap::PixelFormat::RGB: + return 3; + case Bitmap::PixelFormat::RGBA: + case Bitmap::PixelFormat::RGBAPremul: + return 4; + } + RIVE_UNREACHABLE(); +} + +void Bitmap::pixelFormat(PixelFormat format) +{ + if (format == m_PixelFormat) + { + return; + } + + size_t imageNumPixels = m_Height * m_Width; + size_t fromBytesPerPixel = bytes_per_pixel(m_PixelFormat); + size_t toBytesPerPixel = bytes_per_pixel(format); + size_t toSizeInBytes = imageNumPixels * toBytesPerPixel; + + // Round our allocation up to a multiple of 8 so we can premultiply two + // pixels at once if needed. + size_t allocSize = (toSizeInBytes + 7) & ~7llu; + assert(allocSize >= toSizeInBytes && allocSize <= toSizeInBytes + 7); + auto toBytes = std::unique_ptr(new uint8_t[allocSize]); + + // Copy into the new pixel buffer. + int writeIndex = 0; + int readIndex = 0; + for (size_t i = 0; i < imageNumPixels; i++) + { + for (size_t j = 0; j < toBytesPerPixel; j++) + { + toBytes[writeIndex++] = + j < fromBytesPerPixel ? m_Bytes[readIndex++] : 255; + } + } + + if (format == PixelFormat::RGBAPremul) + { + // Convert to premultiplied alpha. + for (size_t i = 0; i < toSizeInBytes; i += 8) + { + // Load 2 pixels into 64 bits. We overallocated our buffer to ensure + // we could always premultiply in twos. + assert(i + 8 <= allocSize); + rive::uint8x8 twoPx = rive::simd::load(&toBytes[i]); + uint8_t a0 = twoPx[3]; + uint8_t a1 = twoPx[7]; + // Don't premultiply fully opaque pixels. + if (a0 != 255 || a1 != 255) + { + // Cast to 16 bits to avoid overflow. + rive::uint16x8 widePx = rive::simd::cast(twoPx); + // Multiply by alpha. + rive::uint16x8 alpha = {a0, a0, a0, 255, a1, a1, a1, 255}; + widePx = rive::simd::div255(widePx * alpha); + // Cast back to 8 bits and store. + twoPx = rive::simd::cast(widePx); + rive::simd::store(&toBytes[i], twoPx); + } + } + } + else + { + // Unmultiplying alpha is not currently supported. + assert(m_PixelFormat != PixelFormat::RGBAPremul); + } + + m_Bytes = std::move(toBytes); + m_PixelFormat = format; +} + +} // namespace rive diff --git a/third_party/rive_decoders/source/bitmap_decoder_thirdparty.cpp b/third_party/rive_decoders/source/bitmap_decoder_thirdparty.cpp new file mode 100644 index 0000000..2d9b85c --- /dev/null +++ b/third_party/rive_decoders/source/bitmap_decoder_thirdparty.cpp @@ -0,0 +1,232 @@ +/* + * Copyright 2023 Rive + */ + +#include "rive/decoders/bitmap_decoder.hpp" + +#ifdef __APPLE__ +#include "rive/rive_types.hpp" +#include "rive/math/math_types.hpp" +#include "rive/core/type_conversions.hpp" +#include "utils/auto_cf.hpp" + +#include + +#if TARGET_OS_IPHONE +#import +#include +#elif TARGET_OS_MAC +#include +#endif +#endif + +#include +#include +#include + +namespace rive { + +#ifdef RIVE_PNG +std::unique_ptr DecodePng(const uint8_t bytes[], size_t byteCount); +#endif +#ifdef RIVE_JPEG +std::unique_ptr DecodeJpeg(const uint8_t bytes[], size_t byteCount); +#endif +#ifdef RIVE_WEBP +std::unique_ptr DecodeWebP(const uint8_t bytes[], size_t byteCount); +#endif + +static Bitmap::ImageFormat _formats[] = { + { + "png", + Bitmap::ImageType::png, + {0x89, 0x50, 0x4E, 0x47}, +#ifdef RIVE_PNG + DecodePng, +#else + nullptr, +#endif + }, + { + "jpeg", + Bitmap::ImageType::jpeg, + {0xFF, 0xD8, 0xFF}, +#ifdef RIVE_JPEG + DecodeJpeg, +#else + nullptr, +#endif + }, + { + "webp", + Bitmap::ImageType::webp, + {0x52, 0x49, 0x46}, +#ifdef RIVE_WEBP + DecodeWebP, +#else + nullptr, +#endif + }, +}; + +const Bitmap::ImageFormat* Bitmap::RecognizeImageFormat(const uint8_t bytes[], + size_t byteCount) +{ + for (const ImageFormat& format : _formats) + { + auto& fingerprint = format.fingerprint; + + // Immediately discard decoders with fingerprints that are longer than + // the file buffer. + if (format.fingerprint.size() > byteCount) + { + continue; + } + + // If the fingerprint doesn't match, discrd this decoder. These are all + // bytes so .size() is fine here. + if (memcmp(fingerprint.data(), bytes, fingerprint.size()) != 0) + { + continue; + } + + return &format; + } + return nullptr; +} + +#ifdef __APPLE__ +// Represents raw, premultiplied, RGBA image data with tightly packed rows +// (width * 4 bytes). +struct PlatformCGImage +{ + uint32_t width = 0; + uint32_t height = 0; + bool opaque = false; + std::unique_ptr pixels; +}; + +bool cg_image_decode(const uint8_t* encodedBytes, + size_t encodedSizeInBytes, + PlatformCGImage* platformImage) +{ + AutoCF data = + CFDataCreate(kCFAllocatorDefault, encodedBytes, encodedSizeInBytes); + if (!data) + { + return false; + } + + AutoCF source = CGImageSourceCreateWithData(data, nullptr); + if (!source) + { + return false; + } + + AutoCF image = CGImageSourceCreateImageAtIndex(source, 0, nullptr); + if (!image) + { + return false; + } + + bool isOpaque = false; + switch (CGImageGetAlphaInfo(image.get())) + { + case kCGImageAlphaNone: + case kCGImageAlphaNoneSkipFirst: + case kCGImageAlphaNoneSkipLast: + isOpaque = true; + break; + default: + break; + } + + const size_t width = CGImageGetWidth(image); + const size_t height = CGImageGetHeight(image); + const size_t rowBytes = width * 4; // 4 bytes per pixel + const size_t size = rowBytes * height; + + const size_t bitsPerComponent = 8; + CGBitmapInfo cgInfo = kCGBitmapByteOrder32Big; // rgba + if (isOpaque) + { + cgInfo |= kCGImageAlphaNoneSkipLast; + } + else + { + cgInfo |= kCGImageAlphaPremultipliedLast; + } + + std::unique_ptr pixels(new uint8_t[size]); + + AutoCF cs = CGColorSpaceCreateDeviceRGB(); + AutoCF cg = CGBitmapContextCreate(pixels.get(), + width, + height, + bitsPerComponent, + rowBytes, + cs, + cgInfo); + if (!cg) + { + return false; + } + + CGContextSetBlendMode(cg, kCGBlendModeCopy); + CGContextDrawImage(cg, CGRectMake(0, 0, width, height), image); + + platformImage->width = rive::castTo(width); + platformImage->height = rive::castTo(height); + platformImage->opaque = isOpaque; + platformImage->pixels = std::move(pixels); + + return true; +} + +std::unique_ptr Bitmap::decode(const uint8_t bytes[], size_t byteCount) +{ + PlatformCGImage image; + if (!cg_image_decode(bytes, byteCount, &image)) + { +#if defined RIVE_APPLETVOS || defined RIVE_APPLETVOS_SIMULATOR + const Bitmap::ImageFormat* format = + Bitmap::RecognizeImageFormat(bytes, byteCount); + if (format != nullptr) + { + auto bitmap = format->decodeImage != nullptr + ? format->decodeImage(bytes, byteCount) + : nullptr; + return bitmap; + } +#endif + return nullptr; + } + + return std::make_unique(image.width, + image.height, + // CG always premultiplies alpha. + PixelFormat::RGBAPremul, + std::move(image.pixels)); +} +#else +std::unique_ptr Bitmap::decode(const uint8_t bytes[], size_t byteCount) +{ + const ImageFormat* format = RecognizeImageFormat(bytes, byteCount); + if (format != nullptr) + { + auto bitmap = format->decodeImage != nullptr + ? format->decodeImage(bytes, byteCount) + : nullptr; + if (!bitmap) + { + fprintf(stderr, + "Bitmap::decode - failed to decode a %s.\n", + format->name); + } + return bitmap; + } + return nullptr; +} +#endif + +} // namespace rive diff --git a/third_party/rive_decoders/source/decode_jpeg.cpp b/third_party/rive_decoders/source/decode_jpeg.cpp new file mode 100644 index 0000000..0633652 --- /dev/null +++ b/third_party/rive_decoders/source/decode_jpeg.cpp @@ -0,0 +1,135 @@ +// Adapted from libjpeg-turbo's example: +// https://github.com/libjpeg-turbo/libjpeg-turbo/blob/main/example.c +#include "rive/decoders/bitmap_decoder.hpp" + +#include "jpeglib.h" +#include "jerror.h" + +#include +#include +#include +#include + +namespace rive { + +struct my_error_mgr +{ + struct jpeg_error_mgr pub; + jmp_buf setjmp_buffer; +}; + +typedef struct my_error_mgr* my_error_ptr; + +void my_error_exit(j_common_ptr cinfo) +{ + // cinfo.err really points to a my_error_mgr struct, so coerce pointer + my_error_ptr myerr = (my_error_ptr)cinfo->err; + + // Always display the message. + // We could postpone this until after returning, if we chose. + (*cinfo->err->output_message)(cinfo); + + // Return control to the setjmp point + longjmp(myerr->setjmp_buffer, 1); +} + +std::unique_ptr DecodeJpeg(const uint8_t bytes[], size_t byteCount) +{ + struct jpeg_decompress_struct cinfo; + struct my_error_mgr jerr; + + JSAMPARRAY buffer = nullptr; + std::unique_ptr pixelBuffer; + int row_stride; + + // Step 1: allocate and initialize JPEG decompression object. + + // We set up the normal JPEG error routines, then override error_exit. + cinfo.err = jpeg_std_error(&jerr.pub); + jerr.pub.error_exit = my_error_exit; + // Establish the setjmp return context for my_error_exit to use. + if (setjmp(jerr.setjmp_buffer)) + { + // If we get here, the JPEG code has signaled an error. + // We need to clean up the JPEG object, close the input file, and + // return. + jpeg_destroy_decompress(&cinfo); + return nullptr; + } + + // Now we can initialize the JPEG decompression object. + jpeg_create_decompress(&cinfo); + + // Step 2: specify data source + jpeg_mem_src(&cinfo, bytes, byteCount); + + // Step 3: read file parameters with jpeg_read_header() + + jpeg_read_header(&cinfo, TRUE); + + // Step 4: set parameters for decompression + + // always want 8 bit RGB + cinfo.data_precision = 8; + cinfo.out_color_space = JCS_RGB; + + // Step 5: Start decompressor + jpeg_start_decompress(&cinfo); + + /// Api worked as expected and gave us correct format even for jpeg 12 or 16 + assert(cinfo.data_precision == 8); + assert(cinfo.output_components == 3); + + size_t pixelBufferSize = static_cast(cinfo.output_width) * + static_cast(cinfo.output_height) * + static_cast(cinfo.output_components); + pixelBuffer = std::make_unique(pixelBufferSize); + + uint8_t* pixelWriteBuffer = (uint8_t*)pixelBuffer.get(); + const uint8_t* pixelWriteBufferEnd = pixelWriteBuffer + pixelBufferSize; + + // Samples per row in output buffer + row_stride = cinfo.output_width * cinfo.output_components; + // Make a one-row-high sample array that will go away when done with image + buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr)&cinfo, + JPOOL_IMAGE, + row_stride, + 1); + + // Step 6: while (scan lines remain to be read) + // jpeg_read_scanlines(...); + + // Here we use the library's state variable cinfo->output_scanline as the + // loop counter, so that we don't have to keep track ourselves. + // + while (cinfo.output_scanline < cinfo.output_height) + { + // jpeg_read_scanlines expects an array of pointers to scanlines. + // Here the array is only one element long, but you could ask for + // more than one scanline at a time if that's more convenient. + jpeg_read_scanlines(&cinfo, buffer, 1); + + if (pixelWriteBuffer + row_stride > pixelWriteBufferEnd) + { + // memcpy would cause an overflow. + jpeg_finish_decompress(&cinfo); + jpeg_destroy_decompress(&cinfo); + return nullptr; + } + memcpy(pixelWriteBuffer, buffer[0], row_stride); + pixelWriteBuffer += row_stride; + } + + // Step 7: Finish decompression + jpeg_finish_decompress(&cinfo); + + // Step 8: Release JPEG decompression object + jpeg_destroy_decompress(&cinfo); + + return std::make_unique(cinfo.output_width, + cinfo.output_height, + Bitmap::PixelFormat::RGB, + std::move(pixelBuffer)); +} + +} // namespace rive diff --git a/third_party/rive_decoders/source/decode_png.cpp b/third_party/rive_decoders/source/decode_png.cpp new file mode 100644 index 0000000..a764846 --- /dev/null +++ b/third_party/rive_decoders/source/decode_png.cpp @@ -0,0 +1,166 @@ +/* + * Copyright 2023 Rive + */ + +#include "rive/decoders/bitmap_decoder.hpp" + +#include + +#include +#include +#include +#include + +namespace rive { + +struct EncodedImageBuffer +{ + const uint8_t* bytes; + size_t position; + size_t size; +}; + +static void ReadDataFromMemory(png_structp png_ptr, + png_bytep outBytes, + png_size_t byteCountToRead) +{ + png_voidp a = png_get_io_ptr(png_ptr); + if (a == nullptr) + { + return; + } + EncodedImageBuffer& stream = *(EncodedImageBuffer*)a; + + size_t bytesRead = + std::min(byteCountToRead, (stream.size - stream.position)); + memcpy(outBytes, stream.bytes + stream.position, bytesRead); + stream.position += bytesRead; + + if ((png_size_t)bytesRead != byteCountToRead) + { + // Report image error? + } +} + +std::unique_ptr DecodePng(const uint8_t bytes[], size_t byteCount) +{ + png_structp png_ptr; + png_infop info_ptr; + png_uint_32 width, height; + int bit_depth, color_type, interlace_type; + std::unique_ptr pixelBuffer; + std::unique_ptr rowsPointer; + + png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, + nullptr, + nullptr, + nullptr); + + if (png_ptr == nullptr) + { + printf("DecodePng - libpng failed (png_create_read_struct)."); + return nullptr; + } + + info_ptr = png_create_info_struct(png_ptr); + if (info_ptr == NULL) + { + png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); + printf("DecodePng - libpng failed (png_create_info_struct)."); + return nullptr; + } + + if (setjmp(png_jmpbuf(png_ptr))) + { + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + return nullptr; + } + + EncodedImageBuffer stream = {bytes, 0, byteCount}; + + png_set_read_fn(png_ptr, &stream, ReadDataFromMemory); + + png_read_info(png_ptr, info_ptr); + + png_get_IHDR(png_ptr, + info_ptr, + &width, + &height, + &bit_depth, + &color_type, + &interlace_type, + NULL, + NULL); + + if (color_type == PNG_COLOR_TYPE_PALETTE || + (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)) + { + // expand to 3 or 4 channels + png_set_expand(png_ptr); + } + + png_bytep trns = 0; + int trnsCount = 0; + if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) + { + png_get_tRNS(png_ptr, info_ptr, &trns, &trnsCount, 0); + png_set_expand(png_ptr); + } + + if (bit_depth == 16) + { + png_set_strip_16(png_ptr); + } + + if (color_type == PNG_COLOR_TYPE_GRAY || + color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + { + png_set_gray_to_rgb(png_ptr); + } + + png_read_update_info(png_ptr, info_ptr); + uint8_t channels = png_get_channels(png_ptr, info_ptr); + + size_t pixelBufferSize = static_cast(width) * + static_cast(height) * + static_cast(channels); + pixelBuffer = std::make_unique(pixelBufferSize); + const uint8_t* pixelBufferEnd = pixelBuffer.get() + pixelBufferSize; + + rowsPointer = std::make_unique(height); + png_bytep* rows = rowsPointer.get(); + size_t rowStride = (size_t)width * (size_t)channels; + uint8_t* rowWrite = pixelBuffer.get(); + for (png_uint_32 row = 0; row < height; row++) + { + rows[row] = rowWrite; + rowWrite += rowStride; + if (rowWrite > pixelBufferEnd) + { + // Read would overflow. + return nullptr; + } + } + png_read_image(png_ptr, rows); + png_read_end(png_ptr, info_ptr); + + png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) nullptr); + + Bitmap::PixelFormat pixelFormat; + assert(channels == 3 || channels == 4); + switch (channels) + { + case 4: + pixelFormat = Bitmap::PixelFormat::RGBA; + break; + case 3: + pixelFormat = Bitmap::PixelFormat::RGB; + break; + } + return std::make_unique(width, + height, + pixelFormat, + std::move(pixelBuffer)); +} + +} // namespace rive diff --git a/third_party/rive_decoders/source/decode_webp.cpp b/third_party/rive_decoders/source/decode_webp.cpp new file mode 100644 index 0000000..ffd484c --- /dev/null +++ b/third_party/rive_decoders/source/decode_webp.cpp @@ -0,0 +1,77 @@ +#include "rive/decoders/bitmap_decoder.hpp" + +#include + +#include +#include +#include + +namespace rive { + +std::unique_ptr DecodeWebP(const uint8_t bytes[], size_t byteCount) +{ + WebPDecoderConfig config; + if (!WebPInitDecoderConfig(&config)) + { + fprintf(stderr, "DecodeWebP - Library version mismatch!\n"); + return nullptr; + } + config.options.dithering_strength = 50; + config.options.alpha_dithering_strength = 100; + + if (!WebPGetInfo(bytes, byteCount, nullptr, nullptr)) + { + fprintf(stderr, + "DecodeWebP - Input file doesn't appear to be WebP format.\n"); + } + + WebPData data = {bytes, byteCount}; + WebPDemuxer* demuxer = WebPDemux(&data); + if (demuxer == nullptr) + { + fprintf(stderr, "DecodeWebP - Could not create demuxer.\n"); + } + + WebPIterator currentFrame; + if (!WebPDemuxGetFrame(demuxer, 1, ¤tFrame)) + { + fprintf(stderr, "DecodeWebP - WebPDemuxGetFrame couldn't get frame.\n"); + WebPDemuxDelete(demuxer); + return nullptr; + } + config.output.colorspace = MODE_RGBA; + + uint32_t width = WebPDemuxGetI(demuxer, WEBP_FF_CANVAS_WIDTH); + uint32_t height = WebPDemuxGetI(demuxer, WEBP_FF_CANVAS_HEIGHT); + + size_t pixelBufferSize = static_cast(width) * + static_cast(height) * + static_cast(4); + std::unique_ptr pixelBuffer = + std::make_unique(pixelBufferSize); + + config.output.u.RGBA.rgba = (uint8_t*)pixelBuffer.get(); + config.output.u.RGBA.stride = (int)(width * 4); + config.output.u.RGBA.size = pixelBufferSize; + config.output.is_external_memory = 1; + + if (WebPDecode(currentFrame.fragment.bytes, + currentFrame.fragment.size, + &config) != VP8_STATUS_OK) + { + fprintf(stderr, "DecodeWebP - WebPDemuxGetFrame couldn't decode.\n"); + WebPDemuxReleaseIterator(¤tFrame); + WebPDemuxDelete(demuxer); + return nullptr; + } + + WebPDemuxReleaseIterator(¤tFrame); + WebPDemuxDelete(demuxer); + + return std::make_unique(width, + height, + Bitmap::PixelFormat::RGBA, + std::move(pixelBuffer)); +} + +} // namespace rive diff --git a/third_party/rive_renderer/include/rive/renderer/buffer_ring.hpp b/third_party/rive_renderer/include/rive/renderer/buffer_ring.hpp new file mode 100644 index 0000000..e8bbd98 --- /dev/null +++ b/third_party/rive_renderer/include/rive/renderer/buffer_ring.hpp @@ -0,0 +1,99 @@ +/* + * Copyright 2022 Rive + */ + +#pragma once + +#include "rive/renderer/gpu.hpp" + +namespace rive::gpu +{ +// API-agnostic implementation of an abstract buffer ring. We use rings to +// ensure the GPU can render one frame in parallel while the CPU prepares the +// next frame. +// +// Calling mapBuffer() maps the next buffer in the ring. +// +// Calling unmapAndSubmitBuffer() submits the currently-mapped buffer for GPU +// rendering, in whatever way that is meaningful for the RenderContext +// implementation. +// +// This class is meant to only be used through BufferRing<>. +class BufferRing +{ +public: + BufferRing(size_t capacityInBytes) : m_capacityInBytes(capacityInBytes) {} + virtual ~BufferRing() {} + + size_t capacityInBytes() const { return m_capacityInBytes; } + bool isMapped() const { return m_mapSizeInBytes != 0; } + size_t mapSizeInBytes() const { return m_mapSizeInBytes; } + + // Maps the next buffer in the ring. + void* mapBuffer(size_t mapSizeInBytes) + { + assert(!isMapped()); + assert(mapSizeInBytes > 0); + assert(mapSizeInBytes <= m_capacityInBytes); + m_submittedBufferIdx = (m_submittedBufferIdx + 1) % kBufferRingSize; + m_mapSizeInBytes = mapSizeInBytes; + return onMapBuffer(m_submittedBufferIdx, m_mapSizeInBytes); + } + + // Submits the currently-mapped buffer for GPU rendering, in whatever way + // that is meaningful for the RenderContext implementation. + void unmapAndSubmitBuffer() + { + assert(isMapped()); + onUnmapAndSubmitBuffer(m_submittedBufferIdx, m_mapSizeInBytes); + m_mapSizeInBytes = 0; + } + +protected: + int submittedBufferIdx() const + { + assert(!isMapped()); + return m_submittedBufferIdx; + } + + virtual void* onMapBuffer(int bufferIdx, size_t mapSizeInBytes) = 0; + virtual void onUnmapAndSubmitBuffer(int bufferIdx, + size_t mapSizeInBytes) = 0; + + uint8_t* shadowBuffer() const + { + if (m_shadowBuffer == nullptr && m_capacityInBytes > 0) + { + m_shadowBuffer.reset(new uint8_t[m_capacityInBytes]); + } + return m_shadowBuffer.get(); + } + +private: + size_t m_capacityInBytes; + size_t m_mapSizeInBytes = 0; + int m_submittedBufferIdx = 0; + + // Lazy-allocated CPU buffer for when buffer mapping isn't supported by the + // API. + mutable std::unique_ptr m_shadowBuffer; +}; + +// BufferRing that resides solely in CPU memory, and therefore doesn't require a +// ring. +class HeapBufferRing : public BufferRing +{ +public: + HeapBufferRing(size_t capacityInBytes) : BufferRing(capacityInBytes) {} + + uint8_t* contents() const { return shadowBuffer(); } + +protected: + void* onMapBuffer(int bufferIdx, size_t mapSizeInBytes) override + { + return shadowBuffer(); + } + void onUnmapAndSubmitBuffer(int bufferIdx, size_t mapSizeInBytes) override + {} +}; +} // namespace rive::gpu diff --git a/third_party/rive_renderer/include/rive/renderer/d3d/d3d.hpp b/third_party/rive_renderer/include/rive/renderer/d3d/d3d.hpp new file mode 100644 index 0000000..56587c3 --- /dev/null +++ b/third_party/rive_renderer/include/rive/renderer/d3d/d3d.hpp @@ -0,0 +1,45 @@ +/* + * Copyright 2025 Rive + */ + +#pragma once + +#include +#include +#include + +using Microsoft::WRL::ComPtr; + +#define VERIFY_OK(CODE) \ + { \ + HRESULT hr = (CODE); \ + if (hr != S_OK) \ + { \ + fprintf(stderr, \ + __FILE__ ":%i: D3D error %s: %s\n", \ + static_cast(__LINE__), \ + std::system_category().message(hr).c_str(), \ + #CODE); \ + abort(); \ + } \ + } +namespace rive::gpu +{ +struct D3DCapabilities +{ + bool supportsRasterizerOrderedViews = false; + bool supportsTypedUAVLoadStore = + false; // Can we load/store all UAV formats used by Rive? + bool supportsMin16Precision = + false; // Can we use minimum 16-bit types (e.g. min16int)? + bool isIntel = false; + bool allowsUAVSlot0WithColorOutput = true; +}; + +struct D3DContextOptions +{ + bool disableRasterizerOrderedViews = false; // Primarily for testing. + bool disableTypedUAVLoadStore = false; // Primarily for testing. + bool isIntel = false; +}; +} // namespace rive::gpu diff --git a/third_party/rive_renderer/include/rive/renderer/d3d/d3d_constants.hpp b/third_party/rive_renderer/include/rive/renderer/d3d/d3d_constants.hpp new file mode 100644 index 0000000..4cf1746 --- /dev/null +++ b/third_party/rive_renderer/include/rive/renderer/d3d/d3d_constants.hpp @@ -0,0 +1,18 @@ +/* + * Copyright 2025 Rive + */ +#pragma once +#include "shaders/constants.glsl" +namespace rive::gpu +{ +// D3D11 doesn't let us bind the framebuffer UAV to slot 0 when there is a color +// output. Use the (unused in this case) SCRATCH_COLOR_PLANE_IDX instead when we +// are doing a coalesced resolve and transfer. +#define COALESCED_OFFSCREEN_COLOR_PLANE_IDX SCRATCH_COLOR_PLANE_IDX + +constexpr static UINT PATCH_VERTEX_DATA_SLOT = 0; +constexpr static UINT TRIANGLE_VERTEX_DATA_SLOT = 1; +constexpr static UINT IMAGE_RECT_VERTEX_DATA_SLOT = 2; +constexpr static UINT IMAGE_MESH_VERTEX_DATA_SLOT = 3; +constexpr static UINT IMAGE_MESH_UV_DATA_SLOT = 4; +} // namespace rive::gpu \ No newline at end of file diff --git a/third_party/rive_renderer/include/rive/renderer/d3d/pipeline_manager.hpp b/third_party/rive_renderer/include/rive/renderer/d3d/pipeline_manager.hpp new file mode 100644 index 0000000..4c741a7 --- /dev/null +++ b/third_party/rive_renderer/include/rive/renderer/d3d/pipeline_manager.hpp @@ -0,0 +1,212 @@ +/* + * Copyright 2025 Rive + */ +#pragma once + +#include "rive/renderer/d3d/d3d.hpp" +#include "rive/renderer/gpu.hpp" + +#include +#include + +namespace rive::gpu +{ +namespace d3d_utils +{ +// generates a shader using ostringstream +std::string build_shader(DrawType drawType, + ShaderFeatures shaderFeatures, + InterlockMode interlockMode, + ShaderMiscFlags shaderMiscFlags, + const D3DCapabilities& d3dCapabilities); +// compile shader to source using "main" as an entry point +ComPtr compile_vertex_source_to_blob(const std::string& source, + const char* target); +// compile shader to source using "main" as an entry point +ComPtr compile_pixel_source_to_blob(const std::string& source, + const char* target); +} // namespace d3d_utils + +// Handles managing and compiling shaders. +// Has hooks to allow managing pipelines for d3d12 +// Will also manages threading for just in time compiling of shaders once +// thats in +template +class D3DPipelineManager +{ +public: + // everything needed to compile a vertex + pixel shader combo + struct ShaderCompileRequest + { + DrawType drawType; + ShaderFeatures shaderFeatures; + InterlockMode interlockMode; + ShaderMiscFlags shaderMiscFlags; + const D3DCapabilities& d3dCapabilities; + }; + + // shader compiler result including keys for m_drawVertexShaders and + // m_drawPixelShaders + struct ShaderCompileResult + { + uint32_t vertexShaderKey; + uint32_t pixelShaderKey; + struct VertexResult + { + bool hasResult = false; + VetexShaderType vertexShaderResult; + } vertexResult; + struct PixelResult + { + bool hasResult = false; + PixelShaderType pixelShaderResult; + } pixelResult; + // needed for d3d12 + void* resultData = nullptr; + }; + + D3DPipelineManager(ComPtr device, + const D3DCapabilities& capabilities, + const char* vertexTarget, + const char* pixelTarget) : + m_device(std::move(device)), + m_d3dCapabilities(capabilities), + m_vertexTarget(vertexTarget), + m_pixelTarget(pixelTarget) + {} + + const D3DCapabilities d3dCapabilities() const { return m_d3dCapabilities; } + + DeviceType* device() const { return m_device.Get(); } + +protected: + // called when shaderCompileWorker finished compiling the source shader to + // blobs and now we need to convert that to the platform specific shader + // tpes i.e. ID3D11Vertex/PixelShader for 11 and ID3D12PilineState for 12. + // note: this could be called on a background thread + virtual void compileBlobToFinalType(const ShaderCompileRequest&, + ComPtr vertexShader, + ComPtr pixelShader, + ShaderCompileResult*) = 0; + + // get shaders with given compiler request. returns true and sets + // outShaderResult on succes, returns false and outShaderResult is undefined + // on failure + bool getShader(const ShaderCompileRequest& shaderCompileRequest, + ShaderCompileResult* outShaderResult) + { + // dont pass nullptr here + assert(outShaderResult); + + outShaderResult->vertexShaderKey = gpu::ShaderUniqueKey( + shaderCompileRequest.drawType, + shaderCompileRequest.shaderFeatures & kVertexShaderFeaturesMask, + shaderCompileRequest.interlockMode, + gpu::ShaderMiscFlags::none); + + outShaderResult->pixelShaderKey = + ShaderUniqueKey(shaderCompileRequest.drawType, + shaderCompileRequest.shaderFeatures, + shaderCompileRequest.interlockMode, + shaderCompileRequest.shaderMiscFlags); + + auto vertexEntry = + m_drawVertexShaders.find(outShaderResult->vertexShaderKey); + + auto pixelEntry = + m_drawPixelShaders.find(outShaderResult->pixelShaderKey); + + if (vertexEntry != m_drawVertexShaders.end()) + { + outShaderResult->vertexResult.hasResult = true; + outShaderResult->vertexResult.vertexShaderResult = + vertexEntry->second; + } + + if (pixelEntry != m_drawPixelShaders.end()) + { + outShaderResult->pixelResult.hasResult = true; + outShaderResult->pixelResult.pixelShaderResult = pixelEntry->second; + } + + if (vertexEntry == m_drawVertexShaders.end() || + pixelEntry == m_drawPixelShaders.end()) + { + if (!shaderCompileWorker(shaderCompileRequest, outShaderResult)) + { + // eventually this means background shader compile happening, so + // we would set uber shader here and return + RIVE_UNREACHABLE(); + } + if (vertexEntry == m_drawVertexShaders.end()) + { + assert(outShaderResult->vertexResult.hasResult); + m_drawVertexShaders.insert( + {outShaderResult->vertexShaderKey, + outShaderResult->vertexResult.vertexShaderResult}); + } + + if (pixelEntry == m_drawPixelShaders.end()) + { + assert(outShaderResult->pixelResult.hasResult); + m_drawPixelShaders.insert( + {outShaderResult->pixelShaderKey, + outShaderResult->pixelResult.pixelShaderResult}); + } + } + + return true; + } + +private: + // build shader (currnetly runs synchronously but will be async eventually) + bool shaderCompileWorker(const ShaderCompileRequest& compileRequest, + ShaderCompileResult* outShaderResult) + { + assert(outShaderResult->vertexResult.hasResult == false || + outShaderResult->pixelResult.hasResult == false); + + auto shader = d3d_utils::build_shader(compileRequest.drawType, + compileRequest.shaderFeatures, + compileRequest.interlockMode, + compileRequest.shaderMiscFlags, + compileRequest.d3dCapabilities); + + ComPtr vertexShader; + ComPtr pixelShader; + + if (!outShaderResult->vertexResult.hasResult) + { + vertexShader = + d3d_utils::compile_vertex_source_to_blob(shader, + m_vertexTarget); + } + + if (!outShaderResult->pixelResult.hasResult) + { + pixelShader = + d3d_utils::compile_pixel_source_to_blob(shader, m_pixelTarget); + } + + compileBlobToFinalType(compileRequest, + vertexShader, + pixelShader, + outShaderResult); + + return true; + } + +private: + std::unordered_map m_drawVertexShaders; + std::unordered_map m_drawPixelShaders; + + ComPtr m_device; + const D3DCapabilities m_d3dCapabilities; + + const char* m_vertexTarget; + const char* m_pixelTarget; +}; + +}; // namespace rive::gpu diff --git a/third_party/rive_renderer/include/rive/renderer/d3d11/d3d11.hpp b/third_party/rive_renderer/include/rive/renderer/d3d11/d3d11.hpp new file mode 100644 index 0000000..bb4126c --- /dev/null +++ b/third_party/rive_renderer/include/rive/renderer/d3d11/d3d11.hpp @@ -0,0 +1,8 @@ +/* + * Copyright 2025 Rive + */ + +#pragma once + +#include "rive/renderer/d3d/d3d.hpp" +#include diff --git a/third_party/rive_renderer/include/rive/renderer/d3d11/render_context_d3d_impl.hpp b/third_party/rive_renderer/include/rive/renderer/d3d11/render_context_d3d_impl.hpp new file mode 100644 index 0000000..892ee48 --- /dev/null +++ b/third_party/rive_renderer/include/rive/renderer/d3d11/render_context_d3d_impl.hpp @@ -0,0 +1,254 @@ +/* + * Copyright 2023 Rive + */ + +#pragma once + +#include "rive/renderer/d3d/pipeline_manager.hpp" +#include "rive/renderer/d3d11/d3d11.hpp" +#include "rive/renderer/render_context_helper_impl.hpp" +#include +#include + +namespace rive::gpu +{ +class RenderContextD3DImpl; + +// D3D backend implementation of RenderTarget. +class RenderTargetD3D : public RenderTarget +{ +public: + RenderTargetD3D(RenderContextD3DImpl*, uint32_t width, uint32_t height); + ~RenderTargetD3D() override {} + + void setTargetTexture(ComPtr tex); + + ID3D11Texture2D* targetTexture() const { return m_targetTexture.Get(); } + bool targetTextureSupportsUAV() const { return m_targetTextureSupportsUAV; } + ID3D11RenderTargetView* targetRTV(); + + // Alternate rendering target when targetTextureSupportsUAV() is false. + ID3D11Texture2D* offscreenTexture(); + + // Returns an unordered access view of targetTexture(), if + // targetTextureSupportsUAV() is true, otherwise returns a UAV of + // offscreenTexture(). + ID3D11UnorderedAccessView* targetUAV(); + + ID3D11UnorderedAccessView* clipUAV(); + ID3D11UnorderedAccessView* scratchColorUAV(); + ID3D11UnorderedAccessView* coverageUAV(); + +private: + const ComPtr m_gpu; + const bool m_gpuSupportsTypedUAVLoadStore; + + ComPtr m_targetTexture; + bool m_targetTextureSupportsUAV = false; + DXGI_FORMAT m_targetFormat = DXGI_FORMAT_UNKNOWN; + + ComPtr m_offscreenTexture; + ComPtr m_coverageTexture; + ComPtr m_scratchColorTexture; + ComPtr m_clipTexture; + + ComPtr m_targetRTV; + ComPtr m_targetUAV; + ComPtr m_coverageUAV; + ComPtr m_clipUAV; + ComPtr m_scratchColorUAV; +}; + +struct D3D11DrawVertexShader +{ + ComPtr layout; + ComPtr shader; +}; + +class D3D11PipelineManager + : public D3DPipelineManager, + ID3D11Device> +{ +public: + D3D11PipelineManager(ComPtr context, + ComPtr device, + const D3DCapabilities& capabilities); + + void setPipelineState(rive::gpu::DrawType, + rive::gpu::ShaderFeatures, + rive::gpu::InterlockMode, + rive::gpu::ShaderMiscFlags); + + void setColorRampState() const + { + m_context->IASetInputLayout(m_colorRampLayout.Get()); + m_context->VSSetShader(m_colorRampVertexShader.Get(), NULL, 0); + m_context->PSSetShader(m_colorRampPixelShader.Get(), NULL, 0); + } + + void setTesselationState() const + { + m_context->IASetInputLayout(m_tessellateLayout.Get()); + m_context->VSSetShader(m_tessellateVertexShader.Get(), NULL, 0); + m_context->PSSetShader(m_tessellatePixelShader.Get(), NULL, 0); + } + + void setAtlasVertexState() const + { + m_context->IASetInputLayout(m_atlasLayout.Get()); + m_context->VSSetShader(m_atlasVertexShader.Get(), NULL, 0); + } + + void setAtlasFillState() const + { + m_context->PSSetShader(m_atlasFillPixelShader.Get(), NULL, 0); + } + + void setAtlasStrokeState() const + { + m_context->PSSetShader(m_atlasStrokePixelShader.Get(), NULL, 0); + } + +protected: + virtual void compileBlobToFinalType(const ShaderCompileRequest&, + ComPtr vertexShader, + ComPtr pixelShader, + ShaderCompileResult*) override; + +private: + ComPtr m_context; + + ComPtr m_colorRampLayout; + ComPtr m_colorRampVertexShader; + ComPtr m_colorRampPixelShader; + + ComPtr m_tessellateLayout; + ComPtr m_tessellateVertexShader; + ComPtr m_tessellatePixelShader; + + ComPtr m_atlasLayout; + ComPtr m_atlasVertexShader; + ComPtr m_atlasFillPixelShader; + ComPtr m_atlasStrokePixelShader; +}; + +// D3D backend implementation of RenderContextImpl. +class RenderContextD3DImpl : public RenderContextHelperImpl +{ +public: + static std::unique_ptr MakeContext( + ComPtr, + ComPtr, + const D3DContextOptions&); + + rcp makeRenderTarget(uint32_t width, uint32_t height) + { + return make_rcp(this, width, height); + } + + const D3DCapabilities& d3dCapabilities() const { return m_d3dCapabilities; } + ID3D11Device* gpu() const { return m_gpu.Get(); } + ID3D11DeviceContext* gpuContext() const { return m_gpuContext.Get(); } + + // D3D helpers + ComPtr makeSimple2DTexture(DXGI_FORMAT format, + UINT width, + UINT height, + UINT mipLevelCount, + UINT bindFlags, + UINT miscFlags = 0); + ComPtr makeSimple2DUAV(ID3D11Texture2D* tex, + DXGI_FORMAT format); + ComPtr makeSimpleImmutableBuffer(size_t sizeInBytes, + UINT bindFlags, + const void* data); + +private: + RenderContextD3DImpl(ComPtr, + ComPtr, + const D3DCapabilities&); + + rcp makeRenderBuffer(RenderBufferType, + RenderBufferFlags, + size_t) override; + + rcp makeImageTexture(uint32_t width, + uint32_t height, + uint32_t mipLevelCount, + const uint8_t imageDataRGBAPremul[]) override; + + std::unique_ptr makeUniformBufferRing( + size_t capacityInBytes) override; + std::unique_ptr makeStorageBufferRing( + size_t capacityInBytes, + gpu::StorageBufferStructure) override; + std::unique_ptr makeVertexBufferRing( + size_t capacityInBytes) override; + + void resizeGradientTexture(uint32_t width, uint32_t height) override; + void resizeTessellationTexture(uint32_t width, uint32_t height) override; + void resizeAtlasTexture(uint32_t width, uint32_t height) override; + + void flush(const FlushDescriptor&) override; + + D3D11PipelineManager m_pipelineManager; + + const D3DCapabilities m_d3dCapabilities; + + ComPtr m_gpu; + ComPtr m_gpuContext; + + ComPtr m_gradTexture; + ComPtr m_gradTextureSRV; + ComPtr m_gradTextureRTV; + + // Gaussian integral table for feathering. + ComPtr m_featherTexture; + ComPtr m_featherTextureSRV; + + ComPtr m_tessTexture; + ComPtr m_tessTextureSRV; + ComPtr m_tessTextureRTV; + ComPtr m_tessSpanIndexBuffer; + + ComPtr m_atlasTexture; + ComPtr m_atlasTextureSRV; + ComPtr m_atlasTextureRTV; + + // Vertex/index buffers for drawing path patches. + ComPtr m_patchVertexBuffer; + ComPtr m_patchIndexBuffer; + + // Vertex/index buffers for drawing image rects. + // (gpu::InterlockMode::atomics only.) + ComPtr m_imageRectVertexBuffer; + ComPtr m_imageRectIndexBuffer; + + struct DrawUniforms + { + DrawUniforms(uint32_t baseInstance_) : baseInstance(baseInstance_) {} + uint32_t baseInstance; + uint32_t pad0; + uint32_t pad1; + uint32_t pad2; + }; + static_assert(sizeof(DrawUniforms) == 16); + + ComPtr m_flushUniforms; + ComPtr m_drawUniforms; + ComPtr m_imageDrawUniforms; + + ComPtr m_linearSampler; + ComPtr + m_samplerStates[rive::ImageSampler::MAX_SAMPLER_PERMUTATIONS]; + + ComPtr m_atlasRasterState; + ComPtr m_backCulledRasterState[2]; + ComPtr m_doubleSidedRasterState[2]; + + ComPtr m_srcOverBlendState; + ComPtr m_plusBlendState; + ComPtr m_maxBlendState; +}; +} // namespace rive::gpu diff --git a/third_party/rive_renderer/include/rive/renderer/d3d12/d3d12.hpp b/third_party/rive_renderer/include/rive/renderer/d3d12/d3d12.hpp new file mode 100644 index 0000000..f5f4874 --- /dev/null +++ b/third_party/rive_renderer/include/rive/renderer/d3d12/d3d12.hpp @@ -0,0 +1,9 @@ +/* + * Copyright 2025 Rive + */ + +#pragma once +// d3dx12.h needs to be included first because it re defines some thing from +// d3dcommon.h which is included from d3d.hpp +#include +#include "rive/renderer/d3d/d3d.hpp" diff --git a/third_party/rive_renderer/include/rive/renderer/d3d12/d3d12_pipeline_manager.hpp b/third_party/rive_renderer/include/rive/renderer/d3d12/d3d12_pipeline_manager.hpp new file mode 100644 index 0000000..d03c0e5 --- /dev/null +++ b/third_party/rive_renderer/include/rive/renderer/d3d12/d3d12_pipeline_manager.hpp @@ -0,0 +1,84 @@ +/* + * Copyright 2025 Rive + */ +#pragma once +#include "rive/renderer/d3d12/d3d12.hpp" +#include "rive/renderer/d3d/pipeline_manager.hpp" +#include "rive/renderer/gpu.hpp" +// holds all shader stuff including inputlayouts, source blobs and pipeline +// states +struct D3D12DrawVertexShader +{ + D3D12_INPUT_ELEMENT_DESC m_layoutDesc[2]; + uint32_t m_vertexAttribCount; + ComPtr m_shader; +}; + +namespace rive::gpu +{ +class D3D12PipelineManager + : D3DPipelineManager, ID3D12Device> +{ +public: + D3D12PipelineManager(ComPtr device, + const D3DCapabilities& capabilities); + + ID3D12PipelineState* getDrawPipelineState( + DrawType drawType, + gpu::ShaderFeatures shaderFeatures, + gpu::InterlockMode interlockMode, + gpu::ShaderMiscFlags shaderMiscFlags); + + void compileTesselationPipeline(); + void compileGradientPipeline(); + void compileAtlasPipeline(); + + void setRootSig(ID3D12GraphicsCommandList* cmdList) const + { + assert(m_rootSignature); + cmdList->SetGraphicsRootSignature(m_rootSignature.Get()); + } + + void setTesselationPipeline(ID3D12GraphicsCommandList* cmdList) const + { + assert(m_tesselationPipeline); + cmdList->SetPipelineState(m_tesselationPipeline.Get()); + } + + void setAtlasFillPipeline(ID3D12GraphicsCommandList* cmdList) const + { + assert(m_atlasFillPipeline); + cmdList->SetPipelineState(m_atlasFillPipeline.Get()); + } + + void setAtlasStrokePipeline(ID3D12GraphicsCommandList* cmdList) const + { + assert(m_atlasStrokePipeline); + cmdList->SetPipelineState(m_atlasStrokePipeline.Get()); + } + + void setGradientPipeline(ID3D12GraphicsCommandList* cmdList) const + { + assert(m_gradientPipeline); + cmdList->SetPipelineState(m_gradientPipeline.Get()); + } + +protected: + virtual void compileBlobToFinalType(const ShaderCompileRequest&, + ComPtr vertexShader, + ComPtr pixelShader, + ShaderCompileResult*) override; + +private: + std::unordered_map> m_drawPipelines; + + // maybe these could be moved to D3DPipelineState but to do so + // required a lot of extra complexity that didnt seem worth it + ComPtr m_tesselationPipeline; + ComPtr m_atlasStrokePipeline; + ComPtr m_atlasFillPipeline; + ComPtr m_gradientPipeline; + + ComPtr m_rootSignature; +}; +} // namespace rive::gpu \ No newline at end of file diff --git a/third_party/rive_renderer/include/rive/renderer/d3d12/d3d12_utils.hpp b/third_party/rive_renderer/include/rive/renderer/d3d12/d3d12_utils.hpp new file mode 100644 index 0000000..87eaa12 --- /dev/null +++ b/third_party/rive_renderer/include/rive/renderer/d3d12/d3d12_utils.hpp @@ -0,0 +1,563 @@ +/* + * Copyright 2025 Rive + */ +#pragma once + +#include "rive/refcnt.hpp" +#include "rive/shapes/paint/image_sampler.hpp" +#include "rive/renderer/d3d12/d3d12.hpp" +#include "rive/renderer/gpu_resource.hpp" +#include + +namespace rive::gpu +{ + +class D3D12Resource; +// print the descriptor of the root signature +void print_sig_descriptor(LPCVOID data, SIZE_T size); +#if defined(DEBUG) +// Assign a name to the object to aid with debugging. +void SetName(D3D12Resource* pObject, LPCWSTR name); +#define NAME_D3D12_OBJECT(x) SetName(x.get(), L#x) +#define RNAME_D3D12_OBJECT(x, s) \ + std::wstringstream ss; \ + ss << L#x; \ + ss << " " << s; \ + SetName(x, ss.str().c_str()) +#define SNAME_D3D12_OBJECT(x, s) SetName(x.get(), L##s) +#define VNAME_D3D12_OBJECT(x) SetName(x->resource(), L#x) +#define SVNAME_D3D12_OBJECT(x, s) SetName(x->resource(), L##s) +#define NAME_RAW_D3D12_OBJECT(x) x->SetName(L#x) +#else +#define NAME_D3D12_OBJECT(x) +#define RNAME_D3D12_OBJECT(x, s) +#define SNAME_D3D12_OBJECT(x, s) +#define VNAME_D3D12_OBJECT(x) +#define SVNAME_D3D12_OBJECT(x, s) +#define NAME_RAW_D3D12_OBJECT(x) +#endif + +class D3D12Buffer; +class D3D12Texture; +class D3D12TextureArray; +class D3D12DescriptorHeap : public GPUResource +{ +public: + D3D12DescriptorHeap(rcp manager, + ID3D12Device* device, + UINT numDescriptors, + D3D12_DESCRIPTOR_HEAP_TYPE type, + D3D12_DESCRIPTOR_HEAP_FLAGS flags); + + ID3D12DescriptorHeap* heap() const { return m_heap.Get(); } + + void markSamplerToIndex(ID3D12Device* device, + const D3D12_SAMPLER_DESC& desc, + UINT index); + void markCbvToIndex(ID3D12Device* device, + D3D12Buffer* resource, + UINT index, + UINT sizeInBytes, + SIZE_T offset = 0); + void markSrvToIndex(ID3D12Device* device, + D3D12Buffer* resource, + UINT index, + UINT numElements, + UINT elementByteStride, + UINT64 firstElement); + void markUavToIndex(ID3D12Device* device, + D3D12Buffer* resource, + DXGI_FORMAT format, + UINT index, + UINT numElements, + UINT elementByteStride); + void markSrvToIndex(ID3D12Device* device, + D3D12Texture* resource, + UINT index); + void markSrvToIndex(ID3D12Device* device, + D3D12TextureArray* resource, + UINT index); + void markUavToIndex(ID3D12Device* device, + D3D12Texture* resource, + DXGI_FORMAT format, + UINT index); + void markRtvToIndex(ID3D12Device* device, + D3D12Texture* resource, + UINT index); + + CD3DX12_CPU_DESCRIPTOR_HANDLE cpuHandleForUpload(UINT index) const + { + return CD3DX12_CPU_DESCRIPTOR_HANDLE( + m_heap->GetCPUDescriptorHandleForHeapStart(), + index, + m_heapDescriptorSize); + } + + CD3DX12_CPU_DESCRIPTOR_HANDLE cpuHandleForIndex(UINT index) const + { + assert(m_flags == D3D12_DESCRIPTOR_HEAP_FLAG_NONE); + return CD3DX12_CPU_DESCRIPTOR_HANDLE( + m_heap->GetCPUDescriptorHandleForHeapStart(), + index, + m_heapDescriptorSize); + } + + CD3DX12_GPU_DESCRIPTOR_HANDLE gpuHandleForIndex(UINT index) const + { + assert(m_flags == D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE); + return CD3DX12_GPU_DESCRIPTOR_HANDLE( + m_heap->GetGPUDescriptorHandleForHeapStart(), + index, + m_heapDescriptorSize); + } + +private: + ComPtr m_heap; +#ifndef NDEBUG + const D3D12_DESCRIPTOR_HEAP_TYPE m_type; + const D3D12_DESCRIPTOR_HEAP_FLAGS m_flags; +#endif + const UINT m_heapDescriptorSize; +}; + +class D3D12Resource : public GPUResource +{ +public: + virtual ~D3D12Resource() {} + + ID3D12Resource* resource() const { return m_resource.Get(); } + const D3D12_RESOURCE_DESC& desc() const { return m_desc; } + +#if DEBUG + LPCWSTR m_name = L""; + void SetName(LPCWSTR name) + { + m_name = name; + m_resource->SetName(name); + } +#endif + +protected: + D3D12Resource(rcp manager, + ComPtr resource, + D3D12_RESOURCE_STATES initialState); + + D3D12Resource(rcp manager, + ID3D12Device* device, + D3D12_RESOURCE_STATES initialState, + D3D12_HEAP_FLAGS heapFlags, + const D3D12_RESOURCE_DESC& desc, + const D3D12_CLEAR_VALUE* clearValue = nullptr); + + D3D12Resource(rcp manager, + ID3D12Device* device, + D3D12_RESOURCE_STATES initialState, + D3D12_HEAP_FLAGS heapFlags, + CD3DX12_HEAP_PROPERTIES heapPropeties, + const D3D12_RESOURCE_DESC& desc, + const D3D12_CLEAR_VALUE* clearValue = nullptr); + + // the gpu side resource + ComPtr m_resource; + // used for barrier state tracking + D3D12_RESOURCE_STATES m_lastState; + D3D12_RESOURCE_DESC m_desc; + CD3DX12_HEAP_PROPERTIES m_heapPropeties; + D3D12_HEAP_FLAGS m_heapFlags; + + friend class D3D12ResourceManager; +}; + +class D3D12Texture : public D3D12Resource +{ +public: + D3D12Texture( + rcp manager, + ComPtr resource, + D3D12_RESOURCE_STATES initialState = D3D12_RESOURCE_STATE_COMMON) : + D3D12Resource(manager, resource, initialState) + {} + + D3D12Texture(rcp manager, + ID3D12Device* device, + D3D12_RESOURCE_STATES initialState, + D3D12_HEAP_FLAGS heapFlags, + const D3D12_RESOURCE_DESC& desc, + const D3D12_CLEAR_VALUE* clearValue = nullptr) : + D3D12Resource(manager, + device, + initialState, + heapFlags, + desc, + clearValue) + {} + + D3D12Texture(rcp manager, + ID3D12Device* device, + D3D12_RESOURCE_STATES initialState, + D3D12_HEAP_FLAGS heapFlags, + CD3DX12_HEAP_PROPERTIES heapPropeties, + const D3D12_RESOURCE_DESC& desc, + const D3D12_CLEAR_VALUE* clearValue = nullptr) : + D3D12Resource(manager, + device, + initialState, + heapFlags, + heapPropeties, + desc, + clearValue) + {} + + // helpers + UINT64 width() const { return m_desc.Width; } + UINT64 height() const { return m_desc.Height; } + DXGI_FORMAT format() const { return m_desc.Format; } + + // USE WITH CAUTION !! this force release the ID3D12Resource held by this + // texture. Be sure that it is no longer needed or in any active command + // list + void forceReleaseResource() { m_resource.Reset(); } +}; + +class D3D12TextureArray : public D3D12Resource +{ +public: + D3D12TextureArray( + rcp manager, + ComPtr resource, + D3D12_RESOURCE_STATES initialState = D3D12_RESOURCE_STATE_COMMON) : + D3D12Resource(manager, resource, initialState) + {} + + D3D12TextureArray(rcp manager, + ID3D12Device* device, + D3D12_RESOURCE_STATES initialState, + D3D12_HEAP_FLAGS heapFlags, + const D3D12_RESOURCE_DESC& desc) : + D3D12Resource(manager, device, initialState, heapFlags, desc) + {} + + D3D12TextureArray(rcp manager, + ID3D12Device* device, + D3D12_RESOURCE_STATES initialState, + D3D12_HEAP_FLAGS heapFlags, + CD3DX12_HEAP_PROPERTIES heapPropeties, + const D3D12_RESOURCE_DESC& desc) : + D3D12Resource(manager, + device, + initialState, + heapFlags, + heapPropeties, + desc) + {} + + // helpers + UINT64 width() const { return m_desc.Width; } + UINT16 length() const { return m_desc.DepthOrArraySize; } + DXGI_FORMAT format() const { return m_desc.Format; } +}; + +class D3D12Buffer : public D3D12Resource +{ +public: + D3D12Buffer(rcp manager, + ID3D12Device* device, + D3D12_RESOURCE_STATES initialState, + D3D12_HEAP_FLAGS heapFlags, + UINT size, + const D3D12_RESOURCE_DESC& desc) : + D3D12Resource(manager, device, initialState, heapFlags, desc), + m_sizeInBytes(size) + {} + + D3D12Buffer(rcp manager, + ID3D12Device* device, + D3D12_RESOURCE_STATES initialState, + D3D12_HEAP_FLAGS heapFlags, + CD3DX12_HEAP_PROPERTIES heapPropeties, + UINT size, + const D3D12_RESOURCE_DESC& desc) : + D3D12Resource(manager, + device, + initialState, + heapFlags, + heapPropeties, + desc), + m_sizeInBytes(size) + {} + + void* map(); + void unmap(); + + UINT sizeInBytes() const { return m_sizeInBytes; } + + D3D12_GPU_VIRTUAL_ADDRESS getGPUVirtualAddress() const + { + return m_resource->GetGPUVirtualAddress(); + } + + D3D12_VERTEX_BUFFER_VIEW vertexBufferView(uint32_t strideInBytes) const + { + return vertexBufferView(0, + m_sizeInBytes / strideInBytes, + strideInBytes); + } + + D3D12_VERTEX_BUFFER_VIEW vertexBufferView(uint32_t firstElement, + uint32_t strideInBytes) const + { + return vertexBufferView(firstElement, + (m_sizeInBytes / strideInBytes) - firstElement, + strideInBytes); + } + + D3D12_VERTEX_BUFFER_VIEW vertexBufferView(uint32_t firstElement, + uint32_t numElements, + uint32_t strideInBytes) const + { + D3D12_VERTEX_BUFFER_VIEW VBView; + VBView.BufferLocation = + resource()->GetGPUVirtualAddress() + (firstElement * strideInBytes); + VBView.SizeInBytes = numElements * strideInBytes; + VBView.StrideInBytes = strideInBytes; + return VBView; + } + + D3D12_INDEX_BUFFER_VIEW indexBufferView() const + { + return indexBufferView(0, m_sizeInBytes); + } + + D3D12_INDEX_BUFFER_VIEW indexBufferView(size_t Offset, + uint32_t sizeInBytes) const + { + D3D12_INDEX_BUFFER_VIEW IBView; + IBView.BufferLocation = resource()->GetGPUVirtualAddress() + Offset; + IBView.SizeInBytes = sizeInBytes; + IBView.Format = DXGI_FORMAT_R16_UINT; + return IBView; + } + +private: + UINT m_sizeInBytes; +#ifndef NDEBUG + bool m_isMapped = false; +#endif +}; +class D3D12ResourceManager; +// A buffer that is intended to be updated every frame +class D3D12VolatileBuffer : public GPUResource +{ +public: + // create buffers with intialSize, initialSize must not be 0 + D3D12VolatileBuffer( + rcp manager, + UINT initialSize, + D3D12_RESOURCE_FLAGS bindFlags = D3D12_RESOURCE_FLAG_NONE, + D3D12_HEAP_FLAGS heapFlags = D3D12_HEAP_FLAG_NONE); + + // maps the upload buffer + void* map(size_t mapSizeInBytes) + { + m_lastMapSize = mapSizeInBytes; + assert(m_uploadBuffer); + return m_uploadBuffer->map(); + } + // unmaps the upload buffer + void unmap(size_t unmapSizeInBytes) + { + assert(unmapSizeInBytes == m_lastMapSize); + assert(m_uploadBuffer); + m_uploadBuffer->unmap(); + } + // sync the upload buffer to the gpu buffer using m_lastMapSize as + // bytesToSync + void sync(ID3D12GraphicsCommandList* cmdList, UINT64 offsetBytes); + // sync the upload buffer to the gpu buffer + void sync(ID3D12GraphicsCommandList* cmdList, + UINT64 offsetBytes, + UINT64 bytesToSync); + + void syncToBuffer(ID3D12GraphicsCommandList* cmdList, + D3D12Buffer* buffer, + UINT64 offsetBytes, + UINT64 bytesToSync) const; + + D3D12_GPU_VIRTUAL_ADDRESS GPUVirtualAddress() const + { + return m_gpuBuffer->resource()->GetGPUVirtualAddress(); + } + D3D12Buffer* resource() const { return m_gpuBuffer.get(); } + UINT64 sizeInBytes() const + { + assert(m_uploadBuffer->sizeInBytes() == m_gpuBuffer->sizeInBytes()); + return m_uploadBuffer->sizeInBytes(); + } + + // recreates the buffers with given size, there is no way to just inflate or + // deflate a buffer + void resizeBuffers(UINT newSize); + +private: + D3D12ResourceManager* d3d() const; + + rcp m_uploadBuffer; + rcp m_gpuBuffer; + + // used for creating gpu buffers + D3D12_RESOURCE_FLAGS m_bindFlags; + D3D12_HEAP_FLAGS m_heapFlags; + + UINT64 m_lastMapSize = 0; +}; + +class D3D12ResourceManager : public GPUResourceManager +{ +public: + D3D12ResourceManager(ComPtr device) : + m_device(std::move(device)) + {} + + rcp makeHeap(UINT numDescriptors, + D3D12_DESCRIPTOR_HEAP_TYPE type, + D3D12_DESCRIPTOR_HEAP_FLAGS flags); + rcp make1DTextureArray( + UINT width, + UINT16 length, + UINT mipLevelCount, + DXGI_FORMAT format, + D3D12_RESOURCE_FLAGS bindFlags = D3D12_RESOURCE_FLAG_NONE, + D3D12_RESOURCE_STATES initialState = D3D12_RESOURCE_STATE_COMMON, + D3D12_HEAP_FLAGS heapFlags = D3D12_HEAP_FLAG_NONE); + + rcp make2DTexture( + UINT width, + UINT height, + UINT mipLevelCount, + DXGI_FORMAT format, + D3D12_RESOURCE_FLAGS bindFlags = D3D12_RESOURCE_FLAG_NONE, + D3D12_RESOURCE_STATES initialState = D3D12_RESOURCE_STATE_COMMON, + D3D12_HEAP_FLAGS heapFlags = D3D12_HEAP_FLAG_NONE, + const D3D12_CLEAR_VALUE* clearValue = nullptr); + + rcp makeBuffer( + UINT size, + D3D12_RESOURCE_FLAGS bindFlags = D3D12_RESOURCE_FLAG_NONE, + D3D12_RESOURCE_STATES initialState = D3D12_RESOURCE_STATE_COMMON, + D3D12_HEAP_FLAGS heapFlags = D3D12_HEAP_FLAG_NONE); + + rcp makeUploadBuffer( + UINT size, + D3D12_RESOURCE_FLAGS bindFlags = D3D12_RESOURCE_FLAG_NONE, + D3D12_RESOURCE_STATES initialState = D3D12_RESOURCE_STATE_COPY_SOURCE, + D3D12_HEAP_FLAGS heapFlags = D3D12_HEAP_FLAG_NONE); + + rcp makeVolatileBuffer( + UINT size, + D3D12_RESOURCE_FLAGS bindFlags = D3D12_RESOURCE_FLAG_NONE, + D3D12_HEAP_FLAGS heapFlags = D3D12_HEAP_FLAG_NONE); + + template + rcp makeImmutableBuffer(ID3D12GraphicsCommandList* cmdList, + const DataType (&data)[N]) + { + constexpr size_t sizeInBytes = N * sizeof(DataType); + rcp uploadBuffer = + makeUploadBuffer(sizeInBytes, + D3D12_RESOURCE_FLAG_NONE, + D3D12_RESOURCE_STATE_COPY_SOURCE); + rcp constBuffer = makeBuffer(sizeInBytes, + D3D12_RESOURCE_FLAG_NONE, + D3D12_RESOURCE_STATE_COMMON); + + void* ptr = uploadBuffer->map(); + memcpy(ptr, data, sizeInBytes); + uploadBuffer->unmap(); + + cmdList->CopyBufferRegion(constBuffer->resource(), + 0, + uploadBuffer->resource(), + 0, + sizeInBytes); + + return constBuffer; + } + + rcp makeExternalTexture( + ComPtr externalTexture, + D3D12_RESOURCE_STATES lastState); + // transition resource to "toState" + void transition(ID3D12GraphicsCommandList* cmdList, + D3D12Resource* resource, + D3D12_RESOURCE_STATES toState); + void clearUAV(ID3D12GraphicsCommandList* cmdList, + ID3D12Resource* resource, + CD3DX12_GPU_DESCRIPTOR_HANDLE&, + CD3DX12_CPU_DESCRIPTOR_HANDLE&, + const UINT clearColor[4], + bool needsBarrier); + void clearUAV(ID3D12GraphicsCommandList* cmdList, + ID3D12Resource* resource, + CD3DX12_GPU_DESCRIPTOR_HANDLE&, + CD3DX12_CPU_DESCRIPTOR_HANDLE&, + const float clearColor[4], + bool needsBarrier); + + ID3D12Device* device() const { return m_device.Get(); } + +private: + ComPtr m_device; +}; + +class D3D12VolatileBufferPool : public GPUResourcePool +{ +public: + D3D12VolatileBufferPool(rcp manager, + UINT alignment = 1, + UINT size = 0); + + size_t size() const { return m_targetSize; } + void setTargetSize(size_t size); + + // Returns a Buffer that is guaranteed to exist and be of size + // 'm_targetSize'. + rcp acquire(); + + void recycle(rcp resource) + { + GPUResourcePool::recycle(std::move(resource)); + } + +private: + D3D12ResourceManager* d3d() const; + + constexpr static size_t MAX_POOL_SIZE = 8; + UINT m_targetSize; + UINT m_alignment; +}; + +class D3D12DescriptorHeapPool : public GPUResourcePool +{ +public: + D3D12DescriptorHeapPool(rcp manager, + UINT numDescriptors, + D3D12_DESCRIPTOR_HEAP_TYPE type, + D3D12_DESCRIPTOR_HEAP_FLAGS flags); + + rcp acquire(); + void recycle(rcp resource) + { + GPUResourcePool::recycle(std::move(resource)); + } + +private: + D3D12ResourceManager* d3d() const; + + constexpr static size_t MAX_POOL_SIZE = 8; + // heap pools do not change over time, they are expected to be initialized + // with the max number of descriptors ever used + const UINT m_numDescriptors; + const D3D12_DESCRIPTOR_HEAP_TYPE m_type; + const D3D12_DESCRIPTOR_HEAP_FLAGS m_flags; +}; +} // namespace rive::gpu \ No newline at end of file diff --git a/third_party/rive_renderer/include/rive/renderer/d3d12/render_context_d3d12_impl.hpp b/third_party/rive_renderer/include/rive/renderer/d3d12/render_context_d3d12_impl.hpp new file mode 100644 index 0000000..3ae9b5a --- /dev/null +++ b/third_party/rive_renderer/include/rive/renderer/d3d12/render_context_d3d12_impl.hpp @@ -0,0 +1,277 @@ +/* + * Copyright 2025 Rive + */ + +#pragma once + +#include "rive/shapes/paint/image_sampler.hpp" +#include "rive/renderer/d3d12/d3d12_utils.hpp" +#include "rive/renderer/d3d12/d3d12_pipeline_manager.hpp" +#include "rive/renderer/render_context_impl.hpp" +#include "rive/renderer/texture.hpp" + +#include + +namespace rive::gpu +{ +class RenderContextD3D12Impl; + +class RenderTargetD3D12 : public RenderTarget +{ +public: + RenderTargetD3D12(RenderContextD3D12Impl*, int width, int height); + ~RenderTargetD3D12() override {} + + void setTargetTexture(rcp tex); + void setTargetTexture(ComPtr tex); + void releaseTexturesImmediately() + { + if (m_targetTexture) + m_targetTexture->forceReleaseResource(); + if (m_offscreenTexture) + m_offscreenTexture->forceReleaseResource(); + if (m_coverageTexture) + m_coverageTexture->forceReleaseResource(); + if (m_scratchColorTexture) + m_scratchColorTexture->forceReleaseResource(); + if (m_clipTexture) + m_clipTexture->forceReleaseResource(); + + m_targetTexture = nullptr; + m_offscreenTexture = nullptr; + m_coverageTexture = nullptr; + m_scratchColorTexture = nullptr; + m_clipTexture = nullptr; + } + + D3D12Texture* targetTexture() const { return m_targetTexture.get(); } + D3D12Texture* clip() const { return m_clipTexture.get(); } + D3D12Texture* coverage() const { return m_coverageTexture.get(); } + + D3D12Texture* offscreenTexture(); + + bool targetTextureSupportsUAV() const { return m_targetTextureSupportsUAV; } + + // Alternate rendering target when targetTextureSupportsUAV() is false. + void markTargetUAV(D3D12DescriptorHeap*); + void markClipUAV(D3D12DescriptorHeap*); + void markScratchColorUAV(D3D12DescriptorHeap*); + void markCoverageUAV(D3D12DescriptorHeap*); + +private: + rcp m_manager; + const bool m_gpuSupportsTypedUAVLoadStore; + + rcp m_targetTexture; + bool m_targetTextureSupportsUAV = false; + DXGI_FORMAT m_targetFormat = DXGI_FORMAT_UNKNOWN; + + rcp m_offscreenTexture; + rcp m_coverageTexture; + rcp m_scratchColorTexture; + rcp m_clipTexture; +}; + +// D3D 12 backend implementation of RenderContextImpl. +class RenderContextD3D12Impl : public RenderContextImpl +{ +public: + struct CommandLists + { + // used for resource syncing and copies, expected to be created with + // D3D12_COMMAND_LIST_TYPE_COPY type if this is null, drawCommandList + // will be used for all , operations. However, this one can be provided + // for optimization + ID3D12GraphicsCommandList* copyComandList; + // used for draw commands, expected to be created with + // D3D12_COMMAND_LIST_TYPE_DIRECT type if copyComandList is provided, + // the ID3D12CommandQueue that executes this list must wait on the + // ID3D12CommandQueue that executes the copyComandList with + // ID3D12CommandQueue::Wait + ID3D12GraphicsCommandList* directComandList; + }; + + // the command lit is used to construct static buffers. + static std::unique_ptr MakeContext( + ComPtr, + ID3D12GraphicsCommandList*, + const D3DContextOptions&); + + rcp makeRenderBuffer(RenderBufferType, + RenderBufferFlags, + size_t) override; + + virtual rcp makeImageTexture( + uint32_t width, + uint32_t height, + uint32_t mipLevelCount, + const uint8_t imageDataRGBAPremul[]) override; + +#define IMPLEMENT_RIVE_BUFFER(Name, m_buffer) \ + void resize##Name(size_t sizeInBytes) override \ + { \ + assert(m_buffer == nullptr); \ + m_buffer##Pool.setTargetSize(sizeInBytes); \ + } \ + void* map##Name(size_t mapSizeInBytes) override \ + { \ + assert(m_buffer != nullptr); \ + return m_buffer->map(mapSizeInBytes); \ + } \ + void unmap##Name(size_t mapSizeInBytes) override \ + { \ + assert(m_buffer != nullptr); \ + m_buffer->unmap(mapSizeInBytes); \ + } + +#define IMPLEMENT_RIVE_STRUCTURED_BUFFER(Name, m_buffer) \ + void resize##Name(size_t sizeInBytes, gpu::StorageBufferStructure) \ + override \ + { \ + assert(m_buffer == nullptr); \ + m_buffer##Pool.setTargetSize(sizeInBytes); \ + } \ + void* map##Name(size_t mapSizeInBytes) override \ + { \ + assert(m_buffer != nullptr); \ + return m_buffer->map(mapSizeInBytes); \ + } \ + void unmap##Name(size_t mapSizeInBytes) override \ + { \ + assert(m_buffer != nullptr); \ + m_buffer->unmap(mapSizeInBytes); \ + } + + IMPLEMENT_RIVE_BUFFER(FlushUniformBuffer, m_flushUniformBuffer) + IMPLEMENT_RIVE_BUFFER(ImageDrawUniformBuffer, m_imageDrawUniformBuffer) + IMPLEMENT_RIVE_STRUCTURED_BUFFER(PathBuffer, m_pathBuffer) + IMPLEMENT_RIVE_STRUCTURED_BUFFER(PaintBuffer, m_paintBuffer) + IMPLEMENT_RIVE_STRUCTURED_BUFFER(PaintAuxBuffer, m_paintAuxBuffer) + IMPLEMENT_RIVE_STRUCTURED_BUFFER(ContourBuffer, m_contourBuffer) + IMPLEMENT_RIVE_BUFFER(GradSpanBuffer, m_gradSpanBuffer) + IMPLEMENT_RIVE_BUFFER(TessVertexSpanBuffer, m_tessSpanBuffer) + IMPLEMENT_RIVE_BUFFER(TriangleVertexBuffer, m_triangleBuffer) + +#undef IMPLEMENT_RIVE_BUFFER +#undef IMPLEMENT_RIVE_STRUCTURED_BUFFER + + void resizeGradientTexture(uint32_t width, uint32_t height) override; + void resizeTessellationTexture(uint32_t width, uint32_t height) override; + void resizeAtlasTexture(uint32_t width, uint32_t height) override; + + void flush(const FlushDescriptor&) override; + + rcp makeRenderTarget(uint32_t width, uint32_t height) + { + return make_rcp(this, width, height); + } + + ComPtr device() const { return m_device; } + + rcp manager() const { return m_resourceManager; } + + const D3DCapabilities& d3dCapabilities() const { return m_capabilities; } + + double secondsNow() const override + { + auto elapsed = std::chrono::steady_clock::now() - m_localEpoch; + return std::chrono::duration(elapsed).count(); + } + + void prepareToFlush(uint64_t nextFrameNumber, + uint64_t safeFrameNumber) override; + + virtual void postFlush(const RenderContext::FlushResources&) override; + +private: + RenderContextD3D12Impl(ComPtr, + ID3D12GraphicsCommandList*, + const D3DCapabilities&); + + void blitSubRect(ID3D12GraphicsCommandList* cmdList, + D3D12Texture* dst, + D3D12Texture* src, + const IAABB& rect); + + ComPtr m_device; + const D3DCapabilities m_capabilities; + + rcp m_gradientTexture; + rcp m_tesselationTexture; + rcp m_atlasTexture; + rcp m_featherTexture; + + D3D12PipelineManager m_pipelineManager; + rcp m_resourceManager; + + // Rive buffer pools. These don't need to be rcp<> because the destructor of + // RenderContextVulkanImpl is already synchronized. + D3D12VolatileBufferPool m_flushUniformBufferPool; + D3D12VolatileBufferPool m_imageDrawUniformBufferPool; + D3D12VolatileBufferPool m_pathBufferPool; + D3D12VolatileBufferPool m_paintBufferPool; + D3D12VolatileBufferPool m_paintAuxBufferPool; + D3D12VolatileBufferPool m_contourBufferPool; + D3D12VolatileBufferPool m_gradSpanBufferPool; + D3D12VolatileBufferPool m_tessSpanBufferPool; + D3D12VolatileBufferPool m_triangleBufferPool; + + // this have to be re created every frame, rtv heaps do not + D3D12DescriptorHeapPool m_srvUavCbvHeapPool; + D3D12DescriptorHeapPool m_cpuSrvUavCbvHeapPool; + D3D12DescriptorHeapPool m_samplerHeapPool; + // Specific Rive buffers that have been acquired for the current frame. + // When the frame ends, these get recycled back in their respective pools. + rcp m_flushUniformBuffer; + rcp m_imageDrawUniformBuffer; + rcp m_pathBuffer; + rcp m_paintBuffer; + rcp m_paintAuxBuffer; + rcp m_contourBuffer; + rcp m_gradSpanBuffer; + rcp m_tessSpanBuffer; + rcp m_triangleBuffer; + + rcp m_srvUavCbvHeap; + // mirrors m_srvUavCbvHeap, needed for clearing resourcess via ClearUAV + // calls + rcp m_cpuSrvUavCbvHeap; + rcp m_samplerHeap; + // this doesn't need to be pooled because rtv heaps are not sent to the gpu, + // they are only used cpu side + rcp m_rtvHeap; + + // this is needed for multiple logical flushes and is also used for images + UINT m_heapDescriptorOffset; + // this is needed for multiple logical flushes and is also used for image + // samplers + UINT m_samplerHeapDescriptorOffset; + ImageSampler m_lastDynamicSampler = ImageSampler::LinearClamp(); + // this is a max number of bound descriptors at once. + // TODO: replace this with a refactor that allows being told up front how + // many reosurces will need to be bound per total flush (that means all + // logical flushes combined) this number is the limit for my computer, i do + // not know if it is different for different hardware + // our stress testing only needed about 10012, so we will use 10x that here + // for now + static constexpr int MAX_DESCRIPTOR_HEAPS_PER_FLUSH = 100000; + // same as above, but for samplers + static constexpr int MAX_DESCRIPTOR_SAMPLER_HEAPS_PER_FLUSH = 2000; + + // these buffers are created once and potentially used every frame + rcp m_pathPatchVertexBuffer; + rcp m_pathPatchIndexBuffer; + rcp m_tessSpanIndexBuffer; + rcp m_imageRectVertexBuffer; + rcp m_imageRectIndexBuffer; + + D3D12_SAMPLER_DESC m_linearSampler; + D3D12_SAMPLER_DESC + m_imageSamplers[ImageSampler::MAX_SAMPLER_PERMUTATIONS]; + + std::chrono::steady_clock::time_point m_localEpoch = + std::chrono::steady_clock::now(); + + bool m_isFirstFlushOfFrame = true; +}; +} // namespace rive::gpu diff --git a/third_party/rive_renderer/include/rive/renderer/draw.hpp b/third_party/rive_renderer/include/rive/renderer/draw.hpp new file mode 100644 index 0000000..5392198 --- /dev/null +++ b/third_party/rive_renderer/include/rive/renderer/draw.hpp @@ -0,0 +1,518 @@ +/* + * Copyright 2023 Rive + */ + +#pragma once + +#include "rive/math/raw_path.hpp" +#include "rive/renderer/gpu.hpp" +#include "rive/renderer/render_context.hpp" +#include "rive/renderer/fixed_queue.hpp" +#include "rive/shapes/paint/stroke_cap.hpp" +#include "rive/shapes/paint/stroke_join.hpp" +#include "rive/refcnt.hpp" + +namespace rive +{ +class RiveRenderPath; +class RiveRenderPaint; +} // namespace rive + +namespace rive::gpu +{ +class Draw; +class RenderContext; +class Gradient; + +// High level abstraction of a single object to be drawn (path, imageRect, or +// imageMesh). These get built up for an entire frame in order to count GPU +// resource allocation sizes, and then sorted, batched, and drawn. +class Draw +{ +public: + // Use a "fullscreen" bounding box that is reasonably larger than any + // screen, but not so big that it runs the risk of overflowing. + constexpr static IAABB FULLSCREEN_PIXEL_BOUNDS = {0, 0, 1 << 24, 1 << 24}; + + enum class Type : uint8_t + { + path, + imageRect, + imageMesh, + stencilClipReset, + }; + + Draw(IAABB pixelBounds, + const Mat2D&, + BlendMode, + rcp imageTexture, + ImageSampler imageSampler, + Type); + + Texture* imageTexture() const { return m_imageTextureRef; } + ImageSampler imageSampler() const { return m_imageSampler; } + const IAABB& pixelBounds() const { return m_pixelBounds; } + const Mat2D& matrix() const { return m_matrix; } + BlendMode blendMode() const { return m_blendMode; } + Type type() const { return m_type; } + gpu::DrawContents drawContents() const { return m_drawContents; } + bool isOpaque() const + { + return m_drawContents & gpu::DrawContents::opaquePaint; + } + uint32_t clipID() const { return m_clipID; } + bool hasClipRect() const { return m_clipRectInverseMatrix != nullptr; } + const gpu::ClipRectInverseMatrix* clipRectInverseMatrix() const + { + return m_clipRectInverseMatrix; + } + gpu::SimplePaintValue simplePaintValue() const + { + return m_simplePaintValue; + } + + // Clipping setup. + void setClipID(uint32_t clipID); + void setClipRect(const gpu::ClipRectInverseMatrix* m) + { + m_clipRectInverseMatrix = m; + } + + // Used to allocate GPU resources for a collection of draws. + using ResourceCounters = RenderContext::LogicalFlush::ResourceCounters; + const ResourceCounters& resourceCounts() const { return m_resourceCounts; } + + // Combined number of low-level draws required to render this object. The + // renderContext will call pushToRenderContext() "prepassCount() + + // subpassCount()" times, potentially with other non-overlapping draws in + // between. + // + // All prepasses from all draws are rendered first, before drawing any + // subpasses. Prepasses are rendered in front-to-back order and subpasses + // are drawn back-to-front. + int prepassCount() const { return m_prepassCount; } + int subpassCount() const { return m_subpassCount; } + + // When shaders don't have a mechanism to read the framebuffer (e.g., + // WebGL msaa), this is a linked list of all the draws from a single batch + // whose bounding boxes needs to be blitted to the "dstRead" texture before + // drawing. + const Draw* addToDstReadList(const Draw* head) const + { + assert(m_nextDstRead == nullptr); + m_nextDstRead = head; + return this; + }; + const Draw* nextDstRead() const { return m_nextDstRead; } + + // Finalizes m_prepassCount and m_subpassCount. + virtual void countSubpasses() + { + // The subclass must set m_prepassCount and m_subpassCount in this call + // if they are not 0 & 1. + assert(m_prepassCount == 0); + assert(m_subpassCount == 1); + } + + // Allocates any remaining resources necessary for the draw (gradients, + // coverage buffer ranges, atlas slots, etc.). + // + // Returns false if any allocation failed due to resource constraints, at + // which point the caller will have to issue a logical flush and try again. + virtual bool allocateResources(RenderContext::LogicalFlush*) + { + return true; + } + + // Pushes the data for the given subpassIndex of this draw to the + // renderContext. Called once the GPU buffers have been counted and + // allocated, and the draws have been sorted. + // + // NOTE: Subpasses are not necessarily rendered one after the other. + // Separate, non-overlapping draws may have gotten sorted between subpasses. + virtual void pushToRenderContext(RenderContext::LogicalFlush*, + int subpassIndex) = 0; + + // We can't have a destructor because we're block-allocated. Instead, the + // client calls this method before clearing the drawList to release all our + // held references. + virtual void releaseRefs(); + +protected: + Texture* const m_imageTextureRef; + const ImageSampler m_imageSampler; + const IAABB m_pixelBounds; + const Mat2D m_matrix; + const BlendMode m_blendMode; + const Type m_type; + + uint32_t m_clipID = 0; + const gpu::ClipRectInverseMatrix* m_clipRectInverseMatrix = nullptr; + + gpu::DrawContents m_drawContents = gpu::DrawContents::none; + + // Filled in by the subclass constructor. + ResourceCounters m_resourceCounts; + + // Before issuing the main draws, the renderContext may do a front-to-back + // pass. Any draw who wants to participate in front-to-back rendering can + // register a positive prepass count during countSubpasses(). + // + // For prepasses, pushToRenderContext() gets called with subpassIndex + // values: [-m_prepassCount, .., -1]. + int m_prepassCount = 0; + + // This is the number of low-level draws that the draw requires during main + // (back-to-front) rendering. A draw can register the number of subpasses it + // requires during countSubpasses(). + // + // For subpasses, pushToRenderContext() gets called with subpassIndex + // values: [0, .., m_subpassCount - 1]. + int m_subpassCount = 1; + + gpu::SimplePaintValue m_simplePaintValue; + + // When shaders don't have a mechanism to read the framebuffer (e.g., + // WebGL msaa), this is a linked list of all the draws from a single batch + // whose bounding boxes needs to be blitted to the "dstRead" texture before + // drawing. + const Draw mutable* m_nextDstRead = nullptr; +}; + +// Implement DrawReleaseRefs (defined in pls_render_context.hpp) now that Draw +// is defined. +inline void DrawReleaseRefs::operator()(Draw* draw) { draw->releaseRefs(); } + +// High level abstraction of a single path to be drawn (midpoint fan or interior +// triangulation). +class PathDraw : public Draw +{ +public: + // Creates either a normal path draw or an interior triangulation if the + // path is large enough. + static DrawUniquePtr Make(RenderContext*, + const Mat2D&, + rcp, + FillRule, + const RiveRenderPaint*, + RawPath* scratchPath); + + // Determines how coverage is calculated for antialiasing and feathers. + // CoverageType is mostly decided by the InterlockMode, but we keep these + // concepts separate because atlas coverage may be used with any + // InterlockMode. + enum class CoverageType + { + pixelLocalStorage, // InterlockMode::rasterOrdering and atomics + clockwiseAtomic, // InterlockMode::clockwiseAtomic + msaa, // InterlockMode::msaa + atlas, // Any InterlockMode may opt to use atlas coverage for large + // feathers; msaa always has to use an atlas for feathers. + }; + + PathDraw(IAABB pixelBounds, + const Mat2D&, + rcp, + FillRule, + const RiveRenderPaint*, + CoverageType, + const RenderContext::FrameDescriptor&); + + CoverageType coverageType() const { return m_coverageType; } + + const Gradient* gradient() const { return m_gradientRef; } + gpu::PaintType paintType() const { return m_paintType; } + bool isFeatheredFill() const + { + return m_featherRadius != 0 && m_strokeRadius == 0; + } + bool isStrokeOrFeather() const + { + return (math::bit_cast(m_featherRadius) | + math::bit_cast(m_strokeRadius)) != 0; + } + bool isStroke() const { return m_strokeRadius != 0; } + float strokeRadius() const { return m_strokeRadius; } + float featherRadius() const { return m_featherRadius; } + gpu::ContourDirections contourDirections() const + { + return m_contourDirections; + } + + // Only used when rendering coverage via the atlas. + const gpu::AtlasTransform& atlasTransform() const + { + return m_atlasTransform; + } + const TAABB& atlasScissor() const { return m_atlasScissor; } + bool atlasScissorEnabled() const { return m_atlasScissorEnabled; } + + // clockwiseAtomic only. + const gpu::CoverageBufferRange& coverageBufferRange() const + { + return m_coverageBufferRange; + } + + GrInnerFanTriangulator* triangulator() const { return m_triangulator; } + + bool allocateResources(RenderContext::LogicalFlush*) override; + void countSubpasses() override; + + void pushToRenderContext(RenderContext::LogicalFlush*, + int subpassIndex) override; + + // Called after pushToRenderContext(), and only when this draw uses an atlas + // for tessellation. In the CoverageType::atlas case, pushToRenderContext() + // is where we emit the rectangle that reads the atlas (and writes to the + // main render target). So this method is where we push the tessellation + // that gets rendered separately to the offscreen atlas. + void pushAtlasTessellation(RenderContext::LogicalFlush*, + uint32_t* tessVertexCount, + uint32_t* tessBaseVertex); + + void releaseRefs() override; + +protected: + static CoverageType SelectCoverageType(const RiveRenderPaint*, + float matrixMaxScale, + const gpu::PlatformFeatures&, + gpu::InterlockMode); + + // Prepares to draw the path by tessellating a fan around its midpoint. + void initForMidpointFan(RenderContext*, const RiveRenderPaint*); + + enum class TriangulatorAxis + { + horizontal, + vertical, + dontCare, + }; + + // Prepares to draw the path by triangulating the interior into + // non-overlapping triangles and tessellating the outer cubics. + void initForInteriorTriangulation(RenderContext*, + RawPath*, + TriangulatorAxis); + + uint32_t allocateTessellationVertices(RenderContext::LogicalFlush* flush, + uint32_t tessVertexCount) + { + if (m_triangulator != nullptr) + return flush->allocateOuterCubicTessVertices(tessVertexCount); + else + return flush->allocateMidpointFanTessVertices(tessVertexCount); + } + + // Calls LogicalFlush::pushOuterCubicsDraw() or + // LogicalFlush::pushMidpointFanDraw() for this PathDraw. + void pushTessellationDraw( + RenderContext::LogicalFlush*, + uint32_t tessVertexCount, + uint32_t tessLocation, + gpu::ShaderMiscFlags = gpu::ShaderMiscFlags::none); + + // Pushes TessVertexSpans that will tessellate this PathDraw at the given + // location. + void pushTessellationData(RenderContext::LogicalFlush*, + uint32_t tessVertexCount, + uint32_t tessLocation); + + // Pushes the contours and cubics to the renderContext for a + // "midpointFanPatches" draw. + void pushMidpointFanTessellationData(RenderContext::TessellationWriter*); + + // Emulates a stroke cap before the given cubic by pushing a copy of the + // cubic, reversed, with 0 tessellation segments leading up to the join + // section, and a 180-degree join that looks like the desired stroke cap. + void pushEmulatedStrokeCapAsJoinBeforeCubic( + RenderContext::TessellationWriter*, + const Vec2D cubic[], + uint32_t strokeCapSegmentCount, + uint32_t contourIDWithFlags); + + enum class InteriorTriangulationOp : bool + { + // Fills in m_resourceCounts and runs a GrInnerFanTriangulator on the + // path's interior polygon. + countDataAndTriangulate, + + // Pushes the contours and cubics to the renderContext for an + // "outerCurvePatches" draw. + pushOuterCubicTessellationData, + }; + + // Called to processes the interior triangulation both during initialization + // and submission. For now, we just iterate and subdivide the path twice + // (once for each enum in InteriorTriangulationOp). Since we only do this + // for large paths, and since we're triangulating the path interior anyway, + // adding complexity to only run Wang's formula and chop once would save + // about ~5% of the total CPU time. (And large paths are GPU-bound anyway.) + void iterateInteriorTriangulation(InteriorTriangulationOp op, + TrivialBlockAllocator*, + RawPath* scratchPath, + TriangulatorAxis, + RenderContext::TessellationWriter*); + + const RiveRenderPath* const m_pathRef; + const FillRule m_pathFillRule; // Fill rule can mutate on RenderPath. + const Gradient* m_gradientRef; + const gpu::PaintType m_paintType; + const CoverageType m_coverageType; + float m_strokeRadius = 0; + float m_featherRadius = 0; + gpu::ContourDirections m_contourDirections; + uint32_t m_contourFlags = 0; + + // Only used when rendering coverage via the atlas. + gpu::AtlasTransform m_atlasTransform; + TAABB m_atlasScissor; // Scissor rect when rendering to the atlas. + bool m_atlasScissorEnabled; + + // clockwiseAtomic only. + gpu::CoverageBufferRange m_coverageBufferRange; + + GrInnerFanTriangulator* m_triangulator = nullptr; + + StrokeJoin m_strokeJoin; + StrokeCap m_strokeCap; + float m_strokeMatrixMaxScale; + float m_polarSegmentsPerRadian; + + struct ContourInfo + { + RawPath::Iter endOfContour; + size_t endLineIdx; + size_t firstCurveIdx; + size_t endCurveIdx; + size_t firstRotationIdx; // We measure rotations on both curves and + // round joins. + size_t endRotationIdx; + Vec2D midpoint; + bool closed; + size_t strokeJoinCount; + uint32_t strokeCapSegmentCount; + uint32_t paddingVertexCount; + RIVE_DEBUG_CODE(uint32_t tessVertexCount;) + }; + + ContourInfo* m_contours; + FixedQueue m_numChops; + FixedQueue m_chopVertices; + std::array* m_tangentPairs = nullptr; + uint32_t* m_polarSegmentCounts = nullptr; + uint32_t* m_parametricSegmentCounts = nullptr; + + // Unique ID used by shaders for the current frame. + uint32_t m_pathID = 0; + + union + { + // Used in clockwiseAtomic mode. The negative triangles get rendered in + // a separate prepass, and their tessellations need to be allocated + // before the main subpass pushes the path to the renderContext. + uint32_t m_prepassTessLocation = 0; + + // Used in msaa mode. Multiple msaa subpasses use the same tesellation + // data. + uint32_t m_msaaTessLocation; + }; + + // Used to guarantee m_pathRef doesn't change for the entire time we hold + // it. + RIVE_DEBUG_CODE(uint64_t m_rawPathMutationID;) + + // Consistency checks for pushToRenderContext(). + RIVE_DEBUG_CODE(size_t m_pendingLineCount;) + RIVE_DEBUG_CODE(size_t m_pendingCurveCount;) + RIVE_DEBUG_CODE(size_t m_pendingRotationCount;) + RIVE_DEBUG_CODE(size_t m_pendingStrokeJoinCount;) + RIVE_DEBUG_CODE(size_t m_pendingStrokeCapCount;) + // Counts how many additional curves were pushed by + // pushEmulatedStrokeCapAsJoinBeforeCubic(). + RIVE_DEBUG_CODE(size_t m_pendingEmptyStrokeCountForCaps;) + RIVE_DEBUG_CODE(size_t m_numInteriorTriangleVerticesPushed = 0;) +}; + +// Pushes an imageRect to the render context. +// This should only be used in atomic mode. Otherwise, images should be drawn as +// rectangular paths with an image paint. +class ImageRectDraw : public Draw +{ +public: + ImageRectDraw(RenderContext*, + IAABB pixelBounds, + const Mat2D&, + BlendMode, + rcp, + const ImageSampler imageSampler, + float opacity); + + float opacity() const { return m_opacity; } + + void pushToRenderContext(RenderContext::LogicalFlush*, + int subpassIndex) override; + +protected: + const float m_opacity; +}; + +// Pushes an imageMesh to the render context. +class ImageMeshDraw : public Draw +{ +public: + ImageMeshDraw(IAABB pixelBounds, + const Mat2D&, + BlendMode, + rcp, + const ImageSampler imageSampler, + rcp vertexBuffer, + rcp uvBuffer, + rcp indexBuffer, + uint32_t indexCount, + float opacity); + + RenderBuffer* vertexBuffer() const { return m_vertexBufferRef; } + RenderBuffer* uvBuffer() const { return m_uvBufferRef; } + RenderBuffer* indexBuffer() const { return m_indexBufferRef; } + uint32_t indexCount() const { return m_indexCount; } + float opacity() const { return m_opacity; } + + void pushToRenderContext(RenderContext::LogicalFlush*, + int subpassIndex) override; + + void releaseRefs() override; + +protected: + RenderBuffer* const m_vertexBufferRef; + RenderBuffer* const m_uvBufferRef; + RenderBuffer* const m_indexBufferRef; + const uint32_t m_indexCount; + const float m_opacity; +}; + +// Resets the stencil clip by either entirely erasing the existing clip, or +// intersecting it with a nested clip (i.e., erasing the region outside the +// nested clip). +class StencilClipReset : public Draw +{ +public: + enum class ResetAction + { + clearPreviousClip, + intersectPreviousClip, + }; + + StencilClipReset(RenderContext*, + uint32_t previousClipID, + gpu::DrawContents previousClipDrawContents, + ResetAction); + + uint32_t previousClipID() const { return m_previousClipID; } + + void pushToRenderContext(RenderContext::LogicalFlush*, + int subpassIndex) override; + +protected: + const uint32_t m_previousClipID; +}; +} // namespace rive::gpu diff --git a/third_party/rive_renderer/include/rive/renderer/fixed_queue.hpp b/third_party/rive_renderer/include/rive/renderer/fixed_queue.hpp new file mode 100644 index 0000000..41c081a --- /dev/null +++ b/third_party/rive_renderer/include/rive/renderer/fixed_queue.hpp @@ -0,0 +1,73 @@ +/* + * Copyright 2022 Rive + */ + +#pragma once + +#include "rive/renderer/trivial_block_allocator.hpp" + +namespace rive::gpu +{ +// Fast, simple queue that operates on a block-allocated array. push_back() may +// only be called up to m_capacity times before the queue must be rewound. +template class FixedQueue +{ +public: + void reset(TrivialArrayAllocator& allocator, size_t capacity) + { + m_array = allocator.alloc(capacity); + rewind(); + RIVE_DEBUG_CODE(m_capacity = capacity;) + } + + void rewind() { m_front = m_end = m_array; } + + void shrinkToFit(TrivialArrayAllocator& allocator, + size_t originalCapacity) + { + assert(m_capacity == originalCapacity); + size_t newCapacity = m_end - m_array; + assert(newCapacity <= originalCapacity); + allocator.rewindLastAllocation(originalCapacity - newCapacity); + RIVE_DEBUG_CODE(m_capacity = newCapacity;) + } + + size_t pushCount() const { return m_end - m_array; } + + T& push_back() + { + assert(m_end < m_array + m_capacity); + return *m_end++; + } + + T& push_back(const T& t) { return push_back() = t; } + + T* push_back_n(size_t n) + { + assert(m_end + n <= m_array + m_capacity); + T* ptr = m_end; + m_end += n; + return ptr; + } + + const T& pop_front() + { + assert(m_front < m_end); + return *m_front++; + } + + const T* pop_front_n(size_t n) + { + assert(m_front + n <= m_end); + const T* ptr = m_front; + m_front += n; + return ptr; + } + +private: + T* m_array = nullptr; + T* m_front = nullptr; + T* m_end = nullptr; + RIVE_DEBUG_CODE(size_t m_capacity = 0;) +}; +} // namespace rive::gpu diff --git a/third_party/rive_renderer/include/rive/renderer/gl/gl_state.hpp b/third_party/rive_renderer/include/rive/renderer/gl/gl_state.hpp new file mode 100644 index 0000000..c4b678c --- /dev/null +++ b/third_party/rive_renderer/include/rive/renderer/gl/gl_state.hpp @@ -0,0 +1,70 @@ +/* + * Copyright 2023 Rive + */ + +#pragma once + +#include "rive/renderer/gl/gles3.hpp" +#include "rive/refcnt.hpp" +#include "rive/renderer/gpu.hpp" + +namespace rive::gpu +{ +// Lightweight wrapper around common GL state. +class GLState : public RefCnt +{ +public: + GLState(const GLCapabilities& capabilities) : m_capabilities(capabilities) + { + invalidate(); + } + + const GLCapabilities& capabilities() const { return m_capabilities; } + + void invalidate(); + + void setDepthStencilEnabled(bool depthEnabled, bool stencilEnabled); + void setCullFace(GLenum); + void setBlendEquation(gpu::BlendEquation); + void disableBlending() { setBlendEquation(gpu::BlendEquation::none); } + void setWriteMasks(bool colorWriteMask, + bool depthWriteMask, + uint8_t stencilWriteMask); + void setPipelineState(const gpu::PipelineState&); + + void bindProgram(GLuint); + void bindVAO(GLuint); + void bindBuffer(GLenum target, GLuint); + + void deleteProgram(GLuint); + void deleteVAO(GLuint); + void deleteBuffer(GLuint); + +private: + const GLCapabilities m_capabilities; + gpu::BlendEquation m_blendEquation; + bool m_depthTestEnabled; + bool m_stencilTestEnabled; + bool m_colorWriteMask; + bool m_depthWriteMask; + GLuint m_stencilWriteMask; + GLenum m_cullFace; + GLuint m_boundProgramID; + GLuint m_boundVAO; + GLuint m_boundArrayBufferID; + GLuint m_boundUniformBufferID; + + struct + { + bool blendEquation : 1; + bool depthStencilEnabled : 1; + bool writeMasks : 1; + bool cullFace : 1; + bool boundProgramID : 1; + bool boundVAO : 1; + bool boundArrayBufferID : 1; + bool boundUniformBufferID : 1; + bool boundPixelUnpackBufferID : 1; + } m_validState; +}; +} // namespace rive::gpu diff --git a/third_party/rive_renderer/include/rive/renderer/gl/gl_utils.hpp b/third_party/rive_renderer/include/rive/renderer/gl/gl_utils.hpp new file mode 100644 index 0000000..e9783d4 --- /dev/null +++ b/third_party/rive_renderer/include/rive/renderer/gl/gl_utils.hpp @@ -0,0 +1,253 @@ +/* + * Copyright 2022 Rive + */ + +#pragma once + +#include "rive/renderer/gl/gles3.hpp" +#include "rive/math/aabb.hpp" +#include "rive/shapes/paint/image_sampler.hpp" +#include +#include + +namespace glutils +{ +// Used when the driver doesn't support gl_BaseInstance +// (GLCapabilities::ANGLE_base_vertex_base_instance_shader_builtin is false). +// +// The client must set this uniform value before drawing if the shader needs an +// instance index. +// +// (Begin the variable name with an underscore so it won't collide with any +// renames from minify.py.) +constexpr static char BASE_INSTANCE_UNIFORM_NAME[] = "_baseInstance"; + +void CompileAndAttachShader(GLuint program, + GLenum type, + const char* source, + const GLCapabilities&); + +void CompileAndAttachShader(GLuint program, + GLenum type, + const char* defines[], + size_t numDefines, + const char* sources[], + size_t numSources, + const GLCapabilities&); + +[[nodiscard]] GLuint CompileShader(GLuint type, + const char* source, + const GLCapabilities&); + +[[nodiscard]] GLuint CompileShader(GLuint type, + const char* defines[], + size_t numDefines, + const char* sources[], + size_t numSources, + const GLCapabilities&); + +[[nodiscard]] GLuint CompileRawGLSL(GLenum shaderType, const char* rawGLSL); + +void LinkProgram(GLuint program); + +class GLObject +{ +public: + GLObject() = default; + GLObject(GLObject&& rhs) : m_id(std::exchange(rhs.m_id, 0)) {} + + GLObject(const GLObject&) = delete; + GLObject& operator=(const GLObject&) = delete; + + operator GLuint() const { return m_id; } + +protected: + explicit GLObject(GLuint adoptedID) : m_id(adoptedID) {} + + GLuint m_id = 0; +}; + +class Buffer : public GLObject +{ +public: + Buffer() { glGenBuffers(1, &m_id); } + ~Buffer() { glDeleteBuffers(1, &m_id); } +}; + +class Texture : public GLObject +{ +public: + Texture() { glGenTextures(1, &m_id); } + Texture(Texture&& rhs) : GLObject(std::move(rhs)) {} + Texture& operator=(Texture&& rhs) + { + reset(std::exchange(rhs.m_id, 0)); + return *this; + } + ~Texture() { reset(0); } + + static Texture Zero() { return Texture(0); } + static Texture Adopt(GLuint id) { return Texture(id); } + +private: + explicit Texture(GLuint adoptedID) : GLObject(adoptedID) {} + + void reset(GLuint adoptedID) + { + if (m_id != 0) + { + glDeleteTextures(1, &m_id); + } + m_id = adoptedID; + } +}; + +class Framebuffer : public GLObject +{ +public: + Framebuffer() { glGenFramebuffers(1, &m_id); } + Framebuffer(Framebuffer&& rhs) : GLObject(std::move(rhs)) {} + Framebuffer& operator=(Framebuffer&& rhs) + { + reset(std::exchange(rhs.m_id, 0)); + return *this; + } + ~Framebuffer() { reset(0); } + + static Framebuffer Zero() { return Framebuffer(0); } + +private: + explicit Framebuffer(GLuint adoptedID) : GLObject(adoptedID) {} + + void reset(GLuint adoptedID) + { + if (m_id != 0) + { + glDeleteFramebuffers(1, &m_id); + } + m_id = adoptedID; + } +}; + +class Renderbuffer : public GLObject +{ +public: + Renderbuffer() { glGenRenderbuffers(1, &m_id); } + Renderbuffer(Renderbuffer&& rhs) : GLObject(std::move(rhs)) {} + Renderbuffer& operator=(Renderbuffer&& rhs) + { + reset(std::exchange(rhs.m_id, 0)); + return *this; + } + ~Renderbuffer() { reset(0); } + + static Renderbuffer Zero() { return Renderbuffer(0); } + +private: + explicit Renderbuffer(GLuint adoptedID) : GLObject(adoptedID) {} + + void reset(GLuint adoptedID) + { + if (m_id != 0) + { + glDeleteRenderbuffers(1, &m_id); + } + m_id = adoptedID; + } +}; + +class VAO : public GLObject +{ +public: + VAO() { glGenVertexArrays(1, &m_id); } + ~VAO() { glDeleteVertexArrays(1, &m_id); } +}; + +class Shader : public GLObject +{ +public: + Shader() = default; + Shader(Shader&& rhs) : GLObject(std::move(rhs)) {} + Shader& operator=(Shader&& rhs) + { + reset(std::exchange(rhs.m_id, 0)); + return *this; + } + ~Shader() { reset(0); } + + void compile(GLenum type, + const char* source, + const GLCapabilities& capabilities) + { + compile(type, nullptr, 0, &source, 1, capabilities); + } + void compile(GLenum type, + const char* defines[], + size_t numDefines, + const char* sources[], + size_t numSources, + const GLCapabilities&); + + void reset(GLuint adoptedID = 0) + { + if (m_id != 0) + { + glDeleteShader(m_id); + } + m_id = adoptedID; + } +}; + +class Program : public GLObject +{ +public: + Program() : GLObject(glCreateProgram()) {} + Program& operator=(Program&& rhs) + { + reset(std::exchange(rhs.m_id, 0)); + m_vertexShader = std::move(rhs.m_vertexShader); + m_fragmentShader = std::move(rhs.m_fragmentShader); + return *this; + } + ~Program() { reset(0); } + + void compileAndAttachShader(GLenum type, + const char* source, + const GLCapabilities& capabilities) + { + compileAndAttachShader(type, nullptr, 0, &source, 1, capabilities); + } + void compileAndAttachShader(GLenum type, + const char* defines[], + size_t numDefines, + const char* sources[], + size_t numSources, + const GLCapabilities&); + + void link() { LinkProgram(m_id); } + + static Program Zero() { return Program(0); } + +private: + explicit Program(GLuint adoptedID) : GLObject(adoptedID) {} + + void reset(GLuint adoptedProgramID); + + glutils::Shader m_vertexShader; + glutils::Shader m_fragmentShader; +}; + +void SetTexture2DSamplingParams(GLenum minFilter, GLenum magFilter); +void SetTexture2DSamplingParams(rive::ImageSampler); + +void BlitFramebuffer(rive::IAABB bounds, + uint32_t renderTargetHeight, + GLbitfield mask = GL_COLOR_BUFFER_BIT); + +void Uniform1iByName(GLuint programID, const char* name, GLint value); + +// ANGLE_shader_pixel_local_storage enum values had a breaking change in early +// 2025. Return true if we can verify that we're running on the latest +// ANGLE_shader_pixel_local_storage spec. +bool validate_pixel_local_storage_angle(); +} // namespace glutils diff --git a/third_party/rive_renderer/include/rive/renderer/gl/gles3.hpp b/third_party/rive_renderer/include/rive/renderer/gl/gles3.hpp new file mode 100644 index 0000000..9d0eba0 --- /dev/null +++ b/third_party/rive_renderer/include/rive/renderer/gl/gles3.hpp @@ -0,0 +1,180 @@ +/* + * Copyright 2023 Rive + */ + +#pragma once + +#include +#include + +#ifdef RIVE_DESKTOP_GL +#include "glad_custom.h" +#define GL_APIENTRY GLAPIENTRY +#define GL_SHADER_PIXEL_LOCAL_STORAGE_EXT 0x8F64 +#define GL_FRAMEBUFFER_FETCH_NONCOHERENT_QCOM 0x96A2 +#define glFramebufferFetchBarrierQCOM(...) RIVE_UNREACHABLE() +#endif + +#ifdef RIVE_ANDROID +#include +#include +#include +#include +#endif + +#ifdef RIVE_WEBGL +#include +#include + +#ifndef WEBGL_debug_renderer_info +#define WEBGL_debug_renderer_info 1 +#define GL_UNMASKED_VENDOR_WEBGL 0x9245 +#define GL_UNMASKED_RENDERER_WEBGL 0x9246 +#endif + +#ifndef GL_ANGLE_shader_pixel_local_storage +#define GL_ANGLE_shader_pixel_local_storage 1 +#define GL_MAX_PIXEL_LOCAL_STORAGE_PLANES_ANGLE 0x96E0 +#define GL_MAX_COMBINED_DRAW_BUFFERS_AND_PIXEL_LOCAL_STORAGE_PLANES_ANGLE 0x96E1 +#define GL_PIXEL_LOCAL_STORAGE_ACTIVE_PLANES_ANGLE 0x96E2 +#define GL_LOAD_OP_ZERO_ANGLE 0x96E3 +#define GL_LOAD_OP_CLEAR_ANGLE 0x96E4 +#define GL_LOAD_OP_LOAD_ANGLE 0x96E5 +#define GL_STORE_OP_STORE_ANGLE 0x96E6 +#define GL_PIXEL_LOCAL_FORMAT_ANGLE 0x96E7 +#define GL_PIXEL_LOCAL_TEXTURE_NAME_ANGLE 0x96E8 +#define GL_PIXEL_LOCAL_TEXTURE_LEVEL_ANGLE 0x96E9 +#define GL_PIXEL_LOCAL_TEXTURE_LAYER_ANGLE 0x96EA +#define GL_PIXEL_LOCAL_CLEAR_VALUE_FLOAT_ANGLE 0x96EB +#define GL_PIXEL_LOCAL_CLEAR_VALUE_INT_ANGLE 0x96EC +#define GL_PIXEL_LOCAL_CLEAR_VALUE_UNSIGNED_INT_ANGLE 0x96ED +extern bool webgl_enable_WEBGL_shader_pixel_local_storage_coherent(); +extern bool webgl_enable_WEBGL_provoking_vertex(); +extern bool webgl_shader_pixel_local_storage_is_coherent(); +extern void glFramebufferTexturePixelLocalStorageANGLE(GLint plane, + GLuint backingtexture, + GLint level, + GLint layer); +extern void glFramebufferPixelLocalClearValuefvANGLE(GLint plane, + const GLfloat value[4]); +extern void glBeginPixelLocalStorageANGLE(GLsizei n, const GLenum loadops[]); +extern void glEndPixelLocalStorageANGLE(GLsizei n, const GLenum storeops[]); +extern void glGetFramebufferPixelLocalStorageParameterivANGLE(GLint plane, + GLenum pname, + GLint* param); +#endif + +#ifndef GL_ANGLE_provoking_vertex +#define GL_ANGLE_provoking_vertex 1 +#define GL_FIRST_VERTEX_CONVENTION_ANGLE 0x8E4D +#define GL_LAST_VERTEX_CONVENTION_ANGLE 0x8E4E +#define GL_PROVOKING_VERTEX_ANGLE 0x8E4F +extern void glProvokingVertexANGLE(GLenum provokeMode); +#endif + +#ifndef GL_KHR_blend_equation_advanced +#define GL_KHR_blend_equation_advanced 1 +#define GL_MULTIPLY_KHR 0x9294 +#define GL_SCREEN_KHR 0x9295 +#define GL_OVERLAY_KHR 0x9296 +#define GL_DARKEN_KHR 0x9297 +#define GL_LIGHTEN_KHR 0x9298 +#define GL_COLORDODGE_KHR 0x9299 +#define GL_COLORBURN_KHR 0x929A +#define GL_HARDLIGHT_KHR 0x929B +#define GL_SOFTLIGHT_KHR 0x929C +#define GL_DIFFERENCE_KHR 0x929E +#define GL_EXCLUSION_KHR 0x92A0 +#define GL_HSL_HUE_KHR 0x92AD +#define GL_HSL_SATURATION_KHR 0x92AE +#define GL_HSL_COLOR_KHR 0x92AF +#define GL_HSL_LUMINOSITY_KHR 0x92B0 +#define GL_BLEND_ADVANCED_COHERENT_KHR 0x9285 +#endif + +#ifndef GL_EXT_clip_cull_distance +#define GL_EXT_clip_cull_distance 1 +#define GL_CLIP_DISTANCE0_EXT 0x3000 +#define GL_CLIP_DISTANCE1_EXT 0x3001 +#define GL_CLIP_DISTANCE2_EXT 0x3002 +#define GL_CLIP_DISTANCE3_EXT 0x3003 +#endif + +#endif // RIVE_WEBGL + +#if defined(RIVE_ANDROID) || defined(RIVE_WEBGL) +// GLES 3.1 functionality is pulled in as an extension. Define these to avoid +// compile errors, even if we won't use them. +#define GL_SHADER_STORAGE_BUFFER 0x90D2 +#define GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS 0x90D6 +#endif + +struct GLCapabilities +{ + GLCapabilities() { memset(this, 0, sizeof(*this)); } + + bool isContextVersionAtLeast(int major, int minor) const + { + return ((contextVersionMajor << 16) | contextVersionMinor) >= + ((major << 16) | minor); + } + + // GL version. + int contextVersionMajor; + int contextVersionMinor; + + // Driver info. + bool isGLES : 1; + bool isANGLEOrWebGL : 1; + bool isAdreno : 1; + bool isMali : 1; + bool isPowerVR : 1; + + // Workarounds. + // Some devices crash when issuing draw commands with a large instancecount. + uint32_t maxSupportedInstancesPerDrawCommand = ~0u; + // Chrome 136 crashes when trying to run Rive because it attempts to enable + // blending on the tessellation texture, which is invalid for an integer + // render target. The workaround is to use a floating-point tessellation + // texture. + // https://issues.chromium.org/issues/416294709 + bool needsFloatingPointTessellationTexture = false; + + // Extensions + bool ANGLE_base_vertex_base_instance_shader_builtin : 1; + bool ANGLE_shader_pixel_local_storage : 1; + bool ANGLE_shader_pixel_local_storage_coherent : 1; + bool ANGLE_polygon_mode : 1; + bool ANGLE_provoking_vertex : 1; + bool ARM_shader_framebuffer_fetch : 1; + bool ARB_fragment_shader_interlock : 1; + bool ARB_shader_image_load_store : 1; + bool ARB_shader_storage_buffer_object : 1; + bool KHR_blend_equation_advanced : 1; + bool KHR_blend_equation_advanced_coherent : 1; + bool EXT_base_instance : 1; + bool EXT_clip_cull_distance : 1; + bool EXT_color_buffer_half_float : 1; + bool EXT_float_blend : 1; // Implies EXT_color_buffer_float. + bool EXT_multisampled_render_to_texture : 1; + bool EXT_shader_framebuffer_fetch : 1; + bool EXT_shader_pixel_local_storage : 1; + bool INTEL_fragment_shader_ordering : 1; + bool QCOM_shader_framebuffer_fetch_noncoherent : 1; +}; + +#ifdef RIVE_ANDROID +// Android doesn't load extension functions for us. +extern PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEEXTPROC + glDrawArraysInstancedBaseInstanceEXT; +extern PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEEXTPROC + glDrawElementsInstancedBaseInstanceEXT; +extern PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEEXTPROC + glDrawElementsInstancedBaseVertexBaseInstanceEXT; +extern PFNGLFRAMEBUFFERFETCHBARRIERQCOMPROC glFramebufferFetchBarrierQCOM; +extern PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC + glFramebufferTexture2DMultisampleEXT; +extern PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC + glRenderbufferStorageMultisampleEXT; +void LoadGLESExtensions(const GLCapabilities&); +#endif diff --git a/third_party/rive_renderer/include/rive/renderer/gl/load_store_actions_ext.hpp b/third_party/rive_renderer/include/rive/renderer/gl/load_store_actions_ext.hpp new file mode 100644 index 0000000..fbd87af --- /dev/null +++ b/third_party/rive_renderer/include/rive/renderer/gl/load_store_actions_ext.hpp @@ -0,0 +1,35 @@ +/* + * Copyright 2022 Rive + */ + +#pragma once + +#include "rive/renderer/gpu.hpp" +#include "rive/enum_bitset.hpp" +#include + +namespace rive::gpu +{ +// When using EXT_shader_pixel_local_storage, we have to emulate the render pass +// load/store actions using a shader. These bits define specific actions that +// can be turned on or off in that shader. +enum class LoadStoreActionsEXT +{ + none = 0, + clearColor = 1, + loadColor = 2, + storeColor = 4, + clearCoverage = 8, + clearClip = 16, +}; +RIVE_MAKE_ENUM_BITSET(LoadStoreActionsEXT) + +// Determines the specific load actions that need to be emulated for the given +// render pass, and unpacks the clear color, if required. +LoadStoreActionsEXT BuildLoadActionsEXT(const gpu::FlushDescriptor&, + std::array* clearColor4f); + +// Appends load_store_ext.glsl to the stream, with the appropriate #defines +// prepended. +std::ostream& BuildLoadStoreEXTGLSL(std::ostream&, LoadStoreActionsEXT); +} // namespace rive::gpu diff --git a/third_party/rive_renderer/include/rive/renderer/gl/render_buffer_gl_impl.hpp b/third_party/rive_renderer/include/rive/renderer/gl/render_buffer_gl_impl.hpp new file mode 100644 index 0000000..46576f5 --- /dev/null +++ b/third_party/rive_renderer/include/rive/renderer/gl/render_buffer_gl_impl.hpp @@ -0,0 +1,57 @@ +/* + * Copyright 2023 Rive + */ + +#pragma once + +#include "rive/renderer/rive_render_buffer.hpp" +#include "rive/renderer/gl/gles3.hpp" +#include "rive/renderer/gpu.hpp" +#include + +namespace rive::gpu +{ +class GLState; + +// OpenGL backend implementation of rive::RenderBuffer. +class RenderBufferGLImpl + : public LITE_RTTI_OVERRIDE(RiveRenderBuffer, RenderBufferGLImpl) +{ +public: + RenderBufferGLImpl(RenderBufferType, + RenderBufferFlags, + size_t, + rcp); + ~RenderBufferGLImpl(); + + // Returns the buffer to submit to GL draw calls, updating it if dirty. + GLuint bufferID() { return m_bufferID; } + +protected: + RenderBufferGLImpl(RenderBufferType type, + RenderBufferFlags flags, + size_t sizeInBytes); + + void init(rcp); + + // Used by the android runtime to marshal the buffer off to the GL thread + // for deletion. + GLuint detachBuffer(); + + void* onMap() override; + void onUnmap() override; + + GLState* state() const { return m_state.get(); } + +private: + // Returns whether glMapBufferRange() is supported for our buffer. If not, + // we use m_fallbackMappedMemory. + bool canMapBuffer() const; + + const GLenum m_target; + GLuint m_bufferID = 0; + // Used when canMapBuffer() is false. + std::unique_ptr m_fallbackMappedMemory; + rcp m_state; +}; +} // namespace rive::gpu diff --git a/third_party/rive_renderer/include/rive/renderer/gl/render_context_gl_impl.hpp b/third_party/rive_renderer/include/rive/renderer/gl/render_context_gl_impl.hpp new file mode 100644 index 0000000..dfcc566 --- /dev/null +++ b/third_party/rive_renderer/include/rive/renderer/gl/render_context_gl_impl.hpp @@ -0,0 +1,306 @@ +/* + * Copyright 2022 Rive + */ + +#pragma once + +#include "rive/renderer/gl/gl_state.hpp" +#include "rive/renderer/gl/gl_utils.hpp" +#include "rive/renderer/render_context_helper_impl.hpp" +#include + +namespace rive +{ +class RiveRenderPath; +class RiveRenderPaint; +} // namespace rive + +namespace rive::gpu +{ +class RenderTargetGL; + +// OpenGL backend implementation of RenderContextImpl. +class RenderContextGLImpl : public RenderContextHelperImpl +{ +public: + struct ContextOptions + { + bool disablePixelLocalStorage = false; + bool disableFragmentShaderInterlock = false; + }; + + static std::unique_ptr MakeContext(const ContextOptions&); + static std::unique_ptr MakeContext() + { + return MakeContext(ContextOptions()); + } + + ~RenderContextGLImpl() override; + + const GLCapabilities& capabilities() const { return m_capabilities; } + + rcp makeRenderBuffer(RenderBufferType, + RenderBufferFlags, + size_t) override; + + rcp makeImageTexture(uint32_t width, + uint32_t height, + uint32_t mipLevelCount, + const uint8_t imageDataRGBAPremul[]) override; + + // Takes ownership of textureID and responsibility for deleting it. + rcp adoptImageTexture(uint32_t width, + uint32_t height, + GLuint textureID); + + // Called *after* the GL context has been modified externally. + // Re-binds Rive internal resources and invalidates the internal cache of GL + // state. + void invalidateGLState(); + + // Called *before* the GL context will be modified externally. + // Unbinds Rive internal resources before yielding control of the GL + // context. + void unbindGLInternalResources(); + + // Utility for rendering a texture to an MSAA framebuffer, since + // glBlitFramebuffer() doesn't support copying non-MSAA to MSAA. + void blitTextureToFramebufferAsDraw(GLuint textureID, + const IAABB& bounds, + uint32_t renderTargetHeight); + + GLState* state() const { return m_state.get(); } + +private: + class DrawProgram; + + // Manages how we implement pixel local storage in shaders. + class PixelLocalStorageImpl + { + public: + virtual void init(rcp) {} + + virtual bool supportsRasterOrdering(const GLCapabilities&) const = 0; + virtual bool supportsFragmentShaderAtomics( + const GLCapabilities&) const = 0; + + virtual void activatePixelLocalStorage(RenderContextGLImpl*, + const FlushDescriptor&) = 0; + virtual void deactivatePixelLocalStorage(RenderContextGLImpl*, + const FlushDescriptor&) = 0; + + // Depending on how we handle PLS atomic resolves, the + // PixelLocalStorageImpl may require certain flags. + virtual gpu::ShaderMiscFlags shaderMiscFlags( + const gpu::FlushDescriptor&, + gpu::DrawType) const + { + return gpu::ShaderMiscFlags::none; + } + + virtual void pushShaderDefines( + gpu::InterlockMode, + std::vector* defines) const = 0; + + void ensureRasterOrderingEnabled(RenderContextGLImpl*, + const gpu::FlushDescriptor&, + bool enabled); + + void barrier(const gpu::FlushDescriptor& desc) + { + assert(m_rasterOrderingEnabled == gpu::TriState::no); + onBarrier(desc); + } + + virtual ~PixelLocalStorageImpl() {} + +#ifndef NDEBUG + bool rasterOrderingKnownDisabled() const + { + return m_rasterOrderingEnabled == gpu::TriState::no; + } +#endif + + private: + virtual void onEnableRasterOrdering(bool enabled) {} + virtual void onBarrier(const gpu::FlushDescriptor& desc) {} + + gpu::TriState m_rasterOrderingEnabled = gpu::TriState::unknown; + }; + + class PLSImplEXTNative; + class PLSImplFramebufferFetch; + class PLSImplWebGL; + class PLSImplRWTexture; + + static std::unique_ptr MakePLSImplEXTNative( + const GLCapabilities&); + static std::unique_ptr MakePLSImplWebGL(); + static std::unique_ptr MakePLSImplRWTexture(); + + static std::unique_ptr MakeContext( + const char* rendererString, + GLCapabilities, + std::unique_ptr); + + RenderContextGLImpl(const char* rendererString, + GLCapabilities, + std::unique_ptr); + + std::unique_ptr makeUniformBufferRing( + size_t capacityInBytes) override; + std::unique_ptr makeStorageBufferRing( + size_t capacityInBytes, + gpu::StorageBufferStructure) override; + std::unique_ptr makeVertexBufferRing( + size_t capacityInBytes) override; + + void resizeGradientTexture(uint32_t width, uint32_t height) override; + void resizeTessellationTexture(uint32_t width, uint32_t height) override; + void resizeAtlasTexture(uint32_t width, uint32_t height) override; + + void flush(const FlushDescriptor&) override; + + // Issues the equivalent of glDrawElementsInstancedBaseInstanceEXT(), + // assuming no vertex attribs are instanced, indices are uint16_t, and + // applying workarounds for known driver bugs. + // + // If ANGLE_base_vertex_base_instance_shader_builtin is not supported, + // the intended value of gl_BaseInstance is supplied via + // baseInstanceUniformLocation. + void drawIndexedInstancedNoInstancedAttribs( + GLenum primitiveTopology, + uint32_t indexCount, + uint32_t baseIndex, + uint32_t instanceCount, + uint32_t baseInstance, + GLint baseInstanceUniformLocation); + + GLCapabilities m_capabilities; + + std::unique_ptr m_plsImpl; + + // Gradient texture rendering. + glutils::Program m_colorRampProgram; + glutils::VAO m_colorRampVAO; + glutils::Framebuffer m_colorRampFBO; + GLuint m_gradientTexture = 0; + + // Gaussian integral table for feathering. + glutils::Texture m_featherTexture; + + // Tessellation texture rendering. + glutils::Program m_tessellateProgram; + glutils::VAO m_tessellateVAO; + glutils::Buffer m_tessSpanIndexBuffer; + glutils::Framebuffer m_tessellateFBO; + GLuint m_tessVertexTexture = 0; + + // Atlas rendering. + class AtlasProgram + { + public: + void compile(GLuint vertexShaderID, + const char* defines[], + size_t numDefines, + const char* sources[], + size_t numSources, + const GLCapabilities&, + GLState* state); + + operator GLuint() const { return m_program; } + + GLint baseInstanceUniformLocation() const + { + return m_baseInstanceUniformLocation; + } + + private: + glutils::Program m_program = glutils::Program::Zero(); + GLint m_baseInstanceUniformLocation = -1; + }; + + glutils::Shader m_atlasVertexShader; + AtlasProgram m_atlasFillProgram; + AtlasProgram m_atlasStrokeProgram; + glutils::Texture m_atlasTexture = glutils::Texture::Zero(); + glutils::Framebuffer m_atlasFBO; + + // Wraps a compiled GL shader of draw_path.glsl or draw_image_mesh.glsl, + // either vertex or fragment, with a specific set of features enabled via + // #define. The set of features to enable is dictated by ShaderFeatures. + class DrawShader + { + public: + DrawShader(const DrawShader&) = delete; + DrawShader& operator=(const DrawShader&) = delete; + + DrawShader(RenderContextGLImpl* renderContextImpl, + GLenum shaderType, + gpu::DrawType drawType, + ShaderFeatures shaderFeatures, + gpu::InterlockMode interlockMode, + gpu::ShaderMiscFlags shaderMiscFlags); + + ~DrawShader() { glDeleteShader(m_id); } + + GLuint id() const { return m_id; } + + private: + GLuint m_id; + }; + + // Wraps a compiled and linked GL program of draw_path.glsl or + // draw_image_mesh.glsl, with a specific set of features enabled via + // #define. The set of features to enable is dictated by ShaderFeatures. + class DrawProgram + { + public: + DrawProgram(const DrawProgram&) = delete; + DrawProgram& operator=(const DrawProgram&) = delete; + DrawProgram(RenderContextGLImpl*, + gpu::DrawType, + gpu::ShaderFeatures, + gpu::InterlockMode, + gpu::ShaderMiscFlags); + ~DrawProgram(); + + GLuint id() const { return m_id; } + GLint baseInstanceUniformLocation() const + { + return m_baseInstanceUniformLocation; + } + + private: + DrawShader m_fragmentShader; + GLuint m_id; + GLint m_baseInstanceUniformLocation = -1; + const rcp m_state; + }; + + // Not all programs have a unique vertex shader, so we cache and reuse them + // where possible. + std::map m_vertexShaders; + std::map m_drawPrograms; + + // Vertex/index buffers for drawing paths. + glutils::VAO m_drawVAO; + glutils::Buffer m_patchVerticesBuffer; + glutils::Buffer m_patchIndicesBuffer; + glutils::VAO m_trianglesVAO; + + // Vertex/index buffers for drawing image rects. (Atomic mode only.) + glutils::VAO m_imageRectVAO; + glutils::Buffer m_imageRectVertexBuffer; + glutils::Buffer m_imageRectIndexBuffer; + + glutils::VAO m_imageMeshVAO; + glutils::VAO m_emptyVAO; + + // Used for blitting non-MSAA -> MSAA, which isn't supported by + // glBlitFramebuffer(). + glutils::Program m_blitAsDrawProgram = glutils::Program::Zero(); + + const rcp m_state; +}; +} // namespace rive::gpu diff --git a/third_party/rive_renderer/include/rive/renderer/gl/render_target_gl.hpp b/third_party/rive_renderer/include/rive/renderer/gl/render_target_gl.hpp new file mode 100644 index 0000000..cdbaa11 --- /dev/null +++ b/third_party/rive_renderer/include/rive/renderer/gl/render_target_gl.hpp @@ -0,0 +1,213 @@ +/* + * Copyright 2023 Rive + */ + +#pragma once + +#include "rive/renderer/gpu.hpp" +#include "rive/renderer/render_target.hpp" +#include "rive/renderer/gl/gles3.hpp" +#include "rive/renderer/gl/gl_utils.hpp" +#include "utils/lite_rtti.hpp" + +namespace rive::gpu +{ +class RenderContextGLImpl; + +class RenderTargetGL : public RenderTarget, + public ENABLE_LITE_RTTI(RenderTargetGL) +{ +public: + // Bind a framebuffer whose color attachment is the final rendering + // destination. When rendering to an external framebuffer, this is that same + // framebuffer. When rendering to a texture, it's an internal framebuffer + // that targets the texture. + virtual void bindDestinationFramebuffer(GLenum target) = 0; + + // Ensures backing textures for the internal PLS planes are allocated. + // Does not allocate an offscreen target texture. + // Does not allocate an "scratchColor" texture if InterlockMode is + // experimentalAtomics. + virtual void allocateInternalPLSTextures(gpu::InterlockMode) = 0; + + // Specifies which PLS planes to enable when a render target is bound. + enum class DrawBufferMask + { + color = 1 << 0, + clip = 1 << 1, + scratchColor = 1 << 2, + coverage = 1 << 3, + + rasterOrderingBuffers = color | coverage | clip | scratchColor, + atomicBuffers = color | coverage | clip, + }; + + // Binds a framebuffer with all allocated textures attached as color + // attachments. Used for clearing, blitting, and for rendering with + // EXT_shader_framebuffer_fetch. + // + // 'drawBufferCount' specifies the number of glDrawBuffers to enable, + // starting with GL_COLOR_ATTACHMENT0. Ignored for GL_READ_FRAMEBUFFER. + virtual void bindInternalFramebuffer(GLenum target, DrawBufferMask) = 0; + + // Binds a "headless" framebuffer to GL_DRAW_FRAMEBUFFER with no color + // attachments and no enabled draw buffers. + // + // If ARB_shader_image_load_store is supported, + // GL_FRAMEBUFFER_DEFAULT_WIDTH/HEIGHT will be the render target's + // dimensions. + // + // If ANGLE_shader_pixel_local_storage is supported, the allocated textures + // will also be bound to their corresponding pixel local storage planes. + virtual void bindHeadlessFramebuffer(const GLCapabilities&) = 0; + + // Binds the allocated textures to their corresponding GL image binding + // slots. + virtual void bindAsImageTextures(DrawBufferMask) = 0; + + enum class MSAAResolveAction + { + automatic, // The MSAA framebuffer will be resolved automatically. + framebufferBlit, // Caller must call glBlitFramebuffer() to resolve the + // MSAA framebuffer. + }; + + // Bind the renderTarget as a multisampled framebuffer. + // + // If the msaa framebuffer is offscreen, returns + // MSAAResolveAction::framebufferBlit, indicating that the caller must + // resolve it when done. + virtual MSAAResolveAction bindMSAAFramebuffer( + RenderContextGLImpl*, + int sampleCount, + const IAABB* preserveBounds = nullptr, + bool* isFBO0 = nullptr) = 0; + + // Binds the internal framebuffer as a texture that can be used to fetch the + // destination color (for blending). + virtual void bindInternalDstTexture(GLenum activeTexture) = 0; + +protected: + RenderTargetGL(uint32_t width, uint32_t height) : + RenderTarget(width, height) + {} +}; + +RIVE_MAKE_ENUM_BITSET(RenderTargetGL::DrawBufferMask); + +// GL render target that draws to an external texture provided by the client. +// +// Client must call setTargetTexture() before using this render target. +class TextureRenderTargetGL + : public LITE_RTTI_OVERRIDE(RenderTargetGL, TextureRenderTargetGL) +{ +public: + TextureRenderTargetGL(uint32_t width, uint32_t height) : + lite_rtti_override(width, height) + {} + ~TextureRenderTargetGL(); + + GLuint externalTextureID() const { return m_externalTextureID; } + + // Set the texture being rendered to. Ownership of this object is not + // assumed; the caller must delete it when done. + void setTargetTexture(GLuint externalTextureID) + { + m_externalTextureID = externalTextureID; + m_framebufferTargetAttachmentDirty = true; + m_framebufferTargetPLSBindingDirty = true; + } + + void bindDestinationFramebuffer(GLenum target) final + { + bindInternalFramebuffer(target, DrawBufferMask::color); + } + void allocateInternalPLSTextures(gpu::InterlockMode) final; + void bindInternalFramebuffer(GLenum target, DrawBufferMask) final; + void bindHeadlessFramebuffer(const GLCapabilities&) final; + void bindAsImageTextures(DrawBufferMask) final; + MSAAResolveAction bindMSAAFramebuffer(RenderContextGLImpl*, + int sampleCount, + const IAABB* preserveBounds, + bool* isFBO0) final; + void bindInternalDstTexture(GLenum activeTexture) final; + +private: + // Not owned or deleted by us. + GLuint m_externalTextureID = 0; + + glutils::Framebuffer m_framebufferID = glutils::Framebuffer::Zero(); + glutils::Texture m_coverageTexture = glutils::Texture::Zero(); + glutils::Texture m_clipTexture = glutils::Texture::Zero(); + glutils::Texture m_scratchColorTexture = glutils::Texture::Zero(); + glutils::Framebuffer m_headlessFramebuffer = glutils::Framebuffer::Zero(); + + // GL enables the first drawBuffer by default. + DrawBufferMask m_internalDrawBufferMask = DrawBufferMask::color; + + // For framebuffer color attachments. + bool m_framebufferTargetAttachmentDirty = false; + bool m_framebufferInternalAttachmentsDirty = false; + + // For ANGLE_shader_pixel_local_storage attachments. + bool m_framebufferTargetPLSBindingDirty = false; + bool m_framebufferInternalPLSBindingsDirty = false; + + glutils::Framebuffer m_msaaFramebuffer = glutils::Framebuffer::Zero(); + glutils::Renderbuffer m_msaaColorBuffer = glutils::Renderbuffer::Zero(); + glutils::Renderbuffer m_msaaDepthStencilBuffer = + glutils::Renderbuffer::Zero(); + int m_msaaFramebufferSampleCount = 0; +}; + +// GL render target that draws to an external, immutable FBO provided by the +// client. Since the external FBO is immutable and usually not readable either, +// it is almost always better to use TextureRenderTargetGL if possible. +class FramebufferRenderTargetGL + : public LITE_RTTI_OVERRIDE(RenderTargetGL, FramebufferRenderTargetGL) +{ +public: + FramebufferRenderTargetGL(uint32_t width, + uint32_t height, + GLuint externalFramebufferID, + uint32_t sampleCount) : + lite_rtti_override(width, height), + m_externalFramebufferID(externalFramebufferID), + m_sampleCount(sampleCount), + m_textureRenderTarget(width, height) + {} + + ~FramebufferRenderTargetGL(); + + uint32_t sampleCount() const { return m_sampleCount; } + + // Ensures a texture is allocated that mirrors our external FBO. (We can't + // modify the external FBO and usually can't read it either, so we often + // have no choice but to render to an offscreen texture first.) + void allocateOffscreenTargetTexture(); + + void bindDestinationFramebuffer(GLenum target) final; + void allocateInternalPLSTextures(gpu::InterlockMode) final; + void bindInternalFramebuffer(GLenum target, DrawBufferMask) final; + void bindHeadlessFramebuffer(const GLCapabilities&) final; + void bindAsImageTextures(DrawBufferMask) final; + MSAAResolveAction bindMSAAFramebuffer(RenderContextGLImpl*, + int sampleCount, + const IAABB* preserveBounds, + bool* isFBO0) final; + void bindInternalDstTexture(GLenum activeTexture) final; + +private: + // Ownership of this object is not assumed; the client must delete it when + // done. + const GLuint m_externalFramebufferID; + const uint32_t m_sampleCount; + + // Holds the PLS textures we might need. + TextureRenderTargetGL m_textureRenderTarget; + + // Created for m_textureRenderTarget if/when we can't render directly to the + // framebuffer. + glutils::Texture m_offscreenTargetTexture = glutils::Texture::Zero(); +}; +} // namespace rive::gpu diff --git a/third_party/rive_renderer/include/rive/renderer/gpu.hpp b/third_party/rive_renderer/include/rive/renderer/gpu.hpp new file mode 100644 index 0000000..d459d1f --- /dev/null +++ b/third_party/rive_renderer/include/rive/renderer/gpu.hpp @@ -0,0 +1,1725 @@ +/* + * Copyright 2022 Rive + */ + +#pragma once + +#include "rive/enum_bitset.hpp" +#include "rive/math/aabb.hpp" +#include "rive/math/mat2d.hpp" +#include "rive/math/vec2d.hpp" +#include "rive/math/simd.hpp" +#include "rive/shapes/paint/blend_mode.hpp" +#include "rive/shapes/paint/color.hpp" +#include "rive/renderer/trivial_block_allocator.hpp" +#include "rive/shapes/paint/image_sampler.hpp" + +namespace rive +{ +class GrInnerFanTriangulator; +class RenderBuffer; +} // namespace rive + +// This header defines constants and data structures for Rive's pixel local +// storage path rendering algorithm. +// +// Main algorithm: +// https://docs.google.com/document/d/19Uk9eyFxav6dNSYsI2ZyiX9zHU1YOaJsMB2sdDFVz6s/edit +// +// Batching multiple unique paths: +// https://docs.google.com/document/d/1DLrQimS5pbNaJJ2sAW5oSOsH6_glwDPo73-mtG5_zns/edit +// +// Batching strokes as well: +// https://docs.google.com/document/d/1CRKihkFjbd1bwT08ErMCP4fwSR7D4gnHvgdw_esY9GM/edit +namespace rive::gpu +{ +class Draw; +class Gradient; +class RenderContextImpl; +class RenderTarget; +class Texture; + +// Tessellate in parametric space until each segment is within 1/4 pixel of the +// true curve. +constexpr static int kParametricPrecision = 4; + +// Tessellate in polar space until the outset edge is within 1/8 pixel of the +// true stroke. +constexpr static int kPolarPrecision = 8; + +// Maximum supported numbers of tessellated segments in a single curve. +constexpr static uint32_t kMaxParametricSegments = 1023; +constexpr static uint32_t kMaxPolarSegments = 1023; + +// The Gaussian distribution is very blurry on the outer edges. Regardless of +// how wide a feather is, the polar segments never need to have a finer angle +// than this value. +constexpr static float FEATHER_POLAR_SEGMENT_MIN_ANGLE = math::PI / 16; + +// cos(FEATHER_MIN_POLAR_SEGMENT_ANGLE / 2) +constexpr static float COS_FEATHER_POLAR_SEGMENT_MIN_ANGLE_OVER_2 = + 0.99518472667f; + +// We allocate all our GPU buffers in rings. This ensures the CPU can prepare +// frames in parallel while the GPU renders them. +constexpr static int kBufferRingSize = 3; + +// Every coverage value in pixel local storage has an associated 16-bit path ID. +// This ID enables us to batch multiple paths together without having to clear +// the coverage buffer in between. This ID is implemented as an fp16, so the +// maximum path ID therefore cannot be NaN (or conservatively, all 5 exponent +// bits cannot be 1's). We also skip denormalized values (exp == 0) because they +// have been empirically unreliable on Android as ID values. +constexpr static int kLargestFP16BeforeExponentAll1s = (0x1f << 10) - 1; +constexpr static int kLargestDenormalizedFP16 = 1023; +constexpr static int MaxPathID(int granularity) +{ + // Floating point equality gets funky when the exponent bits are all 1's, so + // the largest pathID we can support is kLargestFP16BeforeExponentAll1s. + // + // The shader converts an integer path ID to fp16 as: + // + // (id + kLargestDenormalizedFP16) * granularity + // + // So the largest path ID we can support is as follows. + return kLargestFP16BeforeExponentAll1s / granularity - + kLargestDenormalizedFP16; +} + +// Each contour has its own unique ID, which it uses to index a data record +// containing per-contour information. This value is currently 16 bit. +constexpr static size_t kMaxContourID = 65535; +constexpr static uint32_t kContourIDMask = 0xffff; +static_assert((kMaxContourID & kContourIDMask) == kMaxContourID); + +// Tessellation is performed by rendering vertices into a data texture. These +// values define the dimensions of the tessellation data texture. +constexpr static size_t kTessTextureWidth = + 2048; // GL_MAX_TEXTURE_SIZE spec minimum on ES3/WebGL2. +constexpr static size_t kTessTextureWidthLog2 = 11; +static_assert(1 << kTessTextureWidthLog2 == kTessTextureWidth); + +// Gradients are implemented by sampling a horizontal ramp of pixels allocated +// in a global gradient texture. +constexpr static uint32_t kGradTextureWidth = 512; +constexpr static uint32_t kGradTextureWidthInSimpleRamps = + kGradTextureWidth / 2; + +// Depth/stencil parameters +constexpr static float DEPTH_MIN = 0.0f; +constexpr static float DEPTH_MAX = 1.0f; +constexpr static uint32_t STENCIL_CLEAR = 0u; + +// Backend-specific capabilities/workarounds and fine tunin// g. +struct PlatformFeatures +{ + // InterlockMode::rasterOrdering. + bool supportsRasterOrdering = false; + // InterlockMode::atomics. + bool supportsFragmentShaderAtomics = false; + // Experimental rendering mode selected by InterlockMode::clockwiseAtomic. + bool supportsClockwiseAtomicRendering = false; + // Use KHR_blend_equation_advanced in msaa mode? + bool supportsKHRBlendEquations = false; + // Required for @ENABLE_CLIP_RECT in msaa mode. + bool supportsClipPlanes = false; + bool avoidFlatVaryings = false; + // Vivo Y21 (PowerVR Rogue GE8320; OpenGL ES 3.2 build 1.13@5776728a) seems + // to hit some sort of reset condition that corrupts pixel local storage + // when rendering a complex feather. Provide a workaround that allows the + // implementation to opt in to always feathering to the atlas instead of + // rendering directly to the screen. + bool alwaysFeatherToAtlas = false; + // clipSpaceBottomUp specifies whether the top of the viewport, in clip + // coordinates, is at Y=+1 (OpenGL, Metal, D3D, WebGPU) or Y=-1 (Vulkan). + // + // framebufferBottomUp specifies whether "row 0" of the framebuffer is the + // bottom of the image (OpenGL) or the top (Metal, D3D, WebGPU, Vulkan). + // + // + // OpenGL + // (clipSpaceBottomUp=true, framebufferBottomUp=true) + // + // Rive Pixel Space Clip Space Framebuffer + // + // 0 -----------> ^ +1 ^ height + // | width | | + // | -1 | +1 | + // | ===> <------|------> ===> | + // | | | + // | | | width + // v height v -1 0 -----------> + // + // + // + // Metal/D3D/WebGPU + // (clipSpaceBottomUp=true, framebufferBottomUp=false) + // + // Rive Pixel Space Clip Space Framebuffer + // + // 0 -----------> ^ +1 0 -----------> + // | width | | width + // | -1 | +1 | + // | ===> <------|------> ===> | + // | | | + // | | | + // v height v -1 v height + // + // + // + // Vulkan + // (clipSpaceBottomUp=false, framebufferBottomUp=false) + // + // Rive Pixel Space Clip Space Framebuffer + // + // 0 -----------> ^ -1 0 -----------> + // | width | | width + // | -1 | +1 | + // | ===> <------|------> ===> | + // | | | + // | | | + // v height v +1 v height + // + bool clipSpaceBottomUp = false; + bool framebufferBottomUp = false; + // Backend cannot initialize PLS with typical clear/load APIs in atomic + // mode. Issue a "DrawType::atomicInitialize" draw instead. + bool atomicPLSMustBeInitializedAsDraw = false; + // Workaround for precision issues. Determines how far apart we space unique + // path IDs when they will be bit-casted to fp16. + uint8_t pathIDGranularity = 1; + // Maximum size (width or height) of a texture. + uint32_t maxTextureSize = 2048; + // Maximum length (in 32-bit uints) of the coverage buffer used for paths in + // clockwiseFill/atomic mode. 2^27 bytes is the minimum storage buffer size + // requirement in the Vulkan, GL, and D3D11 specs. Metal guarantees 256 MB. + size_t maxCoverageBufferLength = (1 << 27) / sizeof(uint32_t); +}; + +// Gradient color stops are implemented as a horizontal span of pixels in a +// global gradient texture. They are rendered by "GradientSpan" instances. +struct GradientSpan +{ + // x0Fixed and x1Fixed are normalized texel x coordinates, in the + // fixed-point range 0..65535. + RIVE_ALWAYS_INLINE void set(uint32_t x0Fixed, + uint32_t x1Fixed, + uint32_t y, + uint32_t flags, + ColorInt color0_, + ColorInt color1_) + { + assert(x0Fixed < 65536); + assert(x1Fixed < 65536); + horizontalSpan = (x1Fixed << 16) | x0Fixed; + yWithFlags = flags | y; + color0 = color0_; + color1 = color1_; + } + uint32_t horizontalSpan; + uint32_t yWithFlags; + uint32_t color0; + uint32_t color1; +}; +static_assert(sizeof(GradientSpan) == sizeof(uint32_t) * 4); +static_assert(256 % sizeof(GradientSpan) == 0); +// Metal requires vertex buffers to be 256-byte aligned. +constexpr static size_t kGradSpanBufferAlignmentInElements = + 256 / sizeof(GradientSpan); + +// Gradient spans are drawn as 1px-tall triangle strips with 3 sub-rectangles. +constexpr uint32_t GRAD_SPAN_TRI_STRIP_VERTEX_COUNT = 8; + +// Each curve gets tessellated into vertices. This is performed by rendering a +// horizontal span of positions and normals into the tessellation data texture, +// GP-GPU style. TessVertexSpan defines one instance of a horizontal +// tessellation span for rendering. +// +// Each span has an optional reflection, rendered right to left, with the same +// vertices in reverse order. These are used to draw mirrored patches with +// negative coverage when we have back-face culling enabled. This emits every +// triangle twice, once clockwise and once counterclockwise, and back-face +// culling naturally selects the triangle with the appropriately signed coverage +// (discarding the other). +struct TessVertexSpan +{ + RIVE_ALWAYS_INLINE void set(const Vec2D pts_[4], + Vec2D joinTangent_, + float y_, + int32_t x0, + int32_t x1, + uint32_t parametricSegmentCount, + uint32_t polarSegmentCount, + uint32_t joinSegmentCount, + uint32_t contourIDWithFlags_) + { + set(pts_, + joinTangent_, + y_, + x0, + x1, + std::numeric_limits::quiet_NaN(), // Discard the reflection. + -1, + -1, + parametricSegmentCount, + polarSegmentCount, + joinSegmentCount, + contourIDWithFlags_); + } + + RIVE_ALWAYS_INLINE void set(const Vec2D pts_[4], + Vec2D joinTangent_, + float y_, + int32_t x0, + int32_t x1, + float reflectionY_, + int32_t reflectionX0, + int32_t reflectionX1, + uint32_t parametricSegmentCount, + uint32_t polarSegmentCount, + uint32_t joinSegmentCount, + uint32_t contourIDWithFlags_) + { +#ifndef NDEBUG + // Write to an intermediate local object in debug mode, so we can check + // its values. (Otherwise we can't read it because mapped memory is + // write-only.) + TessVertexSpan localCopy; +#define LOCAL(VAR) localCopy.VAR +#else +#define LOCAL(VAR) VAR +#endif + RIVE_INLINE_MEMCPY(LOCAL(pts), pts_, sizeof(LOCAL(pts))); + LOCAL(joinTangent) = joinTangent_; + LOCAL(y) = y_; + LOCAL(reflectionY) = reflectionY_; + LOCAL(x0x1) = (x1 << 16 | (x0 & 0xffff)); + LOCAL(reflectionX0X1) = (reflectionX1 << 16 | (reflectionX0 & 0xffff)); + LOCAL(segmentCounts) = (joinSegmentCount << 20) | + (polarSegmentCount << 10) | + parametricSegmentCount; + LOCAL(contourIDWithFlags) = contourIDWithFlags_; +#undef LOCAL + + // Ensure we didn't lose any data from packing. + assert(localCopy.x0x1 << 16 >> 16 == x0); + assert(localCopy.x0x1 >> 16 == x1); + assert(localCopy.reflectionX0X1 << 16 >> 16 == reflectionX0); + assert(localCopy.reflectionX0X1 >> 16 == reflectionX1); + assert((localCopy.segmentCounts & 0x3ff) == parametricSegmentCount); + assert(((localCopy.segmentCounts >> 10) & 0x3ff) == polarSegmentCount); + assert(localCopy.segmentCounts >> 20 == joinSegmentCount); + +#ifndef NDEBUG + memcpy(this, &localCopy, sizeof(*this)); +#endif + } + + Vec2D pts[4]; // Cubic bezier curve. + Vec2D joinTangent; // Ending tangent of the join that follows the cubic. + float y; + float reflectionY; + int32_t x0x1; + int32_t reflectionX0X1; + uint32_t segmentCounts; // [joinSegmentCount, polarSegmentCount, + // parametricSegmentCount] + uint32_t contourIDWithFlags; // flags | contourID +}; +static_assert(sizeof(TessVertexSpan) == sizeof(float) * 16); +static_assert(256 % sizeof(TessVertexSpan) == 0); +// Metal requires vertex buffers to be 256-byte aligned. +constexpr static size_t kTessVertexBufferAlignmentInElements = + 256 / sizeof(TessVertexSpan); + +// Tessellation spans are drawn as two distinct, 1px-tall rectangles: the span +// and its reflection. +constexpr uint16_t kTessSpanIndices[4 * 3] = + {0, 1, 2, 2, 1, 3, 4, 5, 6, 6, 5, 7}; + +// ImageRects are a special type of non-overlapping antialiased draw that we +// only have to use in atomic mode. They allow us to bind a texture and draw it +// in its entirety in a single pass. +struct ImageRectVertex +{ + float x; + float y; + float aaOffsetX; + float aaOffsetY; +}; + +constexpr ImageRectVertex kImageRectVertices[12] = { + {0, 0, .0, -1}, + {1, 0, .0, -1}, + {1, 0, +1, .0}, + {1, 1, +1, .0}, + {1, 1, .0, +1}, + {0, 1, .0, +1}, + {0, 1, -1, .0}, + {0, 0, -1, .0}, + {0, 0, +1, +1}, + {1, 0, -1, +1}, + {1, 1, -1, -1}, + {0, 1, +1, -1}, +}; + +constexpr uint16_t kImageRectIndices[14 * 3] = { + 8, 0, 9, 9, 0, 1, 1, 2, 9, 9, 2, 10, 10, 2, 3, 3, 4, 10, 10, 4, 11, + 11, 4, 5, 5, 6, 11, 11, 6, 8, 8, 6, 7, 7, 0, 8, 9, 10, 8, 10, 8, 11, +}; + +enum class PaintType : uint32_t +{ + clipUpdate, // Update the clip buffer instead of drawing to the framebuffer. + solidColor, + linearGradient, + radialGradient, + image, +}; + +// Specifies the location of a simple or complex horizontal color ramp within +// the gradient texture. A simple color ramp is two texels wide, beginning at +// the specified row and column. A complex color ramp spans the entire width of +// the gradient texture, on the row: +// "GradTextureLayout::complexOffsetY + ColorRampLocation::row". +struct ColorRampLocation +{ + constexpr static uint16_t kComplexGradientMarker = 0xffff; + bool isComplex() const { return col == kComplexGradientMarker; } + uint16_t row; + uint16_t col; +}; + +// Most of a paint's information can be described in a single value. Gradients +// and images reference an additional Gradient* and Texture* respectively. +union SimplePaintValue +{ + ColorInt color = 0xff000000; // PaintType::solidColor + ColorRampLocation colorRampLocation; // Paintype::linear/radialGradient + float imageOpacity; // PaintType::image + uint32_t outerClipID; // Paintype::clipUpdate +}; +static_assert(sizeof(SimplePaintValue) == 4); + +// This class encapsulates a matrix that maps from _fragCoord to a space where +// the clipRect is the normalized rectangle: [-1, -1, +1, +1] +class ClipRectInverseMatrix +{ +public: + // When the clipRect inverse matrix is singular (e.g., all 0 in scale and + // skew), the shader uses tx and ty as fixed clip coverage values instead of + // finding edge distances. + constexpr static ClipRectInverseMatrix WideOpen() + { + return Mat2D{0, 0, 0, 0, 1, 1}; + } + constexpr static ClipRectInverseMatrix Empty() + { + return Mat2D{0, 0, 0, 0, 0, 0}; + } + + ClipRectInverseMatrix() = default; + + ClipRectInverseMatrix(const Mat2D& clipMatrix, const AABB& clipRect) + { + reset(clipMatrix, clipRect); + } + + void reset(const Mat2D& clipMatrix, const AABB& clipRect); + + const Mat2D& inverseMatrix() const { return m_inverseMatrix; } + +private: + constexpr ClipRectInverseMatrix(const Mat2D& inverseMatrix) : + m_inverseMatrix(inverseMatrix) + {} + Mat2D m_inverseMatrix; +}; + +// Specifies the height of the gradient texture, and the row at which we +// transition from simple color ramps to complex. +// +// This information is computed at flush time, once we know exactly how many +// color ramps of each type will be in the gradient texture. +struct GradTextureLayout +{ + uint32_t complexOffsetY; // Row of the first complex gradient. + float inverseHeight; // 1 / textureHeight +}; + +// Once all curves in a contour have been tessellated, we render the tessellated +// vertices in "patches" (aka specific instanced geometry). +// +// See: +// https://docs.google.com/document/d/19Uk9eyFxav6dNSYsI2ZyiX9zHU1YOaJsMB2sdDFVz6s/edit#heading=h.fa4kubk3vimk +// +// With strokes: +// https://docs.google.com/document/d/1CRKihkFjbd1bwT08ErMCP4fwSR7D4gnHvgdw_esY9GM/edit#heading=h.dcd0c58pxfs5 +// +// A single patch spans N tessellation segments, connecting N + 1 tessellation +// vertices. It is composed of a an AA border and fan triangles. The specifics +// of the fan triangles depend on the PatchType. +enum class PatchType +{ + // Patches fan around the contour midpoint. Outer edges are inset by ~1px, + // followed by a ~1px AA ramp. + midpointFan, + + // Similar to midpointFan, except AA ramps are split down the center and + // drawn with a ~1/2px outset AA ramp and a ~1/2px inset AA ramp that + // overlaps the inner tessellation and has negative coverage. + midpointFanCenterAA, + + // Patches only cover the AA ramps and interiors of bezier curves. The + // interior path triangles that connect the outer curves are triangulated on + // the CPU to eliminate overlap, and are drawn in a separate call. AA ramps + // are split down the center (on the same lines as the interior + // triangulation), and drawn with a ~1/2px outset AA ramp and a ~1/2px inset + // AA ramp that overlaps the inner tessellation and has negative coverage. A + // lone bowtie join is emitted at the end of the patch to tie the outer + // curves together. + outerCurves, +}; + +// When tessellating path vertices, we have the ability to generate the +// triangles wound in forward or reverse order. Depending on the path and the +// rendering algorithm, we will either want the triangles wound forward, +// reverse, or BOTH. +enum class ContourDirections +{ + forward, + reverse, + // Generate two tessellations of the contour: reverse first, then forward. + reverseThenForward, + // Generate two tessellations of the contour: forward first, then reverse. + forwardThenReverse, +}; +constexpr static bool ContourDirectionsAreDoubleSided( + ContourDirections contourDirections) +{ + return contourDirections >= ContourDirections::reverseThenForward; +} + +struct PatchVertex +{ + void set(float localVertexID_, + float outset_, + float fillCoverage_, + float params_) + { + localVertexID = localVertexID_; + outset = outset_; + fillCoverage = fillCoverage_; + params = params_; + setMirroredPosition(localVertexID_, outset_, fillCoverage_); + } + + // Patch vertices can have an optional, alternate position when mirrored. + // This is so we can ensure the diagonals inside the stroke line up on both + // versions of the patch (mirrored and not). + void setMirroredPosition(float localVertexID_, + float outset_, + float fillCoverage_) + { + mirroredVertexID = localVertexID_; + mirroredOutset = outset_; + mirroredFillCoverage = fillCoverage_; + } + + float localVertexID; // 0 or 1 -- which tessellated vertex of the two that + // we are connecting? + float outset; // Outset from the tessellated position, in the direction of + // the normal. + float fillCoverage; // 0..1 for the stroke. 1 all around for the triangles. + // (Coverage will be negated later for counterclockwise + // triangles.) + int32_t params; // "(patchSize << 2) | [flags::kStrokeVertex, + // flags::kFanVertex, + // flags::kFanMidpointVertex]" + float mirroredVertexID; + float mirroredOutset; + float mirroredFillCoverage; + int32_t padding = 0; +}; +static_assert(sizeof(PatchVertex) == sizeof(float) * 8); + +// # of tessellation segments spanned by the midpoint fan patch. +constexpr static uint32_t kMidpointFanPatchSegmentSpan = 8; + +// # of tessellation segments spanned by the outer curve patch. (In this +// particular instance, the final segment is a bowtie join with zero length and +// no fan triangle.) +constexpr static uint32_t kOuterCurvePatchSegmentSpan = 17; + +// Define vertex and index buffers that contain all the triangles in every +// PatchType. +constexpr static uint32_t kMidpointFanPatchVertexCount = + kMidpointFanPatchSegmentSpan * 4 /*Stroke and/or AA outer ramp*/ + + (kMidpointFanPatchSegmentSpan + 1) /*Curve fan*/ + + 1 /*Triangle from path midpoint*/; +constexpr static uint32_t kMidpointFanPatchBorderIndexCount = + kMidpointFanPatchSegmentSpan * 6 /*Stroke and/or AA outer ramp*/; +constexpr static uint32_t kMidpointFanPatchIndexCount = + kMidpointFanPatchBorderIndexCount /*Stroke and/or AA outer ramp*/ + + (kMidpointFanPatchSegmentSpan - 1) * 3 /*Curve fan*/ + + 3 /*Triangle from path midpoint*/; +constexpr static uint32_t kMidpointFanPatchBaseIndex = 0; +static_assert((kMidpointFanPatchBaseIndex * sizeof(uint16_t)) % 4 == 0); + +constexpr static uint32_t kMidpointFanCenterAAPatchVertexCount = + kMidpointFanPatchSegmentSpan * 4 * 2 /*Stroke and/or AA outer ramp*/ + + (kMidpointFanPatchSegmentSpan + 1) /*Curve fan*/ + + 1 /*Triangle from path midpoint*/; +constexpr static uint32_t kMidpointFanCenterAAPatchBorderIndexCount = + kMidpointFanPatchSegmentSpan * 12 /*Stroke and/or AA outer ramp*/; +constexpr static uint32_t kMidpointFanCenterAAPatchIndexCount = + kMidpointFanCenterAAPatchBorderIndexCount /*Stroke and/or AA outer ramp*/ + + (kMidpointFanPatchSegmentSpan - 1) * 3 /*Curve fan*/ + + 3 /*Triangle from path midpoint*/; +constexpr static uint32_t kMidpointFanCenterAAPatchBaseIndex = + kMidpointFanPatchBaseIndex + kMidpointFanPatchIndexCount; +static_assert((kMidpointFanCenterAAPatchBaseIndex * sizeof(uint16_t)) % 4 == 0); + +constexpr static uint32_t kOuterCurvePatchVertexCount = + kOuterCurvePatchSegmentSpan * 8 /*AA center ramp with bowtie*/ + + kOuterCurvePatchSegmentSpan /*Curve fan*/; +constexpr static uint32_t kOuterCurvePatchBorderIndexCount = + kOuterCurvePatchSegmentSpan * 12 /*AA center ramp with bowtie*/; +constexpr static uint32_t kOuterCurvePatchIndexCount = + kOuterCurvePatchBorderIndexCount /*AA center ramp with bowtie*/ + + (kOuterCurvePatchSegmentSpan - 2) * 3 /*Curve fan*/; +constexpr static uint32_t kOuterCurvePatchBaseIndex = + kMidpointFanCenterAAPatchBaseIndex + kMidpointFanCenterAAPatchIndexCount; +static_assert((kOuterCurvePatchBaseIndex * sizeof(uint16_t)) % 4 == 0); + +constexpr static uint32_t kPatchVertexBufferCount = + kMidpointFanPatchVertexCount + kMidpointFanCenterAAPatchVertexCount + + kOuterCurvePatchVertexCount; +constexpr static uint32_t kPatchIndexBufferCount = + kMidpointFanPatchIndexCount + kMidpointFanCenterAAPatchIndexCount + + kOuterCurvePatchIndexCount; +void GeneratePatchBufferData(PatchVertex[kPatchVertexBufferCount], + uint16_t indices[kPatchIndexBufferCount]); + +enum class DrawType : uint8_t +{ + // Fills, strokes, feathered strokes. + midpointFanPatches, + + // Feathered fills. + midpointFanCenterAAPatches, + + // Just the outer curves of a path; the interior will be triangulated. + outerCurvePatches, + + interiorTriangulation, + atlasBlit, + imageRect, + imageMesh, + + // Clear/init PLS data when we can't do it with existing clear/load APIs. + atomicInitialize, + + // Resolve PLS data to the final renderTarget color in atomic mode. + atomicResolve, + + // MSAA strokes can't be merged with fills because they require their own + // dedicated stencil settings. + msaaStrokes, + + // MSAA "fast" path: (effectively) single pass rendering. + msaaMidpointFanBorrowedCoverage, + msaaMidpointFans, + msaaMidpointFanStencilReset, + + // MSAA "slow" path: stencil-then-cover. + msaaMidpointFanPathsStencil, + msaaMidpointFanPathsCover, + + // MSAA interior triangulation is not currently supported, but this one draw + // type is included in order to support the "retrofittedcubictriangles" GM. + msaaOuterCubics, + + // Clear or intersect (based on DrawContents) the stencil clip bit. + msaaStencilClipReset, +}; + +constexpr static bool DrawTypeIsImageDraw(DrawType drawType) +{ + switch (drawType) + { + case DrawType::imageRect: + case DrawType::imageMesh: + return true; + case DrawType::midpointFanPatches: + case DrawType::midpointFanCenterAAPatches: + case DrawType::outerCurvePatches: + case DrawType::interiorTriangulation: + case DrawType::atlasBlit: + case DrawType::atomicInitialize: + case DrawType::atomicResolve: + case DrawType::msaaStrokes: + case DrawType::msaaMidpointFanBorrowedCoverage: + case DrawType::msaaMidpointFans: + case DrawType::msaaMidpointFanStencilReset: + case DrawType::msaaMidpointFanPathsStencil: + case DrawType::msaaMidpointFanPathsCover: + case DrawType::msaaOuterCubics: + case DrawType::msaaStencilClipReset: + return false; + } + RIVE_UNREACHABLE(); +} + +constexpr static uint32_t PatchIndexCount(DrawType drawType) +{ + switch (drawType) + { + case DrawType::midpointFanPatches: + return kMidpointFanPatchIndexCount; + case DrawType::midpointFanCenterAAPatches: + return kMidpointFanCenterAAPatchIndexCount; + case DrawType::outerCurvePatches: + return kOuterCurvePatchIndexCount; + case DrawType::msaaStrokes: + return kMidpointFanPatchBorderIndexCount; + case DrawType::msaaMidpointFanBorrowedCoverage: + case DrawType::msaaMidpointFans: + case DrawType::msaaMidpointFanStencilReset: + case DrawType::msaaMidpointFanPathsStencil: + case DrawType::msaaMidpointFanPathsCover: + return kMidpointFanPatchIndexCount - + kMidpointFanPatchBorderIndexCount; + case DrawType::msaaOuterCubics: + return kOuterCurvePatchIndexCount - + kOuterCurvePatchBorderIndexCount; + case DrawType::interiorTriangulation: + case DrawType::atlasBlit: + case DrawType::imageRect: + case DrawType::imageMesh: + case DrawType::atomicInitialize: + case DrawType::atomicResolve: + case DrawType::msaaStencilClipReset: + RIVE_UNREACHABLE(); + } + RIVE_UNREACHABLE(); +} + +constexpr static uint32_t PatchBaseIndex(DrawType drawType) +{ + switch (drawType) + { + case DrawType::midpointFanPatches: + case DrawType::msaaStrokes: + return kMidpointFanPatchBaseIndex; + case DrawType::midpointFanCenterAAPatches: + return kMidpointFanCenterAAPatchBaseIndex; + case DrawType::outerCurvePatches: + return kOuterCurvePatchBaseIndex; + case DrawType::msaaMidpointFanBorrowedCoverage: + case DrawType::msaaMidpointFans: + case DrawType::msaaMidpointFanStencilReset: + case DrawType::msaaMidpointFanPathsStencil: + case DrawType::msaaMidpointFanPathsCover: + return kMidpointFanPatchBaseIndex + + kMidpointFanPatchBorderIndexCount; + case DrawType::msaaOuterCubics: + return kOuterCurvePatchBaseIndex + kOuterCurvePatchBorderIndexCount; + case DrawType::interiorTriangulation: + case DrawType::atlasBlit: + case DrawType::imageRect: + case DrawType::imageMesh: + case DrawType::atomicInitialize: + case DrawType::atomicResolve: + case DrawType::msaaStencilClipReset: + RIVE_UNREACHABLE(); + } + RIVE_UNREACHABLE(); +} + +// Specifies what to do with the render target at the beginning of a flush. +enum class LoadAction +{ + clear, + preserveRenderTarget, + dontCare, +}; + +// Synchronization method for pixel local storage with overlapping fragments. +enum class InterlockMode +{ + rasterOrdering, + atomics, + // Use an experimental path rendering algorithm that utilizes atomics + // without barriers. This requires that we override all paths' fill rules + // (winding or even/odd) with a "clockwise" fill rule, where only regions + // with a positive winding number get filled. + clockwiseAtomic, + msaa, +}; +constexpr static size_t kInterlockModeCount = 4; + +// Low-level batch of scissored geometry for rendering to the offscreen atlas. +struct AtlasDrawBatch +{ + TAABB scissor; + uint32_t patchCount; + uint32_t basePatch; +}; + +// "Uber shader" features that can be #defined in a draw shader. +// This set is strictly limited to switches that don't *change* the behavior of +// the shader, i.e., turning them all on will enable all types Rive content, but +// simple content will still draw identically; we can turn a feature off if we +// know a batch doesn't need it for better performance. +enum class ShaderFeatures +{ + NONE = 0, + + // Whole program features. + ENABLE_CLIPPING = 1 << 0, + ENABLE_CLIP_RECT = 1 << 1, + ENABLE_ADVANCED_BLEND = 1 << 2, + ENABLE_FEATHER = 1 << 3, + + // Fragment-only features. + ENABLE_EVEN_ODD = 1 << 4, + ENABLE_NESTED_CLIPPING = 1 << 5, + ENABLE_HSL_BLEND_MODES = 1 << 6, +}; +RIVE_MAKE_ENUM_BITSET(ShaderFeatures) +constexpr static size_t kShaderFeatureCount = 7; +constexpr static ShaderFeatures kAllShaderFeatures = + static_cast((1 << kShaderFeatureCount) - 1); +constexpr static ShaderFeatures kVertexShaderFeaturesMask = + ShaderFeatures::ENABLE_CLIPPING | ShaderFeatures::ENABLE_CLIP_RECT | + ShaderFeatures::ENABLE_ADVANCED_BLEND | ShaderFeatures::ENABLE_FEATHER; + +constexpr static ShaderFeatures ShaderFeaturesMaskFor( + InterlockMode interlockMode) +{ + switch (interlockMode) + { + case InterlockMode::rasterOrdering: + return kAllShaderFeatures; + case InterlockMode::atomics: + return kAllShaderFeatures & ~ShaderFeatures::ENABLE_NESTED_CLIPPING; + case InterlockMode::clockwiseAtomic: + // TODO: shader features aren't fully implemented yet in + // clockwiseAtomic mode. + return ShaderFeatures::ENABLE_FEATHER; + case InterlockMode::msaa: + return ShaderFeatures::ENABLE_CLIP_RECT | + ShaderFeatures::ENABLE_ADVANCED_BLEND | + ShaderFeatures::ENABLE_HSL_BLEND_MODES; + } + RIVE_UNREACHABLE(); +} + +// Miscellaneous switches that *do* affect the behavior of the fragment shader. +// The renderContext may add some of these, and a backend may also add them to a +// shader key if it wants to implement the behavior. +enum class ShaderMiscFlags : uint32_t +{ + none = 0, + + // InterlockMode::atomics only (without advanced blend). Render color to a + // standard attachment instead of PLS. The backend implementation is + // responsible to turn on src-over blending. + fixedFunctionColorOutput = 1 << 0, + + // Override all paths' fill rules (winding or even/odd) with an experimental + // "clockwise" fill rule, where only regions with a positive winding number + // get filled. + clockwiseFill = 1 << 1, + + // clockwiseAtomic mode only. This shader is a prepass that only subtracts + // (counterclockwise) borrowed coverage from the coverage buffer. It doesn't + // output color or clip. + borrowedCoveragePrepass = 1 << 2, + + // DrawType::atomicInitialize only. Also store the color clear value to PLS + // when drawing a clear, in addition to clearing the other PLS planes. + storeColorClear = 1 << 3, + + // DrawType::atomicInitialize only. Swizzle the existing framebuffer + // contents from BGRA to RGBA. (For when this data had to get copied from a + // BGRA target.) + swizzleColorBGRAToRGBA = 1 << 4, + + // DrawType::atomicResolve only. Optimization for when rendering to an + // offscreen texture. + // + // It renders the final "resolve" operation directly to the renderTarget in + // a single pass, instead of (1) resolving the offscreen texture, and then + // (2) copying the offscreen texture to back the renderTarget. + coalescedResolveAndTransfer = 1 << 5, +}; +RIVE_MAKE_ENUM_BITSET(ShaderMiscFlags) + +constexpr static ShaderFeatures ShaderFeaturesMaskFor( + DrawType drawType, + InterlockMode interlockMode) +{ + ShaderFeatures mask = ShaderFeatures::NONE; + switch (drawType) + { + case DrawType::imageRect: + case DrawType::imageMesh: + case DrawType::atlasBlit: + if (interlockMode != gpu::InterlockMode::atomics) + { + mask = ShaderFeatures::ENABLE_CLIPPING | + ShaderFeatures::ENABLE_CLIP_RECT | + ShaderFeatures::ENABLE_ADVANCED_BLEND | + ShaderFeatures::ENABLE_HSL_BLEND_MODES; + break; + } + // Since atomic mode has to resolve previous draws, images need to + // consider the same shader features for path draws. + [[fallthrough]]; + case DrawType::midpointFanPatches: + case DrawType::midpointFanCenterAAPatches: + case DrawType::outerCurvePatches: + case DrawType::interiorTriangulation: + case DrawType::msaaStrokes: + case DrawType::msaaMidpointFanBorrowedCoverage: + case DrawType::msaaMidpointFans: + case DrawType::msaaMidpointFanStencilReset: + case DrawType::msaaMidpointFanPathsStencil: + case DrawType::msaaMidpointFanPathsCover: + case DrawType::msaaOuterCubics: + case DrawType::atomicResolve: + mask = kAllShaderFeatures; + break; + case DrawType::atomicInitialize: + assert(interlockMode == gpu::InterlockMode::atomics); + mask = ShaderFeatures::ENABLE_CLIPPING | + ShaderFeatures::ENABLE_ADVANCED_BLEND; + break; + case DrawType::msaaStencilClipReset: + mask = ShaderFeatures::NONE; + break; + } + return mask & ShaderFeaturesMaskFor(interlockMode); +} + +// Returns a unique value that can be used to key a shader. +uint32_t ShaderUniqueKey(DrawType, + ShaderFeatures, + InterlockMode, + ShaderMiscFlags); + +extern const char* GetShaderFeatureGLSLName(ShaderFeatures feature); + +// Flags indicating the contents of a draw. These don't affect shaders, but in +// msaa mode they are needed to break up batching. (msaa needs different +// stencil/blend state, depending on the DrawContents.) +// +// These also affect the draw sort order, so we attempt associate more expensive +// shader branch misses with higher flags. +enum class DrawContents +{ + none = 0, + opaquePaint = 1 << 0, + // Put feathered fills down low because they only need to draw different + // geometry, which isn't really a context switch at all. + featheredFill = 1 << 1, + stroke = 1 << 2, + clockwiseFill = 1 << 3, + nonZeroFill = 1 << 4, + evenOddFill = 1 << 5, + activeClip = 1 << 6, + clipUpdate = 1 << 7, + advancedBlend = 1 << 8, +}; +RIVE_MAKE_ENUM_BITSET(DrawContents) + +// A nestedClip draw updates the clip buffer while simultaneously clipping +// against the outerClip that is currently in the clip buffer. +constexpr static gpu::DrawContents kNestedClipUpdateMask = + (gpu::DrawContents::activeClip | gpu::DrawContents::clipUpdate); + +// Types of barriers that may be required between DrawBatches. +enum class BarrierFlags : uint8_t +{ + none = 0, + + // Pixel-local dependency in the PLS planes. (Atomic mode only.) Ensure + // prior draws complete at each pixel before beginning new ones. + plsAtomic = 1 << 0, + plsAtomicPostInit = 1 << 1, // Once after the initial clear/load. + plsAtomicPreResolve = 1 << 2, // Once before the final resolve. + + // Pixel-local dependency in the coverage buffer. (clockwiseAtomic mode + // only.) All "borrowed coverage" draws have now been issued. Ensure they + // complete at each pixel before beginning the "forward coverage" draws. + clockwiseBorrowedCoverage = 1 << 3, + + // The next DrawBatch needs to perform an advanced blend, but on the current + // hardware, we can only fetch the dst color via a separate texture. (MSAA + // mode only.) Prepare a dstColorTexture with the current framebuffer + // contents. If we're lucky, this will be a Vulkan input attachment. On GL, + // this is a literal MSAA resolve & blit to a separate texture. + dstColorTexture = 1 << 4, + + // Only prevent future DrawBatches from being combined with the current + // drawList. (No GPU dependencies.) + drawBatchBreak = 1 << 5, +}; +RIVE_MAKE_ENUM_BITSET(BarrierFlags); + +// Low-level batch of geometry to submit to the GPU. +struct DrawBatch +{ + DrawBatch(DrawType drawType_, + gpu::ShaderMiscFlags shaderMiscFlags_, + uint32_t elementCount_, + uint32_t baseElement_, + rive::BlendMode blendMode_, + rive::ImageSampler imageSampler_, + BarrierFlags barrierFlags_) : + drawType(drawType_), + shaderMiscFlags(shaderMiscFlags_), + elementCount(elementCount_), + baseElement(baseElement_), + firstBlendMode(blendMode_), + barriers(barrierFlags_), + imageSampler(imageSampler_) + {} + + const DrawType drawType; + const ShaderMiscFlags shaderMiscFlags; + uint32_t elementCount; // Vertex, index, or instance count. + uint32_t baseElement; // Base vertex, index, or instance. + rive::BlendMode firstBlendMode; + BarrierFlags barriers; // Barriers to execute before drawing this batch. + + DrawContents drawContents = DrawContents::none; + ShaderFeatures shaderFeatures = ShaderFeatures::NONE; + + // DrawType::imageRect and DrawType::imageMesh. + uint32_t imageDrawDataOffset = 0; + Texture* imageTexture = nullptr; + const ImageSampler imageSampler = ImageSampler::LinearClamp(); + + // DrawType::imageMesh. + RenderBuffer* vertexBuffer; + RenderBuffer* uvBuffer; + RenderBuffer* indexBuffer; + + // When shaders don't have a mechanism to read the framebuffer (e.g., + // WebGL msaa), this is a linked list of all the draws in the batch whose + // bounding boxes needs to be blitted to the "dstRead" texture before + // drawing. + const Draw* dstReadList = nullptr; +}; + +// Simple gradients only have 2 texels, so we write them to mapped texture +// memory from the CPU instead of rendering them. +struct TwoTexelRamp +{ + ColorInt color0, color1; +}; +static_assert(sizeof(TwoTexelRamp) == 8 * sizeof(uint8_t)); + +// Detailed description of exactly how a RenderContextImpl should bind its +// buffers and draw a flush. A typical flush is done in 4 steps: +// +// 1. Render the complex gradients from the gradSpanBuffer to the gradient +// texture (gradSpanCount, firstComplexGradSpan, complexGradRowsTop, +// complexGradRowsHeight). +// +// 2. Transfer the simple gradient texels from the simpleColorRampsBuffer to +// the top of the gradient texture (simpleGradTexelsWidth, +// simpleGradTexelsHeight, simpleGradDataOffsetInBytes, tessDataHeight). +// +// 3. Render the tessellation texture from the tessVertexSpanBuffer +// (tessVertexSpanCount, firstTessVertexSpan). +// +// 4. Execute the drawList, reading from the newly rendered resource textures. +// +struct FlushDescriptor +{ + RenderTarget* renderTarget = nullptr; + ShaderFeatures combinedShaderFeatures = ShaderFeatures::NONE; + InterlockMode interlockMode = InterlockMode::rasterOrdering; + // Atomic mode only: there a no advanced blend modes, so we can render + // directly to the main target with fixed function (src-over) blending. + bool atomicFixedFunctionColorOutput = false; + int msaaSampleCount = 0; // (0 unless interlockMode is msaa.) + + LoadAction colorLoadAction = LoadAction::clear; + ColorInt colorClearValue = 0; // When loadAction == LoadAction::clear. + uint32_t coverageClearValue = 0; + float depthClearValue = DEPTH_MAX; + ColorInt stencilClearValue = STENCIL_CLEAR; + + IAABB renderTargetUpdateBounds; // drawBounds, or renderTargetBounds if + // loadAction == LoadAction::clear. + + // Physical size of the atlas texture. + uint16_t atlasTextureWidth; + uint16_t atlasTextureHeight; + + // Boundaries of the content for this specific flush within the atlas + // texture. + uint16_t atlasContentWidth; + uint16_t atlasContentHeight; + + // Monotonically increasing prefix that gets appended to the most + // significant "32 - CLOCKWISE_COVERAGE_BIT_COUNT" bits of coverage buffer + // values. + // + // The coverage buffer is used in clockwiseAtomic mode. + // + // Increasing this prefix implicitly clears the entire coverage buffer to + // zero. + uint32_t coverageBufferPrefix = 0; + + // (clockwiseAtomic mode only.) We usually don't have to clear the coverage + // buffer because of coverageBufferPrefix, but when this value is true, the + // entire coverage buffer must be cleared to zero before rendering. + bool needsCoverageBufferClear = false; + + size_t flushUniformDataOffsetInBytes = 0; + uint32_t pathCount = 0; + size_t firstPath = 0; + size_t firstPaint = 0; + size_t firstPaintAux = 0; + uint32_t contourCount = 0; + size_t firstContour = 0; + uint32_t gradSpanCount = 0; + size_t firstGradSpan = 0; + uint32_t tessVertexSpanCount = 0; + size_t firstTessVertexSpan = 0; + uint32_t gradDataHeight = 0; + uint32_t tessDataHeight = 0; + // Override path fill rules with "clockwise". + bool clockwiseFillOverride = false; + bool hasTriangleVertices = false; + bool wireframe = false; +#ifdef WITH_RIVE_TOOLS + // Synthesize compilation failures to make sure the device handles them + // gracefully. (e.g., by falling back on an uber shader or at least not + // crashing.) Valid compilations may fail in the real world if the device is + // pressed for resources or in a bad state. + bool synthesizeCompilationFailures = false; +#endif + + // Command buffer that rendering commands will be added to. + // - VkCommandBuffer on Vulkan. + // - id on Metal. + // - Unused otherwise. + void* externalCommandBuffer = nullptr; + + // List of feathered fills (if any) that must be rendered to the atlas + // before the main render pass. + const AtlasDrawBatch* atlasFillBatches = nullptr; + size_t atlasFillBatchCount = 0; + + // List of feathered strokes (if any) that must be rendered to the atlas + // before the main render pass. + const AtlasDrawBatch* atlasStrokeBatches = nullptr; + size_t atlasStrokeBatchCount = 0; + + // List of draws in the main render pass. These are rendered directly to the + // renderTarget. + const BlockAllocatedLinkedList* drawList = nullptr; +}; + +// Returns the area of the (potentially non-rectangular) quadrilateral that +// results from transforming the given bounds by the given matrix. +float find_transformed_area(const AABB& bounds, const Mat2D&); + +// Convert a BlendMode to the tightly-packed range used by PLS shaders. +uint32_t ConvertBlendModeToPLSBlendMode(BlendMode riveMode); + +// Swizzles the byte order of ColorInt to litte-endian RGBA (the order expected +// by GLSL). +RIVE_ALWAYS_INLINE uint32_t SwizzleRiveColorToRGBA(ColorInt riveColor) +{ + return (riveColor & 0xff00ff00) | + (math::rotateleft32(riveColor, 16) & 0x00ff00ff); +} + +// Swizzles the byte order of ColorInt to litte-endian RGBA (the order expected +// by GLSL), and premultiplies alpha. +uint32_t SwizzleRiveColorToRGBAPremul(ColorInt riveColor); + +// Used for fields that are used to layout write-only mapped GPU memory. +// "volatile" to discourage the compiler from generating code that reads these +// values (e.g., don't let the compiler generate "x ^= x" instead of "x = 0"). +// "RIVE_MAYBE_UNUSED" to suppress -Wunused-private-field. +#define WRITEONLY RIVE_MAYBE_UNUSED volatile + +// Per-flush shared uniforms used by all shaders. +struct FlushUniforms +{ +public: + FlushUniforms(const FlushDescriptor&, const PlatformFeatures&); + + FlushUniforms(const FlushUniforms& other) { *this = other; } + + void operator=(const FlushUniforms& rhs) + { + memcpy(static_cast(this), + &rhs, + sizeof(*this) - sizeof(m_padTo256Bytes)); + } + + bool operator!=(const FlushUniforms& rhs) const + { + return memcmp(this, &rhs, sizeof(*this) - sizeof(m_padTo256Bytes)) != 0; + } + +private: + class InverseViewports + { + public: + InverseViewports() = default; + + InverseViewports(const FlushDescriptor&, const PlatformFeatures&); + + private: + // [complexGradientsY, tessDataY, renderTargetX, renderTargetY] + WRITEONLY float m_vals[4]; + }; + + WRITEONLY InverseViewports m_inverseViewports; + WRITEONLY uint32_t m_renderTargetWidth; + WRITEONLY uint32_t m_renderTargetHeight; + // Only used if clears are implemented as draws. + WRITEONLY uint32_t m_colorClearValue; + // Only used if clears are implemented as draws. + WRITEONLY uint32_t m_coverageClearValue; + // drawBounds, or renderTargetBounds if there is a clear. (Used by the + // "@RESOLVE_PLS" step in InterlockMode::atomics.) + WRITEONLY IAABB m_renderTargetUpdateBounds; + WRITEONLY Vec2D m_atlasTextureInverseSize; // 1 / [atlasWidth, atlasHeight] + WRITEONLY Vec2D m_atlasContentInverseViewport; // 2 / atlasContentBounds + // Monotonically increasing prefix that gets appended to the most + // significant "32 - CLOCKWISE_COVERAGE_BIT_COUNT" bits of coverage buffer + // values. (clockwiseAtomic mode only.) + WRITEONLY uint32_t m_coverageBufferPrefix; + // Spacing between adjacent path IDs (1 if IEEE compliant). + WRITEONLY uint32_t m_pathIDGranularity; + WRITEONLY float m_vertexDiscardValue; + WRITEONLY uint32_t m_wireframeEnabled; // Forces coverage to solid. + // Uniform blocks must be multiples of 256 bytes in size. + WRITEONLY uint8_t m_padTo256Bytes[256 - 80]; +}; +static_assert(sizeof(FlushUniforms) == 256); + +// Storage buffers are logically layed out as arrays of structs on the CPU, but +// the GPU shaders access them as arrays of basic types. We do it this way in +// order to be able to easily polyfill them with textures. +// +// This enum defines the underlying basic type that each storage buffer struct +// is layed on top of. +enum StorageBufferStructure +{ + uint32x4, + uint32x2, + float32x4, +}; + +constexpr static uint32_t StorageBufferElementSizeInBytes( + StorageBufferStructure bufferStructure) +{ + switch (bufferStructure) + { + case StorageBufferStructure::uint32x4: + return sizeof(uint32_t) * 4; + case StorageBufferStructure::uint32x2: + return sizeof(uint32_t) * 2; + case StorageBufferStructure::float32x4: + return sizeof(float) * 4; + } + RIVE_UNREACHABLE(); +} + +// Defines a transform from screen space into a region of the atlas. +// The atlas may have a different scale factor than the screen. +struct AtlasTransform +{ + float scaleFactor; + float translateX; + float translateY; +}; + +// Defines a sub-allocation for a path's coverage data within the +// renderContext's coverage buffer. (clockwiseAtomic mode only.) +struct CoverageBufferRange +{ + // Index of the first pixel of this allocation within the coverage buffer. + // Must be a multiple of 32*32. + uint32_t offset; + // Line width in pixels of the image in this coverage allocation. + // Must be a multiple of 32. + uint32_t pitch; + // Offset from screen space to image coords within the coverage allocation. + float offsetX; + float offsetY; +}; + +// High level structure of the "path" storage buffer. Each path has a unique +// data record on the GPU that is accessed from the vertex shader. +struct PathData +{ +public: + constexpr static StorageBufferStructure kBufferStructure = + StorageBufferStructure::uint32x4; + + void set(const Mat2D&, + float strokeRadius, + float featherRadius, + uint32_t zIndex, + const AtlasTransform&, + const CoverageBufferRange&); + +private: + WRITEONLY float m_matrix[6]; + // "0" indicates that the path is filled, not stroked. + WRITEONLY float m_strokeRadius; + WRITEONLY float m_featherRadius; + // InterlockMode::msaa. + WRITEONLY uint32_t m_zIndex; + // Only used when rendering coverage via the atlas. + WRITEONLY AtlasTransform m_atlasTransform; + // InterlockMode::clockwiseAtomic. + WRITEONLY CoverageBufferRange m_coverageBufferRange; +}; +static_assert(sizeof(PathData) == + StorageBufferElementSizeInBytes(PathData::kBufferStructure) * 4); +static_assert(256 % sizeof(PathData) == 0); +constexpr static size_t kPathBufferAlignmentInElements = 256 / sizeof(PathData); + +// High level structure of the "paint" storage buffer. Each path also has a data +// small record describing its paint at a high level. Complex paints (gradients, +// images, or any path with a clipRect) store additional rendering info in the +// PaintAuxData buffer. +struct PaintData +{ +public: + constexpr static StorageBufferStructure kBufferStructure = + StorageBufferStructure::uint32x2; + + void set(DrawContents singleDrawContents, + PaintType, + SimplePaintValue, + GradTextureLayout, + uint32_t clipID, + bool hasClipRect, + BlendMode); + +private: + WRITEONLY uint32_t m_params; // [clipID, flags, paintType] + union + { + WRITEONLY uint32_t m_color; // PaintType::solidColor + WRITEONLY float m_gradTextureY; // Paintype::linearGradient, + // Paintype::radialGradient + WRITEONLY float m_opacity; // PaintType::image + WRITEONLY uint32_t m_shiftedClipReplacementID; // PaintType::clipUpdate + }; +}; +static_assert(sizeof(PaintData) == + StorageBufferElementSizeInBytes(PaintData::kBufferStructure)); +static_assert(256 % sizeof(PaintData) == 0); +constexpr static size_t kPaintBufferAlignmentInElements = + 256 / sizeof(PaintData); + +// Structure of the "paintAux" storage buffer. Gradients, images, and clipRects +// store their details here, indexed by pathID. +struct PaintAuxData +{ +public: + constexpr static StorageBufferStructure kBufferStructure = + StorageBufferStructure::float32x4; + + void set(const Mat2D& viewMatrix, + PaintType, + SimplePaintValue, + const Gradient*, + const Texture*, + const ClipRectInverseMatrix*, + const RenderTarget*, + const gpu::PlatformFeatures&); + +private: + WRITEONLY float m_matrix[6]; // Maps _fragCoord to paint coordinates. + union + { + WRITEONLY float + m_gradTextureHorizontalSpan[2]; // Paintype::linearGradient, + // Paintype::radialGradient + WRITEONLY float m_imageTextureLOD; // PaintType::image + }; + + WRITEONLY float m_clipRectInverseMatrix[6]; // Maps _fragCoord to normalized + // clipRect coords. + WRITEONLY Vec2D m_inverseFwidth; // -1 / fwidth(matrix * _fragCoord) -- for + // antialiasing. +}; +static_assert(sizeof(PaintAuxData) == + StorageBufferElementSizeInBytes(PaintAuxData::kBufferStructure) * + 4); +static_assert(256 % sizeof(PaintAuxData) == 0); +constexpr static size_t kPaintAuxBufferAlignmentInElements = + 256 / sizeof(PaintAuxData); + +// High level structure of the "contour" storage buffer. Each contour of every +// path has a data record describing its info. +struct ContourData +{ +public: + constexpr static StorageBufferStructure kBufferStructure = + StorageBufferStructure::uint32x4; + + ContourData(Vec2D midpoint, uint32_t pathID, uint32_t vertexIndex0) : + m_midpoint(midpoint), m_pathID(pathID), m_vertexIndex0(vertexIndex0) + {} + +private: + WRITEONLY Vec2D + m_midpoint; // Midpoint of the curve endpoints in just this contour. + WRITEONLY uint32_t m_pathID; // ID of the path this contour belongs to. + WRITEONLY uint32_t m_vertexIndex0; // Index of the first tessellation vertex + // of the contour. +}; +static_assert(sizeof(ContourData) == + StorageBufferElementSizeInBytes(ContourData::kBufferStructure)); +static_assert(256 % sizeof(ContourData) == 0); +constexpr static size_t kContourBufferAlignmentInElements = + 256 / sizeof(ContourData); + +// Per-vertex data for shaders that draw triangles. +struct TriangleVertex +{ +public: + TriangleVertex() = default; + TriangleVertex(Vec2D point, int16_t weight, uint16_t pathID) : + m_point(point), + m_weight_pathID((static_cast(weight) << 16) | pathID) + {} + +#ifdef TESTING + Vec2D testing_point() const { return {m_point.x, m_point.y}; } + int32_t testing_weight_pathID() const { return m_weight_pathID; } +#endif + +private: + WRITEONLY Vec2D m_point; + WRITEONLY int32_t m_weight_pathID; // [(weight << 16 | pathID] +}; +static_assert(sizeof(TriangleVertex) == sizeof(float) * 3); + +// Per-draw uniforms used by image meshes. +struct ImageDrawUniforms +{ +public: + ImageDrawUniforms() = default; + + ImageDrawUniforms(const Mat2D&, + float opacity, + const ClipRectInverseMatrix*, + uint32_t clipID, + BlendMode, + uint32_t zIndex); + +private: + WRITEONLY float m_matrix[6]; + WRITEONLY float m_opacity; + WRITEONLY float m_padding = 0; + WRITEONLY float m_clipRectInverseMatrix[6]; + WRITEONLY uint32_t m_clipID; + WRITEONLY uint32_t m_blendMode; + WRITEONLY uint32_t m_zIndex; // gpu::InterlockMode::msaa only. + // Uniform blocks must be multiples of 256 bytes in size. + WRITEONLY uint8_t m_padTo256Bytes[256 - 68]; + + constexpr void staticChecks() + { + static_assert(offsetof(ImageDrawUniforms, m_matrix) % 16 == 0); + static_assert( + offsetof(ImageDrawUniforms, m_clipRectInverseMatrix) % 16 == 0); + static_assert(sizeof(ImageDrawUniforms) == 256); + } +}; + +#undef WRITEONLY + +// The maximum number of storage buffers we will ever use in a vertex or +// fragment shader. +constexpr static size_t kMaxStorageBuffers = 4; + +// If the backend doesn't support "kMaxStorageBuffers" a shader, we polyfill +// with textures. This function returns the dimensions to use for these +// textures. +std::tuple StorageTextureSize(size_t bufferSizeInBytes, + StorageBufferStructure); + +// If the backend doesn't support "kMaxStorageBuffers" in a shader, we polyfill +// with textures. The polyfill texture needs to be updated in entire rows at a +// time, meaning, its transfer buffer might need to be larger than requested. +// This function returns a size that is large enough to service a worst-case +// texture update. +size_t StorageTextureBufferSize(size_t bufferSizeInBytes, + StorageBufferStructure); + +// Should the triangulator emit triangles with negative winding, positive +// winding, or both? +enum class WindingFaces +{ + negative = 1 << 0, + positive = 1 << 1, + all = negative | positive, +}; +RIVE_MAKE_ENUM_BITSET(WindingFaces) + +// Represents a block of mapped GPU memory. Since it can be extremely expensive +// to read mapped memory, we use this class to enforce the write-only nature of +// this memory. +template class WriteOnlyMappedMemory +{ +public: + WriteOnlyMappedMemory() { reset(); } + WriteOnlyMappedMemory(T* ptr, size_t elementCount) + { + reset(ptr, elementCount); + } + + void reset() { reset(nullptr, 0); } + + void reset(T* ptr, size_t elementCount) + { + m_mappedMemory = ptr; + m_nextMappedItem = ptr; + m_mappingEnd = ptr + elementCount; + } + + using MapResourceBufferFn = + void* (RenderContextImpl::*)(size_t mapSizeInBytes); + void mapElements(RenderContextImpl* impl, + MapResourceBufferFn mapFn, + size_t elementCount) + { + assert(m_mappedMemory == nullptr); + void* ptr = (impl->*mapFn)(elementCount * sizeof(T)); + reset(reinterpret_cast(ptr), elementCount); + } + + using UnmapResourceBufferFn = + void (RenderContextImpl::*)(size_t mapSizeInBytes); + void unmapElements(RenderContextImpl* impl, + UnmapResourceBufferFn unmapFn, + size_t elementCount) + { + assert(m_mappedMemory != nullptr); + assert(m_mappingEnd - m_mappedMemory == elementCount); + (impl->*unmapFn)(elementCount * sizeof(T)); + reset(); + } + + operator bool() const { return m_mappedMemory; } + + // How many bytes have been written to the buffer? + size_t bytesWritten() const + { + return reinterpret_cast(m_nextMappedItem) - + reinterpret_cast(m_mappedMemory); + } + + size_t elementsWritten() const { return bytesWritten() / sizeof(T); } + + // Is there room to push() itemCount items to the buffer? + bool hasRoomFor(size_t itemCount) + { + return m_nextMappedItem + itemCount <= m_mappingEnd; + } + + // Append and write a new item to the buffer. In order to enforce the + // write-only requirement of a mapped buffer, these methods do not return + // any pointers to the client. + template + RIVE_ALWAYS_INLINE void emplace_back(Args&&... args) + { + new (&push()) T(std::forward(args)...); + } + template RIVE_ALWAYS_INLINE void set_back(Args&&... args) + { + push().set(std::forward(args)...); + } + void push_back_n(const T* values, size_t count) + { + T* dst = push(count); + if (values != nullptr) + { + memcpy(static_cast(dst), values, count * sizeof(T)); + } + } + void skip_back() { push(); } + +private: + RIVE_ALWAYS_INLINE T& push() + { + assert(hasRoomFor(1)); + return *m_nextMappedItem++; + } + RIVE_ALWAYS_INLINE T* push(size_t count) + { + assert(hasRoomFor(count)); + T* ret = m_nextMappedItem; + m_nextMappedItem += count; + return ret; + } + + T* m_mappedMemory; + T* m_nextMappedItem; + const T* m_mappingEnd; +}; + +// Utility for tracking booleans that may be unknown (e.g., lazily computed +// values, GL state, etc.) +enum class TriState +{ + no, + yes, + unknown +}; + +enum class StencilOp : uint8_t +{ + keep, + replace, + zero, + decrClamp, + incrWrap, + decrWrap +}; + +enum class StencilCompareOp : uint8_t +{ + less, + equal, + lessOrEqual, + notEqual, + always, +}; + +struct StencilFaceOps +{ + StencilOp failOp; + StencilOp passOp; + StencilOp depthFailOp; + StencilCompareOp compareOp; +}; + +enum class CullFace : uint8_t +{ + none, + clockwise, + counterclockwise, +}; + +// Blend equation to select for the fixed-function GPU pipeline (not our own +// in-shader blending). For now, the backend is free to decide whether it will +// use premultiplied alpha or not. +enum class BlendEquation : uint8_t +{ + // Hardware blend is disabled. + none = 0, + + // Core hardware blend equations supported on all platforms. + srcOver = static_cast(rive::BlendMode::srcOver), + plus = srcOver + 1, + max = plus + 1, + + // "Advanced" hardware blend equations. + // PlatformFeatures::supportsKHRBlendEquations is required. + screen = static_cast(rive::BlendMode::screen), + overlay = static_cast(rive::BlendMode::overlay), + darken = static_cast(rive::BlendMode::darken), + lighten = static_cast(rive::BlendMode::lighten), + colorDodge = static_cast(rive::BlendMode::colorDodge), + colorBurn = static_cast(rive::BlendMode::colorBurn), + hardLight = static_cast(rive::BlendMode::hardLight), + softLight = static_cast(rive::BlendMode::softLight), + difference = static_cast(rive::BlendMode::difference), + exclusion = static_cast(rive::BlendMode::exclusion), + multiply = static_cast(rive::BlendMode::multiply), + hue = static_cast(rive::BlendMode::hue), + saturation = static_cast(rive::BlendMode::saturation), + color = static_cast(rive::BlendMode::color), + luminosity = static_cast(rive::BlendMode::luminosity), +}; + +// Common pipeline state that applies to every low-level draw and every backend. +struct PipelineState +{ + bool depthTestEnabled; + bool depthWriteEnabled; + bool stencilTestEnabled; + bool stencilDoubleSided; + uint8_t stencilCompareMask; + uint8_t stencilWriteMask; + uint8_t stencilReference; + StencilFaceOps stencilFrontOps; + StencilFaceOps stencilBackOps; + CullFace cullFace; + BlendEquation blendEquation; + bool colorWriteEnabled; +}; + +void get_pipeline_state(const DrawBatch&, + const FlushDescriptor&, + const PlatformFeatures&, + PipelineState*); + +constexpr static PipelineState COLOR_ONLY_PIPELINE_STATE = { + .depthTestEnabled = false, + .depthWriteEnabled = false, + .stencilTestEnabled = false, + .stencilWriteMask = 0, + .cullFace = CullFace::none, + .blendEquation = BlendEquation::none, + .colorWriteEnabled = true, +}; + +constexpr static PipelineState ATLAS_FILL_PIPELINE_STATE = { + .depthTestEnabled = false, + .depthWriteEnabled = false, + .stencilTestEnabled = false, + .stencilWriteMask = 0, + .cullFace = CullFace::counterclockwise, + .blendEquation = BlendEquation::plus, + .colorWriteEnabled = true, +}; + +constexpr static PipelineState ATLAS_STROKE_PIPELINE_STATE = { + .depthTestEnabled = false, + .depthWriteEnabled = false, + .stencilTestEnabled = false, + .stencilWriteMask = 0, + .cullFace = CullFace::counterclockwise, + .blendEquation = BlendEquation::max, + .colorWriteEnabled = true, +}; + +float4 cast_f16_to_f32(uint16x4 x); +uint16x4 cast_f32_to_f16(float4); + +// These tables integrate the gaussian function, and its inverse, covering a +// spread of -FEATHER_TEXTURE_STDDEVS to +FEATHER_TEXTURE_STDDEVS. +constexpr static uint32_t GAUSSIAN_TABLE_SIZE = 512; +extern const uint16_t g_gaussianIntegralTableF16[GAUSSIAN_TABLE_SIZE]; +extern const uint16_t g_inverseGaussianIntegralTableF16[GAUSSIAN_TABLE_SIZE]; + +// Code to generate g_gaussianIntegralTableF16 and +// g_inverseGaussianIntegralTableF32. This is left in the codebase but #ifdef'd +// out in case we ever want to change any parameters of the built-in tables. +#if 0 +void generate_gausian_integral_table(float (&)[GAUSSIAN_TABLE_SIZE]); +void generate_inverse_gausian_integral_table(float (&)[GAUSSIAN_TABLE_SIZE]); +#endif +} // namespace rive::gpu diff --git a/third_party/rive_renderer/include/rive/renderer/gpu_resource.hpp b/third_party/rive_renderer/include/rive/renderer/gpu_resource.hpp new file mode 100644 index 0000000..23bcf41 --- /dev/null +++ b/third_party/rive_renderer/include/rive/renderer/gpu_resource.hpp @@ -0,0 +1,118 @@ +/* + * Copyright 2025 Rive + */ + +#pragma once + +#include "rive/refcnt.hpp" + +#include + +namespace rive::gpu +{ +class GPUResourceManager; + +// Base class for a GPU resource that needs to be kept alive until any in-flight +// command buffers that reference it have completed. +class GPUResource : public RefCnt +{ +public: + virtual ~GPUResource(); + + GPUResourceManager* manager() const { return m_manager.get(); } + +protected: + GPUResource(rcp manager) : m_manager(std::move(manager)) + {} + + const rcp m_manager; + +private: + friend class RefCnt; + + // Don't delete GPUResources immediately when their ref count reaches zero; + // instead wait until their safe frame number is reached. + void onRefCntReachedZero() const; +}; + +// A GPUResource that has been fully released, but whose underlying native +// resource may still be referenced by an in-flight command buffer. +struct ZombieResource +{ + ZombieResource(GPUResource* resource_, uint64_t lastFrameNumber_) : + resource(resource_), lastFrameNumber(lastFrameNumber_) + {} + + std::unique_ptr resource; + const uint64_t lastFrameNumber; // Frame number at which the underlying + // native resource was last used. +}; + +// Manages the lifecycle of GPUResources. When the refcount reaches zero, rather +// than deleting it immediately, this class places it in "purgatory" until its +// safe frame number is reached. +class GPUResourceManager : public RefCnt +{ +public: + virtual ~GPUResourceManager(); + + // Resource lifetime counters. Resources last used on or before + // 'safeFrameNumber' are safe to be released or recycled. + uint64_t currentFrameNumber() const { return m_currentFrameNumber; } + uint64_t safeFrameNumber() const { return m_safeFrameNumber; } + + // Purges released resources whose lastFrameNumber is on or before + // safeFrameNumber, and updates the monotonically increasing + // m_currentFrameNumber. + void advanceFrameNumber(uint64_t nextFrameNumber, uint64_t safeFrameNumber); + + // Called when a GPUResource has been fully released (refcount reaches 0). + // The underlying native resource won't actually be deleted until the + // resource's safe frame number is reached. + void onRenderingResourceReleased(GPUResource*); + + // Called prior to the client beginning its shutdown cycle, and after all + // command buffers from all frames have finished executing. After shutting + // down, we delete GPUResources immediately instead of going + // through m_resourcePurgatory. + void shutdown(); + +private: + // An m_currentFrameNumber of this value indicates we're in a shutdown cycle + // and resources should be deleted immediately upon release instead of going + // through m_resourcePurgatory. + constexpr static uint64_t SHUTDOWN_FRAME_NUMBER = 0xffffffffffffffff; + + // Resource lifetime counters. Resources last used on or before + // 'safeFrameNumber' are safe to be released or recycled. + uint64_t m_currentFrameNumber = 0; + uint64_t m_safeFrameNumber = 0; + + // Temporary container for GPUResource instances that have been fully + // released, but need to persist until their safe frame number is reached. + std::deque m_resourcePurgatory; +}; + +// Manual GPUResource lifecycle manager. Rather than allowing GPUResourceManager +// to vaccuum up resources, they may be placed in a pool instead, which will +// recycle them once their safeFrameNumber is reached. +class GPUResourcePool : public GPUResource +{ +public: + GPUResourcePool(rcp manager, size_t maxPoolSize) : + GPUResource(std::move(manager)), m_maxPoolCount(maxPoolSize) + {} + + // Returns a previously-recycled resource whose safe frame number has been + // reached, or null of no such resource exists. + rcp acquire(); + + // Places the given resouce back in the pool, where it waits until its safe + // frame number is reached. Refcount must be 1. + void recycle(rcp); + +private: + const size_t m_maxPoolCount; + std::deque m_pool; +}; +} // namespace rive::gpu diff --git a/third_party/rive_renderer/include/rive/renderer/metal/render_context_metal_impl.h b/third_party/rive_renderer/include/rive/renderer/metal/render_context_metal_impl.h new file mode 100644 index 0000000..01ca28c --- /dev/null +++ b/third_party/rive_renderer/include/rive/renderer/metal/render_context_metal_impl.h @@ -0,0 +1,250 @@ +/* + * Copyright 2023 Rive + */ + +#pragma once + +#include "rive/renderer/render_context_helper_impl.hpp" +#include "rive/shapes/paint/image_sampler.hpp" +#include +#include + +#ifndef RIVE_OBJC_NOP +#import +#endif + +namespace rive::gpu +{ +class BackgroundShaderCompiler; + +// Metal backend implementation of RenderTarget. +class RenderTargetMetal : public RenderTarget +{ +public: + ~RenderTargetMetal() override {} + + MTLPixelFormat pixelFormat() const { return m_pixelFormat; } + + bool compatibleWith(id texture) const + { + assert(texture.usage & MTLTextureUsageRenderTarget); + return width() == texture.width && height() == texture.height && + m_pixelFormat == texture.pixelFormat; + } + + void setTargetTexture(id texture); + id targetTexture() const { return m_targetTexture; } + +private: + friend class RenderContextMetalImpl; + + RenderTargetMetal(id, + MTLPixelFormat, + uint32_t width, + uint32_t height, + const PlatformFeatures&); + + // Lazily-allocated buffers for atomic mode. Unlike the memoryless textures, + // these buffers have actual physical storage that gets allocated the first + // time they're accessed. + id colorAtomicBuffer() + { + return m_colorAtomicBuffer != nil + ? m_colorAtomicBuffer + : m_colorAtomicBuffer = makeAtomicBuffer(); + } + id coverageAtomicBuffer() + { + return m_coverageAtomicBuffer != nil + ? m_coverageAtomicBuffer + : m_coverageAtomicBuffer = makeAtomicBuffer(); + } + id clipAtomicBuffer() + { + return m_clipAtomicBuffer != nil + ? m_clipAtomicBuffer + : m_clipAtomicBuffer = makeAtomicBuffer(); + } + id makeAtomicBuffer() + { + return [m_gpu newBufferWithLength:height() * width() * sizeof(uint32_t) + options:MTLResourceStorageModePrivate]; + } + + const id m_gpu; + const MTLPixelFormat m_pixelFormat; + + id m_targetTexture = nil; + + id m_coverageMemorylessTexture = nil; + id m_clipMemorylessTexture = nil; + id m_scratchColorMemorylessTexture = nil; + + id m_colorAtomicBuffer = nil; + id m_coverageAtomicBuffer = nil; + id m_clipAtomicBuffer = nil; +}; + +// Metal backend implementation of RenderContextImpl. +class RenderContextMetalImpl : public RenderContextHelperImpl +{ +public: + struct ContextOptions + { + // Wait for shaders to compile inline with rendering (causing jank), + // instead of compiling asynchronously in a background thread. + // (Primarily for testing.) + bool synchronousShaderCompilations = false; + + // (macOS only -- ignored on iOS). Override + // m_platformFeatures.supportsRasterOrdering to false, forcing us to + // always render in atomic mode. + bool disableFramebufferReads = false; + }; + + static std::unique_ptr MakeContext(id, + const ContextOptions&); + + static std::unique_ptr MakeContext(id gpu) + { + return MakeContext(gpu, ContextOptions()); + } + + ~RenderContextMetalImpl() override; + + id gpu() const { return m_gpu; } + + rcp makeRenderTarget(MTLPixelFormat, + uint32_t width, + uint32_t height); + + rcp makeRenderBuffer(RenderBufferType, + RenderBufferFlags, + size_t) override; + + rcp makeImageTexture(uint32_t width, + uint32_t height, + uint32_t mipLevelCount, + const uint8_t imageDataRGBAPremul[]) override; + + // Atomic mode requires a barrier between overlapping draws. We have to + // implement this barrier in various different ways, depending on which + // hardware we're on. + enum class AtomicBarrierType + { + // The hardware supports a normal fragment-fragment memory barrier. (Not + // supported on Apple-Silicon). + memoryBarrier, + + // Apple Silicon is very fast at raster ordering, and doesn't support + // fragment-fragment memory barriers anyway, so on this hardware we just + // use raster order groups in atomic mode. + rasterOrderGroup, + + // On very old hardware that can't support barriers, we just take a + // sledge hammer and break the entire render pass between overlapping + // draws. + // TODO: Is there a lighter way to accomplish this? + renderPassBreak, + }; + + struct MetalFeatures + { + AtomicBarrierType atomicBarrierType = + AtomicBarrierType::renderPassBreak; + }; + + const MetalFeatures& metalFeatures() const { return m_metalFeatures; } + +protected: + RenderContextMetalImpl(id, const ContextOptions&); + + std::unique_ptr makeUniformBufferRing( + size_t capacityInBytes) override; + std::unique_ptr makeStorageBufferRing( + size_t capacityInBytes, StorageBufferStructure) override; + std::unique_ptr makeVertexBufferRing( + size_t capacityInBytes) override; + +private: + // Renders paths to the main render target. + class DrawPipeline; + + void resizeGradientTexture(uint32_t width, uint32_t height) override; + void resizeTessellationTexture(uint32_t width, uint32_t height) override; + void resizeAtlasTexture(uint32_t width, uint32_t height) override; + + // Obtains an exclusive lock on the next buffer ring index, potentially + // blocking until the GPU has finished rendering with it. This ensures it is + // safe for the CPU to begin modifying the next buffers in our rings. + void prepareToFlush(uint64_t nextFrameNumber, + uint64_t safeFrameNumber) override; + + // Creates a MTLRenderCommandEncoder and sets the common state for PLS + // draws. + id makeRenderPassForDraws( + const gpu::FlushDescriptor&, + MTLRenderPassDescriptor*, + id, + gpu::ShaderMiscFlags baselineMiscFlags); + + // Returns the specific DrawPipeline for the given feature set, if it has + // been compiled. If it has not finished compiling yet, this method may + // return a (potentially slower) DrawPipeline that can draw a superset of + // the given features. + const DrawPipeline* findCompatibleDrawPipeline(gpu::DrawType, + gpu::ShaderFeatures, + const gpu::FlushDescriptor&, + gpu::ShaderMiscFlags); + + void flush(const FlushDescriptor&) override; + + void postFlush(const RenderContext::FlushResources&) override; + + const ContextOptions m_contextOptions; + const id m_gpu; + + MetalFeatures m_metalFeatures; + std::unique_ptr m_backgroundShaderCompiler; + id m_plsPrecompiledLibrary; // Many shaders come precompiled in + // a static library. + + // Renders color ramps to the gradient texture. + class ColorRampPipeline; + std::unique_ptr m_colorRampPipeline; + id m_gradientTexture = nullptr; + + // Gaussian integral table for feathering. + id m_featherTexture = nullptr; + + // Renders tessellated vertices to the tessellation texture. + class TessellatePipeline; + std::unique_ptr m_tessPipeline; + id m_tessSpanIndexBuffer = nullptr; + id m_tessVertexTexture = nullptr; + + // Atlas rendering. + class AtlasPipeline; + std::unique_ptr m_atlasFillPipeline; + std::unique_ptr m_atlasStrokePipeline; + id m_atlasTexture = nullptr; + + id m_imageSamplers[ImageSampler::MAX_SAMPLER_PERMUTATIONS]; + + std::unordered_map> m_drawPipelines; + + // Vertex/index buffers for drawing path patches. + id m_pathPatchVertexBuffer; + id m_pathPatchIndexBuffer; + + // Vertex/index buffers for drawing image rects. + // (gpu::InterlockMode::atomics only.) + id m_imageRectVertexBuffer; + id m_imageRectIndexBuffer; + + // Locks buffer contents until the GPU has finished rendering with them. + // Prevents the CPU from overriding data before the GPU is done with it. + std::mutex m_bufferRingLocks[kBufferRingSize]; + int m_bufferRingIdx = 0; +}; +} // namespace rive::gpu diff --git a/third_party/rive_renderer/include/rive/renderer/render_context.hpp b/third_party/rive_renderer/include/rive/renderer/render_context.hpp new file mode 100644 index 0000000..86723f9 --- /dev/null +++ b/third_party/rive_renderer/include/rive/renderer/render_context.hpp @@ -0,0 +1,931 @@ +/* + * Copyright 2022 Rive + */ + +#pragma once + +#include "rive/math/vec2d.hpp" +#include "rive/renderer/gpu.hpp" +#include "rive/renderer/rive_render_factory.hpp" +#include "rive/renderer/render_target.hpp" +#include "rive/renderer/sk_rectanizer_skyline.hpp" +#include "rive/renderer/trivial_block_allocator.hpp" +#include "rive/shapes/paint/color.hpp" +#include +#include + +class PushRetrofittedTrianglesGMDraw; +class RenderContextTest; + +namespace rive +{ +class RawPath; +class RiveRenderPaint; +class RiveRenderPath; +} // namespace rive + +namespace rive::gpu +{ +class GradientLibrary; +class IntersectionBoard; +class ImageMeshDraw; +class ImageRectDraw; +class StencilClipReset; +class Draw; +class Gradient; +class RenderContextImpl; +class PathDraw; + +// Used as a key for complex gradients. +class GradientContentKey +{ +public: + inline GradientContentKey(rcp gradient); + inline GradientContentKey(GradientContentKey&& other); + bool operator==(const GradientContentKey&) const; + const Gradient* gradient() const { return m_gradient.get(); } + +private: + rcp m_gradient; +}; + +// Hashes all stops and all colors in a complex gradient. +class DeepHashGradient +{ +public: + size_t operator()(const GradientContentKey&) const; +}; + +// Even though Draw is block-allocated, we still need to call releaseRefs() on +// each individual instance before releasing the block. This smart pointer +// guarantees we always call releaseRefs() (implementation in pls_draw.hpp). +struct DrawReleaseRefs +{ + void operator()(Draw* draw); +}; +using DrawUniquePtr = std::unique_ptr; + +// Top-level, API agnostic rendering context for RiveRenderer. This class +// manages all the GPU buffers, context state, and other resources required for +// Rive's pixel local storage path rendering algorithm. +class RenderContext : public RiveRenderFactory +{ +public: + RenderContext(std::unique_ptr); + ~RenderContext(); + + RenderContextImpl* impl() { return m_impl.get(); } + template T* static_impl_cast() + { + return static_cast(m_impl.get()); + } + + const gpu::PlatformFeatures& platformFeatures() const; + + // Options for controlling how and where a frame is rendered. + struct FrameDescriptor + { + uint32_t renderTargetWidth = 0; + uint32_t renderTargetHeight = 0; + LoadAction loadAction = LoadAction::clear; + ColorInt clearColor = 0; + // If nonzero, the number of MSAA samples to use. + // Setting this to a nonzero value forces msaa mode. + int msaaSampleCount = 0; + // Use atomic mode (preferred) or msaa instead of rasterOrdering. + bool disableRasterOrdering = false; + + // Testing flags. + bool wireframe = false; + bool fillsDisabled = false; + bool strokesDisabled = false; + // Override all paths' fill rules (winding or even/odd) to emulate + // clockwiseAtomic mode. + bool clockwiseFillOverride = false; +#ifdef WITH_RIVE_TOOLS + // Synthesize compilation failures to make sure the device handles them + // gracefully. (e.g., by falling back on an uber shader or at least not + // crashing.) Valid compilations may fail in the real world if the + // device is pressed for resources or in a bad state. + bool synthesizeCompilationFailures = false; +#endif + }; + + // Called at the beginning of a frame and establishes where and how it will + // be rendered. + // + // All rendering related calls must be made between beginFrame() and + // flush(). + void beginFrame(const FrameDescriptor&); + + const FrameDescriptor& frameDescriptor() const + { + assert(m_didBeginFrame); + return m_frameDescriptor; + } + + // True if bounds is empty or outside [0, 0, renderTargetWidth, + // renderTargetHeight]. + bool isOutsideCurrentFrame(const IAABB& pixelBounds); + + // True if the current frame supports draws with clipRects + // (clipRectInverseMatrix != null). If false, all clipping must be done with + // clipPaths. + bool frameSupportsClipRects() const; + + // If the frame doesn't support image paints, the client must draw images + // with pushImageRect(). If it DOES support image paints, the client CANNOT + // use pushImageRect(); it should draw images as rectangular paths with an + // image paint. + bool frameSupportsImagePaintForPaths() const; + + const gpu::InterlockMode frameInterlockMode() const + { + return m_frameInterlockMode; + } + + // Generates a unique clip ID that is guaranteed to not exist in the current + // clip buffer, and assigns a contentBounds to it. + // + // Returns 0 if a unique ID could not be generated, at which point the + // caller must issue a logical flush and try again. + uint32_t generateClipID(const IAABB& contentBounds); + + // Screen-space bounding box of the region inside the given clip. + const IAABB& getClipContentBounds(uint32_t clipID) + { + assert(m_didBeginFrame); + assert(!m_logicalFlushes.empty()); + return m_logicalFlushes.back()->getClipInfo(clipID).contentBounds; + } + + // Mark the given clip as being read from within a screen-space bounding + // box. + void addClipReadBounds(uint32_t clipID, const IAABB& bounds) + { + assert(m_didBeginFrame); + assert(!m_logicalFlushes.empty()); + return m_logicalFlushes.back()->addClipReadBounds(clipID, bounds); + } + + // Union of screen-space bounding boxes from all draws that read the given + // clip element. + const IAABB& getClipReadBounds(uint32_t clipID) + { + assert(m_didBeginFrame); + assert(!m_logicalFlushes.empty()); + return m_logicalFlushes.back()->getClipInfo(clipID).readBounds; + } + + // Get/set a "clip content ID" that uniquely identifies the current contents + // of the clip buffer. This ID is reset to 0 on every logical flush. + void setClipContentID(uint32_t clipID) + { + assert(m_didBeginFrame); + m_clipContentID = clipID; + } + + uint32_t getClipContentID() + { + assert(m_didBeginFrame); + return m_clipContentID; + } + + // Appends a list of high-level Draws to the current frame. + // Returns false if the draws don't fit within the current resource + // constraints, at which point the caller must issue a logical flush and try + // again. + [[nodiscard]] bool pushDraws(DrawUniquePtr draws[], size_t drawCount); + + // Records a "logical" flush, in that it builds up commands to break up the + // render pass and re-render the resource textures, but it won't submit any + // command buffers or rotate/synchronize the buffer rings. + void logicalFlush(); + + // GPU resources required to execute the GPU commands for a frame. + struct FlushResources + { + RenderTarget* renderTarget = nullptr; + + // Command buffer that rendering commands will be added to. + // - VkCommandBuffer on Vulkan. + // - id on Metal. + // - Unused otherwise. + void* externalCommandBuffer = nullptr; + + // Resource lifetime counters. Resources used during the upcoming flush + // will belong to 'currentFrameNumber'. Resources last used on or before + // 'safeFrameNumber' are safe to be released or recycled. + uint64_t currentFrameNumber = 0; + uint64_t safeFrameNumber = 0; + }; + + // Submits all GPU commands that have been built up since beginFrame(). + void flush(const FlushResources&); + + // Called when the client will stop rendering. Releases all CPU and GPU + // resources associated with this render context. + void releaseResources(); + + // Returns the context's TrivialBlockAllocator, which is automatically reset + // at the end of every frame. (Memory in this allocator is preserved between + // logical flushes.) + TrivialBlockAllocator& perFrameAllocator() + { + assert(m_didBeginFrame); + return m_perFrameAllocator; + } + + // Allocators for intermediate path processing buffers. + TrivialArrayAllocator& numChopsAllocator() + { + return m_numChopsAllocator; + } + TrivialArrayAllocator& chopVerticesAllocator() + { + return m_chopVerticesAllocator; + } + TrivialArrayAllocator>& tangentPairsAllocator() + { + return m_tangentPairsAllocator; + } + TrivialArrayAllocator& + polarSegmentCountsAllocator() + { + return m_polarSegmentCountsAllocator; + } + TrivialArrayAllocator& + parametricSegmentCountsAllocator() + { + return m_parametricSegmentCountsAllocator; + } + + // Allocates a trivially destructible object that will be automatically + // dropped at the end of the current frame. + template T* make(Args&&... args) + { + assert(m_didBeginFrame); + return m_perFrameAllocator.make(std::forward(args)...); + } + + // Backend-specific RiveRenderFactory implementation. + rcp makeRenderBuffer(RenderBufferType, + RenderBufferFlags, + size_t) override; + rcp decodeImage(Span) override; + +private: + friend class Draw; + friend class PathDraw; + friend class ImageRectDraw; + friend class ImageMeshDraw; + friend class StencilClipReset; + friend class ::PushRetrofittedTrianglesGMDraw; // For testing. + friend class ::RenderContextTest; // For testing. + + // Resets the CPU-side STL containers so they don't have unbounded growth. + void resetContainers(); + + // Throttled width/height of the atlas texture. If drawing to a render + // target larger than this, we may create a larger atlas anyway. + uint32_t atlasMaxSize() const + { + constexpr static uint32_t MAX_ATLAS_MAX_SIZE = 4096; + return std::min(platformFeatures().maxTextureSize, MAX_ATLAS_MAX_SIZE); + } + + // Defines the exact size of each of our GPU resources. Computed during + // flush(), based on LogicalFlush::ResourceCounters and + // LogicalFlush::LayoutCounters. + struct ResourceAllocationCounts + { + constexpr static int NUM_ELEMENTS = 14; + using VecType = simd::gvec; + + RIVE_ALWAYS_INLINE VecType toVec() const + { + static_assert(sizeof(*this) == sizeof(size_t) * NUM_ELEMENTS); + static_assert(sizeof(VecType) >= sizeof(*this)); + VecType vec; + RIVE_INLINE_MEMCPY(&vec, this, sizeof(*this)); + return vec; + } + + RIVE_ALWAYS_INLINE ResourceAllocationCounts(const VecType& vec) + { + static_assert(sizeof(*this) == sizeof(size_t) * NUM_ELEMENTS); + static_assert(sizeof(VecType) >= sizeof(*this)); + RIVE_INLINE_MEMCPY(this, &vec, sizeof(*this)); + } + + ResourceAllocationCounts() = default; + + size_t flushUniformBufferCount = 0; + size_t imageDrawUniformBufferCount = 0; + size_t pathBufferCount = 0; + size_t paintBufferCount = 0; + size_t paintAuxBufferCount = 0; + size_t contourBufferCount = 0; + size_t gradSpanBufferCount = 0; + size_t tessSpanBufferCount = 0; + size_t triangleVertexBufferCount = 0; + size_t gradTextureHeight = 0; + size_t tessTextureHeight = 0; + size_t atlasTextureWidth = 0; + size_t atlasTextureHeight = 0; + size_t coverageBufferLength = 0; // clockwiseAtomic mode only. + }; + + // Reallocates GPU resources and updates m_currentResourceAllocations. + // If forceRealloc is true, every GPU resource is allocated, even if the + // size would not change. + void setResourceSizes(ResourceAllocationCounts, bool forceRealloc = false); + + void mapResourceBuffers(const ResourceAllocationCounts&); + void unmapResourceBuffers(const ResourceAllocationCounts&); + + // Returns the next coverage buffer prefix to use in a logical flush. + // Sets needsCoverageBufferClear if the coverage buffer must be cleared in + // order to support the returned coverage buffer prefix. + // (clockwiseAtomic mode only.) + uint32_t incrementCoverageBufferPrefix(bool* needsCoverageBufferClear); + + const std::unique_ptr m_impl; + const size_t m_maxPathID; + + ResourceAllocationCounts m_currentResourceAllocations; + ResourceAllocationCounts m_maxRecentResourceRequirements; + double m_lastResourceTrimTimeInSeconds; + + // Per-frame state. + FrameDescriptor m_frameDescriptor; + gpu::InterlockMode m_frameInterlockMode; + gpu::ShaderFeatures m_frameShaderFeaturesMask; + RIVE_DEBUG_CODE(bool m_didBeginFrame = false;) + + // Clipping state. + uint32_t m_clipContentID = 0; + + // Monotonically increasing prefix that gets appended to the most + // significant "32 - CLOCKWISE_COVERAGE_BIT_COUNT" bits of coverage buffer + // values. + // + // Increasing this prefix implicitly clears the entire coverage buffer to + // zero. + // + // (clockwiseAtomic mode only.) + uint32_t m_coverageBufferPrefix = 0; + + // Used by LogicalFlushes for re-ordering high level draws. + std::vector m_indirectDrawList; + std::unique_ptr m_intersectionBoard; + + WriteOnlyMappedMemory m_flushUniformData; + WriteOnlyMappedMemory m_pathData; + WriteOnlyMappedMemory m_paintData; + WriteOnlyMappedMemory m_paintAuxData; + WriteOnlyMappedMemory m_contourData; + WriteOnlyMappedMemory m_gradSpanData; + WriteOnlyMappedMemory m_tessSpanData; + WriteOnlyMappedMemory m_triangleVertexData; + WriteOnlyMappedMemory m_imageDrawUniformData; + + // Simple allocator for trivially-destructible data that needs to persist + // until the current frame has completed. All memory in this allocator is + // dropped at the end of the every frame. + constexpr static size_t kPerFlushAllocatorInitialBlockSize = + 1024 * 1024; // 1 MiB. + TrivialBlockAllocator m_perFrameAllocator{ + kPerFlushAllocatorInitialBlockSize}; + + // Allocators for intermediate path processing buffers. + constexpr static size_t kIntermediateDataInitialStrokes = + 8192; // * 84 == 688 KiB. + constexpr static size_t kIntermediateDataInitialFillCurves = + 32768; // * 4 == 128 KiB. + TrivialArrayAllocator m_numChopsAllocator{ + kIntermediateDataInitialStrokes * 4}; // 4 byte per stroke curve. + TrivialArrayAllocator m_chopVerticesAllocator{ + kIntermediateDataInitialStrokes * 4}; // 32 bytes per stroke curve. + TrivialArrayAllocator> m_tangentPairsAllocator{ + kIntermediateDataInitialStrokes * 2}; // 32 bytes per stroke curve. + TrivialArrayAllocator + m_polarSegmentCountsAllocator{kIntermediateDataInitialStrokes * + 4}; // 16 bytes per stroke curve. + TrivialArrayAllocator + m_parametricSegmentCountsAllocator{ + kIntermediateDataInitialFillCurves}; // 4 bytes per fill curve. + + class TessellationWriter; + + // Manages a list of high-level Draws and their required resources. + // + // Since textures have hard size limits, we can't always fit an entire frame + // into one flush. It's rare for us to require more than one flush in a + // single frame, but for the times that we do, this flush logic is + // encapsulated in a nested class that can be built up into a list and + // executed the end of a frame. + class LogicalFlush + { + public: + LogicalFlush(RenderContext* parent); + + // Rewinds this flush object back to an empty state without shrinking + // any internal allocations held by CPU-side STL containers. + void rewind(); + + // Resets the CPU-side STL containers so they don't have unbounded + // growth. + void resetContainers(); + + const FrameDescriptor& frameDescriptor() const + { + return m_ctx->frameDescriptor(); + } + gpu::InterlockMode interlockMode() const + { + return m_ctx->frameInterlockMode(); + } + + // Access this flush's gpu::FlushDescriptor (which is not valid until + // layoutResources()). NOTE: Some fields in the FlushDescriptor + // (tessVertexSpanCount, hasTriangleVertices, drawList, and + // combinedShaderFeatures) do not become valid until after + // writeResources(). + const gpu::FlushDescriptor& desc() + { + assert(m_hasDoneLayout); + return m_flushDesc; + } + + // Generates a unique clip ID that is guaranteed to not exist in the + // current clip buffer. + // + // Returns 0 if a unique ID could not be generated, at which point the + // caller must issue a logical flush and try again. + uint32_t generateClipID(const IAABB& contentBounds); + + struct ClipInfo + { + ClipInfo(const IAABB& contentBounds_) : + contentBounds(contentBounds_) + {} + + // Screen-space bounding box of the region inside the clip. + const IAABB contentBounds; + + // Union of screen-space bounding boxes from all draws that read the + // clip. + // + // (Initialized with a maximally negative rectangle whose union with + // any other rectangle will be equal to that same rectangle.) + IAABB readBounds = {std::numeric_limits::max(), + std::numeric_limits::max(), + std::numeric_limits::min(), + std::numeric_limits::min()}; + }; + + const ClipInfo& getClipInfo(uint32_t clipID) + { + return getWritableClipInfo(clipID); + } + + // Mark the given clip as being read from within a screen-space bounding + // box. + void addClipReadBounds(uint32_t clipID, const IAABB& bounds); + + // Appends a list of high-level Draws to the flush. + // Returns false if the draws don't fit within the current resource + // constraints, at which point the context must append a new logical + // flush and try again. + [[nodiscard]] bool pushDraws(DrawUniquePtr draws[], size_t drawCount); + + // Running counts of data records required by Draws that need to be + // allocated in the render context's various GPU buffers. + struct ResourceCounters + { + constexpr static int NUM_ELEMENTS = 7; + using VecType = simd::gvec; + + VecType toVec() const + { + static_assert(sizeof(*this) == sizeof(size_t) * NUM_ELEMENTS); + static_assert(sizeof(VecType) >= sizeof(*this)); + VecType vec; + RIVE_INLINE_MEMCPY(&vec, this, sizeof(*this)); + return vec; + } + + ResourceCounters(const VecType& vec) + { + static_assert(sizeof(*this) == sizeof(size_t) * NUM_ELEMENTS); + static_assert(sizeof(VecType) >= sizeof(*this)); + RIVE_INLINE_MEMCPY(this, &vec, sizeof(*this)); + } + + ResourceCounters() = default; + + size_t midpointFanTessVertexCount = 0; + size_t outerCubicTessVertexCount = 0; + size_t pathCount = 0; + size_t contourCount = 0; + // lines, curves, lone joins, emulated caps, etc. + size_t maxTessellatedSegmentCount = 0; + size_t maxTriangleVertexCount = 0; + size_t imageDrawCount = 0; // imageRect or imageMesh. + }; + + // Additional counters for layout state that don't need to be tracked by + // individual draws. + struct LayoutCounters + { + uint32_t pathPaddingCount = 0; + uint32_t paintPaddingCount = 0; + uint32_t paintAuxPaddingCount = 0; + uint32_t contourPaddingCount = 0; + uint32_t gradSpanCount = 0; + uint32_t gradSpanPaddingCount = 0; + uint32_t maxGradTextureHeight = 0; + uint32_t maxTessTextureHeight = 0; + uint32_t maxAtlasWidth = 0; + uint32_t maxAtlasHeight = 0; + size_t maxCoverageBufferLength = 0; + }; + + // Allocates a horizontal span of texels in the gradient texture and + // schedules either a texture upload or a draw that fills it with the + // given gradient's color ramp. + // + // Fills out a ColorRampLocation record that tells the shader how to + // access the gradient. + // + // Returns false if the gradient texture is out of space, at which point + // the caller must issue a logical flush and try again. + [[nodiscard]] bool allocateGradient(const Gradient*, + gpu::ColorRampLocation*); + + // Allocates a rectangular region in the atlas for this draw to use, and + // registers a future callback to PathDraw::pushAtlasTessellation() + // where it will render its coverage data to this same region in the + // atlas. + // + // Attempts to leave a border of "desiredPadding" pixels surrounding the + // rectangular region, but the allocation may not be padded if the path + // is up against an edge. + bool allocateAtlasDraw(PathDraw*, + uint16_t drawWidth, + uint16_t drawHeight, + uint16_t desiredPadding, + uint16_t* x, + uint16_t* y, + TAABB* paddedRegion); + + // Reserves a range within the coverage buffer for a path to use in + // clockwiseAtomic mode. + // + // "length" is the length in pixels of this allocation and must be a + // multiple of 32*32, in order to support 32x32 tiling. + // + // Returns the offset of the allocated range within the coverage buffer, + // or -1 if there was not room. + size_t allocateCoverageBufferRange(size_t length); + + // Carves out space for this specific flush within the total frame's + // resource buffers and lays out the flush-specific resource textures. + // Updates the total frame running conters based on layout. + void layoutResources(const FlushResources&, + size_t logicalFlushIdx, + ResourceCounters* runningFrameResourceCounts, + LayoutCounters* runningFrameLayoutCounts); + + // Called after all flushes in a frame have done their layout and the + // render context has allocated and mapped its resource buffers. Writes + // the GPU data for this flush to the context's actively mapped resource + // buffers. + void writeResources(); + + // Reserves a span of "count" vertices from the "midpointFanPatches" + // section of the tessellation texture. + // + // This method must be called for a total count of precisely + // "m_resourceCounts.midpointFanTessVertexCount" vertices. + // + // The caller must fill these vertices in with TessellationWriter. + // + // Returns the index of the first vertex in the newly allocated span. + uint32_t allocateMidpointFanTessVertices(uint32_t count); + + // Reserves a span of "count" vertices from the "outerCurvePatches" + // section of the tessellation texture. + // + // This method must be called for a total count of precisely + // "m_resourceCounts.outerCubicTessVertexCount" vertices. + // + // The caller must fill these vertices in with TessellationWriter. + // + // Returns the index of the first vertex in the newly allocated span. + uint32_t allocateOuterCubicTessVertices(uint32_t count); + + // Allocates and initializes a record on the GPU for the given path. + // + // Returns a unique 16-bit "pathID" handle for this specific record. + // + // This method does not add the path to the draw list. The caller must + // define that draw specifically with a separate call to + // pushMidpointFanDraw() or pushOuterCubicsDraw(). + [[nodiscard]] uint32_t pushPath(const PathDraw* draw); + + // Pushes a contour record to the GPU that references the given path. + // + // "vertexIndex0" is the index within the tessellation where the first + // vertex of the contour resides. Shaders need this when the contour is + // closed. + // + // Returns a unique 16-bit "contourID" handle for this specific record. + // This ID may be or-ed with '*_CONTOUR_FLAG' bits from constants.glsl. + [[nodiscard]] uint32_t pushContour(uint32_t pathID, + Vec2D midpoint, + bool isStroke, + bool closed, + uint32_t vertexIndex0); + + // Writes padding vertices to the tessellation texture, with an invalid + // contour ID that is guaranteed to not be the same ID as any neighbors. + void pushPaddingVertices(uint32_t count, uint32_t tessLocation); + + // Pushes a "midpointFanPatches" draw to the list. Path, contour, and + // cubic data are pushed separately. + // + // Also adds the PathDraw to a dstRead list if one is + // required, and if this is the path's first subpass. + void pushMidpointFanDraw( + const PathDraw*, + gpu::DrawType, + uint32_t tessVertexCount, + uint32_t tessLocation, + gpu::ShaderMiscFlags = gpu::ShaderMiscFlags::none); + + // Pushes an "outerCurvePatches" draw to the list. Path, contour, and + // cubic data are pushed separately. + // + // Also adds the PathDraw to a dstRead list if one is + // required, and if this is the path's first subpass. + void pushOuterCubicsDraw( + const PathDraw*, + gpu::DrawType, + uint32_t tessVertexCount, + uint32_t tessLocation, + gpu::ShaderMiscFlags = gpu::ShaderMiscFlags::none); + + // Writes out triangle verties for the desired WindingFaces and pushes + // an "interiorTriangulation" draw to the list. + // Returns the number of vertices actually written. + size_t pushInteriorTriangulationDraw( + const PathDraw*, + uint32_t pathID, + gpu::WindingFaces, + gpu::ShaderMiscFlags = gpu::ShaderMiscFlags::none); + + // Pushes a screen-space rectangle to the draw list, whose pixel + // coverage is determined by the atlas region associated with the given + // pathID. + void pushAtlasBlit(PathDraw*, uint32_t pathID); + + // Pushes an "imageRect" to the draw list. + // This should only be used when we in atomic mode. Otherwise, images + // should be drawn as rectangular paths with an image paint. + void pushImageRectDraw(ImageRectDraw*); + + // Pushes an "imageMesh" draw to the list. + void pushImageMeshDraw(ImageMeshDraw*); + + // Pushes a "stencilClipReset" draw to the list. + void pushStencilClipResetDraw(StencilClipReset*); + + private: + friend class TessellationWriter; + + ClipInfo& getWritableClipInfo(uint32_t clipID); + + // Either appends a new drawBatch to m_drawList or merges into + // m_drawList.tail(). Updates the batch's ShaderFeatures according to + // the passed parameters. + DrawBatch& pushPathDraw(const PathDraw*, + DrawType, + gpu::ShaderMiscFlags, + uint32_t vertexCount, + uint32_t baseVertex); + DrawBatch& pushDraw(const Draw*, + DrawType, + gpu::ShaderMiscFlags, + gpu::PaintType, + uint32_t elementCount, + uint32_t baseElement); + + // Instance pointer to the outer parent class. + RenderContext* const m_ctx; + + // Running counts of GPU data records that need to be allocated for + // draws. + ResourceCounters m_resourceCounts; + + // Running count of combined prepasses and subpasses from every draw in + // m_draws. + int m_drawPassCount; + + // Simple gradients have one stop at t=0 and one stop at t=1. They're + // implemented with 2 texels. + std::unordered_map + m_simpleGradients; // [color0, color1] -> texelsIdx. + std::vector m_pendingSimpleGradDraws; + + // Complex gradients have stop(s) between t=0 and t=1. In theory they + // should be scaled to a ramp where every stop lands exactly on a pixel + // center, but for now we just always scale them to the entire gradient + // texture width. + std::unordered_map + m_complexGradients; // [colors[0..n], stops[0..n]] -> rowIdx + std::vector m_pendingComplexGradDraws; + + // Simple and complex gradients both get uploaded to the GPU as sets of + // "GradientSpan" instances. + size_t m_pendingGradSpanCount; + + std::vector m_clips; + + // High-level draw list. These get built into a low-level list of + // gpu::DrawBatch objects during writeResources(). + std::vector m_draws; + IAABB m_combinedDrawBounds; + + // Layout state. + uint32_t m_pathPaddingCount; + uint32_t m_paintPaddingCount; + uint32_t m_paintAuxPaddingCount; + uint32_t m_contourPaddingCount; + uint32_t m_gradSpanPaddingCount; + uint32_t m_midpointFanTessEndLocation; + uint32_t m_outerCubicTessEndLocation; + uint32_t m_outerCubicTessVertexIdx; + uint32_t m_midpointFanTessVertexIdx; + + gpu::GradTextureLayout m_gradTextureLayout; + + gpu::FlushDescriptor m_flushDesc; + + BlockAllocatedLinkedList m_drawList; + gpu::ShaderFeatures m_combinedShaderFeatures; + + // Most recent path and contour state. + uint32_t m_currentPathID; + uint32_t m_currentContourID; + + // Atlas for offscreen feathering. + std::unique_ptr m_atlasRectanizer; + uint32_t m_atlasMaxX = 0; + uint32_t m_atlasMaxY = 0; + std::vector m_pendingAtlasDraws; + + // Total coverage allocated via allocateCoverageBufferRange(). + // (clockwiseAtomic mode only.) + uint32_t m_coverageBufferLength = 0; + + // Barriers that must execute before pushing the next DrawBatch + // (pushPathDraw()/pushDraw()). If any barriers are pending, this also + // prevents DrawBatches from being combined with the existing drawList. + BarrierFlags m_pendingBarriers; + + // Stateful Z index of the current draw being pushed. Used by msaa mode + // to avoid double hits and to reverse-sort opaque paths front to back. + uint32_t m_currentZIndex; + + RIVE_DEBUG_CODE(bool m_hasDoneLayout = false;) + }; + + std::vector> m_logicalFlushes; + + // Writes out TessVertexSpans that are used to tessellate the vertices + // in a path. + class TessellationWriter + { + public: + // forwardTessLocation & mirroredTessLocation are allocated by + // allocate*TessVertices(). + // + // forwardTessLocation starts at the beginning of the vertex span + // and advances forward. + // + // mirroredTessLocation starts at the end of the vertex span and + // advances backward. + // + // If the ContourDirections are double sided, forwardTessVertexCount + // & mirroredTessVertexCount must both be equal, and + // forwardTessLocation & mirroredTessLocation must both be valid. + // Otherwise, one span or the other may be empty. + TessellationWriter(LogicalFlush* flush, + uint32_t pathID, + gpu::ContourDirections, + uint32_t forwardTessVertexCount, + uint32_t forwardTessLocation, + uint32_t mirroredTessVertexCount = 0, + uint32_t mirroredTessLocation = 0); + + ~TessellationWriter(); + + // Returns the index of the next vertex to be written. + // + // In the case of double-sided tessellations the next vertex gets + // tessellated twice, and either index will be identical. So we just + // return the next *forward* tessellation index when it's double sided. + uint32_t nextVertexIndex() + { + return m_contourDirections != gpu::ContourDirections::reverse + ? m_pathTessLocation + : m_pathMirroredTessLocation - 1; + } + + // Wrapper around LogicalFlush::pushContour(), with an additional + // padding option. + // + // The first curve of the contour will be pre-padded with + // 'paddingVertexCount' tessellation vertices, colocated at T=0. The + // caller must use this argument to align the end of the contour on + // a boundary of the patch size. (See gpu::PaddingToAlignUp().) + [[nodiscard]] uint32_t pushContour(Vec2D midpoint, + bool isStroke, + bool closed, + uint32_t paddingVertexCount); + + // Wites out (potentially wrapped) TessVertexSpan(s) that tessellate + // a cubic curve & join at the current tessellation location(s). + // Advances the tessellation location(s). + // + // The bottom 16 bits of contourIDWithFlags must match the most + // recent contourID returned by pushContour(), but it may also have + // extra '*_CONTOUR_FLAG' bits from constants.glsl + // + // An instance consists of a cubic curve with + // "parametricSegmentCount + polarSegmentCount" segments, followed + // by a join with "joinSegmentCount" segments, for a grand total of + // "parametricSegmentCount + polarSegmentCount + joinSegmentCount - + // 1" vertices. + // + // If a cubic has already been pushed to the current contour, pts[0] + // must be equal to the former cubic's pts[3]. + // + // "joinTangent" is the ending tangent of the join that follows the + // cubic. + void pushCubic(const Vec2D pts[4], + gpu::ContourDirections, + Vec2D joinTangent, + uint32_t parametricSegmentCount, + uint32_t polarSegmentCount, + uint32_t joinSegmentCount, + uint32_t contourIDWithFlags); + + // pushCubic() impl for forward tessellations. + RIVE_ALWAYS_INLINE void pushTessellationSpans( + const Vec2D pts[4], + Vec2D joinTangent, + uint32_t totalVertexCount, + uint32_t parametricSegmentCount, + uint32_t polarSegmentCount, + uint32_t joinSegmentCount, + uint32_t contourIDWithFlags); + + // pushCubic() impl for mirrored tessellations. + RIVE_ALWAYS_INLINE void pushMirroredTessellationSpans( + const Vec2D pts[4], + Vec2D joinTangent, + uint32_t totalVertexCount, + uint32_t parametricSegmentCount, + uint32_t polarSegmentCount, + uint32_t joinSegmentCount, + uint32_t contourIDWithFlags); + + // Functionally equivalent to "pushMirroredTessellationSpans(); + // pushTessellationSpans();", but packs each forward and mirrored + // pair into a single gpu::TessVertexSpan. + RIVE_ALWAYS_INLINE void pushDoubleSidedTessellationSpans( + const Vec2D pts[4], + Vec2D joinTangent, + uint32_t totalVertexCount, + uint32_t parametricSegmentCount, + uint32_t polarSegmentCount, + uint32_t joinSegmentCount, + uint32_t contourIDWithFlags); + + private: + LogicalFlush* const m_flush; + WriteOnlyMappedMemory& m_tessSpanData; + const uint32_t m_pathID; + const gpu::ContourDirections m_contourDirections; + uint32_t m_pathTessLocation; + uint32_t m_pathMirroredTessLocation; + // Padding to add to the next curve. + uint32_t m_nextCubicPaddingVertexCount = 0; + RIVE_DEBUG_CODE(uint32_t m_expectedPathTessEndLocation;) + RIVE_DEBUG_CODE(uint32_t m_expectedPathMirroredTessEndLocation;) + }; +}; +} // namespace rive::gpu diff --git a/third_party/rive_renderer/include/rive/renderer/render_context_helper_impl.hpp b/third_party/rive_renderer/include/rive/renderer/render_context_helper_impl.hpp new file mode 100644 index 0000000..259bde1 --- /dev/null +++ b/third_party/rive_renderer/include/rive/renderer/render_context_helper_impl.hpp @@ -0,0 +1,92 @@ +/* + * Copyright 2023 Rive + */ + +#pragma once + +#include "rive/renderer/render_context_impl.hpp" +#include "rive/renderer/buffer_ring.hpp" +#include + +namespace rive::gpu +{ +// RenderContextImpl that uses BufferRing to manage GPU resources. +class RenderContextHelperImpl : public RenderContextImpl +{ +public: + void resizeFlushUniformBuffer(size_t sizeInBytes) override; + void resizeImageDrawUniformBuffer(size_t sizeInBytes) override; + void resizePathBuffer(size_t sizeInBytes, + gpu::StorageBufferStructure) override; + void resizePaintBuffer(size_t sizeInBytes, + gpu::StorageBufferStructure) override; + void resizePaintAuxBuffer(size_t sizeInBytes, + gpu::StorageBufferStructure) override; + void resizeContourBuffer(size_t sizeInBytes, + gpu::StorageBufferStructure) override; + void resizeGradSpanBuffer(size_t sizeInBytes) override; + void resizeTessVertexSpanBuffer(size_t sizeInBytes) override; + void resizeTriangleVertexBuffer(size_t sizeInBytes) override; + + void* mapFlushUniformBuffer(size_t mapSizeInBytes) override; + void* mapImageDrawUniformBuffer(size_t mapSizeInBytes) override; + void* mapPathBuffer(size_t mapSizeInBytes) override; + void* mapPaintBuffer(size_t mapSizeInBytes) override; + void* mapPaintAuxBuffer(size_t mapSizeInBytes) override; + void* mapContourBuffer(size_t mapSizeInBytes) override; + void* mapGradSpanBuffer(size_t mapSizeInBytes) override; + void* mapTessVertexSpanBuffer(size_t mapSizeInBytes) override; + void* mapTriangleVertexBuffer(size_t mapSizeInBytes) override; + + void unmapFlushUniformBuffer(size_t mapSizeInBytes) override; + void unmapImageDrawUniformBuffer(size_t mapSizeInBytes) override; + void unmapPathBuffer(size_t mapSizeInBytes) override; + void unmapPaintBuffer(size_t mapSizeInBytes) override; + void unmapPaintAuxBuffer(size_t mapSizeInBytes) override; + void unmapContourBuffer(size_t mapSizeInBytes) override; + void unmapGradSpanBuffer(size_t mapSizeInBytes) override; + void unmapTessVertexSpanBuffer(size_t mapSizeInBytes) override; + void unmapTriangleVertexBuffer(size_t mapSizeInBytes) override; + + double secondsNow() const override + { + auto elapsed = std::chrono::steady_clock::now() - m_localEpoch; + return std::chrono::duration(elapsed).count(); + } + +protected: + BufferRing* flushUniformBufferRing() { return m_flushUniformBuffer.get(); } + BufferRing* imageDrawUniformBufferRing() + { + return m_imageDrawUniformBuffer.get(); + } + BufferRing* pathBufferRing() { return m_pathBuffer.get(); } + BufferRing* paintBufferRing() { return m_paintBuffer.get(); } + BufferRing* paintAuxBufferRing() { return m_paintAuxBuffer.get(); } + BufferRing* contourBufferRing() { return m_contourBuffer.get(); } + BufferRing* gradSpanBufferRing() { return m_gradSpanBuffer.get(); } + BufferRing* tessSpanBufferRing() { return m_tessSpanBuffer.get(); } + BufferRing* triangleBufferRing() { return m_triangleBuffer.get(); } + + virtual std::unique_ptr makeUniformBufferRing( + size_t capacityInBytes) = 0; + virtual std::unique_ptr makeStorageBufferRing( + size_t capacityInBytes, + gpu::StorageBufferStructure) = 0; + virtual std::unique_ptr makeVertexBufferRing( + size_t capacityInBytes) = 0; + +private: + std::unique_ptr m_flushUniformBuffer; + std::unique_ptr m_imageDrawUniformBuffer; + std::unique_ptr m_pathBuffer; + std::unique_ptr m_paintBuffer; + std::unique_ptr m_paintAuxBuffer; + std::unique_ptr m_contourBuffer; + std::unique_ptr m_gradSpanBuffer; + std::unique_ptr m_tessSpanBuffer; + std::unique_ptr m_triangleBuffer; + std::chrono::steady_clock::time_point m_localEpoch = + std::chrono::steady_clock::now(); +}; +} // namespace rive::gpu diff --git a/third_party/rive_renderer/include/rive/renderer/render_context_impl.hpp b/third_party/rive_renderer/include/rive/renderer/render_context_impl.hpp new file mode 100644 index 0000000..80eac26 --- /dev/null +++ b/third_party/rive_renderer/include/rive/renderer/render_context_impl.hpp @@ -0,0 +1,146 @@ +/* + * Copyright 2023 Rive + */ + +#pragma once + +#include "rive/renderer/render_context.hpp" +#include "rive/renderer/texture.hpp" + +namespace rive::gpu +{ +class Texture; + +// This class manages GPU buffers and isues the actual rendering commands from +// RenderContext. +class RenderContextImpl +{ +public: + virtual ~RenderContextImpl() {} + + const PlatformFeatures& platformFeatures() const + { + return m_platformFeatures; + } + + virtual rcp makeRenderBuffer(RenderBufferType, + RenderBufferFlags, + size_t) = 0; + + // Use platform apis to decode the image bytes and creates a texture if + // available. If not available leaving its default implementation will cause + // rive decoders to be used instead + virtual rcp platformDecodeImageTexture( + Span encodedBytes) + { + return nullptr; + }; + + // this is called in the case of the default Bitmap class being used to + // decode images so that it can be converted into a backend specific image. + virtual rcp makeImageTexture( + uint32_t width, + uint32_t height, + uint32_t mipLevelCount, + const uint8_t imageDataRGBAPremul[]) = 0; + + // Resize GPU buffers. These methods cannot fail, and must allocate the + // exact size requested. + // + // RenderContext takes care to minimize how often these methods are called, + // while also growing and shrinking the memory footprint to fit current + // usage. + // + // 'elementSizeInBytes' represents the size of one array element when the + // shader accesses this buffer as a storage buffer. + virtual void resizeFlushUniformBuffer(size_t sizeInBytes) = 0; + virtual void resizeImageDrawUniformBuffer(size_t sizeInBytes) = 0; + virtual void resizePathBuffer(size_t sizeInBytes, + gpu::StorageBufferStructure) = 0; + virtual void resizePaintBuffer(size_t sizeInBytes, + gpu::StorageBufferStructure) = 0; + virtual void resizePaintAuxBuffer(size_t sizeInBytes, + gpu::StorageBufferStructure) = 0; + virtual void resizeContourBuffer(size_t sizeInBytes, + gpu::StorageBufferStructure) = 0; + virtual void resizeGradSpanBuffer(size_t sizeInBytes) = 0; + virtual void resizeTessVertexSpanBuffer(size_t sizeInBytes) = 0; + virtual void resizeTriangleVertexBuffer(size_t sizeInBytes) = 0; + + // Perform any bookkeeping or other tasks that need to run before + // RenderContext begins accessing GPU resources for the flush. (Update + // counters, advance buffer pools, etc.) + // + // The provided resource lifetime counters communicate how the client is + // performing CPU-GPU synchronization. Resources used during the upcoming + // flush will belong to 'nextFrameNumber'. Resources last used on or before + // 'safeFrameNumber' are safe to be released or recycled. + virtual void prepareToFlush(uint64_t nextFrameNumber, + uint64_t safeFrameNumber) + {} + + // Map GPU buffers. (The implementation may wish to allocate the mappable + // buffers in rings, in order to avoid expensive synchronization with the + // GPU pipeline. See RenderContextBufferRingImpl.) + virtual void* mapFlushUniformBuffer(size_t mapSizeInBytes) = 0; + virtual void* mapImageDrawUniformBuffer(size_t mapSizeInBytes) = 0; + virtual void* mapPathBuffer(size_t mapSizeInBytes) = 0; + virtual void* mapPaintBuffer(size_t mapSizeInBytes) = 0; + virtual void* mapPaintAuxBuffer(size_t mapSizeInBytes) = 0; + virtual void* mapContourBuffer(size_t mapSizeInBytes) = 0; + virtual void* mapGradSpanBuffer(size_t mapSizeInBytes) = 0; + virtual void* mapTessVertexSpanBuffer(size_t mapSizeInBytes) = 0; + virtual void* mapTriangleVertexBuffer(size_t mapSizeInBytes) = 0; + + // Unmap GPU buffers. All buffers will be unmapped before flush(). + virtual void unmapFlushUniformBuffer(size_t mapSizeInBytes) = 0; + virtual void unmapImageDrawUniformBuffer(size_t mapSizeInBytes) = 0; + virtual void unmapPathBuffer(size_t mapSizeInBytes) = 0; + virtual void unmapPaintBuffer(size_t mapSizeInBytes) = 0; + virtual void unmapPaintAuxBuffer(size_t mapSizeInBytes) = 0; + virtual void unmapContourBuffer(size_t mapSizeInBytes) = 0; + virtual void unmapGradSpanBuffer(size_t mapSizeInBytes) = 0; + virtual void unmapTessVertexSpanBuffer(size_t mapSizeInBytes) = 0; + virtual void unmapTriangleVertexBuffer(size_t mapSizeInBytes) = 0; + + // Allocate resources that are updated and used during flush(). + virtual void resizeGradientTexture(uint32_t width, uint32_t height) = 0; + virtual void resizeTessellationTexture(uint32_t width, uint32_t height) = 0; + virtual void resizeAtlasTexture(uint32_t width, uint32_t height) + { + // Override this method to support atlas feathering. + assert(width == 0 && height == 0); + } + virtual void resizeCoverageBuffer(size_t sizeInBytes) + { + // Override this method to support the experimental clockwiseAtomic + // mode. + assert(sizeInBytes == 0); + } + + // Perform rendering in three steps: + // + // 1. Prepare the gradient texture: + // * Render the GradientSpan instances into the gradient texture. + // * Copy the TwoTexelRamp data directly into the gradient texture. + // + // 2. Render the TessVertexSpan instances into the tessellation texture. + // + // 3. Execute the draw list. (The Rive renderer shaders read the gradient + // and tessellation textures in order to do path rendering.) + // + // A single frame may have multiple logical flushes (and call flush() + // multiple times). + virtual void flush(const gpu::FlushDescriptor&) = 0; + + // Called after all logical flushes in a frame have completed. + virtual void postFlush(const RenderContext::FlushResources&) {} + + // Steady clock, used to determine when we should trim our resource + // allocations. + virtual double secondsNow() const = 0; + +protected: + PlatformFeatures m_platformFeatures; +}; +} // namespace rive::gpu diff --git a/third_party/rive_renderer/include/rive/renderer/render_target.hpp b/third_party/rive_renderer/include/rive/renderer/render_target.hpp new file mode 100644 index 0000000..20c6900 --- /dev/null +++ b/third_party/rive_renderer/include/rive/renderer/render_target.hpp @@ -0,0 +1,40 @@ +/* + * Copyright 2023 Rive + */ + +#pragma once + +#include "rive/refcnt.hpp" + +#include "rive/math/aabb.hpp" +#include "rive/math/simd.hpp" + +namespace rive::gpu +{ +// Wraps a backend-specific buffer that RenderContext draws into. +class RenderTarget : public RefCnt +{ +public: + virtual ~RenderTarget() {} + + uint32_t width() const { return m_width; } + uint32_t height() const { return m_height; } + uint2 size() const { return {m_width, m_height}; } + IAABB bounds() const + { + return IAABB{0, + 0, + static_cast(m_width), + static_cast(m_height)}; + } + +protected: + RenderTarget(uint32_t width, uint32_t height) : + m_width(width), m_height(height) + {} + +private: + uint32_t m_width; + uint32_t m_height; +}; +} // namespace rive::gpu diff --git a/third_party/rive_renderer/include/rive/renderer/rive_render_buffer.hpp b/third_party/rive_renderer/include/rive/renderer/rive_render_buffer.hpp new file mode 100644 index 0000000..2752258 --- /dev/null +++ b/third_party/rive_renderer/include/rive/renderer/rive_render_buffer.hpp @@ -0,0 +1,43 @@ +/* + * Copyright 2022 Rive + */ + +#pragma once + +#include "rive/renderer.hpp" +#include "rive/renderer/gpu.hpp" + +namespace rive +{ +// RenderBuffer with additional indices to track the "front" and "back" buffers, +// assuming a ring of gpu::kBufferRingSize buffers. +class RiveRenderBuffer : public RenderBuffer +{ +protected: + RiveRenderBuffer(RenderBufferType type, + RenderBufferFlags flags, + size_t sizeInBytes) : + RenderBuffer(type, flags, sizeInBytes) + {} + + // Returns the index of the buffer to map and update, prior to rendering. + int backBufferIdx() const { return m_backBufferIdx; } + + // Returns the index of the buffer to submit with rendering commands. + // Automatically advances the buffer ring if the RenderBuffer is dirty. + int frontBufferIdx() + { + if (checkAndResetDirty()) + { + // The update buffer is dirty. Advance the buffer ring. + m_frontBufferIdx = m_backBufferIdx; + m_backBufferIdx = (m_backBufferIdx + 1) % gpu::kBufferRingSize; + } + return m_frontBufferIdx; + } + +private: + int m_backBufferIdx = 0; + int m_frontBufferIdx = -1; +}; +} // namespace rive diff --git a/third_party/rive_renderer/include/rive/renderer/rive_render_factory.hpp b/third_party/rive_renderer/include/rive/renderer/rive_render_factory.hpp new file mode 100644 index 0000000..5e7cfee --- /dev/null +++ b/third_party/rive_renderer/include/rive/renderer/rive_render_factory.hpp @@ -0,0 +1,37 @@ +/* + * Copyright 2022 Rive + */ + +#pragma once + +#include "rive/factory.hpp" + +namespace rive +{ +// Partial rive::Factory implementation for the PLS objects that are +// backend-agnostic. +class RiveRenderFactory : public Factory +{ +public: + rcp makeLinearGradient(float sx, + float sy, + float ex, + float ey, + const ColorInt colors[], // [count] + const float stops[], // [count] + size_t count) override; + + rcp makeRadialGradient(float cx, + float cy, + float radius, + const ColorInt colors[], // [count] + const float stops[], // [count] + size_t count) override; + + rcp makeRenderPath(RawPath&, FillRule) override; + + rcp makeEmptyRenderPath() override; + + rcp makeRenderPaint() override; +}; +} // namespace rive diff --git a/third_party/rive_renderer/include/rive/renderer/rive_render_image.hpp b/third_party/rive_renderer/include/rive/renderer/rive_render_image.hpp new file mode 100644 index 0000000..38ced55 --- /dev/null +++ b/third_party/rive_renderer/include/rive/renderer/rive_render_image.hpp @@ -0,0 +1,44 @@ +/* + * Copyright 2023 Rive + */ + +#pragma once + +#include "rive/renderer/texture.hpp" + +namespace rive +{ +class RiveRenderImage : public LITE_RTTI_OVERRIDE(RenderImage, RiveRenderImage) +{ +public: + RiveRenderImage(rcp texture) : + RiveRenderImage(texture->width(), texture->height()) + { + resetTexture(std::move(texture)); + } + + rcp refTexture() const { return m_texture; } + const gpu::Texture* getTexture() const { return m_texture.get(); } + +protected: + RiveRenderImage(int width, int height) + { + m_Width = width; + m_Height = height; + } + + void resetTexture(rcp texture = nullptr) + { + assert(texture == nullptr || texture->width() == m_Width); + assert(texture == nullptr || texture->height() == m_Height); + m_texture = std::move(texture); + } + + // Used by the android runtime to send m_texture off to the worker thread to + // be deleted. + gpu::Texture* releaseTexture() { return m_texture.release(); } + +private: + rcp m_texture; +}; +} // namespace rive diff --git a/third_party/rive_renderer/include/rive/renderer/rive_renderer.hpp b/third_party/rive_renderer/include/rive/renderer/rive_renderer.hpp new file mode 100644 index 0000000..1fb6004 --- /dev/null +++ b/third_party/rive_renderer/include/rive/renderer/rive_renderer.hpp @@ -0,0 +1,129 @@ +/* + * Copyright 2022 Rive + */ + +#pragma once + +#include "rive/math/raw_path.hpp" +#include "rive/renderer.hpp" +#include "rive/renderer/gpu.hpp" +#include "rive/renderer/draw.hpp" +#include "rive/renderer/render_context.hpp" +#include + +namespace rive::gpu +{ +class RenderContext; +} // namespace rive::gpu + +namespace rive +{ +class GrInnerFanTriangulator; +class RiveRenderPath; +class RiveRenderPaint; + +// Renderer implementation for Rive's pixel local storage renderer. +class RiveRenderer : public Renderer +{ +public: + RiveRenderer(gpu::RenderContext*); + ~RiveRenderer() override; + + void save() override; + void restore() override; + void transform(const Mat2D& matrix) override; + void drawPath(RenderPath*, RenderPaint*) override; + void clipPath(RenderPath*) override; + void drawImage(const RenderImage*, + ImageSampler, + BlendMode, + float opacity) override; + void drawImageMesh(const RenderImage*, + ImageSampler, + rcp vertices_f32, + rcp uvCoords_f32, + rcp indices_u16, + uint32_t vertexCount, + uint32_t indexCount, + BlendMode, + float opacity) override; + + // Determines if a path is an axis-aligned rectangle that can be represented + // by rive::AABB. + static bool IsAABB(const RawPath&, AABB* result); + +#ifdef TESTING + bool hasClipRect() const + { + return m_stack.back().clipRectInverseMatrix != nullptr; + } + const AABB& getClipRect() const { return m_stack.back().clipRect; } + const Mat2D& getClipRectMatrix() const + { + return m_stack.back().clipRectMatrix; + } +#endif + +private: + void clipRectImpl(AABB, const RiveRenderPath* originalPath); + void clipPathImpl(const RiveRenderPath*); + + // Clips and pushes the given draw to m_context. If the clipped draw is too + // complex to be supported by the GPU buffers, even after a logical flush, + // then nothing is drawn. + void clipAndPushDraw(gpu::DrawUniquePtr); + + // Pushes any necessary clip updates to m_internalDrawBatch and sets the + // Draw's clipID and clipRectInverseMatrix, if any. Returns failure if the + // operation failed, at which point the caller should issue a logical flush + // and try again. + enum class ApplyClipResult + { + success, + failure, + clipEmpty, + }; + [[nodiscard]] ApplyClipResult applyClip(gpu::Draw*); + + struct RenderState + { + Mat2D matrix; + size_t clipStackHeight = 0; + AABB clipRect; + Mat2D clipRectMatrix; + const gpu::ClipRectInverseMatrix* clipRectInverseMatrix = nullptr; + bool clipIsEmpty = false; + }; + std::vector m_stack{1}; + + struct ClipElement + { + ClipElement() = default; + ClipElement(const Mat2D&, const RiveRenderPath*, FillRule); + ~ClipElement(); + + void reset(const Mat2D&, const RiveRenderPath*, FillRule); + bool isEquivalent(const Mat2D&, const RiveRenderPath*) const; + + Mat2D matrix; + uint64_t rawPathMutationID; + AABB pathBounds; + rcp path; + FillRule fillRule; // Bc RiveRenderPath fillRule can mutate during the + // artboard draw process. + uint32_t clipID; + }; + std::vector m_clipStack; + + gpu::RenderContext* const m_context; + + std::vector m_internalDrawBatch; + + // Path of the rectangle [0, 0, 1, 1]. Used to draw images. + rcp m_unitRectPath; + + // Used to build coarse path interiors for the "interior triangulation" + // algorithm. + RawPath m_scratchPath; +}; +} // namespace rive diff --git a/third_party/rive_renderer/include/rive/renderer/sk_rectanizer_skyline.hpp b/third_party/rive_renderer/include/rive/renderer/sk_rectanizer_skyline.hpp new file mode 100644 index 0000000..1b78d05 --- /dev/null +++ b/third_party/rive_renderer/include/rive/renderer/sk_rectanizer_skyline.hpp @@ -0,0 +1,85 @@ +/* + * Copyright 2014 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Initial import from + * skia:b4171f5ba83048039097bbc664eaa076190f6239@src/gpu/RectanizerSkyline.h + * + * Copyright 2025 Rive + */ + +#pragma once + +#include +#include + +namespace skgpu +{ +// Pack rectangles and track the current silhouette +// Based, in part, on Jukka Jylanki's work at http://clb.demon.fi +class RectanizerSkyline +{ +public: + RectanizerSkyline(int w, int h) : fWidth(w), fHeight(h) { this->reset(); } + + int width() const { return fWidth; } + int height() const { return fHeight; } + + void reset() + { + fAreaSoFar = 0; + fSkyline.clear(); + fSkyline.push_back(SkylineSegment{0, 0, this->width()}); + } + + bool addRect(int w, int h, int16_t* x, int16_t* y); + + bool addPaddedRect(int width, + int height, + int16_t padding, + int16_t* x, + int16_t* y) + { + if (this->addRect(width + 2 * padding, height + 2 * padding, x, y)) + { + *x += padding; + *y += padding; + return true; + } + return false; + } + + bool empty() const { return fAreaSoFar == 0; } + + float percentFull() const + { + return fAreaSoFar / ((float)this->width() * this->height()); + } + +private: + const int fWidth; + const int fHeight; + + struct SkylineSegment + { + int fX; + int fY; + int fWidth; + }; + + std::vector fSkyline; + + int32_t fAreaSoFar; + + // Can a width x height rectangle fit in the free space represented by + // the skyline segments >= 'skylineIndex'? If so, return true and fill in + // 'y' with the y-location at which it fits (the x location is pulled from + // 'skylineIndex's segment. + bool rectangleFits(int skylineIndex, int width, int height, int* y) const; + // Update the skyline structure to include a width x height rect located + // at x,y. + void addSkylineLevel(int skylineIndex, int x, int y, int width, int height); +}; +} // End of namespace skgpu diff --git a/third_party/rive_renderer/include/rive/renderer/stack_vector.hpp b/third_party/rive_renderer/include/rive/renderer/stack_vector.hpp new file mode 100644 index 0000000..736b43c --- /dev/null +++ b/third_party/rive_renderer/include/rive/renderer/stack_vector.hpp @@ -0,0 +1,79 @@ +/* + * Copyright 2024 Rive + */ + +#pragma once + +#include "rive/math/math_types.hpp" + +namespace rive +{ + +template class StackVector +{ +public: + void clear() { m_size = 0; } + + const T& operator[](uint32_t index) const + { + assert(index < m_size); + return m_data[index]; + } + + T& operator[](uint32_t index) + { + assert(index < m_size); + return m_data[index]; + } + + T& push_back(const T& ele) + { + T* ret = push(1); + *ret = ele; + return *ret; + } + + T* push_back_n(uint32_t numEles, const T* srcData) + { + T* dst = push(numEles); + if (srcData != nullptr) + { + memcpy(dst, srcData, numEles * sizeof(T)); + } + return dst; + } + + T* push_back_n(uint32_t numEles, const T& repeat) + { + T* dst = push(numEles); + for (uint32_t i = 0; i < numEles; ++i) + { + dst[i] = repeat; + } + return dst; + } + + const T* data() const { return m_data; } + const uint32_t size() const { return m_size; } + +private: + uint32_t m_size = 0; + T m_data[MAX_CAPACITY]; + + bool hasRoomFor(size_t itemCount) + { + return m_size + itemCount <= MAX_CAPACITY; + } + + T* push(size_t count) + { + assert(hasRoomFor(count)); + T* ret = &m_data[m_size]; + m_size += count; + return ret; + } + + static_assert(std::is_pod::value == + true); // Currently only supports POD types +}; +} // namespace rive diff --git a/third_party/rive_renderer/include/rive/renderer/texture.hpp b/third_party/rive_renderer/include/rive/renderer/texture.hpp new file mode 100644 index 0000000..ff3021c --- /dev/null +++ b/third_party/rive_renderer/include/rive/renderer/texture.hpp @@ -0,0 +1,31 @@ +/* + * Copyright 2023 Rive + */ + +#pragma once + +#include "rive/refcnt.hpp" +#include "rive/renderer/render_context_impl.hpp" + +namespace rive::gpu +{ +class Texture : public RefCnt +{ +public: + Texture(uint32_t width, uint32_t height); + virtual ~Texture() {} + + uint32_t width() const { return m_width; } + uint32_t height() const { return m_height; } + + // Quazi-unique identifier of the underlying GPU texture resource managed by + // this class. + uint32_t textureResourceHash() const { return m_textureResourceHash; } + +protected: + uint32_t m_width; + uint32_t m_height; + uint32_t m_textureResourceHash; +}; + +} // namespace rive::gpu diff --git a/third_party/rive_renderer/include/rive/renderer/trivial_block_allocator.hpp b/third_party/rive_renderer/include/rive/renderer/trivial_block_allocator.hpp new file mode 100644 index 0000000..a0aeb5b --- /dev/null +++ b/third_party/rive_renderer/include/rive/renderer/trivial_block_allocator.hpp @@ -0,0 +1,207 @@ +/* + * Copyright 2023 Rive + */ + +#pragma once + +#include "rive/math/math_types.hpp" +#include +#include +#include + +namespace rive +{ +// Fast block allocator for trivially-destructible types. +class TrivialBlockAllocator +{ +public: + TrivialBlockAllocator(size_t initialBlockSize) : + m_initialBlockSize(initialBlockSize) + { + m_blocks.push_back( + std::unique_ptr(new char[m_initialBlockSize])); + reset(); + } + + void reset() + { + m_fibMinus2 = 0; + m_fibMinus1 = 1; + m_blocks.resize(1); + m_currentBlockSize = m_initialBlockSize; + m_currentBlockUsage = 0; + } + + template void* alloc(size_t sizeInBytes) + { + uintptr_t start = reinterpret_cast(m_blocks.back().get()) + + m_currentBlockUsage; + size_t alignmentPad = + math::round_up_to_multiple_of(start) - start; + + // Ensure there is room for this allocation in our newest block, pushing + // a new one if needed. + if (m_currentBlockUsage + alignmentPad + sizeInBytes > + m_currentBlockSize) + { + // Grow with a fibonacci function. + size_t fib = m_fibMinus2 + m_fibMinus1; + m_fibMinus2 = m_fibMinus1; + m_fibMinus1 = fib; + + size_t blockSize = std::max(fib * m_initialBlockSize, + sizeInBytes + AlignmentInBytes - 1); + m_blocks.push_back(std::unique_ptr(new char[blockSize])); + m_currentBlockSize = blockSize; + m_currentBlockUsage = 0; + + start = reinterpret_cast(m_blocks.back().get()); + alignmentPad = + math::round_up_to_multiple_of(start) - start; + } + + char* ret = &m_blocks.back()[m_currentBlockUsage + alignmentPad]; + m_currentBlockUsage += alignmentPad + sizeInBytes; + assert((reinterpret_cast(ret) % AlignmentInBytes) == 0); + assert(ret + sizeInBytes <= m_blocks.back().get() + m_currentBlockSize); + return ret; + } + + void rewindLastAllocation(size_t rewindSizeInBytes) + { + assert(rewindSizeInBytes <= m_currentBlockUsage); + m_currentBlockUsage -= rewindSizeInBytes; + } + + template T* make(Args&&... args) + { + // We don't call destructors on objects that get allocated here. We just + // free the blocks at the end. So objects must be trivially + // destructible. + static_assert(std::is_trivially_destructible::value); + return new (alloc(sizeof(T))) + T(std::forward(args)...); + } + + template T* makePODArray(size_t count) + { + static_assert(std::is_pod::value); + return reinterpret_cast(alloc(count * sizeof(T))); + } + +private: + const size_t m_initialBlockSize; + + // Grow block sizes using a fibonacci function. + size_t m_fibMinus2; + size_t m_fibMinus1; + + std::vector> m_blocks; + size_t m_currentBlockSize; + size_t m_currentBlockUsage; +}; + +// Basic array allocator for POD types, based on TrivialBlockAllocator. +template +class TrivialArrayAllocator : private TrivialBlockAllocator +{ + static_assert(std::is_pod::value); + +public: + TrivialArrayAllocator(size_t initialCount) : + TrivialBlockAllocator(initialCount * sizeof(T)) + {} + + T* alloc(size_t count) + { + return reinterpret_cast( + TrivialBlockAllocator::alloc(count * sizeof(T))); + } + + void rewindLastAllocation(size_t rewindCount) + { + TrivialBlockAllocator::rewindLastAllocation(rewindCount * sizeof(T)); + } + + using TrivialBlockAllocator::reset; +}; + +// Simple linked list whose nodes are allocated on a TrivialBlockAllocator. +template class BlockAllocatedLinkedList +{ +public: + size_t count() const + { + assert(static_cast(m_head) == static_cast(m_tail)); + assert(static_cast(m_head) == static_cast(m_tail)); + return m_count; + } + + bool empty() const { return count() == 0; } + + T& tail() const + { + assert(!empty()); + return m_tail->data; + } + + template + T& emplace_back(TrivialBlockAllocator& allocator, Args... args) + { + Node* node = allocator.make(std::forward(args)...); + assert(static_cast(m_head) == static_cast(m_tail)); + if (m_head == nullptr) + { + m_head = node; + } + else + { + m_tail->next = node; + } + m_tail = node; + ++m_count; + return m_tail->data; + } + + void reset() + { + m_tail = nullptr; + m_head = nullptr; + m_count = 0; + } + + struct Node + { + template + Node(Args... args) : data(std::forward(args)...) + {} + T data; + Node* next = nullptr; + }; + + template class Iter + { + public: + Iter(Node* current) : m_current(current) {} + bool operator!=(const Iter& other) const + { + return m_current != other.m_current; + } + void operator++() { m_current = m_current->next; } + U& operator*() { return m_current->data; } + + private: + Node* m_current; + }; + Iter begin() { return {m_head}; } + Iter end() { return {nullptr}; } + Iter begin() const { return {m_head}; } + Iter end() const { return {nullptr}; } + +private: + Node* m_head = nullptr; + Node* m_tail = nullptr; + size_t m_count = 0; +}; + +} // namespace rive diff --git a/third_party/rive_renderer/include/rive/renderer/vulkan/render_context_vulkan_impl.hpp b/third_party/rive_renderer/include/rive/renderer/vulkan/render_context_vulkan_impl.hpp new file mode 100644 index 0000000..32c23bf --- /dev/null +++ b/third_party/rive_renderer/include/rive/renderer/vulkan/render_context_vulkan_impl.hpp @@ -0,0 +1,285 @@ +/* + * Copyright 2023 Rive + */ + +#pragma once + +#include "rive/renderer/render_context_impl.hpp" +#include "rive/renderer/vulkan/vulkan_context.hpp" +#include +#include +#include +#include "rive/shapes/paint/image_sampler.hpp" + +namespace rive::gpu +{ +class RenderTargetVulkanImpl; +class DrawShaderVulkan; + +class RenderContextVulkanImpl : public RenderContextImpl +{ +public: + static std::unique_ptr MakeContext( + VkInstance, + VkPhysicalDevice, + VkDevice, + const VulkanFeatures&, + PFN_vkGetInstanceProcAddr); + ~RenderContextVulkanImpl(); + + VulkanContext* vulkanContext() const { return m_vk.get(); } + + rcp makeRenderTarget( + uint32_t width, + uint32_t height, + VkFormat framebufferFormat, + VkImageUsageFlags targetUsageFlags); + + rcp makeRenderBuffer(RenderBufferType, + RenderBufferFlags, + size_t) override; + + rcp makeImageTexture(uint32_t width, + uint32_t height, + uint32_t mipLevelCount, + const uint8_t imageDataRGBAPremul[]) override; + + void hotloadShaders(rive::Span spirvData); + +private: + RenderContextVulkanImpl(rcp, + const VkPhysicalDeviceProperties&); + + // Called outside the constructor so we can use virtual methods. + void initGPUObjects(); + + void prepareToFlush(uint64_t nextFrameNumber, + uint64_t safeFrameNumber) override; + +#define IMPLEMENT_PLS_BUFFER(Name, m_buffer) \ + void resize##Name(size_t sizeInBytes) override \ + { \ + assert(m_buffer == nullptr); \ + m_buffer##Pool.setTargetSize(sizeInBytes); \ + } \ + void* map##Name(size_t mapSizeInBytes) override \ + { \ + assert(m_buffer != nullptr); \ + return m_buffer->contents(); \ + } \ + void unmap##Name(size_t mapSizeInBytes) override \ + { \ + assert(m_buffer != nullptr); \ + m_buffer->flushContents(mapSizeInBytes); \ + } + +#define IMPLEMENT_PLS_STRUCTURED_BUFFER(Name, m_buffer) \ + void resize##Name(size_t sizeInBytes, gpu::StorageBufferStructure) \ + override \ + { \ + assert(m_buffer == nullptr); \ + m_buffer##Pool.setTargetSize(sizeInBytes); \ + } \ + void* map##Name(size_t mapSizeInBytes) override \ + { \ + assert(m_buffer != nullptr); \ + return m_buffer->contents(); \ + } \ + void unmap##Name(size_t mapSizeInBytes) override \ + { \ + assert(m_buffer != nullptr); \ + m_buffer->flushContents(mapSizeInBytes); \ + } + + IMPLEMENT_PLS_BUFFER(FlushUniformBuffer, m_flushUniformBuffer) + IMPLEMENT_PLS_BUFFER(ImageDrawUniformBuffer, m_imageDrawUniformBuffer) + IMPLEMENT_PLS_STRUCTURED_BUFFER(PathBuffer, m_pathBuffer) + IMPLEMENT_PLS_STRUCTURED_BUFFER(PaintBuffer, m_paintBuffer) + IMPLEMENT_PLS_STRUCTURED_BUFFER(PaintAuxBuffer, m_paintAuxBuffer) + IMPLEMENT_PLS_STRUCTURED_BUFFER(ContourBuffer, m_contourBuffer) + IMPLEMENT_PLS_BUFFER(GradSpanBuffer, m_gradSpanBuffer) + IMPLEMENT_PLS_BUFFER(TessVertexSpanBuffer, m_tessSpanBuffer) + IMPLEMENT_PLS_BUFFER(TriangleVertexBuffer, m_triangleBuffer) + +#undef IMPLEMENT_PLS_BUFFER +#undef IMPLEMENT_PLS_STRUCTURED_BUFFER + + void resizeGradientTexture(uint32_t width, uint32_t height) override; + void resizeTessellationTexture(uint32_t width, uint32_t height) override; + void resizeAtlasTexture(uint32_t width, uint32_t height) override; + void resizeCoverageBuffer(size_t sizeInBytes) override; + + // Wraps a VkDescriptorPool created specifically for a PLS flush, and tracks + // its allocated descriptor sets. + class DescriptorSetPool final : public vkutil::Resource + { + public: + DescriptorSetPool(rcp); + ~DescriptorSetPool(); + + VkDescriptorSet allocateDescriptorSet(VkDescriptorSetLayout); + void reset(); + + private: + VkDescriptorPool m_vkDescriptorPool; + }; + + void flush(const FlushDescriptor&) override; + + void postFlush(const RenderContext::FlushResources&) override; + + double secondsNow() const override + { + auto elapsed = std::chrono::steady_clock::now() - m_localEpoch; + return std::chrono::duration(elapsed).count(); + } + + const rcp m_vk; + const uint32_t m_vendorID; + const VkFormat m_atlasFormat; + + // Rive buffer pools. These don't need to be rcp<> because the destructor of + // RenderContextVulkanImpl is already synchronized. + vkutil::BufferPool m_flushUniformBufferPool; + vkutil::BufferPool m_imageDrawUniformBufferPool; + vkutil::BufferPool m_pathBufferPool; + vkutil::BufferPool m_paintBufferPool; + vkutil::BufferPool m_paintAuxBufferPool; + vkutil::BufferPool m_contourBufferPool; + vkutil::BufferPool m_gradSpanBufferPool; + vkutil::BufferPool m_tessSpanBufferPool; + vkutil::BufferPool m_triangleBufferPool; + + // Specific Rive buffers that have been acquired for the current frame. + // When the frame ends, these get recycled back in their respective pools. + rcp m_flushUniformBuffer; + rcp m_imageDrawUniformBuffer; + rcp m_pathBuffer; + rcp m_paintBuffer; + rcp m_paintAuxBuffer; + rcp m_contourBuffer; + rcp m_gradSpanBuffer; + rcp m_tessSpanBuffer; + rcp m_triangleBuffer; + + std::chrono::steady_clock::time_point m_localEpoch = + std::chrono::steady_clock::now(); + + // Samplers. + VkSampler m_linearSampler; + VkSampler m_imageSamplers[ImageSampler::MAX_SAMPLER_PERMUTATIONS]; + + // Bound when there is not an image paint. + rcp m_nullImageTexture; + + // With the exception of PLS texture bindings, which differ by interlock + // mode, all other shaders use the same shared descriptor set layouts. + VkDescriptorSetLayout m_perFlushDescriptorSetLayout; + VkDescriptorSetLayout m_perDrawDescriptorSetLayout; + VkDescriptorSetLayout m_immutableSamplerDescriptorSetLayout; + VkDescriptorSetLayout m_emptyDescriptorSetLayout; // For when a set isn't + // used by a shader. + VkDescriptorPool m_staticDescriptorPool; // For descriptorSets that never + // change between frames. + VkDescriptorSet m_nullImageDescriptorSet; + VkDescriptorSet m_immutableSamplerDescriptorSet; // Empty since samplers are + // immutable, but also + // required by Vulkan. + + // Renders color ramps to the gradient texture. + class ColorRampPipeline; + std::unique_ptr m_colorRampPipeline; + rcp m_gradTexture; + rcp m_gradTextureFramebuffer; + + // Renders tessellated vertices to the tessellation texture. + class TessellatePipeline; + std::unique_ptr m_tessellatePipeline; + rcp m_tessSpanIndexBuffer; + rcp m_tessTexture; + rcp m_tessTextureFramebuffer; + + // Renders feathers to the atlas. + class AtlasPipeline; + std::unique_ptr m_atlasPipeline; + rcp m_atlasTexture; + rcp m_atlasFramebuffer; + + // Coverage buffer used by shaders in clockwiseAtomic mode. + rcp m_coverageBuffer; + + // Rive-specific options for configuring a flush's VkPipelineLayout. + enum class DrawPipelineLayoutOptions + { + none = 0, + + // No need to attach the COLOR texture as an input attachment. There are + // no advanced blend modes so we can use built-in hardware blending. + fixedFunctionColorOutput = 1 << 0, + + // Use an offscreen texture to render color, but also attach the real + // target texture at the COALESCED_ATOMIC_RESOLVE index, and render to + // it directly in the atomic resolve step. + coalescedResolveAndTransfer = 1 << 1, + }; + constexpr static int DRAW_PIPELINE_LAYOUT_OPTION_COUNT = 2; + + // A VkPipelineLayout for each + // interlockMode x [all DrawPipelineLayoutOptions permutations]. + constexpr static uint32_t DrawPipelineLayoutIdx( + gpu::InterlockMode interlockMode, + DrawPipelineLayoutOptions options) + { + return (static_cast(interlockMode) + << DRAW_PIPELINE_LAYOUT_OPTION_COUNT) | + static_cast(options); + } + constexpr static int DRAW_PIPELINE_LAYOUT_COUNT = + gpu::kInterlockModeCount * (1 << DRAW_PIPELINE_LAYOUT_OPTION_COUNT); + constexpr static int DRAW_PIPELINE_LAYOUT_BIT_COUNT = + DRAW_PIPELINE_LAYOUT_OPTION_COUNT + 2; + static_assert((1 << DRAW_PIPELINE_LAYOUT_BIT_COUNT) >= + DRAW_PIPELINE_LAYOUT_COUNT); + static_assert((1 << (DRAW_PIPELINE_LAYOUT_BIT_COUNT - 1)) < + DRAW_PIPELINE_LAYOUT_COUNT); + RIVE_DECL_ENUM_BITSET_FRIENDS(DrawPipelineLayoutOptions); + + // VkPipelineLayout wrapper for Rive flushes. + class DrawPipelineLayout; + std::array, DRAW_PIPELINE_LAYOUT_COUNT> + m_drawPipelineLayouts; + + // VkRenderPass wrapper for Rive flushes. + class RenderPass; + std::unordered_map> m_renderPasses; + + // VkPipeline wrapper for Rive draw calls. + class DrawPipeline; + std::unordered_map> + m_drawShaders; + std::unordered_map> m_drawPipelines; + + // Gaussian integral table for feathering. + rcp m_featherTexture; + + rcp m_pathPatchVertexBuffer; + rcp m_pathPatchIndexBuffer; + rcp m_imageRectVertexBuffer; + rcp m_imageRectIndexBuffer; + + // Pool of DescriptorSetPool instances for flushing. + class DescriptorSetPoolPool : public GPUResourcePool + { + public: + constexpr static size_t MAX_POOL_SIZE = 64; + DescriptorSetPoolPool(rcp manager) : + GPUResourcePool(std::move(manager), MAX_POOL_SIZE) + {} + + rcp acquire(); + }; + + rcp m_descriptorSetPoolPool; +}; +RIVE_MAKE_ENUM_BITSET(RenderContextVulkanImpl::DrawPipelineLayoutOptions); +} // namespace rive::gpu diff --git a/third_party/rive_renderer/include/rive/renderer/vulkan/render_target_vulkan.hpp b/third_party/rive_renderer/include/rive/renderer/vulkan/render_target_vulkan.hpp new file mode 100644 index 0000000..b22b3ed --- /dev/null +++ b/third_party/rive_renderer/include/rive/renderer/vulkan/render_target_vulkan.hpp @@ -0,0 +1,135 @@ +/* + * Copyright 2023 Rive + */ + +#pragma once + +#include "rive/renderer/render_target.hpp" +#include "rive/renderer/vulkan/vulkan_context.hpp" +#include + +namespace rive::gpu +{ +class RenderTargetVulkan : public RenderTarget +{ +public: + const VkFormat framebufferFormat() const { return m_framebufferFormat; } + const VkImageUsageFlags targetUsageFlags() const + { + return m_targetUsageFlags; + } + + // Returns the target image in the requested layout, performing a pipeline + // barrier if necessary. + virtual VkImage accessTargetImage( + VkCommandBuffer, + const vkutil::ImageAccess& dstAccess, + vkutil::ImageAccessAction = + vkutil::ImageAccessAction::preserveContents) = 0; + + // Returns the target image view, with its image in the requested layout, + // performing a pipeline barrier if necessary. + virtual VkImageView accessTargetImageView( + VkCommandBuffer, + const vkutil::ImageAccess& dstAccess, + vkutil::ImageAccessAction = + vkutil::ImageAccessAction::preserveContents) = 0; + +protected: + friend class RenderContextVulkanImpl; + + RenderTargetVulkan(rcp vk, + uint32_t width, + uint32_t height, + VkFormat framebufferFormat, + VkImageUsageFlags targetUsageFlags); + + // Returns the offscreen texture in the requested layout, performing a + // pipeline barrier if necessary. + vkutil::Texture2D* accessOffscreenColorTexture( + VkCommandBuffer, + const vkutil::ImageAccess& dstAccess, + vkutil::ImageAccessAction = + vkutil::ImageAccessAction::preserveContents); + + // InterlockMode::rasterOrdering. + vkutil::Texture2D* clipTextureR32UI(); + vkutil::Texture2D* scratchColorTexture(); + vkutil::Texture2D* coverageTexture(); + + // InterlockMode::atomics. + vkutil::Texture2D* clipTextureRGBA8(); + vkutil::Texture2D* coverageAtomicTexture(); + + // InterlockMode::msaa. + vkutil::Texture2D* depthStencilTexture(); + vkutil::ImageView* depthStencilTextureView(); + + const rcp m_vk; + const VkFormat m_framebufferFormat; + const VkImageUsageFlags m_targetUsageFlags; + + // Used when m_targetTextureView does not have + // VK_ACCESS_INPUT_ATTACHMENT_READ_BIT + rcp m_offscreenColorTexture; + + // InterlockMode::rasterOrdering. + rcp m_clipTextureR32UI; + rcp m_scratchColorTexture; + rcp m_coverageTexture; + + // InterlockMode::atomics. + rcp m_clipTextureRGBA8; + rcp m_coverageAtomicTexture; + + // InterlockMode::msaa. + rcp m_depthStencilTexture; +}; + +class RenderTargetVulkanImpl : public RenderTargetVulkan +{ +public: + RenderTargetVulkanImpl(rcp vk, + uint32_t width, + uint32_t height, + VkFormat framebufferFormat, + VkImageUsageFlags targetUsageFlags) : + RenderTargetVulkan(std::move(vk), + width, + height, + framebufferFormat, + targetUsageFlags) + {} + + void setTargetImageView(VkImageView imageView, + VkImage image, + vkutil::ImageAccess targetLastAccess) + { + m_targetImageView = imageView; + m_targetImage = image; + m_targetLastAccess = targetLastAccess; + } + + const vkutil::ImageAccess& targetLastAccess() const + { + return m_targetLastAccess; + } + + VkImage accessTargetImage( + VkCommandBuffer, + const vkutil::ImageAccess& dstAccess, + vkutil::ImageAccessAction = + vkutil::ImageAccessAction::preserveContents) override; + + VkImageView accessTargetImageView( + VkCommandBuffer, + const vkutil::ImageAccess& dstAccess, + vkutil::ImageAccessAction = + vkutil::ImageAccessAction::preserveContents) override; + +private: + VkImageView m_targetImageView = VK_NULL_HANDLE; + VkImage m_targetImage = VK_NULL_HANDLE; + vkutil::ImageAccess m_targetLastAccess; +}; +} // namespace rive::gpu diff --git a/third_party/rive_renderer/include/rive/renderer/vulkan/vkutil.hpp b/third_party/rive_renderer/include/rive/renderer/vulkan/vkutil.hpp new file mode 100644 index 0000000..868080c --- /dev/null +++ b/third_party/rive_renderer/include/rive/renderer/vulkan/vkutil.hpp @@ -0,0 +1,371 @@ +/* + * Copyright 2024 Rive + */ + +#pragma once + +#include "rive/refcnt.hpp" +#include "rive/renderer/gpu.hpp" +#include "rive/renderer/gpu_resource.hpp" +#include "rive/renderer/texture.hpp" +#include +#include +#include +#include + +VK_DEFINE_HANDLE(VmaAllocation); + +namespace rive::gpu +{ +class VulkanContext; +} // namespace rive::gpu + +namespace rive::gpu::vkutil +{ +inline static void vk_check(VkResult res, const char* file, int line) +{ + if (res != VK_SUCCESS) + { + fprintf(stderr, + "Vulkan error %i at line: %i in file: %s\n", + res, + line, + file); + abort(); + } +} + +#define VK_CHECK(x) ::rive::gpu::vkutil::vk_check(x, __FILE__, __LINE__) + +constexpr static VkColorComponentFlags kColorWriteMaskNone = 0; +constexpr static VkColorComponentFlags kColorWriteMaskRGBA = + VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | + VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + +enum class Mappability +{ + none, + writeOnly, + readWrite, +}; + +// Base class for a GPU resource that needs to be kept alive until any in-flight +// command buffers that reference it have completed. +class Resource : public GPUResource +{ +public: + virtual ~Resource() {} + + VulkanContext* vk() const; + +protected: + Resource(rcp); +}; + +class Buffer : public Resource +{ +public: + ~Buffer() override; + + VkBufferCreateInfo info() const { return m_info; } + operator VkBuffer() const { return m_vkBuffer; } + const VkBuffer* vkBufferAddressOf() const { return &m_vkBuffer; } + + // Resize the underlying VkBuffer without waiting for any pipeline + // synchronization. The caller is responsible to guarantee the underlying + // VkBuffer is not queued up in any in-flight command buffers. + void resizeImmediately(VkDeviceSize sizeInBytes); + + void* contents() + { + assert(m_contents != nullptr); + return m_contents; + } + + // Calls through to vkFlushMappedMemoryRanges(). + // Called after modifying contents() with the CPU. Makes those modifications + // available to the GPU. + void flushContents(VkDeviceSize sizeInBytes = VK_WHOLE_SIZE); + + // Calls through to vkInvalidateMappedMemoryRanges(). + // Called after modifying the buffer with the GPU. Makes those modifications + // available to the CPU via contents(). + void invalidateContents(VkDeviceSize sizeInBytes = VK_WHOLE_SIZE); + +private: + friend class ::rive::gpu::VulkanContext; + + Buffer(rcp, const VkBufferCreateInfo&, Mappability); + + void init(); + + const Mappability m_mappability; + VkBufferCreateInfo m_info; + VmaAllocation m_vmaAllocation; + VkBuffer m_vkBuffer; + void* m_contents; +}; + +// Wraps a pool of Buffers so we can map one while other(s) are in-flight. +class BufferPool : public GPUResourcePool +{ +public: + BufferPool(rcp, VkBufferUsageFlags, VkDeviceSize size = 0); + + VkDeviceSize size() const { return m_targetSize; } + void setTargetSize(VkDeviceSize size); + + // Returns a Buffer that is guaranteed to exist and be of size + // 'm_targetSize'. + rcp acquire(); + + void recycle(rcp buffer) + { + GPUResourcePool::recycle(std::move(buffer)); + } + +private: + VulkanContext* vk() const; + + constexpr static VkDeviceSize MAX_POOL_SIZE = 8; + const VkBufferUsageFlags m_usageFlags; + VkDeviceSize m_targetSize; +}; + +class Image : public Resource +{ +public: + ~Image() override; + + const VkImageCreateInfo& info() { return m_info; } + operator VkImage() const { return m_vkImage; } + const VkImage* vkImageAddressOf() const { return &m_vkImage; } + +private: + friend class ::rive::gpu::VulkanContext; + + Image(rcp, const VkImageCreateInfo&); + + VkImageCreateInfo m_info; + VmaAllocation m_vmaAllocation; + VkImage m_vkImage; +}; + +class ImageView : public Resource +{ +public: + ~ImageView() override; + + const VkImageViewCreateInfo& info() { return m_info; } + operator VkImageView() const { return m_vkImageView; } + VkImageView vkImageView() const { return m_vkImageView; } + const VkImageView* vkImageViewAddressOf() const { return &m_vkImageView; } + +private: + friend class ::rive::gpu::VulkanContext; + + ImageView(rcp, + rcp textureRef, + const VkImageViewCreateInfo&); + + const rcp m_textureRefOrNull; + VkImageViewCreateInfo m_info; + VkImageView m_vkImageView; +}; + +// Tracks the current layout and access parameters of a VkImage. +struct ImageAccess +{ + VkPipelineStageFlags pipelineStages = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; + VkAccessFlags accessMask = VK_ACCESS_NONE; + VkImageLayout layout = VK_IMAGE_LAYOUT_UNDEFINED; + + bool operator==(const ImageAccess& rhs) const + { + return pipelineStages == rhs.pipelineStages && + accessMask == rhs.accessMask && layout == rhs.layout; + } + bool operator!=(const ImageAccess& rhs) const { return !(*this == rhs); } +}; + +// Provides a way to communicate that a VkImage may be invalidated (layout +// converted to VK_IMAGE_LAYOUT_UNDEFINED) while performing a barrier. +enum class ImageAccessAction : bool +{ + preserveContents, + invalidateContents, +}; + +// Wrapper for a simple 2D VkImage and VkImageView. +class Texture2D : public rive::gpu::Texture +{ +public: + VkImage vkImage() const { return *m_image; } + VkImageView vkImageView() const { return *m_imageView; } + const VkImageView* vkImageViewAddressOf() const + { + return m_imageView->vkImageViewAddressOf(); + } + ImageAccess& lastAccess() { return m_lastAccess; } + + // Deferred mechanism for uploading image data without a command buffer. + void stageContentsForUpload(const void* imageData, + size_t imageDataSizeInBytes); + bool hasUpdates() const { return m_imageUploadBuffer != nullptr; } + void synchronize(VkCommandBuffer); + + void barrier(VkCommandBuffer, + const ImageAccess& dstAccess, + ImageAccessAction = ImageAccessAction::preserveContents, + VkDependencyFlags = 0); + + // Downscales the top level into sub-levels. + // NOTE: Does not wrap the edges when filtering down. This is not an ideal + // situation for non-power-of-two textures that are intended to be used with + // a wrap mode of "repeat". We may want to add a "wrap" argument at some + // point. + void generateMipmaps(VkCommandBuffer, const ImageAccess& dstAccess); + + // Simple mechanism for caching and reusing a descriptor set for this + // texture within a frame. + VkDescriptorSet getCachedDescriptorSet(uint64_t frameNumber, + ImageSampler sampler) const + { + return frameNumber == m_cachedDescriptorSetFrameNumber && + sampler == m_cachedDescriptorSetSampler + ? m_cachedDescriptorSet + : VK_NULL_HANDLE; + } + + void updateCachedDescriptorSet(VkDescriptorSet descriptorSet, + uint64_t frameNumber, + ImageSampler sampler) + { + m_cachedDescriptorSet = descriptorSet; + m_cachedDescriptorSetFrameNumber = frameNumber; + m_cachedDescriptorSetSampler = sampler; + } + +protected: + friend class ::rive::gpu::VulkanContext; + + Texture2D(rcp vk, VkImageCreateInfo); + + rcp m_image; + rcp m_imageView; + ImageAccess m_lastAccess; + + rcp m_imageUploadBuffer; + + // Simple mechanism for caching and reusing a descriptor set for this + // texture within a frame. + VkDescriptorSet m_cachedDescriptorSet = VK_NULL_HANDLE; + uint64_t m_cachedDescriptorSetFrameNumber; + ImageSampler m_cachedDescriptorSetSampler; +}; + +class Framebuffer : public Resource +{ +public: + ~Framebuffer() override; + + const VkFramebufferCreateInfo& info() const { return m_info; } + operator VkFramebuffer() const { return m_vkFramebuffer; } + +private: + friend class ::rive::gpu::VulkanContext; + + Framebuffer(rcp, const VkFramebufferCreateInfo&); + + VkFramebufferCreateInfo m_info; + VkFramebuffer m_vkFramebuffer; +}; + +// Utility to generate a simple 2D VkViewport from a VkRect2D. +class ViewportFromRect2D +{ +public: + ViewportFromRect2D(const VkRect2D rect) : + m_viewport{ + .x = static_cast(rect.offset.x), + .y = static_cast(rect.offset.y), + .width = static_cast(rect.extent.width), + .height = static_cast(rect.extent.height), + .minDepth = DEPTH_MIN, + .maxDepth = DEPTH_MAX, + } + {} + + operator const VkViewport*() const { return &m_viewport; } + +private: + VkViewport m_viewport; +}; + +inline void set_shader_code(VkShaderModuleCreateInfo& info, + const uint32_t* code, + size_t codeSize) +{ + info.codeSize = codeSize; + info.pCode = code; +} + +inline void set_shader_code_if_then_else(VkShaderModuleCreateInfo& info, + bool _if, + const uint32_t* codeIf, + size_t codeSizeIf, + const uint32_t* codeElse, + size_t codeSizeElse) +{ + if (_if) + { + set_shader_code(info, codeIf, codeSizeIf); + } + else + { + set_shader_code(info, codeElse, codeSizeElse); + } +} + +inline void set_shader_code(VkShaderModuleCreateInfo& info, + rive::Span code) +{ + info.codeSize = code.size_bytes(); + info.pCode = code.data(); +} + +inline void set_shader_code_if_then_else(VkShaderModuleCreateInfo& info, + bool _if, + rive::Span codeIf, + rive::Span codeElse) +{ + if (_if) + { + set_shader_code(info, codeIf); + } + else + { + set_shader_code(info, codeElse); + } +} + +inline VkClearColorValue color_clear_rgba32f(ColorInt riveColor) +{ + VkClearColorValue ret; + UnpackColorToRGBA32FPremul(riveColor, ret.float32); + return ret; +} + +inline VkClearColorValue color_clear_r32ui(uint32_t value) +{ + VkClearColorValue ret; + ret.uint32[0] = value; + return ret; +} + +inline VkFormat get_preferred_depth_stencil_format(bool isD24S8Supported) +{ + return isD24S8Supported ? VK_FORMAT_D24_UNORM_S8_UINT + : VK_FORMAT_D32_SFLOAT_S8_UINT; +} +} // namespace rive::gpu::vkutil diff --git a/third_party/rive_renderer/include/rive/renderer/vulkan/vulkan_context.hpp b/third_party/rive_renderer/include/rive/renderer/vulkan/vulkan_context.hpp new file mode 100644 index 0000000..5f4e9c0 --- /dev/null +++ b/third_party/rive_renderer/include/rive/renderer/vulkan/vulkan_context.hpp @@ -0,0 +1,181 @@ +/* + * Copyright 2024 Rive + */ + +#pragma once + +#include "rive/renderer/gpu_resource.hpp" +#include "rive/renderer/vulkan/vkutil.hpp" + +VK_DEFINE_HANDLE(VmaAllocator); + +namespace rive::gpu +{ +// Specifies the Vulkan API version and which relevant features have been +// enabled. The client should ensure the features get enabled if they are +// supported. +struct VulkanFeatures +{ + uint32_t apiVersion = VK_API_VERSION_1_0; + + // VkPhysicalDeviceFeatures. + bool independentBlend = false; + bool fillModeNonSolid = false; + bool fragmentStoresAndAtomics = false; + + // EXT_rasterization_order_attachment_access. + bool rasterizationOrderColorAttachmentAccess = false; +}; + +// Wraps a VkDevice, function dispatch table, and VMA library instance. +// +// Provides methods to allocate vkutil::RenderingResource objects, and manages +// their lifecycles via a "resource purgatory", which keeps resources alive +// until command buffers have finished using them. +// +// Provides minor helper utilities, but for the most part, the client is +// expected to make raw Vulkan calls via the provided function pointers. +class VulkanContext : public GPUResourceManager +{ +public: + VulkanContext(VkInstance, + VkPhysicalDevice, + VkDevice, + const VulkanFeatures&, + PFN_vkGetInstanceProcAddr); + + ~VulkanContext(); + + const VkInstance instance; + const VkPhysicalDevice physicalDevice; + const VkDevice device; + const VulkanFeatures features; + +#define RIVE_VULKAN_INSTANCE_COMMANDS(F) \ + F(GetDeviceProcAddr) \ + F(GetPhysicalDeviceFormatProperties) \ + F(GetPhysicalDeviceProperties) + +#define RIVE_VULKAN_DEVICE_COMMANDS(F) \ + F(AllocateDescriptorSets) \ + F(CmdBeginRenderPass) \ + F(CmdBindDescriptorSets) \ + F(CmdBindIndexBuffer) \ + F(CmdBindPipeline) \ + F(CmdBindVertexBuffers) \ + F(CmdBlitImage) \ + F(CmdClearColorImage) \ + F(CmdCopyBufferToImage) \ + F(CmdDraw) \ + F(CmdDrawIndexed) \ + F(CmdEndRenderPass) \ + F(CmdFillBuffer) \ + F(CmdNextSubpass) \ + F(CmdPipelineBarrier) \ + F(CmdSetScissor) \ + F(CmdSetViewport) \ + F(CreateDescriptorPool) \ + F(CreateDescriptorSetLayout) \ + F(CreateFramebuffer) \ + F(CreateGraphicsPipelines) \ + F(CreateImageView) \ + F(CreatePipelineLayout) \ + F(CreateRenderPass) \ + F(CreateSampler) \ + F(CreateShaderModule) \ + F(DestroyDescriptorPool) \ + F(DestroyDescriptorSetLayout) \ + F(DestroyFramebuffer) \ + F(DestroyImageView) \ + F(DestroyPipeline) \ + F(DestroyPipelineLayout) \ + F(DestroyRenderPass) \ + F(DestroySampler) \ + F(DestroyShaderModule) \ + F(ResetDescriptorPool) \ + F(UpdateDescriptorSets) + +#define DECLARE_VULKAN_COMMAND(CMD) const PFN_vk##CMD CMD; + RIVE_VULKAN_INSTANCE_COMMANDS(DECLARE_VULKAN_COMMAND) + RIVE_VULKAN_DEVICE_COMMANDS(DECLARE_VULKAN_COMMAND) +#undef DECLARE_VULKAN_COMMAND + + VmaAllocator allocator() const { return m_vmaAllocator; } + + bool isFormatSupportedWithFeatureFlags(VkFormat, VkFormatFeatureFlagBits); + bool supportsD24S8() const { return m_supportsD24S8; } + + // Resource allocation. + rcp makeBuffer(const VkBufferCreateInfo&, + vkutil::Mappability); + rcp makeImage(const VkImageCreateInfo&); + rcp makeImageView(rcp); + rcp makeImageView(rcp, + const VkImageViewCreateInfo&); + rcp makeExternalImageView(const VkImageViewCreateInfo&); + rcp makeTexture2D(const VkImageCreateInfo&); + rcp makeFramebuffer(const VkFramebufferCreateInfo&); + + // Helpers. + void updateImageDescriptorSets( + VkDescriptorSet, + VkWriteDescriptorSet, + std::initializer_list); + void updateBufferDescriptorSets( + VkDescriptorSet, + VkWriteDescriptorSet, + std::initializer_list); + + void memoryBarrier(VkCommandBuffer, + VkPipelineStageFlags srcStageMask, + VkPipelineStageFlags dstStageMask, + VkDependencyFlags, + VkMemoryBarrier); + + void imageMemoryBarriers(VkCommandBuffer, + VkPipelineStageFlags srcStageMask, + VkPipelineStageFlags dstStageMask, + VkDependencyFlags, + uint32_t count, + VkImageMemoryBarrier*); + + void imageMemoryBarrier(VkCommandBuffer commandBuffer, + VkPipelineStageFlags srcStageMask, + VkPipelineStageFlags dstStageMask, + VkDependencyFlags dependencyFlags, + VkImageMemoryBarrier imageMemoryBarrier) + { + imageMemoryBarriers(commandBuffer, + srcStageMask, + dstStageMask, + dependencyFlags, + 1, + &imageMemoryBarrier); + } + + const vkutil::ImageAccess& simpleImageMemoryBarrier( + VkCommandBuffer, + const vkutil::ImageAccess& srcAccess, + const vkutil::ImageAccess& dstAccess, + VkImage, + vkutil::ImageAccessAction = vkutil::ImageAccessAction::preserveContents, + VkDependencyFlags = 0); + + void bufferMemoryBarrier(VkCommandBuffer, + VkPipelineStageFlags srcStageMask, + VkPipelineStageFlags dstStageMask, + VkDependencyFlags, + VkBufferMemoryBarrier); + + void blitSubRect(VkCommandBuffer commandBuffer, + VkImage src, + VkImage dst, + const IAABB&); + +private: + const VmaAllocator m_vmaAllocator; + + // Vulkan spec: must support one of D24S8 and D32S8. + bool m_supportsD24S8 = false; +}; +} // namespace rive::gpu diff --git a/third_party/rive_renderer/include/rive/renderer/webgpu/em_js_handle.hpp b/third_party/rive_renderer/include/rive/renderer/webgpu/em_js_handle.hpp new file mode 100644 index 0000000..7096719 --- /dev/null +++ b/third_party/rive_renderer/include/rive/renderer/webgpu/em_js_handle.hpp @@ -0,0 +1,47 @@ +/* + * Copyright 2023 Rive + */ + +#pragma once + +#include "rive/rive_types.hpp" + +#ifdef RIVE_DAWN +#include +#endif + +#ifdef RIVE_WEBGPU +#include +#include +#include +#endif + +// RAII object that stores and releases a handle to a WebGPU object passed from +// Javascript. Original source: +// https://github.com/emscripten-core/emscripten/blob/08cca043d8ba313d774bec8153fab66b70a6fe60/test/webgpu_jsvalstore.cpp +class EmJsHandle +{ +public: + EmJsHandle() : m_handle(0) {} + explicit EmJsHandle(int handle) : m_handle(handle) {} + ~EmJsHandle(); + + EmJsHandle(const EmJsHandle&) = delete; + EmJsHandle& operator=(const EmJsHandle&) = delete; + + EmJsHandle(EmJsHandle&& rhs) : m_handle(rhs.m_handle) { rhs.m_handle = 0; } + EmJsHandle& operator=(EmJsHandle&& rhs); + + int get() const { return m_handle; } + + wgpu::ShaderModule compileSPIRVShaderModule(wgpu::Device device, + const uint32_t* code, + uint32_t codeSize); + + wgpu::ShaderModule compileShaderModule(wgpu::Device device, + const char* language, + const char* source); + +private: + int m_handle; +}; diff --git a/third_party/rive_renderer/include/rive/renderer/webgpu/render_context_webgpu_impl.hpp b/third_party/rive_renderer/include/rive/renderer/webgpu/render_context_webgpu_impl.hpp new file mode 100644 index 0000000..964bc4d --- /dev/null +++ b/third_party/rive_renderer/include/rive/renderer/webgpu/render_context_webgpu_impl.hpp @@ -0,0 +1,226 @@ +/* + * Copyright 2023 Rive + */ + +#pragma once + +#include "rive/renderer/render_context_helper_impl.hpp" +#include "rive/renderer/webgpu/em_js_handle.hpp" +#include "rive/renderer/gl/load_store_actions_ext.hpp" +#include +#include + +namespace rive::gpu +{ +class RenderContextWebGPUVulkan; + +class RenderTargetWebGPU : public RenderTarget +{ +public: + wgpu::TextureFormat framebufferFormat() const + { + return m_framebufferFormat; + } + + void setTargetTextureView(wgpu::TextureView); + +private: + friend class RenderContextWebGPUImpl; + friend class RenderContextWebGPUVulkan; + + RenderTargetWebGPU(wgpu::Device device, + wgpu::TextureFormat framebufferFormat, + uint32_t width, + uint32_t height, + wgpu::TextureUsage additionalTextureFlags); + + const wgpu::TextureFormat m_framebufferFormat; + + wgpu::Texture m_coverageTexture; + wgpu::Texture m_clipTexture; + wgpu::Texture m_scratchColorTexture; + + wgpu::TextureView m_targetTextureView; + wgpu::TextureView m_coverageTextureView; + wgpu::TextureView m_clipTextureView; + wgpu::TextureView m_scratchColorTextureView; +}; + +class RenderContextWebGPUImpl : public RenderContextHelperImpl +{ +public: + enum class PixelLocalStorageType + { + // Pixel local storage cannot be supported; make a best reasonable + // effort to draw shapes. + none, + + // Backend is OpenGL ES 3.1+ and has GL_EXT_shader_pixel_local_storage. + // Use "raw-glsl" shaders that take advantage of the extension. + EXT_shader_pixel_local_storage, + + // Backend is Vulkan with VK_EXT_rasterization_order_attachment_access. + // Use nonstandard WebGPU APIs to set up vulkan input attachments and + // subpassLoad() in shaders. + subpassLoad, + }; + + struct ContextOptions + { + PixelLocalStorageType plsType = PixelLocalStorageType::none; + bool disableStorageBuffers = false; + // Invert Y when drawing to client-provided RenderTargets. + // TODO: We may need to eventually make this configurable + // per-RenderTarget. + bool invertRenderTargetY = false; + // Invert the front face when drawing to client-provied RenderTargets. + bool invertRenderTargetFrontFace = false; + }; + + static std::unique_ptr MakeContext(wgpu::Device, + wgpu::Queue, + const ContextOptions&); + + virtual ~RenderContextWebGPUImpl(); + + virtual rcp makeRenderTarget(wgpu::TextureFormat, + uint32_t width, + uint32_t height); + + rcp makeRenderBuffer(RenderBufferType, + RenderBufferFlags, + size_t) override; + + rcp makeImageTexture(uint32_t width, + uint32_t height, + uint32_t mipLevelCount, + const uint8_t imageDataRGBAPremul[]) override; + +protected: + RenderContextWebGPUImpl(wgpu::Device device, + wgpu::Queue queue, + const ContextOptions&); + + // Create the BindGroupLayout that binds the PLS attachments as textures. + // This is not necessary on all implementations. + virtual wgpu::BindGroupLayout initTextureBindGroup() + { + // Only supported by RenderContextWebGPUVulkan for now. + RIVE_UNREACHABLE(); + } + + // Create a standard PLS "draw" pipeline for the current implementation. + virtual wgpu::RenderPipeline makeDrawPipeline( + rive::gpu::DrawType drawType, + wgpu::TextureFormat framebufferFormat, + wgpu::ShaderModule vertexShader, + wgpu::ShaderModule fragmentShader, + EmJsHandle* pipelineJSHandleIfNeeded); + + // Create a standard PLS "draw" render pass for the current implementation. + virtual wgpu::RenderPassEncoder makePLSRenderPass( + wgpu::CommandEncoder, + const RenderTargetWebGPU*, + wgpu::LoadOp, + const wgpu::Color& clearColor, + EmJsHandle* renderPassJSHandleIfNeeded); + + wgpu::Device device() const { return m_device; } + wgpu::FrontFace frontFaceForRenderTargetDraws() const + { + return m_contextOptions.invertRenderTargetFrontFace + ? wgpu::FrontFace::CCW + : wgpu::FrontFace::CW; + } + wgpu::PipelineLayout drawPipelineLayout() const + { + return m_drawPipelineLayout; + } + +private: + // Called outside the constructor so we can use virtual methods. + void initGPUObjects(); + + void generateMipmaps(wgpu::Texture); + + // PLS always expects a clockwise front face. + constexpr static wgpu::FrontFace kFrontFaceForOffscreenDraws = + wgpu::FrontFace::CW; + + std::unique_ptr makeUniformBufferRing( + size_t capacityInBytes) override; + std::unique_ptr makeStorageBufferRing( + size_t capacityInBytes, + gpu::StorageBufferStructure) override; + std::unique_ptr makeVertexBufferRing( + size_t capacityInBytes) override; + + void resizeGradientTexture(uint32_t width, uint32_t height) override; + void resizeTessellationTexture(uint32_t width, uint32_t height) override; + void resizeAtlasTexture(uint32_t width, uint32_t height) override; + + void flush(const FlushDescriptor&) override; + + const wgpu::Device m_device; + const wgpu::Queue m_queue; + const ContextOptions m_contextOptions; + + constexpr static int COLOR_RAMP_BINDINGS_COUNT = 1; + constexpr static int TESS_BINDINGS_COUNT = 6; + constexpr static int ATLAS_BINDINGS_COUNT = 7; + constexpr static int DRAW_BINDINGS_COUNT = 10; + std::array + m_perFlushBindingLayouts; + + // Draws emulated render-pass load/store actions for + // EXT_shader_pixel_local_storage. + class LoadStoreEXTPipeline; + std::map m_loadStoreEXTPipelines; + EmJsHandle m_loadStoreEXTVertexShaderHandle; + wgpu::ShaderModule m_loadStoreEXTVertexShader; + std::unique_ptr m_loadStoreEXTUniforms; + + // Blits texture-to-texture using a draw command. + class BlitTextureAsDrawPipeline; + std::unique_ptr m_blitTextureAsDrawPipeline; + + // Renders color ramps to the gradient texture. + class ColorRampPipeline; + std::unique_ptr m_colorRampPipeline; + wgpu::Texture m_gradientTexture; + wgpu::TextureView m_gradientTextureView; + + // Renders tessellated vertices to the tessellation texture. + class TessellatePipeline; + std::unique_ptr m_tessellatePipeline; + wgpu::Buffer m_tessSpanIndexBuffer; + wgpu::Texture m_tessVertexTexture; + wgpu::TextureView m_tessVertexTextureView; + + // Renders feathers to the atlas. + class AtlasPipeline; + std::unique_ptr m_atlasPipeline; + wgpu::Texture m_atlasTexture; + wgpu::TextureView m_atlasTextureView; + + // Draw paths and image meshes using the gradient and tessellation textures. + class DrawPipeline; + std::map m_drawPipelines; + wgpu::BindGroupLayout m_drawBindGroupLayouts[4 /*BINDINGS_SET_COUNT*/]; + wgpu::Sampler m_linearSampler; + wgpu::Sampler m_mipmapSampler; + wgpu::BindGroup m_samplerBindings; + wgpu::PipelineLayout m_drawPipelineLayout; + wgpu::BindGroupLayout m_emptyBindingsLayout; // For when a set is unused. + wgpu::Buffer m_pathPatchVertexBuffer; + wgpu::Buffer m_pathPatchIndexBuffer; + + // Gaussian integral table for feathering. + wgpu::Texture m_featherTexture; + wgpu::TextureView m_featherTextureView; + + // Bound when there is not an image paint. + wgpu::Texture m_nullImagePaintTexture; + wgpu::TextureView m_nullImagePaintTextureView; +}; +} // namespace rive::gpu diff --git a/third_party/rive_renderer/rive_renderer.cpp b/third_party/rive_renderer/rive_renderer.cpp new file mode 100644 index 0000000..5ec6269 --- /dev/null +++ b/third_party/rive_renderer/rive_renderer.cpp @@ -0,0 +1,56 @@ +/* + ============================================================================== + + This file is part of the YUP library. + Copyright (c) 2024 - kunitoki@gmail.com + + YUP is an open source library subject to open-source licensing. + + The code included in this file is provided under the terms of the ISC license + http://www.isc.org/downloads/software-support-policy/isc-license. Permission + to use, copy, modify, and/or distribute this software for any purpose with or + without fee is hereby granted provided that the above copyright notice and + this permission notice appear in all copies. + + YUP IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +#include "rive_renderer.h" + +#if __clang__ + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wshorten-64-to-32" + #pragma clang diagnostic ignored "-Wattributes" +#elif __GNUC__ + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wattributes" +#elif _MSC_VER + __pragma (warning (push)) + __pragma (warning (disable: 4244)) +#endif + +#include "source/rive_renderer.cpp" +#include "source/render_context.cpp" +#include "source/rive_render_paint.cpp" +#include "source/rive_render_path.cpp" +#include "source/rive_render_image.cpp" +#include "source/intersection_board.cpp" +#include "source/draw.cpp" +#include "source/gr_triangulator.cpp" +#include "source/gradient.cpp" +#include "source/sk_rectanizer_skyline.cpp" +#include "source/gpu.cpp" +#include "source/rive_render_factory.cpp" +#include "source/render_context_helper_impl.cpp" + +#if __clang__ + #pragma clang diagnostic pop +#elif __GNUC__ + #pragma GCC diagnostic pop +#elif _MSC_VER + __pragma (warning (pop)) +#endif diff --git a/third_party/rive_renderer/rive_renderer.h b/third_party/rive_renderer/rive_renderer.h new file mode 100644 index 0000000..a2985ad --- /dev/null +++ b/third_party/rive_renderer/rive_renderer.h @@ -0,0 +1,155 @@ +/* + ============================================================================== + + This file is part of the YUP library. + Copyright (c) 2024 - kunitoki@gmail.com + + YUP is an open source library subject to open-source licensing. + + The code included in this file is provided under the terms of the ISC license + http://www.isc.org/downloads/software-support-policy/isc-license. Permission + to use, copy, modify, and/or distribute this software for any purpose with or + without fee is hereby granted provided that the above copyright notice and + this permission notice appear in all copies. + + YUP IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +/* + ============================================================================== + + BEGIN_YUP_MODULE_DECLARATION + + ID: rive_renderer + vendor: rive + version: 1.0 + name: Rive Renderer. + description: The Rive Renderer is a vector and raster graphics renderer custom-built for Rive content, for animation, and for runtime. + website: https://github.com/rive-app/rive-runtime + license: MIT + minimumCppStandard: 17 + + dependencies: rive rive_decoders glad + searchpaths: include source source/generated/shaders + osxFrameworks: Metal QuartzCore + defines: WITH_RIVE_TEXT=1 RIVE_DECODERS=1 + iosDefines: RIVE_IOS=1 + iosSimDefines: RIVE_IOS_SIMULATOR=1 + linuxDefines: RIVE_DESKTOP_GL=1 + wasmDefines: RIVE_WEBGL=1 + wasmOptions: -sUSE_SDL=2 + wasmLinkOptions: -sUSE_SDL=2 -sMAX_WEBGL_VERSION=2 + androidDefines: RIVE_ANDROID=1 + androidLibs: EGL GLESv3 + windowsCppStandard: 20 + enableARC: 1 + + END_YUP_MODULE_DECLARATION + + ============================================================================== +*/ + +#pragma once + +//============================================================================== +/** Config: YUP_RIVE_USE_METAL + Enables the use of the Metal renderer on macOS (the default is enabled). +*/ +#ifndef YUP_RIVE_USE_METAL +#define YUP_RIVE_USE_METAL 1 +#endif + +/** Config: YUP_RIVE_USE_D3D + Enables the use of the Direct3D renderer on Windows (the default is enabled). +*/ +#ifndef YUP_RIVE_USE_D3D +#define YUP_RIVE_USE_D3D 1 +#endif + +/** Config: YUP_RIVE_USE_OPENGL + Enables the use of the OpenGL renderer on platform that support it but where it is not used by default (in + the specific case macOS and Windows). + + You will need to link to the specific OpenGL framework on macOS when building your application with this + flag set: add "-framework OpenGL" to link flags. +*/ +#ifndef YUP_RIVE_USE_OPENGL +#define YUP_RIVE_USE_OPENGL 0 +#endif + +/** Config: YUP_RIVE_USE_DAWN + Enables the use of the Dawn renderer on platform that support it. +*/ +#ifndef YUP_RIVE_USE_DAWN +#define YUP_RIVE_USE_DAWN 0 +#endif + +//============================================================================== +/** Config: YUP_RIVE_OPENGL_MAJOR + Enables a speficic OpenGL major version. Must be at least 4. +*/ +#ifndef YUP_RIVE_OPENGL_MAJOR +#define YUP_RIVE_OPENGL_MAJOR 4 +#endif + +/** Config: YUP_RIVE_OPENGL_MINOR + Enables a speficic OpenGL minor version. Must be at least 2. +*/ +#ifndef YUP_RIVE_OPENGL_MINOR +#define YUP_RIVE_OPENGL_MINOR 2 +#endif + +//============================================================================== + +#if YUP_RIVE_USE_OPENGL +#if __APPLE__ && !YUP_RIVE_USE_METAL && !YUP_RIVE_USE_DAWN +#error Must select at least one between YUP_RIVE_USE_METAL, YUP_RIVE_USE_OPENGL or YUP_RIVE_USE_DAWN +#elif _WIN32 && !YUP_RIVE_USE_D3D && !YUP_RIVE_USE_DAWN +#error Must select at least one between YUP_RIVE_USE_D3D, YUP_RIVE_USE_OPENGL or YUP_RIVE_USE_DAWN +#endif + +#if !defined(RIVE_DESKTOP_GL) && !defined(RIVE_WEBGL) +#define RIVE_DESKTOP_GL 1 +#endif +#endif + +#if YUP_RIVE_USE_DAWN +#if !defined(RIVE_DAWN) +#define RIVE_DAWN 1 +#endif +#endif + +//============================================================================== + +#if __GNUC__ + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#elif __clang__ + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wattributes" +#elif _MSC_VER + __pragma (warning (push)) + __pragma (warning (disable: 4244)) +#endif + +// Public API +#include +#include +#include +#include + +// Internals +#include +#include + +#if __GNUC__ + #pragma GCC diagnostic pop +#elif __clang__ + #pragma clang diagnostic pop +#elif _MSC_VER + __pragma (warning (pop)) +#endif diff --git a/third_party/rive_renderer/rive_renderer_android.cpp b/third_party/rive_renderer/rive_renderer_android.cpp new file mode 100644 index 0000000..ee44fb5 --- /dev/null +++ b/third_party/rive_renderer/rive_renderer_android.cpp @@ -0,0 +1,42 @@ +/* + ============================================================================== + + This file is part of the YUP library. + Copyright (c) 2024 - kunitoki@gmail.com + + YUP is an open source library subject to open-source licensing. + + The code included in this file is provided under the terms of the ISC license + http://www.isc.org/downloads/software-support-policy/isc-license. Permission + to use, copy, modify, and/or distribute this software for any purpose with or + without fee is hereby granted provided that the above copyright notice and + this permission notice appear in all copies. + + YUP IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +#include "rive_renderer.h" + +#if __clang__ + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wshorten-64-to-32" + #pragma clang diagnostic ignored "-Wattributes" +#endif + +#include "source/gl/gl_state.cpp" +#include "source/gl/gl_utils.cpp" +#include "source/gl/load_gles_extensions.cpp" +#include "source/gl/load_store_actions_ext.cpp" +#include "source/gl/pls_impl_ext_native.cpp" +#include "source/gl/pls_impl_rw_texture.cpp" +#include "source/gl/render_buffer_gl_impl.cpp" +#include "source/gl/render_context_gl_impl.cpp" +#include "source/gl/render_target_gl.cpp" + +#if __clang__ + #pragma clang diagnostic pop +#endif diff --git a/third_party/rive_renderer/rive_renderer_apple.mm b/third_party/rive_renderer/rive_renderer_apple.mm new file mode 100644 index 0000000..6fbd4ef --- /dev/null +++ b/third_party/rive_renderer/rive_renderer_apple.mm @@ -0,0 +1,49 @@ +/* + ============================================================================== + + This file is part of the YUP library. + Copyright (c) 2024 - kunitoki@gmail.com + + YUP is an open source library subject to open-source licensing. + + The code included in this file is provided under the terms of the ISC license + http://www.isc.org/downloads/software-support-policy/isc-license. Permission + to use, copy, modify, and/or distribute this software for any purpose with or + without fee is hereby granted provided that the above copyright notice and + this permission notice appear in all copies. + + YUP IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +#include "rive_renderer.h" + +#if YUP_RIVE_USE_METAL +#include "source/metal/render_context_metal_impl.mm" +#include "source/metal/background_shader_compiler.mm" + +#include + +#if TARGET_OS_SIMULATOR +#include "source/generated/shaders/rive_pls_ios_simulator.metallib.c" +#elif TARGET_OS_IOS +#include "source/generated/shaders/rive_pls_ios.metallib.c" +#elif TARGET_OS_MAC +#include "source/generated/shaders/rive_pls_macosx.metallib.c" +#endif +#endif + +#if YUP_RIVE_USE_OPENGL +#include "source/gl/gl_state.cpp" +#include "source/gl/gl_utils.cpp" +#include "source/gl/load_gles_extensions.cpp" +#include "source/gl/load_store_actions_ext.cpp" +#include "source/gl/pls_impl_ext_native.cpp" +#include "source/gl/pls_impl_rw_texture.cpp" +#include "source/gl/render_buffer_gl_impl.cpp" +#include "source/gl/render_context_gl_impl.cpp" +#include "source/gl/render_target_gl.cpp" +#endif diff --git a/third_party/rive_renderer/rive_renderer_emscripten.cpp b/third_party/rive_renderer/rive_renderer_emscripten.cpp new file mode 100644 index 0000000..db25ae0 --- /dev/null +++ b/third_party/rive_renderer/rive_renderer_emscripten.cpp @@ -0,0 +1,52 @@ +/* + ============================================================================== + + This file is part of the YUP library. + Copyright (c) 2024 - kunitoki@gmail.com + + YUP is an open source library subject to open-source licensing. + + The code included in this file is provided under the terms of the ISC license + http://www.isc.org/downloads/software-support-policy/isc-license. Permission + to use, copy, modify, and/or distribute this software for any purpose with or + without fee is hereby granted provided that the above copyright notice and + this permission notice appear in all copies. + + YUP IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +#include "rive_renderer.h" + +#if __clang__ + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wshorten-64-to-32" + #pragma clang diagnostic ignored "-Wattributes" +#endif + +#if RIVE_WEBGPU +#include "source/webgpu/em_js_handle.cpp" +#include "source/webgpu/render_context_webgpu_impl.cpp" +//#include "source/webgpu/render_context_webgpu_vulkan.cpp" + +#elif RIVE_WEBGL +#include "source/gl/gl_state.cpp" +#include "source/gl/gl_utils.cpp" +#include "source/gl/load_gles_extensions.cpp" +#include "source/gl/load_store_actions_ext.cpp" +#include "source/gl/pls_impl_webgl.cpp" +#include "source/gl/render_buffer_gl_impl.cpp" +#include "source/gl/render_context_gl_impl.cpp" +#include "source/gl/render_target_gl.cpp" + +#else +#error "No renderer backend defined" + +#endif + +#if __clang__ + #pragma clang diagnostic pop +#endif diff --git a/third_party/rive_renderer/rive_renderer_linux.cpp b/third_party/rive_renderer/rive_renderer_linux.cpp new file mode 100644 index 0000000..1687817 --- /dev/null +++ b/third_party/rive_renderer/rive_renderer_linux.cpp @@ -0,0 +1,48 @@ +/* + ============================================================================== + + This file is part of the YUP library. + Copyright (c) 2024 - kunitoki@gmail.com + + YUP is an open source library subject to open-source licensing. + + The code included in this file is provided under the terms of the ISC license + http://www.isc.org/downloads/software-support-policy/isc-license. Permission + to use, copy, modify, and/or distribute this software for any purpose with or + without fee is hereby granted provided that the above copyright notice and + this permission notice appear in all copies. + + YUP IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +#include "rive_renderer.h" + +#if __clang__ + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wshorten-64-to-32" + #pragma clang diagnostic ignored "-Wattributes" +#elif __GNUC__ + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wattributes" +#endif + +#include "source/gl/gl_state.cpp" +#include "source/gl/gl_utils.cpp" +#include "source/gl/load_gles_extensions.cpp" +#include "source/gl/load_store_actions_ext.cpp" +#include "source/gl/pls_impl_ext_native.cpp" +#include "source/gl/pls_impl_rw_texture.cpp" +#include "source/gl/pls_impl_webgl.cpp" +#include "source/gl/render_buffer_gl_impl.cpp" +#include "source/gl/render_context_gl_impl.cpp" +#include "source/gl/render_target_gl.cpp" + +#if __clang__ + #pragma clang diagnostic pop +#elif __GNUC__ + #pragma GCC diagnostic pop +#endif diff --git a/third_party/rive_renderer/rive_renderer_windows.cpp b/third_party/rive_renderer/rive_renderer_windows.cpp new file mode 100644 index 0000000..046be43 --- /dev/null +++ b/third_party/rive_renderer/rive_renderer_windows.cpp @@ -0,0 +1,48 @@ +/* + ============================================================================== + + This file is part of the YUP library. + Copyright (c) 2024 - kunitoki@gmail.com + + YUP is an open source library subject to open-source licensing. + + The code included in this file is provided under the terms of the ISC license + http://www.isc.org/downloads/software-support-policy/isc-license. Permission + to use, copy, modify, and/or distribute this software for any purpose with or + without fee is hereby granted provided that the above copyright notice and + this permission notice appear in all copies. + + YUP IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +#include "rive_renderer.h" + +#if YUP_RIVE_USE_D3D +#pragma comment (lib, "d3d11.lib") +#pragma comment (lib, "d3dcompiler.lib") +#pragma comment (lib, "dxgi.lib") + +#include "source/d3d/pipeline_manager.cpp" +#include "source/d3d11/render_context_d3d_impl.cpp" +//#include "source/d3d12/d3d12_pipeline_manager.cpp" +//#include "source/d3d12/d3d12_utils.cpp" +//#include "source/d3d12/render_context_d3d12_impl.cpp" +#endif + +#if YUP_RIVE_USE_OPENGL +#pragma comment (lib, "opengl32.lib") + +#include "source/gl/gl_state.cpp" +#include "source/gl/gl_utils.cpp" +#include "source/gl/load_gles_extensions.cpp" +#include "source/gl/load_store_actions_ext.cpp" +#include "source/gl/pls_impl_ext_native.cpp" +#include "source/gl/pls_impl_rw_texture.cpp" +#include "source/gl/render_buffer_gl_impl.cpp" +#include "source/gl/render_context_gl_impl.cpp" +#include "source/gl/render_target_gl.cpp" +#endif diff --git a/third_party/rive_renderer/source/d3d/pipeline_manager.cpp b/third_party/rive_renderer/source/d3d/pipeline_manager.cpp new file mode 100644 index 0000000..114155e --- /dev/null +++ b/third_party/rive_renderer/source/d3d/pipeline_manager.cpp @@ -0,0 +1,261 @@ +/* + * Copyright 2025 Rive + */ +#include "rive/renderer/d3d/pipeline_manager.hpp" +#include "rive/renderer/d3d/d3d_constants.hpp" +#include "generated/shaders/constants.glsl.hpp" +#include + +#include + +#include "generated/shaders/advanced_blend.glsl.hpp" +#include "generated/shaders/atomic_draw.glsl.hpp" +#include "generated/shaders/color_ramp.glsl.hpp" +#include "generated/shaders/constants.glsl.hpp" +#include "generated/shaders/common.glsl.hpp" +#include "generated/shaders/draw_image_mesh.glsl.hpp" +#include "generated/shaders/draw_path_common.glsl.hpp" +#include "generated/shaders/draw_path.glsl.hpp" +#include "generated/shaders/hlsl.glsl.hpp" +#include "generated/shaders/bezier_utils.glsl.hpp" +#include "generated/shaders/render_atlas.glsl.hpp" +#include "generated/shaders/tessellate.glsl.hpp" + +namespace rive::gpu::d3d_utils +{ +std::string build_shader(DrawType drawType, + ShaderFeatures shaderFeatures, + InterlockMode interlockMode, + ShaderMiscFlags shaderMiscFlags, + const D3DCapabilities& d3dCapabilities) +{ + std::ostringstream s; + for (size_t i = 0; i < kShaderFeatureCount; ++i) + { + ShaderFeatures feature = static_cast(1 << i); + if (shaderFeatures & feature) + { + s << "#define " << GetShaderFeatureGLSLName(feature) << " 1\n"; + } + } + if (d3dCapabilities.supportsRasterizerOrderedViews) + { + if (interlockMode == InterlockMode::rasterOrdering && + drawType != DrawType::interiorTriangulation) + { + s << "#define " << GLSL_ENABLE_RASTERIZER_ORDERED_VIEWS << '\n'; + } + } + if (d3dCapabilities.supportsTypedUAVLoadStore) + { + s << "#define " << GLSL_ENABLE_TYPED_UAV_LOAD_STORE << '\n'; + } + if (d3dCapabilities.supportsMin16Precision) + { + s << "#define " << GLSL_ENABLE_MIN_16_PRECISION << '\n'; + } + if (shaderMiscFlags & ShaderMiscFlags::fixedFunctionColorOutput) + { + s << "#define " << GLSL_FIXED_FUNCTION_COLOR_OUTPUT << '\n'; + } + if (shaderMiscFlags & ShaderMiscFlags::coalescedResolveAndTransfer) + { + s << "#define " << GLSL_COALESCED_PLS_RESOLVE_AND_TRANSFER << '\n'; + if (!d3dCapabilities.allowsUAVSlot0WithColorOutput) + { + s << "#define " << GLSL_COLOR_PLANE_IDX_OVERRIDE << ' ' + << COALESCED_OFFSCREEN_COLOR_PLANE_IDX << '\n'; + } + } + if (shaderMiscFlags & ShaderMiscFlags::clockwiseFill) + { + s << "#define " << GLSL_CLOCKWISE_FILL << " 1\n"; + } + switch (drawType) + { + case DrawType::midpointFanPatches: + case DrawType::midpointFanCenterAAPatches: + case DrawType::outerCurvePatches: + s << "#define " << GLSL_DRAW_PATH << '\n'; + break; + case DrawType::atlasBlit: + s << "#define " << GLSL_ATLAS_BLIT << " 1\n"; + [[fallthrough]]; + case DrawType::interiorTriangulation: + s << "#define " << GLSL_DRAW_INTERIOR_TRIANGLES << '\n'; + break; + case DrawType::imageRect: + assert(interlockMode == InterlockMode::atomics); + s << "#define " << GLSL_DRAW_IMAGE << '\n'; + s << "#define " << GLSL_DRAW_IMAGE_RECT << '\n'; + break; + case DrawType::imageMesh: + s << "#define " << GLSL_DRAW_IMAGE << '\n'; + s << "#define " << GLSL_DRAW_IMAGE_MESH << '\n'; + break; + case DrawType::atomicResolve: + assert(interlockMode == InterlockMode::atomics); + s << "#define " << GLSL_DRAW_RENDER_TARGET_UPDATE_BOUNDS << '\n'; + s << "#define " << GLSL_RESOLVE_PLS << '\n'; + break; + case DrawType::atomicInitialize: + case DrawType::msaaStrokes: + case DrawType::msaaMidpointFanBorrowedCoverage: + case DrawType::msaaMidpointFans: + case DrawType::msaaMidpointFanStencilReset: + case DrawType::msaaMidpointFanPathsStencil: + case DrawType::msaaMidpointFanPathsCover: + case DrawType::msaaOuterCubics: + case DrawType::msaaStencilClipReset: + RIVE_UNREACHABLE(); + } + s << glsl::constants << '\n'; + s << glsl::hlsl << '\n'; + s << glsl::common << '\n'; + if (shaderFeatures & ShaderFeatures::ENABLE_ADVANCED_BLEND) + { + s << glsl::advanced_blend << '\n'; + } + switch (drawType) + { + case DrawType::midpointFanPatches: + case DrawType::midpointFanCenterAAPatches: + case DrawType::outerCurvePatches: + s << glsl::draw_path_common << '\n'; + s << (interlockMode == InterlockMode::rasterOrdering + ? glsl::draw_path + : glsl::atomic_draw) + << '\n'; + break; + case DrawType::interiorTriangulation: + case DrawType::atlasBlit: + s << glsl::draw_path_common << '\n'; + s << (interlockMode == InterlockMode::rasterOrdering + ? glsl::draw_path + : glsl::atomic_draw) + << '\n'; + break; + case DrawType::imageRect: + assert(interlockMode == InterlockMode::atomics); + s << glsl::draw_path_common << '\n'; + s << glsl::atomic_draw << '\n'; + break; + case DrawType::imageMesh: + if (interlockMode == InterlockMode::rasterOrdering) + { + s << glsl::draw_image_mesh << '\n'; + } + else + { + s << glsl::draw_path_common << '\n'; + s << glsl::atomic_draw << '\n'; + } + break; + case DrawType::atomicResolve: + case DrawType::msaaStencilClipReset: + assert(interlockMode == InterlockMode::atomics); + s << glsl::draw_path_common << '\n'; + s << glsl::atomic_draw << '\n'; + break; + case DrawType::atomicInitialize: + case DrawType::msaaStrokes: + case DrawType::msaaMidpointFanBorrowedCoverage: + case DrawType::msaaMidpointFans: + case DrawType::msaaMidpointFanStencilReset: + case DrawType::msaaMidpointFanPathsStencil: + case DrawType::msaaMidpointFanPathsCover: + case DrawType::msaaOuterCubics: + RIVE_UNREACHABLE(); + } + + return s.str(); +} + +ComPtr compile_pixel_source_to_blob(const std::string& sharedSource, + const char* target) +{ + std::ostringstream source; + source << "#define " << GLSL_FRAGMENT << '\n'; + source << sharedSource; + + const std::string& sourceStr = source.str(); + ComPtr blob; + ComPtr errors; + HRESULT hr = D3DCompile(sourceStr.c_str(), + sourceStr.length(), + nullptr, + nullptr, + nullptr, + "main", + target, + D3DCOMPILE_ENABLE_STRICTNESS, + 0, + &blob, + &errors); + if (errors && errors->GetBufferPointer()) + { + fprintf(stderr, "Errors or warnings compiling shader.\n"); + int l = 1; + std::stringstream stream(sourceStr); + std::string lineStr; + while (std::getline(stream, lineStr, '\n')) + { + fprintf(stderr, "%4i| %s\n", l++, lineStr.c_str()); + } + fprintf(stderr, + "%s\n", + reinterpret_cast(errors->GetBufferPointer())); + abort(); + } + if (FAILED(hr)) + { + fprintf(stderr, "Failed to compile shader.\n"); + abort(); + } + return blob; +} + +ComPtr compile_vertex_source_to_blob(const std::string& sharedSource, + const char* target) +{ + std::ostringstream source; + source << "#define " << GLSL_VERTEX << '\n'; + source << sharedSource; + + const std::string& sourceStr = source.str(); + ComPtr blob; + ComPtr errors; + HRESULT hr = D3DCompile(sourceStr.c_str(), + sourceStr.length(), + nullptr, + nullptr, + nullptr, + "main", + target, + D3DCOMPILE_ENABLE_STRICTNESS, + 0, + &blob, + &errors); + if (errors && errors->GetBufferPointer()) + { + fprintf(stderr, "Errors or warnings compiling shader.\n"); + int l = 1; + std::stringstream stream(sourceStr); + std::string lineStr; + while (std::getline(stream, lineStr, '\n')) + { + fprintf(stderr, "%4i| %s\n", l++, lineStr.c_str()); + } + fprintf(stderr, + "%s\n", + reinterpret_cast(errors->GetBufferPointer())); + abort(); + } + if (FAILED(hr)) + { + fprintf(stderr, "Failed to compile shader.\n"); + abort(); + } + return blob; +} +}; // namespace rive::gpu::d3d_utils \ No newline at end of file diff --git a/third_party/rive_renderer/source/d3d11/render_context_d3d_impl.cpp b/third_party/rive_renderer/source/d3d11/render_context_d3d_impl.cpp new file mode 100644 index 0000000..f0b6ebe --- /dev/null +++ b/third_party/rive_renderer/source/d3d11/render_context_d3d_impl.cpp @@ -0,0 +1,2014 @@ +/* + * Copyright 2023 Rive + */ + +#include "rive/renderer/d3d11/render_context_d3d_impl.hpp" + +#include "rive/renderer/d3d/d3d_constants.hpp" + +#include "rive/renderer/texture.hpp" + +#include +#include + +#include "generated/shaders/advanced_blend.glsl.hpp" +#include "generated/shaders/atomic_draw.glsl.hpp" +#include "generated/shaders/color_ramp.glsl.hpp" +#include "generated/shaders/constants.glsl.hpp" +#include "generated/shaders/common.glsl.hpp" +#include "generated/shaders/draw_image_mesh.glsl.hpp" +#include "generated/shaders/draw_path_common.glsl.hpp" +#include "generated/shaders/draw_path.glsl.hpp" +#include "generated/shaders/hlsl.glsl.hpp" +#include "generated/shaders/bezier_utils.glsl.hpp" +#include "generated/shaders/render_atlas.glsl.hpp" +#include "generated/shaders/tessellate.glsl.hpp" + +// offline shaders +namespace shader +{ +namespace tess::vert +{ +#include "generated/shaders/d3d/tessellate.vert.h" +} +namespace tess::frag +{ +#include "generated/shaders/d3d/tessellate.frag.h" +} +namespace grad::vert +{ +#include "generated/shaders/d3d/color_ramp.vert.h" +} +namespace grad::frag +{ +#include "generated/shaders/d3d/color_ramp.frag.h" +} +namespace atlas::vert +{ +#include "generated/shaders/d3d/render_atlas.vert.h" +} +namespace atlas::fill +{ +#include "generated/shaders/d3d/render_atlas_fill.frag.h" +} +namespace atlas::stroke +{ +#include "generated/shaders/d3d/render_atlas_stroke.frag.h" +} +} // namespace shader + +namespace rive::gpu +{ +ComPtr make_simple_2d_texture(ID3D11Device* gpu, + DXGI_FORMAT format, + UINT width, + UINT height, + UINT mipLevelCount, + UINT bindFlags, + UINT miscFlags = 0) +{ + D3D11_TEXTURE2D_DESC desc{}; + desc.Width = width; + desc.Height = height; + desc.MipLevels = mipLevelCount; + desc.ArraySize = 1; + desc.Format = format; + desc.SampleDesc.Count = 1; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = bindFlags; + desc.CPUAccessFlags = 0; + desc.MiscFlags = miscFlags; + + ComPtr tex; + VERIFY_OK(gpu->CreateTexture2D(&desc, NULL, tex.ReleaseAndGetAddressOf())); + return tex; +} + +static ComPtr make_simple_2d_uav( + ID3D11Device* gpu, + ID3D11Texture2D* tex, + DXGI_FORMAT format) +{ + D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc{}; + uavDesc.Format = format; + uavDesc.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE2D; + + ComPtr uav; + VERIFY_OK(gpu->CreateUnorderedAccessView(tex, + &uavDesc, + uav.ReleaseAndGetAddressOf())); + return uav; +} + +D3D11PipelineManager::D3D11PipelineManager( + ComPtr context, + ComPtr device, + const D3DCapabilities& capabilities) : + D3DPipelineManager, + ID3D11Device>(device, capabilities, "vs_5_0", "ps_5_0"), + m_context(context) +{ + D3D11_INPUT_ELEMENT_DESC spanDesc = {GLSL_a_span, + 0, + DXGI_FORMAT_R32G32B32A32_UINT, + 0, + 0, + D3D11_INPUT_PER_INSTANCE_DATA, + 1}; + + VERIFY_OK( + this->device()->CreateInputLayout(&spanDesc, + 1, + shader::grad::vert::g_main, + std::size(shader::grad::vert::g_main), + &m_colorRampLayout)); + VERIFY_OK(this->device()->CreateVertexShader( + shader::grad::vert::g_main, + std::size(shader::grad::vert::g_main), + nullptr, + &m_colorRampVertexShader)); + VERIFY_OK( + this->device()->CreatePixelShader(shader::grad::frag::g_main, + std::size(shader::grad::frag::g_main), + nullptr, + &m_colorRampPixelShader)); + + D3D11_INPUT_ELEMENT_DESC attribsDesc[] = {{GLSL_a_p0p1_, + 0, + DXGI_FORMAT_R32G32B32A32_FLOAT, + 0, + D3D11_APPEND_ALIGNED_ELEMENT, + D3D11_INPUT_PER_INSTANCE_DATA, + 1}, + {GLSL_a_p2p3_, + 0, + DXGI_FORMAT_R32G32B32A32_FLOAT, + 0, + D3D11_APPEND_ALIGNED_ELEMENT, + D3D11_INPUT_PER_INSTANCE_DATA, + 1}, + {GLSL_a_joinTan_and_ys, + 0, + DXGI_FORMAT_R32G32B32A32_FLOAT, + 0, + D3D11_APPEND_ALIGNED_ELEMENT, + D3D11_INPUT_PER_INSTANCE_DATA, + 1}, + {GLSL_a_args, + 0, + DXGI_FORMAT_R32G32B32A32_UINT, + 0, + D3D11_APPEND_ALIGNED_ELEMENT, + D3D11_INPUT_PER_INSTANCE_DATA, + 1}}; + VERIFY_OK( + this->device()->CreateInputLayout(attribsDesc, + std::size(attribsDesc), + shader::tess::vert::g_main, + std::size(shader::tess::vert::g_main), + &m_tessellateLayout)); + VERIFY_OK(this->device()->CreateVertexShader( + shader::tess::vert::g_main, + std::size(shader::tess::vert::g_main), + nullptr, + &m_tessellateVertexShader)); + VERIFY_OK( + this->device()->CreatePixelShader(shader::tess::frag::g_main, + std::size(shader::tess::frag::g_main), + nullptr, + &m_tessellatePixelShader)); + + D3D11_INPUT_ELEMENT_DESC layoutDesc[2]; + layoutDesc[0] = {GLSL_a_patchVertexData, + 0, + DXGI_FORMAT_R32G32B32A32_FLOAT, + PATCH_VERTEX_DATA_SLOT, + D3D11_APPEND_ALIGNED_ELEMENT, + D3D11_INPUT_PER_VERTEX_DATA, + 0}; + layoutDesc[1] = {GLSL_a_mirroredVertexData, + 0, + DXGI_FORMAT_R32G32B32A32_FLOAT, + PATCH_VERTEX_DATA_SLOT, + D3D11_APPEND_ALIGNED_ELEMENT, + D3D11_INPUT_PER_VERTEX_DATA, + 0}; + VERIFY_OK(this->device()->CreateInputLayout( + layoutDesc, + 2, + shader::atlas::vert::g_main, + std::size(shader::atlas::vert::g_main), + &m_atlasLayout)); + VERIFY_OK(this->device()->CreateVertexShader( + shader::atlas::vert::g_main, + std::size(shader::atlas::vert::g_main), + nullptr, + &m_atlasVertexShader)); + + VERIFY_OK(this->device()->CreatePixelShader( + shader::atlas::fill::g_main, + std::size(shader::atlas::fill::g_main), + nullptr, + &m_atlasFillPixelShader)); + + VERIFY_OK(this->device()->CreatePixelShader( + shader::atlas::stroke::g_main, + std::size(shader::atlas::stroke::g_main), + nullptr, + &m_atlasStrokePixelShader)); +} + +void D3D11PipelineManager::setPipelineState( + rive::gpu::DrawType drawType, + rive::gpu::ShaderFeatures features, + rive::gpu::InterlockMode interlockMode, + rive::gpu::ShaderMiscFlags miscFlags) +{ + ShaderCompileResult result{}; + if (!getShader( + {drawType, features, interlockMode, miscFlags, d3dCapabilities()}, + &result)) + { + // this should never happen + RIVE_UNREACHABLE(); + } + + assert(result.vertexResult.hasResult); + assert(result.pixelResult.hasResult); + + m_context->IASetInputLayout( + result.vertexResult.vertexShaderResult.layout.Get()); + m_context->VSSetShader(result.vertexResult.vertexShaderResult.shader.Get(), + NULL, + 0); + m_context->PSSetShader(result.pixelResult.pixelShaderResult.Get(), NULL, 0); +} + +void D3D11PipelineManager::compileBlobToFinalType( + const ShaderCompileRequest& request, + ComPtr vertexShader, + ComPtr pixelShader, + ShaderCompileResult* result) +{ + if (result->vertexResult.hasResult == false) + { + D3D11_INPUT_ELEMENT_DESC layoutDesc[2]; + uint32_t vertexAttribCount; + switch (request.drawType) + { + case DrawType::midpointFanPatches: + case DrawType::midpointFanCenterAAPatches: + case DrawType::outerCurvePatches: + layoutDesc[0] = {GLSL_a_patchVertexData, + 0, + DXGI_FORMAT_R32G32B32A32_FLOAT, + PATCH_VERTEX_DATA_SLOT, + D3D11_APPEND_ALIGNED_ELEMENT, + D3D11_INPUT_PER_VERTEX_DATA, + 0}; + layoutDesc[1] = {GLSL_a_mirroredVertexData, + 0, + DXGI_FORMAT_R32G32B32A32_FLOAT, + PATCH_VERTEX_DATA_SLOT, + D3D11_APPEND_ALIGNED_ELEMENT, + D3D11_INPUT_PER_VERTEX_DATA, + 0}; + vertexAttribCount = 2; + break; + case DrawType::interiorTriangulation: + case DrawType::atlasBlit: + layoutDesc[0] = {GLSL_a_triangleVertex, + 0, + DXGI_FORMAT_R32G32B32_FLOAT, + TRIANGLE_VERTEX_DATA_SLOT, + 0, + D3D11_INPUT_PER_VERTEX_DATA, + 0}; + vertexAttribCount = 1; + break; + case DrawType::imageRect: + layoutDesc[0] = {GLSL_a_imageRectVertex, + 0, + DXGI_FORMAT_R32G32B32A32_FLOAT, + IMAGE_RECT_VERTEX_DATA_SLOT, + 0, + D3D11_INPUT_PER_VERTEX_DATA, + 0}; + vertexAttribCount = 1; + break; + case DrawType::imageMesh: + layoutDesc[0] = {GLSL_a_position, + 0, + DXGI_FORMAT_R32G32_FLOAT, + IMAGE_MESH_VERTEX_DATA_SLOT, + D3D11_APPEND_ALIGNED_ELEMENT, + D3D11_INPUT_PER_VERTEX_DATA, + 0}; + layoutDesc[1] = {GLSL_a_texCoord, + 0, + DXGI_FORMAT_R32G32_FLOAT, + IMAGE_MESH_UV_DATA_SLOT, + D3D11_APPEND_ALIGNED_ELEMENT, + D3D11_INPUT_PER_VERTEX_DATA, + 0}; + vertexAttribCount = 2; + break; + case DrawType::atomicResolve: + vertexAttribCount = 0; + break; + case DrawType::atomicInitialize: + case DrawType::msaaStrokes: + case DrawType::msaaMidpointFanBorrowedCoverage: + case DrawType::msaaMidpointFans: + case DrawType::msaaMidpointFanStencilReset: + case DrawType::msaaMidpointFanPathsStencil: + case DrawType::msaaMidpointFanPathsCover: + case DrawType::msaaOuterCubics: + case DrawType::msaaStencilClipReset: + RIVE_UNREACHABLE(); + } + + VERIFY_OK(device()->CreateInputLayout( + layoutDesc, + vertexAttribCount, + vertexShader->GetBufferPointer(), + vertexShader->GetBufferSize(), + &result->vertexResult.vertexShaderResult.layout)); + VERIFY_OK(device()->CreateVertexShader( + vertexShader->GetBufferPointer(), + vertexShader->GetBufferSize(), + nullptr, + &result->vertexResult.vertexShaderResult.shader)); + + result->vertexResult.hasResult = true; + } + + if (result->pixelResult.hasResult == false) + { + ComPtr pixelShaderResult; + + VERIFY_OK(device()->CreatePixelShader(pixelShader->GetBufferPointer(), + pixelShader->GetBufferSize(), + nullptr, + &pixelShaderResult)); + + result->pixelResult.pixelShaderResult = std::move(pixelShaderResult); + result->pixelResult.hasResult = true; + } +} + +static D3D11_FILTER filter_for_sampler_filter_options(ImageFilter option) +{ + switch (option) + { + case ImageFilter::trilinear: + return D3D11_FILTER::D3D11_FILTER_MIN_MAG_MIP_LINEAR; + case ImageFilter::nearest: + return D3D11_FILTER::D3D11_FILTER_MIN_MAG_MIP_POINT; + } + + RIVE_UNREACHABLE(); + return D3D11_FILTER_MIN_MAG_MIP_LINEAR; +} + +static D3D11_TEXTURE_ADDRESS_MODE address_mode_for_sampler_filter_options( + ImageWrap option) +{ + switch (option) + { + case ImageWrap::clamp: + return D3D11_TEXTURE_ADDRESS_CLAMP; + case ImageWrap::repeat: + return D3D11_TEXTURE_ADDRESS_WRAP; + case ImageWrap::mirror: + return D3D11_TEXTURE_ADDRESS_MIRROR; + } + + RIVE_UNREACHABLE(); + return D3D11_TEXTURE_ADDRESS_CLAMP; +} + +std::unique_ptr RenderContextD3DImpl::MakeContext( + ComPtr gpu, + ComPtr gpuContext, + const D3DContextOptions& contextOptions) +{ + D3DCapabilities d3dCapabilities; + D3D11_FEATURE_DATA_D3D11_OPTIONS2 d3d11Options2; + + if (gpu->GetFeatureLevel() >= D3D_FEATURE_LEVEL_11_1) + { + if (SUCCEEDED(gpu->CheckFeatureSupport( + D3D11_FEATURE_D3D11_OPTIONS2, + &d3d11Options2, + sizeof(D3D11_FEATURE_DATA_D3D11_OPTIONS2)))) + { + d3dCapabilities.supportsRasterizerOrderedViews = + d3d11Options2.ROVsSupported; + if (d3d11Options2.TypedUAVLoadAdditionalFormats) + { + // TypedUAVLoadAdditionalFormats is true. Now check if we can + // both load and store all formats used by Rive (currently only + // RGBA8 and BGRA8): + // https://learn.microsoft.com/en-us/windows/win32/direct3d11/typed-unordered-access-view-loads. + auto check_typed_uav_load = [gpu](DXGI_FORMAT format) { + D3D11_FEATURE_DATA_FORMAT_SUPPORT2 d3d11Format2{}; + d3d11Format2.InFormat = format; + if (SUCCEEDED(gpu->CheckFeatureSupport( + D3D11_FEATURE_FORMAT_SUPPORT2, + &d3d11Format2, + sizeof(d3d11Format2)))) + { + constexpr UINT loadStoreFlags = + D3D11_FORMAT_SUPPORT2_UAV_TYPED_LOAD | + D3D11_FORMAT_SUPPORT2_UAV_TYPED_STORE; + return (d3d11Format2.OutFormatSupport2 & + loadStoreFlags) == loadStoreFlags; + } + return false; + }; + d3dCapabilities.supportsTypedUAVLoadStore = + check_typed_uav_load(DXGI_FORMAT_R8G8B8A8_UNORM) && + check_typed_uav_load(DXGI_FORMAT_B8G8R8A8_UNORM); + } + } + + // Check if we can use HLSL minimum precision types (e.g. min16int) + D3D11_FEATURE_DATA_SHADER_MIN_PRECISION_SUPPORT + d3d11MinPrecisionSupport; + if (SUCCEEDED(gpu->CheckFeatureSupport( + D3D11_FEATURE_SHADER_MIN_PRECISION_SUPPORT, + &d3d11MinPrecisionSupport, + sizeof(d3d11MinPrecisionSupport)))) + { + const UINT allStageMinPrecision = + (d3d11MinPrecisionSupport.AllOtherShaderStagesMinPrecision & + d3d11MinPrecisionSupport.PixelShaderMinPrecision); + + d3dCapabilities.supportsMin16Precision = + (allStageMinPrecision & D3D11_SHADER_MIN_PRECISION_16_BIT) != 0; + } + } + + if (contextOptions.disableRasterizerOrderedViews) + { + d3dCapabilities.supportsRasterizerOrderedViews = false; + } + if (contextOptions.disableTypedUAVLoadStore) + { + d3dCapabilities.supportsTypedUAVLoadStore = false; + } + + d3dCapabilities.isIntel = contextOptions.isIntel; + d3dCapabilities.allowsUAVSlot0WithColorOutput = false; + + auto renderContextImpl = std::unique_ptr( + new RenderContextD3DImpl(std::move(gpu), + std::move(gpuContext), + d3dCapabilities)); + return std::make_unique(std::move(renderContextImpl)); +} + +RenderContextD3DImpl::RenderContextD3DImpl( + ComPtr gpu, + ComPtr gpuContext, + const D3DCapabilities& d3dCapabilities) : + m_pipelineManager(gpuContext, gpu, d3dCapabilities), + m_d3dCapabilities(d3dCapabilities), + m_gpu(std::move(gpu)), + m_gpuContext(std::move(gpuContext)) +{ + m_platformFeatures.clipSpaceBottomUp = true; + m_platformFeatures.framebufferBottomUp = false; + m_platformFeatures.supportsRasterOrdering = + d3dCapabilities.supportsRasterizerOrderedViews; + m_platformFeatures.supportsFragmentShaderAtomics = true; + m_platformFeatures.maxTextureSize = D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION; + + // Create a default raster state for path and offscreen draws. + D3D11_RASTERIZER_DESC rasterDesc; + rasterDesc.FillMode = D3D11_FILL_SOLID; + rasterDesc.CullMode = D3D11_CULL_BACK; + rasterDesc.FrontCounterClockwise = + FALSE; // FrontCounterClockwise must be FALSE in order to + // match the winding sense of interior triangulations. + + rasterDesc.DepthBias = 0; + rasterDesc.SlopeScaledDepthBias = 0; + rasterDesc.DepthBiasClamp = 0; + rasterDesc.DepthClipEnable = + TRUE; // This is the default state which reset to before flushing. + // Details on default state here: + // https://learn.microsoft.com/en-us/windows/win32/api/d3d11/ns-d3d11-d3d11_rasterizer_desc + + rasterDesc.ScissorEnable = FALSE; + rasterDesc.MultisampleEnable = FALSE; + rasterDesc.AntialiasedLineEnable = FALSE; + VERIFY_OK(m_gpu->CreateRasterizerState( + &rasterDesc, + m_backCulledRasterState[0].ReleaseAndGetAddressOf())); + + // ...And with scissor for the atlas. + rasterDesc.ScissorEnable = TRUE; + VERIFY_OK(m_gpu->CreateRasterizerState( + &rasterDesc, + m_atlasRasterState.ReleaseAndGetAddressOf())); + + // ...And with wireframe for debugging. + rasterDesc.ScissorEnable = FALSE; + rasterDesc.FillMode = D3D11_FILL_WIREFRAME; + VERIFY_OK(m_gpu->CreateRasterizerState( + &rasterDesc, + m_backCulledRasterState[1].ReleaseAndGetAddressOf())); + + // Create a raster state without face culling for drawing image meshes. + rasterDesc.FillMode = D3D11_FILL_SOLID; + rasterDesc.CullMode = D3D11_CULL_NONE; + VERIFY_OK(m_gpu->CreateRasterizerState( + &rasterDesc, + m_doubleSidedRasterState[0].ReleaseAndGetAddressOf())); + + // ...And once more with wireframe for debugging. + rasterDesc.FillMode = D3D11_FILL_WIREFRAME; + VERIFY_OK(m_gpu->CreateRasterizerState( + &rasterDesc, + m_doubleSidedRasterState[1].ReleaseAndGetAddressOf())); + + // Create the feather texture. + D3D11_TEXTURE1D_DESC featherTextureDesc{}; + featherTextureDesc.Format = DXGI_FORMAT_R16_FLOAT; + featherTextureDesc.Width = gpu::GAUSSIAN_TABLE_SIZE; + featherTextureDesc.MipLevels = 1; + featherTextureDesc.ArraySize = FEATHER_TEXTURE_1D_ARRAY_LENGTH; + featherTextureDesc.Usage = D3D11_USAGE_DEFAULT; + featherTextureDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE; + featherTextureDesc.CPUAccessFlags = 0; + featherTextureDesc.MiscFlags = 0; + VERIFY_OK( + m_gpu->CreateTexture1D(&featherTextureDesc, + NULL, + m_featherTexture.ReleaseAndGetAddressOf())); + + D3D11_BOX box; + box.left = 0; + box.right = gpu::GAUSSIAN_TABLE_SIZE; + box.top = 0; + box.bottom = 1; + box.front = 0; + box.back = 1; + m_gpuContext->UpdateSubresource(m_featherTexture.Get(), + FEATHER_FUNCTION_ARRAY_INDEX, + &box, + gpu::g_gaussianIntegralTableF16, + sizeof(gpu::g_gaussianIntegralTableF16), + sizeof(gpu::g_gaussianIntegralTableF16)); + m_gpuContext->UpdateSubresource(m_featherTexture.Get(), + FEATHER_INVERSE_FUNCTION_ARRAY_INDEX, + &box, + gpu::g_inverseGaussianIntegralTableF16, + sizeof(gpu::g_gaussianIntegralTableF16), + 0); + VERIFY_OK(m_gpu->CreateShaderResourceView( + m_featherTexture.Get(), + NULL, + m_featherTextureSRV.ReleaseAndGetAddressOf())); + + // Compile the tessellation shaders. + { + m_tessSpanIndexBuffer = + makeSimpleImmutableBuffer(sizeof(gpu::kTessSpanIndices), + D3D11_BIND_INDEX_BUFFER, + gpu::kTessSpanIndices); + } + + // Set up the path patch rendering buffers. + PatchVertex patchVertices[kPatchVertexBufferCount]; + uint16_t patchIndices[kPatchIndexBufferCount]; + GeneratePatchBufferData(patchVertices, patchIndices); + m_patchVertexBuffer = makeSimpleImmutableBuffer(sizeof(patchVertices), + D3D11_BIND_VERTEX_BUFFER, + patchVertices); + m_patchIndexBuffer = makeSimpleImmutableBuffer(sizeof(patchIndices), + D3D11_BIND_INDEX_BUFFER, + patchIndices); + + // Set up the imageRect rendering buffers. (gpu::InterlockMode::atomics + // only.) + m_imageRectVertexBuffer = + makeSimpleImmutableBuffer(sizeof(gpu::kImageRectVertices), + D3D11_BIND_VERTEX_BUFFER, + gpu::kImageRectVertices); + m_imageRectIndexBuffer = + makeSimpleImmutableBuffer(sizeof(gpu::kImageRectIndices), + D3D11_BIND_INDEX_BUFFER, + gpu::kImageRectIndices); + + // Create buffers for uniforms. + { + D3D11_BUFFER_DESC desc{}; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; + + desc.ByteWidth = sizeof(gpu::FlushUniforms); + desc.StructureByteStride = sizeof(gpu::FlushUniforms); + VERIFY_OK( + m_gpu->CreateBuffer(&desc, + nullptr, + m_flushUniforms.ReleaseAndGetAddressOf())); + + desc.ByteWidth = sizeof(DrawUniforms); + desc.StructureByteStride = sizeof(DrawUniforms); + VERIFY_OK(m_gpu->CreateBuffer(&desc, + nullptr, + m_drawUniforms.ReleaseAndGetAddressOf())); + + desc.ByteWidth = sizeof(gpu::ImageDrawUniforms); + desc.StructureByteStride = sizeof(gpu::ImageDrawUniforms); + VERIFY_OK( + m_gpu->CreateBuffer(&desc, + nullptr, + m_imageDrawUniforms.ReleaseAndGetAddressOf())); + } + + // Create a linear sampler for the gradient & feather textures. + D3D11_SAMPLER_DESC linearSamplerDesc; + linearSamplerDesc.Filter = D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT; + linearSamplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP; + linearSamplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP; + linearSamplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; + linearSamplerDesc.MipLODBias = 0.0f; + linearSamplerDesc.MaxAnisotropy = 1; + linearSamplerDesc.ComparisonFunc = D3D11_COMPARISON_NEVER; + linearSamplerDesc.MinLOD = 0; + linearSamplerDesc.MaxLOD = 0; + VERIFY_OK( + m_gpu->CreateSamplerState(&linearSamplerDesc, + m_linearSampler.ReleaseAndGetAddressOf())); + + // Create a mipmap sampler for each sampler permutation option. + for (int samplerKey = 0; + samplerKey < ImageSampler::MAX_SAMPLER_PERMUTATIONS; + ++samplerKey) + { + auto xWrap = ImageSampler::GetWrapXOptionFromKey(samplerKey); + auto yWrap = ImageSampler::GetWrapYOptionFromKey(samplerKey); + D3D11_SAMPLER_DESC mipmapSamplerDesc; + mipmapSamplerDesc.Filter = filter_for_sampler_filter_options( + ImageSampler::GetFilterOptionFromKey(samplerKey)); + mipmapSamplerDesc.AddressU = + address_mode_for_sampler_filter_options(xWrap); + mipmapSamplerDesc.AddressV = + address_mode_for_sampler_filter_options(yWrap); + mipmapSamplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; + mipmapSamplerDesc.MipLODBias = 0.0f; + mipmapSamplerDesc.MaxAnisotropy = 1; + mipmapSamplerDesc.ComparisonFunc = D3D11_COMPARISON_NEVER; + mipmapSamplerDesc.MinLOD = 0; + mipmapSamplerDesc.MaxLOD = D3D11_FLOAT32_MAX; + VERIFY_OK(m_gpu->CreateSamplerState( + &mipmapSamplerDesc, + m_samplerStates[samplerKey].ReleaseAndGetAddressOf())); + } + + m_gpuContext->VSSetSamplers(FEATHER_TEXTURE_IDX, + 1, + m_linearSampler.GetAddressOf()); + + D3D11_BLEND_DESC srcOverDesc{}; + srcOverDesc.RenderTarget[0].BlendEnable = TRUE; + srcOverDesc.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE; + srcOverDesc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA; + srcOverDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD; + srcOverDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE; + srcOverDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA; + srcOverDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; + srcOverDesc.RenderTarget[0].RenderTargetWriteMask = + D3D11_COLOR_WRITE_ENABLE_ALL; + VERIFY_OK( + m_gpu->CreateBlendState(&srcOverDesc, + m_srcOverBlendState.ReleaseAndGetAddressOf())); + + D3D11_BLEND_DESC plusDesc{}; + plusDesc.RenderTarget[0].BlendEnable = TRUE; + plusDesc.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE; + plusDesc.RenderTarget[0].DestBlend = D3D11_BLEND_ONE; + plusDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD; + plusDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE; + plusDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ONE; + plusDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; + plusDesc.RenderTarget[0].RenderTargetWriteMask = + D3D11_COLOR_WRITE_ENABLE_ALL; + VERIFY_OK( + m_gpu->CreateBlendState(&plusDesc, + m_plusBlendState.ReleaseAndGetAddressOf())); + + D3D11_BLEND_DESC maxDesc = plusDesc; + maxDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_MAX; + maxDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_MAX; + VERIFY_OK( + m_gpu->CreateBlendState(&maxDesc, + m_maxBlendState.ReleaseAndGetAddressOf())); +} + +ComPtr RenderContextD3DImpl::makeSimple2DTexture( + DXGI_FORMAT format, + UINT width, + UINT height, + UINT mipLevelCount, + UINT bindFlags, + UINT miscFlags) +{ + return make_simple_2d_texture(m_gpu.Get(), + format, + width, + height, + mipLevelCount, + bindFlags, + miscFlags); +} + +ComPtr RenderContextD3DImpl::makeSimple2DUAV( + ID3D11Texture2D* tex, + DXGI_FORMAT format) +{ + return make_simple_2d_uav(m_gpu.Get(), tex, format); +} + +ComPtr RenderContextD3DImpl::makeSimpleImmutableBuffer( + size_t sizeInBytes, + UINT bindFlags, + const void* data) +{ + D3D11_BUFFER_DESC desc{}; + desc.ByteWidth = math::lossless_numeric_cast(sizeInBytes); + desc.Usage = D3D11_USAGE_IMMUTABLE; + desc.BindFlags = bindFlags; + desc.StructureByteStride = sizeof(PatchVertex); + + D3D11_SUBRESOURCE_DATA dataDesc{}; + dataDesc.pSysMem = data; + + ComPtr buffer; + VERIFY_OK( + m_gpu->CreateBuffer(&desc, &dataDesc, buffer.ReleaseAndGetAddressOf())); + return buffer; +} + +class RenderBufferD3DImpl + : public LITE_RTTI_OVERRIDE(RenderBuffer, RenderBufferD3DImpl) +{ +public: + RenderBufferD3DImpl(RenderBufferType renderBufferType, + RenderBufferFlags renderBufferFlags, + size_t sizeInBytes, + ComPtr gpu, + ComPtr gpuContext) : + lite_rtti_override(renderBufferType, renderBufferFlags, sizeInBytes), + m_gpu(std::move(gpu)), + m_gpuContext(std::move(gpuContext)) + { + m_desc.ByteWidth = math::lossless_numeric_cast(sizeInBytes); + m_desc.BindFlags = type() == RenderBufferType::vertex + ? D3D11_BIND_VERTEX_BUFFER + : D3D11_BIND_INDEX_BUFFER; + if (flags() & RenderBufferFlags::mappedOnceAtInitialization) + { + m_desc.Usage = D3D11_USAGE_IMMUTABLE; + m_desc.CPUAccessFlags = 0; + m_mappedMemoryForImmutableBuffer.reset(new char[sizeInBytes]); + } + else + { + m_desc.Usage = D3D11_USAGE_DYNAMIC; + m_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + VERIFY_OK(m_gpu->CreateBuffer(&m_desc, + nullptr, + m_buffer.ReleaseAndGetAddressOf())); + } + } + + ID3D11Buffer* buffer() const { return m_buffer.Get(); } + +protected: + void* onMap() override + { + if (flags() & RenderBufferFlags::mappedOnceAtInitialization) + { + assert(m_mappedMemoryForImmutableBuffer); + return m_mappedMemoryForImmutableBuffer.get(); + } + else + { + D3D11_MAPPED_SUBRESOURCE mappedSubresource; + m_gpuContext->Map(m_buffer.Get(), + 0, + D3D11_MAP_WRITE_DISCARD, + 0, + &mappedSubresource); + return mappedSubresource.pData; + } + } + + void onUnmap() override + { + if (flags() & RenderBufferFlags::mappedOnceAtInitialization) + { + assert(!m_buffer); + D3D11_SUBRESOURCE_DATA bufferDataDesc{}; + bufferDataDesc.pSysMem = m_mappedMemoryForImmutableBuffer.get(); + VERIFY_OK(m_gpu->CreateBuffer(&m_desc, + &bufferDataDesc, + m_buffer.ReleaseAndGetAddressOf())); + m_mappedMemoryForImmutableBuffer + .reset(); // This buffer will only be mapped once. + } + else + { + m_gpuContext->Unmap(m_buffer.Get(), 0); + } + } + +private: + const ComPtr m_gpu; + const ComPtr m_gpuContext; + D3D11_BUFFER_DESC m_desc{}; + ComPtr m_buffer; + std::unique_ptr m_mappedMemoryForImmutableBuffer; +}; + +rcp RenderContextD3DImpl::makeRenderBuffer( + RenderBufferType type, + RenderBufferFlags flags, + size_t sizeInBytes) +{ + return make_rcp(type, + flags, + sizeInBytes, + m_gpu, + m_gpuContext); +} + +class TextureD3DImpl : public Texture +{ +public: + TextureD3DImpl(RenderContextD3DImpl* renderContextImpl, + UINT width, + UINT height, + UINT mipLevelCount, + const uint8_t imageDataRGBAPremul[]) : + Texture(width, height) + { + m_texture = renderContextImpl->makeSimple2DTexture( + DXGI_FORMAT_R8G8B8A8_UNORM, + width, + height, + mipLevelCount, + D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET, + D3D11_RESOURCE_MISC_GENERATE_MIPS); + + // Specify the top-level image in the mipmap chain. + D3D11_BOX box; + box.left = 0; + box.right = width; + box.top = 0; + box.bottom = height; + box.front = 0; + box.back = 1; + renderContextImpl->gpuContext()->UpdateSubresource(m_texture.Get(), + 0, + &box, + imageDataRGBAPremul, + width * 4, + 0); + + // Create a view and generate mipmaps. + VERIFY_OK(renderContextImpl->gpu()->CreateShaderResourceView( + m_texture.Get(), + NULL, + m_srv.ReleaseAndGetAddressOf())); + renderContextImpl->gpuContext()->GenerateMips(m_srv.Get()); + } + + ID3D11ShaderResourceView* srv() const { return m_srv.Get(); } + ID3D11ShaderResourceView* const* srvAddressOf() const + { + return m_srv.GetAddressOf(); + } + +private: + ComPtr m_texture; + ComPtr m_srv; +}; + +rcp RenderContextD3DImpl::makeImageTexture( + uint32_t width, + uint32_t height, + uint32_t mipLevelCount, + const uint8_t imageDataRGBAPremul[]) +{ + return make_rcp(this, + width, + height, + mipLevelCount, + imageDataRGBAPremul); +} + +class BufferRingD3D : public BufferRing +{ +public: + BufferRingD3D(RenderContextD3DImpl* renderContextImpl, + size_t capacityInBytes, + UINT bindFlags) : + BufferRingD3D(renderContextImpl, capacityInBytes, bindFlags, 0, 0) + {} + + ID3D11Buffer* flush(ID3D11DeviceContext* gpuContext) + { + updateBuffer(gpuContext, 0, m_dirtySizeInBytes); + m_dirtySizeInBytes = 0; + return m_buffer.Get(); + } + +protected: + BufferRingD3D(RenderContextD3DImpl* renderContextImpl, + size_t capacityInBytes, + UINT bindFlags, + UINT elementSizeInBytes, + UINT miscFlags) : + BufferRing(capacityInBytes) + { + D3D11_BUFFER_DESC desc{}; + desc.ByteWidth = math::lossless_numeric_cast(capacityInBytes); + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = bindFlags; + desc.CPUAccessFlags = 0; + desc.StructureByteStride = elementSizeInBytes; + desc.MiscFlags = miscFlags; + VERIFY_OK(renderContextImpl->gpu()->CreateBuffer( + &desc, + nullptr, + m_buffer.ReleaseAndGetAddressOf())); + } + + void* onMapBuffer(int bufferIdx, size_t mapSizeInBytes) override + { + // Use a CPU-side shadow buffer since D3D11 doesn't have an API to map a + // sub-range. + return shadowBuffer(); + } + + void onUnmapAndSubmitBuffer(int bufferIdx, size_t mapSizeInBytes) override + { + m_dirtySizeInBytes = math::lossless_numeric_cast(mapSizeInBytes); + } + + void updateBuffer(ID3D11DeviceContext* gpuContext, + UINT offsetInBytes, + UINT sizeInBytes) const + { + assert(offsetInBytes + sizeInBytes <= m_dirtySizeInBytes); + if (sizeInBytes != 0) + { + D3D11_BOX box; + box.left = 0; + box.right = sizeInBytes; + box.top = 0; + box.bottom = 1; + box.front = 0; + box.back = 1; + gpuContext->UpdateSubresource(m_buffer.Get(), + 0, + &box, + shadowBuffer() + offsetInBytes, + 0, + 0); + } + } + + ComPtr m_buffer; + UINT m_dirtySizeInBytes = 0; +}; + +class StructuredBufferRingD3D : public BufferRingD3D +{ +public: + StructuredBufferRingD3D(RenderContextD3DImpl* renderContextImpl, + size_t capacityInBytes, + UINT elementSizeInBytes) : + BufferRingD3D(renderContextImpl, + capacityInBytes, + D3D11_BIND_SHADER_RESOURCE, + elementSizeInBytes, + D3D11_RESOURCE_MISC_BUFFER_STRUCTURED) + { + assert(capacityInBytes % elementSizeInBytes == 0); + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + srvDesc.Format = DXGI_FORMAT_UNKNOWN; + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER; + srvDesc.Buffer.FirstElement = 0; + srvDesc.Buffer.NumElements = math::lossless_numeric_cast( + capacityInBytes / elementSizeInBytes); + VERIFY_OK(renderContextImpl->gpu()->CreateShaderResourceView( + m_buffer.Get(), + &srvDesc, + m_srv.ReleaseAndGetAddressOf())); + } + + ID3D11ShaderResourceView* flush(ID3D11DeviceContext* gpuContext, + UINT offsetInBytes, + UINT sizeInBytes) const + { + updateBuffer(gpuContext, offsetInBytes, sizeInBytes); + return m_srv.Get(); + } + +protected: + ComPtr m_srv; +}; + +std::unique_ptr RenderContextD3DImpl::makeUniformBufferRing( + size_t capacityInBytes) +{ + // In D3D we update uniform data inline with commands, rather than filling a + // buffer up front. + return std::make_unique(capacityInBytes); +} + +std::unique_ptr RenderContextD3DImpl::makeStorageBufferRing( + size_t capacityInBytes, + gpu::StorageBufferStructure bufferStructure) +{ + return capacityInBytes != 0 + ? std::make_unique( + this, + capacityInBytes, + gpu::StorageBufferElementSizeInBytes(bufferStructure)) + : nullptr; +} + +std::unique_ptr RenderContextD3DImpl::makeVertexBufferRing( + size_t capacityInBytes) +{ + return capacityInBytes != 0 + ? std::make_unique(this, + capacityInBytes, + D3D11_BIND_VERTEX_BUFFER) + : nullptr; +} + +RenderTargetD3D::RenderTargetD3D(RenderContextD3DImpl* renderContextImpl, + uint32_t width, + uint32_t height) : + RenderTarget(width, height), + m_gpu(renderContextImpl->gpu()), + m_gpuSupportsTypedUAVLoadStore( + renderContextImpl->d3dCapabilities().supportsTypedUAVLoadStore) +{} + +void RenderTargetD3D::setTargetTexture(ComPtr tex) +{ + if (tex != nullptr) + { + D3D11_TEXTURE2D_DESC desc; + tex->GetDesc(&desc); +#ifdef DEBUG + assert(desc.Width == width()); + assert(desc.Height == height()); + assert(desc.Format == DXGI_FORMAT_R8G8B8A8_UNORM || + desc.Format == DXGI_FORMAT_B8G8R8A8_UNORM || + desc.Format == DXGI_FORMAT_R8G8B8A8_TYPELESS || + desc.Format == DXGI_FORMAT_B8G8R8A8_TYPELESS); +#endif + m_targetTextureSupportsUAV = + (desc.BindFlags & D3D11_BIND_UNORDERED_ACCESS) && + m_gpuSupportsTypedUAVLoadStore; + m_targetFormat = desc.Format; + } + else + { + m_targetTextureSupportsUAV = false; + } + m_targetTexture = std::move(tex); + m_targetRTV = nullptr; + m_targetUAV = nullptr; +} + +ID3D11RenderTargetView* RenderTargetD3D::targetRTV() +{ + if (m_targetRTV == nullptr && m_targetTexture != nullptr) + { + D3D11_RENDER_TARGET_VIEW_DESC desc{}; + desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; + + switch (m_targetFormat) + { + case DXGI_FORMAT_R8G8B8A8_UNORM: + case DXGI_FORMAT_R8G8B8A8_TYPELESS: + desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + break; + case DXGI_FORMAT_B8G8R8A8_UNORM: + case DXGI_FORMAT_B8G8R8A8_TYPELESS: + desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; + break; + + default: + RIVE_UNREACHABLE(); + } + + VERIFY_OK(m_gpu->CreateRenderTargetView( + m_targetTexture.Get(), + &desc, + m_targetRTV.ReleaseAndGetAddressOf())); + } + return m_targetRTV.Get(); +} + +ID3D11Texture2D* RenderTargetD3D::offscreenTexture() +{ + assert(!m_targetTextureSupportsUAV); + if (m_offscreenTexture == nullptr) + { + m_offscreenTexture = + make_simple_2d_texture(m_gpu.Get(), + DXGI_FORMAT_R8G8B8A8_TYPELESS, + width(), + height(), + 1, + D3D11_BIND_UNORDERED_ACCESS); + } + return m_offscreenTexture.Get(); +} + +ID3D11UnorderedAccessView* RenderTargetD3D::targetUAV() +{ + if (m_targetUAV == nullptr) + { + if (auto* uavTexture = m_targetTextureSupportsUAV + ? m_targetTexture.Get() + : offscreenTexture()) + { + DXGI_FORMAT targetUavFormat; + switch (m_targetFormat) + { + case DXGI_FORMAT_R8G8B8A8_UNORM: + case DXGI_FORMAT_R8G8B8A8_TYPELESS: + targetUavFormat = m_gpuSupportsTypedUAVLoadStore + ? DXGI_FORMAT_R8G8B8A8_UNORM + : DXGI_FORMAT_R32_UINT; + break; + case DXGI_FORMAT_B8G8R8A8_UNORM: + case DXGI_FORMAT_B8G8R8A8_TYPELESS: + targetUavFormat = m_gpuSupportsTypedUAVLoadStore + ? DXGI_FORMAT_B8G8R8A8_UNORM + : DXGI_FORMAT_R32_UINT; + break; + default: + RIVE_UNREACHABLE(); + } + m_targetUAV = + make_simple_2d_uav(m_gpu.Get(), uavTexture, targetUavFormat); + } + } + return m_targetUAV.Get(); +} + +ID3D11UnorderedAccessView* RenderTargetD3D::clipUAV() +{ + if (m_clipTexture == nullptr) + { + m_clipTexture = make_simple_2d_texture(m_gpu.Get(), + DXGI_FORMAT_R32_UINT, + width(), + height(), + 1, + D3D11_BIND_UNORDERED_ACCESS); + } + if (m_clipUAV == nullptr) + { + m_clipUAV = make_simple_2d_uav(m_gpu.Get(), + m_clipTexture.Get(), + DXGI_FORMAT_R32_UINT); + } + return m_clipUAV.Get(); +} + +ID3D11UnorderedAccessView* RenderTargetD3D::scratchColorUAV() +{ + if (m_scratchColorTexture == nullptr) + { + m_scratchColorTexture = + make_simple_2d_texture(m_gpu.Get(), + DXGI_FORMAT_R8G8B8A8_TYPELESS, + width(), + height(), + 1, + D3D11_BIND_UNORDERED_ACCESS); + } + if (m_scratchColorUAV == nullptr) + { + m_scratchColorUAV = make_simple_2d_uav(m_gpu.Get(), + m_scratchColorTexture.Get(), + m_gpuSupportsTypedUAVLoadStore + ? DXGI_FORMAT_R8G8B8A8_UNORM + : DXGI_FORMAT_R32_UINT); + } + return m_scratchColorUAV.Get(); +} + +ID3D11UnorderedAccessView* RenderTargetD3D::coverageUAV() +{ + if (m_coverageTexture == nullptr) + { + m_coverageTexture = make_simple_2d_texture(m_gpu.Get(), + DXGI_FORMAT_R32_UINT, + width(), + height(), + 1, + D3D11_BIND_UNORDERED_ACCESS); + } + if (m_coverageUAV == nullptr) + { + m_coverageUAV = make_simple_2d_uav(m_gpu.Get(), + m_coverageTexture.Get(), + DXGI_FORMAT_R32_UINT); + } + return m_coverageUAV.Get(); +} + +void RenderContextD3DImpl::resizeGradientTexture(uint32_t width, + uint32_t height) +{ + if (width == 0 || height == 0) + { + m_gradTexture = nullptr; + m_gradTextureSRV = nullptr; + m_gradTextureRTV = nullptr; + } + else + { + m_gradTexture = makeSimple2DTexture(DXGI_FORMAT_R8G8B8A8_UNORM, + width, + height, + 1, + D3D11_BIND_RENDER_TARGET | + D3D11_BIND_SHADER_RESOURCE); + VERIFY_OK(m_gpu->CreateShaderResourceView( + m_gradTexture.Get(), + NULL, + m_gradTextureSRV.ReleaseAndGetAddressOf())); + VERIFY_OK(m_gpu->CreateRenderTargetView( + m_gradTexture.Get(), + NULL, + m_gradTextureRTV.ReleaseAndGetAddressOf())); + } +} + +void RenderContextD3DImpl::resizeTessellationTexture(uint32_t width, + uint32_t height) +{ + if (width == 0 || height == 0) + { + m_tessTexture = nullptr; + m_tessTextureSRV = nullptr; + m_tessTextureRTV = nullptr; + } + else + { + m_tessTexture = makeSimple2DTexture(DXGI_FORMAT_R32G32B32A32_UINT, + width, + height, + 1, + D3D11_BIND_RENDER_TARGET | + D3D11_BIND_SHADER_RESOURCE); + VERIFY_OK(m_gpu->CreateShaderResourceView( + m_tessTexture.Get(), + NULL, + m_tessTextureSRV.ReleaseAndGetAddressOf())); + VERIFY_OK(m_gpu->CreateRenderTargetView( + m_tessTexture.Get(), + NULL, + m_tessTextureRTV.ReleaseAndGetAddressOf())); + } +} + +void RenderContextD3DImpl::resizeAtlasTexture(uint32_t width, uint32_t height) +{ + + if (width == 0 || height == 0) + { + m_atlasTexture = nullptr; + m_atlasTextureSRV = nullptr; + m_atlasTextureRTV = nullptr; + } + else + { + m_atlasTexture = makeSimple2DTexture(DXGI_FORMAT_R32_FLOAT, + width, + height, + 1, + D3D11_BIND_RENDER_TARGET | + D3D11_BIND_SHADER_RESOURCE); + VERIFY_OK(m_gpu->CreateShaderResourceView( + m_atlasTexture.Get(), + NULL, + m_atlasTextureSRV.ReleaseAndGetAddressOf())); + VERIFY_OK(m_gpu->CreateRenderTargetView( + m_atlasTexture.Get(), + NULL, + m_atlasTextureRTV.ReleaseAndGetAddressOf())); + } +} + +static const char* heap_buffer_contents(const BufferRing* bufferRing) +{ + assert(bufferRing != nullptr); + auto heapBuffer = static_cast(bufferRing); + return reinterpret_cast(heapBuffer->contents()); +} + +static ID3D11Buffer* flush_buffer(ID3D11DeviceContext* gpuContext, + BufferRing* bufferRing) +{ + assert(bufferRing != nullptr); + return static_cast(bufferRing)->flush(gpuContext); +} + +template +ID3D11ShaderResourceView* flush_structured_buffer( + ID3D11DeviceContext* gpuContext, + BufferRing* bufferRing, + UINT highLevelStructCount, + UINT firstHighLevelStruct) +{ + return static_cast(bufferRing) + ->flush(gpuContext, + firstHighLevelStruct * sizeof(HighLevelStruct), + highLevelStructCount * sizeof(HighLevelStruct)); +} + +static void blit_sub_rect(ID3D11DeviceContext* gpuContext, + ID3D11Texture2D* dst, + ID3D11Texture2D* src, + const IAABB& rect) +{ + D3D11_BOX updateBox = { + static_cast(rect.left), + static_cast(rect.top), + 0, + static_cast(rect.right), + static_cast(rect.bottom), + 1, + }; + gpuContext->CopySubresourceRegion(dst, + 0, + updateBox.left, + updateBox.top, + 0, + src, + 0, + &updateBox); +} + +static D3D11_RECT make_scissor(const TAABB scissor) +{ + D3D11_RECT rect; + rect.left = scissor.left; + rect.top = scissor.top; + rect.right = scissor.right; + rect.bottom = scissor.bottom; + return rect; +} + +void RenderContextD3DImpl::flush(const FlushDescriptor& desc) +{ + assert(desc.interlockMode != gpu::InterlockMode::clockwiseAtomic); + auto renderTarget = static_cast(desc.renderTarget); + + m_gpuContext->ClearState(); + + // All programs use the same set of per-flush uniforms. + m_gpuContext->UpdateSubresource( + m_flushUniforms.Get(), + 0, + NULL, + heap_buffer_contents(flushUniformBufferRing()) + + desc.flushUniformDataOffsetInBytes, + 0, + 0); + + ID3D11Buffer* uniformBuffers[] = {m_flushUniforms.Get(), + m_drawUniforms.Get(), + m_imageDrawUniforms.Get()}; + static_assert(PATH_BASE_INSTANCE_UNIFORM_BUFFER_IDX == + FLUSH_UNIFORM_BUFFER_IDX + 1); + static_assert(IMAGE_DRAW_UNIFORM_BUFFER_IDX == + PATH_BASE_INSTANCE_UNIFORM_BUFFER_IDX + 1); + m_gpuContext->VSSetConstantBuffers(FLUSH_UNIFORM_BUFFER_IDX, + std::size(uniformBuffers), + uniformBuffers); + m_gpuContext->PSSetConstantBuffers(FLUSH_UNIFORM_BUFFER_IDX, + std::size(uniformBuffers), + uniformBuffers); + + // All programs use the same storage buffers. + ID3D11ShaderResourceView* storageBufferBufferSRVs[] = { + desc.pathCount > 0 + ? flush_structured_buffer( + m_gpuContext.Get(), + pathBufferRing(), + desc.pathCount, + math::lossless_numeric_cast(desc.firstPath)) + : nullptr, + desc.pathCount > 0 + ? flush_structured_buffer( + m_gpuContext.Get(), + paintBufferRing(), + desc.pathCount, + math::lossless_numeric_cast(desc.firstPaint)) + : nullptr, + desc.pathCount > 0 + ? flush_structured_buffer( + m_gpuContext.Get(), + paintAuxBufferRing(), + desc.pathCount, + math::lossless_numeric_cast(desc.firstPaintAux)) + : nullptr, + desc.contourCount > 0 + ? flush_structured_buffer( + m_gpuContext.Get(), + contourBufferRing(), + desc.contourCount, + math::lossless_numeric_cast(desc.firstContour)) + : nullptr, + }; + static_assert(PAINT_BUFFER_IDX == PATH_BUFFER_IDX + 1); + static_assert(PAINT_AUX_BUFFER_IDX == PAINT_BUFFER_IDX + 1); + static_assert(CONTOUR_BUFFER_IDX == PAINT_AUX_BUFFER_IDX + 1); + m_gpuContext->VSSetShaderResources(PATH_BUFFER_IDX, + std::size(storageBufferBufferSRVs), + storageBufferBufferSRVs); + if (desc.interlockMode == gpu::InterlockMode::atomics) + { + // Atomic mode accesses the paint buffers from the pixel shader. + m_gpuContext->PSSetShaderResources(PAINT_BUFFER_IDX, + 2, + storageBufferBufferSRVs + 1); + } + + // All programs use the same feather texture. + m_gpuContext->VSSetShaderResources(FEATHER_TEXTURE_IDX, + 1, + m_featherTextureSRV.GetAddressOf()); + m_gpuContext->PSSetShaderResources(FEATHER_TEXTURE_IDX, + 1, + m_featherTextureSRV.GetAddressOf()); + + // All programs use the same samplers. + ID3D11SamplerState* samplers[4] = { + m_linearSampler.Get(), + m_linearSampler.Get(), + m_linearSampler.Get(), + // 0 is the default which is MIN_MAG_MIP_LINEAR + m_samplerStates[ImageSampler::LINEAR_CLAMP_SAMPLER_KEY].Get(), + }; + + static_assert(FEATHER_TEXTURE_IDX == GRAD_TEXTURE_IDX + 1); + static_assert(ATLAS_TEXTURE_IDX == FEATHER_TEXTURE_IDX + 1); + static_assert(IMAGE_TEXTURE_IDX == ATLAS_TEXTURE_IDX + 1); + m_gpuContext->PSSetSamplers(GRAD_TEXTURE_IDX, 4, samplers); + m_gpuContext->VSSetSamplers(GRAD_TEXTURE_IDX, 4, samplers); + + // Render the complex color ramps to the gradient texture. + if (desc.gradSpanCount > 0) + { + ID3D11Buffer* gradSpanBuffer = + flush_buffer(m_gpuContext.Get(), gradSpanBufferRing()); + UINT gradStride = sizeof(GradientSpan); + UINT gradOffset = 0; + m_gpuContext->IASetVertexBuffers(0, + 1, + &gradSpanBuffer, + &gradStride, + &gradOffset); + + m_gpuContext->IASetPrimitiveTopology( + D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + + m_pipelineManager.setColorRampState(); + + D3D11_VIEWPORT viewport = {0, + 0, + static_cast(kGradTextureWidth), + static_cast(desc.gradDataHeight), + 0, + 1}; + m_gpuContext->RSSetViewports(1, &viewport); + + // Unbind the gradient texture before rendering it. + ID3D11ShaderResourceView* nullTextureView = nullptr; + m_gpuContext->PSSetShaderResources(GRAD_TEXTURE_IDX, + 1, + &nullTextureView); + + m_gpuContext->OMSetRenderTargets(1, + m_gradTextureRTV.GetAddressOf(), + NULL); + + m_gpuContext->DrawInstanced( + gpu::GRAD_SPAN_TRI_STRIP_VERTEX_COUNT, + desc.gradSpanCount, + 0, + math::lossless_numeric_cast(desc.firstGradSpan)); + } + + // Tessellate all curves into vertices in the tessellation texture. + if (desc.tessVertexSpanCount > 0) + { + ID3D11Buffer* tessSpanBuffer = + flush_buffer(m_gpuContext.Get(), tessSpanBufferRing()); + UINT tessStride = sizeof(TessVertexSpan); + UINT tessOffset = 0; + m_gpuContext->IASetVertexBuffers(0, + 1, + &tessSpanBuffer, + &tessStride, + &tessOffset); + m_gpuContext->IASetIndexBuffer(m_tessSpanIndexBuffer.Get(), + DXGI_FORMAT_R16_UINT, + 0); + + m_pipelineManager.setTesselationState(); + m_gpuContext->IASetPrimitiveTopology( + D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + + // Unbind the tessellation texture before rendering it. + ID3D11ShaderResourceView* nullTessTextureView = NULL; + m_gpuContext->VSSetShaderResources(TESS_VERTEX_TEXTURE_IDX, + 1, + &nullTessTextureView); + + D3D11_VIEWPORT viewport = {0, + 0, + static_cast(kTessTextureWidth), + static_cast(desc.tessDataHeight), + 0, + 1}; + m_gpuContext->RSSetViewports(1, &viewport); + + m_gpuContext->OMSetRenderTargets(1, + m_tessTextureRTV.GetAddressOf(), + NULL); + + m_gpuContext->DrawIndexedInstanced( + std::size(gpu::kTessSpanIndices), + desc.tessVertexSpanCount, + 0, + 0, + math::lossless_numeric_cast(desc.firstTessVertexSpan)); + + if (m_d3dCapabilities.isIntel) + { + // FIXME! Intel needs this flush! Driver bug? Find a lighter + // workaround? + m_gpuContext->Flush(); + } + } + + ID3D11Buffer* vertexBuffers[3] = { + m_patchVertexBuffer.Get(), + desc.hasTriangleVertices + ? flush_buffer(m_gpuContext.Get(), triangleBufferRing()) + : NULL, + m_imageRectVertexBuffer.Get()}; + UINT vertexStrides[3] = {sizeof(gpu::PatchVertex), + sizeof(gpu::TriangleVertex), + sizeof(gpu::ImageRectVertex)}; + UINT vertexOffsets[3] = {0, 0, 0}; + static_assert(PATCH_VERTEX_DATA_SLOT == 0); + static_assert(TRIANGLE_VERTEX_DATA_SLOT == 1); + static_assert(IMAGE_RECT_VERTEX_DATA_SLOT == 2); + m_gpuContext->IASetVertexBuffers(0, + 3, + vertexBuffers, + vertexStrides, + vertexOffsets); + + // Unbind the tess and grad texture as a render target before binding them + // as images. + m_gpuContext->OMSetRenderTargets(0, NULL, NULL); + m_gpuContext->VSSetShaderResources(TESS_VERTEX_TEXTURE_IDX, + 1, + m_tessTextureSRV.GetAddressOf()); + m_gpuContext->PSSetShaderResources(GRAD_TEXTURE_IDX, + 1, + m_gradTextureSRV.GetAddressOf()); + + // Render the atlas if we have any offscreen feathers. + if ((desc.atlasFillBatchCount | desc.atlasStrokeBatchCount) != 0) + { + float clearZero[4]{}; + m_gpuContext->ClearRenderTargetView(m_atlasTextureRTV.Get(), clearZero); + + m_pipelineManager.setAtlasVertexState(); + m_gpuContext->IASetPrimitiveTopology( + D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + m_gpuContext->IASetIndexBuffer(m_patchIndexBuffer.Get(), + DXGI_FORMAT_R16_UINT, + 0); + m_gpuContext->RSSetState(m_atlasRasterState.Get()); + + D3D11_VIEWPORT viewport = {0, + 0, + static_cast(desc.atlasContentWidth), + static_cast(desc.atlasContentHeight), + 0, + 1}; + m_gpuContext->RSSetViewports(1, &viewport); + + m_gpuContext->OMSetRenderTargets(1, + m_atlasTextureRTV.GetAddressOf(), + NULL); + + if (desc.atlasFillBatchCount != 0) + { + m_pipelineManager.setAtlasFillState(); + m_gpuContext->OMSetBlendState(m_plusBlendState.Get(), + NULL, + 0xffffffff); + for (size_t i = 0; i < desc.atlasFillBatchCount; ++i) + { + const gpu::AtlasDrawBatch& fillBatch = desc.atlasFillBatches[i]; + D3D11_RECT scissor = make_scissor(fillBatch.scissor); + m_gpuContext->RSSetScissorRects(1, &scissor); + DrawUniforms drawUniforms(fillBatch.basePatch); + m_gpuContext->UpdateSubresource(m_drawUniforms.Get(), + 0, + NULL, + &drawUniforms, + 0, + 0); + m_gpuContext->DrawIndexedInstanced( + gpu::kMidpointFanCenterAAPatchIndexCount, + fillBatch.patchCount, + gpu::kMidpointFanCenterAAPatchBaseIndex, + 0, + fillBatch.basePatch); + } + } + + if (desc.atlasStrokeBatchCount != 0) + { + m_pipelineManager.setAtlasStrokeState(); + m_gpuContext->OMSetBlendState(m_maxBlendState.Get(), + NULL, + 0xffffffff); + for (size_t i = 0; i < desc.atlasStrokeBatchCount; ++i) + { + const gpu::AtlasDrawBatch& strokeBatch = + desc.atlasStrokeBatches[i]; + D3D11_RECT scissor = make_scissor(strokeBatch.scissor); + m_gpuContext->RSSetScissorRects(1, &scissor); + DrawUniforms drawUniforms(strokeBatch.basePatch); + m_gpuContext->UpdateSubresource(m_drawUniforms.Get(), + 0, + NULL, + &drawUniforms, + 0, + 0); + m_gpuContext->DrawIndexedInstanced( + gpu::kMidpointFanPatchBorderIndexCount, + strokeBatch.patchCount, + gpu::kMidpointFanPatchBaseIndex, + 0, + strokeBatch.basePatch); + } + } + + m_gpuContext->OMSetBlendState(NULL, NULL, 0xffffffff); + } + + // Setup and clear the PLS textures. + switch (desc.colorLoadAction) + { + case gpu::LoadAction::clear: + if (desc.atomicFixedFunctionColorOutput) + { + float clearColor4f[4]; + UnpackColorToRGBA32FPremul(desc.colorClearValue, clearColor4f); + m_gpuContext->ClearRenderTargetView(renderTarget->targetRTV(), + clearColor4f); + } + else if (m_d3dCapabilities.supportsTypedUAVLoadStore) + { + float clearColor4f[4]; + UnpackColorToRGBA32FPremul(desc.colorClearValue, clearColor4f); + m_gpuContext->ClearUnorderedAccessViewFloat( + renderTarget->targetUAV(), + clearColor4f); + } + else + { + UINT clearColorui[4] = { + gpu::SwizzleRiveColorToRGBAPremul(desc.colorClearValue)}; + m_gpuContext->ClearUnorderedAccessViewUint( + renderTarget->targetUAV(), + clearColorui); + } + break; + case gpu::LoadAction::preserveRenderTarget: + if (!desc.atomicFixedFunctionColorOutput && + !renderTarget->targetTextureSupportsUAV()) + { + // We're rendering to an offscreen UAV and preserving the + // target. Copy the target texture over. + blit_sub_rect(m_gpuContext.Get(), + renderTarget->offscreenTexture(), + renderTarget->targetTexture(), + desc.renderTargetUpdateBounds); + } + break; + case gpu::LoadAction::dontCare: + break; + } + if (desc.combinedShaderFeatures & gpu::ShaderFeatures::ENABLE_CLIPPING) + { + constexpr static UINT kZero[4]{}; + m_gpuContext->ClearUnorderedAccessViewUint(renderTarget->clipUAV(), + kZero); + } + { + UINT coverageClear[4]{desc.coverageClearValue}; + m_gpuContext->ClearUnorderedAccessViewUint(renderTarget->coverageUAV(), + coverageClear); + } + + // Execute the DrawList. + ID3D11RenderTargetView* targetRTV = + desc.atomicFixedFunctionColorOutput ? renderTarget->targetRTV() : NULL; + ID3D11UnorderedAccessView* plsUAVs[] = { + desc.atomicFixedFunctionColorOutput ? NULL : renderTarget->targetUAV(), + renderTarget->clipUAV(), + desc.interlockMode == gpu::InterlockMode::rasterOrdering + ? renderTarget->scratchColorUAV() + : NULL, // Atomic mode doesn't use the scratchColor. + renderTarget->coverageUAV(), + }; + static_assert(COLOR_PLANE_IDX == 0); + static_assert(CLIP_PLANE_IDX == 1); + static_assert(SCRATCH_COLOR_PLANE_IDX == 2); + static_assert(COVERAGE_PLANE_IDX == 3); + m_gpuContext->OMSetRenderTargetsAndUnorderedAccessViews( + desc.atomicFixedFunctionColorOutput ? 1 : 0, + &targetRTV, + NULL, + desc.atomicFixedFunctionColorOutput ? 1 : 0, + desc.atomicFixedFunctionColorOutput ? std::size(plsUAVs) - 1 + : std::size(plsUAVs), + desc.atomicFixedFunctionColorOutput ? plsUAVs + 1 : plsUAVs, + NULL); + + if (desc.atomicFixedFunctionColorOutput) + { + // When rendering directly to the target RTV, we use the built-in blend + // hardware for opacity and antialiasing. + m_gpuContext->OMSetBlendState(m_srcOverBlendState.Get(), + NULL, + 0xffffffff); + } + + D3D11_VIEWPORT viewport = {0, + 0, + static_cast(renderTarget->width()), + static_cast(renderTarget->height()), + 0, + 1}; + m_gpuContext->RSSetViewports(1, &viewport); + + // Set this last, when the atlas texture is no longer bound as a render + // target. + m_gpuContext->PSSetShaderResources(ATLAS_TEXTURE_IDX, + 1, + m_atlasTextureSRV.GetAddressOf()); + + m_gpuContext->PSSetConstantBuffers(IMAGE_DRAW_UNIFORM_BUFFER_IDX, + 1, + m_imageDrawUniforms.GetAddressOf()); + + const char* const imageDrawUniformData = + heap_buffer_contents(imageDrawUniformBufferRing()); + + bool renderPassHasCoalescedResolveAndTransfer = + desc.interlockMode == gpu::InterlockMode::atomics && + !desc.atomicFixedFunctionColorOutput && + !renderTarget->targetTextureSupportsUAV(); + + for (const DrawBatch& batch : *desc.drawList) + { + DrawType drawType = batch.drawType; + auto shaderFeatures = desc.interlockMode == gpu::InterlockMode::atomics + ? desc.combinedShaderFeatures + : batch.shaderFeatures; + auto shaderMiscFlags = batch.shaderMiscFlags; + if (drawType == gpu::DrawType::atomicResolve && + renderPassHasCoalescedResolveAndTransfer) + { + shaderMiscFlags |= + gpu::ShaderMiscFlags::coalescedResolveAndTransfer; + } + if (desc.atomicFixedFunctionColorOutput) + { + shaderMiscFlags |= gpu::ShaderMiscFlags::fixedFunctionColorOutput; + } + if (desc.interlockMode == gpu::InterlockMode::rasterOrdering && + (batch.drawContents & gpu::DrawContents::clockwiseFill)) + { + shaderMiscFlags |= gpu::ShaderMiscFlags::clockwiseFill; + } + + m_pipelineManager.setPipelineState(drawType, + shaderFeatures, + desc.interlockMode, + shaderMiscFlags); + + if (auto imageTextureD3D = + static_cast(batch.imageTexture)) + { + m_gpuContext->PSSetShaderResources(IMAGE_TEXTURE_IDX, + 1, + imageTextureD3D->srvAddressOf()); + // we should never get a sampler option that is greater then our + // array size + assert(batch.imageSampler.asKey() < + ImageSampler::MAX_SAMPLER_PERMUTATIONS); + ID3D11SamplerState* samplers[1] = { + m_samplerStates[batch.imageSampler.asKey()].Get()}; + m_gpuContext->PSSetSamplers(IMAGE_SAMPLER_IDX, 1, samplers); + } + + switch (drawType) + { + case DrawType::midpointFanPatches: + case DrawType::midpointFanCenterAAPatches: + case DrawType::outerCurvePatches: + { + m_gpuContext->IASetPrimitiveTopology( + D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + m_gpuContext->IASetIndexBuffer(m_patchIndexBuffer.Get(), + DXGI_FORMAT_R16_UINT, + 0); + m_gpuContext->RSSetState( + m_backCulledRasterState[desc.wireframe].Get()); + DrawUniforms drawUniforms(batch.baseElement); + m_gpuContext->UpdateSubresource(m_drawUniforms.Get(), + 0, + NULL, + &drawUniforms, + 0, + 0); + m_gpuContext->DrawIndexedInstanced(PatchIndexCount(drawType), + batch.elementCount, + PatchBaseIndex(drawType), + 0, + batch.baseElement); + break; + } + case DrawType::interiorTriangulation: + case DrawType::atlasBlit: + { + m_gpuContext->IASetPrimitiveTopology( + D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + m_gpuContext->RSSetState( + m_backCulledRasterState[desc.wireframe].Get()); + m_gpuContext->Draw(batch.elementCount, batch.baseElement); + break; + } + case DrawType::imageRect: + { + m_gpuContext->IASetPrimitiveTopology( + D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + m_gpuContext->IASetIndexBuffer(m_imageRectIndexBuffer.Get(), + DXGI_FORMAT_R16_UINT, + 0); + m_gpuContext->RSSetState( + m_doubleSidedRasterState[desc.wireframe].Get()); + m_gpuContext->UpdateSubresource(m_imageDrawUniforms.Get(), + 0, + NULL, + imageDrawUniformData + + batch.imageDrawDataOffset, + 0, + 0); + m_gpuContext->DrawIndexed(std::size(gpu::kImageRectIndices), + 0, + 0); + break; + } + case DrawType::imageMesh: + { + LITE_RTTI_CAST_OR_BREAK(vertexBuffer, + RenderBufferD3DImpl*, + batch.vertexBuffer); + LITE_RTTI_CAST_OR_BREAK(uvBuffer, + RenderBufferD3DImpl*, + batch.uvBuffer); + LITE_RTTI_CAST_OR_BREAK(indexBuffer, + RenderBufferD3DImpl*, + batch.indexBuffer); + ID3D11Buffer* imageMeshBuffers[] = {vertexBuffer->buffer(), + uvBuffer->buffer()}; + UINT imageMeshStrides[] = {sizeof(Vec2D), sizeof(Vec2D)}; + UINT imageMeshOffsets[] = {0, 0}; + m_gpuContext->IASetVertexBuffers(IMAGE_MESH_VERTEX_DATA_SLOT, + 2, + imageMeshBuffers, + imageMeshStrides, + imageMeshOffsets); + static_assert(IMAGE_MESH_UV_DATA_SLOT == + IMAGE_MESH_VERTEX_DATA_SLOT + 1); + m_gpuContext->IASetPrimitiveTopology( + D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + m_gpuContext->IASetIndexBuffer(indexBuffer->buffer(), + DXGI_FORMAT_R16_UINT, + 0); + m_gpuContext->RSSetState( + m_doubleSidedRasterState[desc.wireframe].Get()); + m_gpuContext->UpdateSubresource(m_imageDrawUniforms.Get(), + 0, + NULL, + imageDrawUniformData + + batch.imageDrawDataOffset, + 0, + 0); + m_gpuContext->DrawIndexed(batch.elementCount, + batch.baseElement, + 0); + break; + } + case DrawType::atomicResolve: + assert(desc.interlockMode == gpu::InterlockMode::atomics); + m_gpuContext->IASetPrimitiveTopology( + D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + m_gpuContext->RSSetState(m_backCulledRasterState[0].Get()); + if (renderPassHasCoalescedResolveAndTransfer) + { + // Bind the actual target texture as the render target for + // the PLS resolve, so we don't have to copy to it after the + // render pass. (And ince we're changing the render target, + // this also better be the final batch of the render pass.) + assert(&batch == &desc.drawList->tail()); + assert(!desc.atomicFixedFunctionColorOutput); + assert(!renderTarget->targetTextureSupportsUAV()); + ID3D11RenderTargetView* resolveRTV = + renderTarget->targetRTV(); + ID3D11UnorderedAccessView* resolveUAVs[] = { + renderTarget->clipUAV(), + renderTarget + ->targetUAV(), // Bind the target UAV (for reading) + // to a different slot for the + // resolve because D3D doesn't let us + // use slot 0 when there's a render + // target. + renderTarget->coverageUAV(), + }; + static_assert(CLIP_PLANE_IDX == 1); + static_assert(COALESCED_OFFSCREEN_COLOR_PLANE_IDX == 2); + static_assert(COVERAGE_PLANE_IDX == 3); + m_gpuContext->OMSetRenderTargetsAndUnorderedAccessViews( + 1, + &resolveRTV, + NULL, + 1, + std::size(resolveUAVs), + resolveUAVs, + NULL); + } + m_gpuContext->Draw(4, 0); + break; + case DrawType::atomicInitialize: + case DrawType::msaaStrokes: + case DrawType::msaaMidpointFanBorrowedCoverage: + case DrawType::msaaMidpointFans: + case DrawType::msaaMidpointFanStencilReset: + case DrawType::msaaMidpointFanPathsStencil: + case DrawType::msaaMidpointFanPathsCover: + case DrawType::msaaOuterCubics: + case DrawType::msaaStencilClipReset: + RIVE_UNREACHABLE(); + } + } + + if (desc.interlockMode == gpu::InterlockMode::rasterOrdering && + !renderTarget->targetTextureSupportsUAV()) + { + // We rendered to an offscreen UAV and did not resolve to the + // renderTarget. Copy back to the main target. + assert(!desc.atomicFixedFunctionColorOutput); + assert(!renderPassHasCoalescedResolveAndTransfer); + blit_sub_rect(m_gpuContext.Get(), + renderTarget->targetTexture(), + renderTarget->offscreenTexture(), + desc.renderTargetUpdateBounds); + } +} +} // namespace rive::gpu diff --git a/third_party/rive_renderer/source/d3d12/d3d12_pipeline_manager.cpp b/third_party/rive_renderer/source/d3d12/d3d12_pipeline_manager.cpp new file mode 100644 index 0000000..4770659 --- /dev/null +++ b/third_party/rive_renderer/source/d3d12/d3d12_pipeline_manager.cpp @@ -0,0 +1,495 @@ +/* + * Copyright 2025 Rive + */ +#include "rive/renderer/d3d12/d3d12_pipeline_manager.hpp" +#include "rive/renderer/d3d/d3d_constants.hpp" + +#include "generated/shaders/advanced_blend.glsl.hpp" +#include "generated/shaders/atomic_draw.glsl.hpp" +#include "generated/shaders/color_ramp.glsl.hpp" +#include "generated/shaders/constants.glsl.hpp" +#include "generated/shaders/common.glsl.hpp" +#include "generated/shaders/draw_image_mesh.glsl.hpp" +#include "generated/shaders/draw_path_common.glsl.hpp" +#include "generated/shaders/draw_path.glsl.hpp" +#include "generated/shaders/hlsl.glsl.hpp" +#include "generated/shaders/bezier_utils.glsl.hpp" +#include "generated/shaders/render_atlas.glsl.hpp" +#include "generated/shaders/tessellate.glsl.hpp" + +// offline shaders +namespace shader +{ +namespace tess::vert +{ +#include "generated/shaders/d3d/tessellate.vert.h" +} +namespace tess::frag +{ +#include "generated/shaders/d3d/tessellate.frag.h" +} +namespace grad::vert +{ +#include "generated/shaders/d3d/color_ramp.vert.h" +} +namespace grad::frag +{ +#include "generated/shaders/d3d/color_ramp.frag.h" +} +namespace atlas::vert +{ +#include "generated/shaders/d3d/render_atlas.vert.h" +} +namespace atlas::fill +{ +#include "generated/shaders/d3d/render_atlas_fill.frag.h" +} +namespace atlas::stroke +{ +#include "generated/shaders/d3d/render_atlas_stroke.frag.h" +} +} // namespace shader +// offline sigs +namespace sig +{ +#include "generated/shaders/d3d/root.sig.h" +} // namespace sig + +namespace rive::gpu +{ + +D3D12PipelineManager::D3D12PipelineManager( + ComPtr device, + const D3DCapabilities& capabilities) : + D3DPipelineManager, ID3D12Device>( + device, + capabilities, + "vs_5_1", + "ps_5_1") +{ + VERIFY_OK( + this->device()->CreateRootSignature(0, + sig::g_ROOT_SIG, + std::size(sig::g_ROOT_SIG), + IID_PPV_ARGS(&m_rootSignature))); +} + +ID3D12PipelineState* D3D12PipelineManager::getDrawPipelineState( + DrawType drawType, + gpu::ShaderFeatures shaderFeatures, + gpu::InterlockMode interlockMode, + gpu::ShaderMiscFlags shaderMiscFlags) +{ + uint32_t pixelShaderKey = ShaderUniqueKey(drawType, + shaderFeatures, + interlockMode, + shaderMiscFlags); + + auto pipelineEntry = m_drawPipelines.find(pixelShaderKey); + if (pipelineEntry != m_drawPipelines.end()) + { + return pipelineEntry->second.Get(); + } + + ShaderCompileResult result{}; + if (!getShader({drawType, + shaderFeatures, + interlockMode, + shaderMiscFlags, + d3dCapabilities()}, + &result)) + { + // this should never happen + RIVE_UNREACHABLE(); + } + + return static_cast(result.resultData); +} + +void D3D12PipelineManager::compileBlobToFinalType( + const ShaderCompileRequest& request, + ComPtr vertexShader, + ComPtr pixelShader, + ShaderCompileResult* result) +{ + if (!result->vertexResult.hasResult) + { + switch (request.drawType) + { + case DrawType::midpointFanPatches: + case DrawType::midpointFanCenterAAPatches: + case DrawType::outerCurvePatches: + result->vertexResult.vertexShaderResult.m_layoutDesc[0] = { + GLSL_a_patchVertexData, + 0, + DXGI_FORMAT_R32G32B32A32_FLOAT, + PATCH_VERTEX_DATA_SLOT, + D3D12_APPEND_ALIGNED_ELEMENT, + D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, + 0}; + result->vertexResult.vertexShaderResult.m_layoutDesc[1] = { + GLSL_a_mirroredVertexData, + 0, + DXGI_FORMAT_R32G32B32A32_FLOAT, + PATCH_VERTEX_DATA_SLOT, + D3D12_APPEND_ALIGNED_ELEMENT, + D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, + 0}; + result->vertexResult.vertexShaderResult.m_vertexAttribCount = 2; + break; + case DrawType::interiorTriangulation: + case DrawType::atlasBlit: + result->vertexResult.vertexShaderResult.m_layoutDesc[0] = { + GLSL_a_triangleVertex, + 0, + DXGI_FORMAT_R32G32B32_FLOAT, + TRIANGLE_VERTEX_DATA_SLOT, + 0, + D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, + 0}; + result->vertexResult.vertexShaderResult.m_vertexAttribCount = 1; + break; + case DrawType::imageRect: + result->vertexResult.vertexShaderResult.m_layoutDesc[0] = { + GLSL_a_imageRectVertex, + 0, + DXGI_FORMAT_R32G32B32A32_FLOAT, + IMAGE_RECT_VERTEX_DATA_SLOT, + 0, + D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, + 0}; + result->vertexResult.vertexShaderResult.m_vertexAttribCount = 1; + break; + case DrawType::imageMesh: + result->vertexResult.vertexShaderResult.m_layoutDesc[0] = { + GLSL_a_position, + 0, + DXGI_FORMAT_R32G32_FLOAT, + IMAGE_MESH_VERTEX_DATA_SLOT, + D3D12_APPEND_ALIGNED_ELEMENT, + D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, + 0}; + result->vertexResult.vertexShaderResult.m_layoutDesc[1] = { + GLSL_a_texCoord, + 0, + DXGI_FORMAT_R32G32_FLOAT, + IMAGE_MESH_UV_DATA_SLOT, + D3D12_APPEND_ALIGNED_ELEMENT, + D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, + 0}; + result->vertexResult.vertexShaderResult.m_vertexAttribCount = 2; + break; + case DrawType::atomicResolve: + result->vertexResult.vertexShaderResult.m_vertexAttribCount = 0; + break; + case DrawType::atomicInitialize: + case DrawType::msaaStrokes: + case DrawType::msaaMidpointFanBorrowedCoverage: + case DrawType::msaaMidpointFans: + case DrawType::msaaMidpointFanStencilReset: + case DrawType::msaaMidpointFanPathsStencil: + case DrawType::msaaMidpointFanPathsCover: + case DrawType::msaaOuterCubics: + case DrawType::msaaStencilClipReset: + RIVE_UNREACHABLE(); + } + + result->vertexResult.vertexShaderResult.m_shader = vertexShader; + result->vertexResult.hasResult = true; + } + + if (result->pixelResult.hasResult == false) + { + result->pixelResult.pixelShaderResult = pixelShader; + result->pixelResult.hasResult = true; + } + + ComPtr pipelineState; + + D3D12_RASTERIZER_DESC rasterDesc = {}; + rasterDesc.FillMode = D3D12_FILL_MODE_SOLID; + rasterDesc.FrontCounterClockwise = FALSE; + rasterDesc.DepthBias = 0; + rasterDesc.SlopeScaledDepthBias = 0; + rasterDesc.DepthBiasClamp = 0; + rasterDesc.DepthClipEnable = TRUE; + rasterDesc.MultisampleEnable = FALSE; + rasterDesc.AntialiasedLineEnable = FALSE; + + switch (request.drawType) + { + case DrawType::midpointFanPatches: + case DrawType::midpointFanCenterAAPatches: + case DrawType::outerCurvePatches: + case DrawType::interiorTriangulation: + case DrawType::atlasBlit: + rasterDesc.CullMode = D3D12_CULL_MODE_BACK; + break; + case DrawType::imageRect: + case DrawType::imageMesh: + case DrawType::atomicResolve: + rasterDesc.CullMode = D3D12_CULL_MODE_NONE; + break; + case DrawType::atomicInitialize: + case DrawType::msaaStrokes: + case DrawType::msaaMidpointFanBorrowedCoverage: + case DrawType::msaaMidpointFans: + case DrawType::msaaMidpointFanStencilReset: + case DrawType::msaaMidpointFanPathsStencil: + case DrawType::msaaMidpointFanPathsCover: + case DrawType::msaaOuterCubics: + case DrawType::msaaStencilClipReset: + break; + } + + D3D12_BLEND_DESC blendDesc{}; + blendDesc.RenderTarget[0].BlendEnable = + request.shaderMiscFlags & + (ShaderMiscFlags::fixedFunctionColorOutput | + ShaderMiscFlags::coalescedResolveAndTransfer); + blendDesc.RenderTarget[0].SrcBlend = D3D12_BLEND_ONE; + blendDesc.RenderTarget[0].DestBlend = D3D12_BLEND_INV_SRC_ALPHA; + blendDesc.RenderTarget[0].BlendOp = D3D12_BLEND_OP_ADD; + blendDesc.RenderTarget[0].SrcBlendAlpha = D3D12_BLEND_ONE; + blendDesc.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_INV_SRC_ALPHA; + blendDesc.RenderTarget[0].BlendOpAlpha = D3D12_BLEND_OP_ADD; + blendDesc.RenderTarget[0].RenderTargetWriteMask = + request.shaderMiscFlags & (ShaderMiscFlags::fixedFunctionColorOutput | + ShaderMiscFlags::coalescedResolveAndTransfer) + ? D3D12_COLOR_WRITE_ENABLE_ALL + : 0; + + D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {}; + psoDesc.InputLayout = { + result->vertexResult.vertexShaderResult.m_layoutDesc, + result->vertexResult.vertexShaderResult.m_vertexAttribCount}; + psoDesc.pRootSignature = m_rootSignature.Get(); + psoDesc.VS = CD3DX12_SHADER_BYTECODE( + result->vertexResult.vertexShaderResult.m_shader.Get()); + psoDesc.PS = + CD3DX12_SHADER_BYTECODE(result->pixelResult.pixelShaderResult.Get()); + psoDesc.RasterizerState = rasterDesc; + psoDesc.BlendState = blendDesc; + psoDesc.DepthStencilState.DepthEnable = FALSE; + psoDesc.DepthStencilState.StencilEnable = FALSE; + psoDesc.SampleMask = UINT_MAX; + psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; + psoDesc.NumRenderTargets = 1; + psoDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM; + psoDesc.SampleDesc.Count = 1; + + VERIFY_OK( + device()->CreateGraphicsPipelineState(&psoDesc, + IID_PPV_ARGS(&pipelineState))); + + result->resultData = + m_drawPipelines.insert({result->pixelShaderKey, pipelineState}) + .first->second.Get(); +} + +void D3D12PipelineManager::compileTesselationPipeline() +{ + + D3D12_INPUT_ELEMENT_DESC layoutDesc[] = { + {GLSL_a_p0p1_, + 0, + DXGI_FORMAT_R32G32B32A32_FLOAT, + 0, + D3D12_APPEND_ALIGNED_ELEMENT, + D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA, + 1}, + {GLSL_a_p2p3_, + 0, + DXGI_FORMAT_R32G32B32A32_FLOAT, + 0, + D3D12_APPEND_ALIGNED_ELEMENT, + D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA, + 1}, + {GLSL_a_joinTan_and_ys, + 0, + DXGI_FORMAT_R32G32B32A32_FLOAT, + 0, + D3D12_APPEND_ALIGNED_ELEMENT, + D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA, + 1}, + {GLSL_a_args, + 0, + DXGI_FORMAT_R32G32B32A32_UINT, + 0, + D3D12_APPEND_ALIGNED_ELEMENT, + D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA, + 1}}; + + D3D12_RASTERIZER_DESC rasterDesc = {}; + rasterDesc.FillMode = D3D12_FILL_MODE_SOLID; + rasterDesc.CullMode = D3D12_CULL_MODE_BACK; + rasterDesc.FrontCounterClockwise = FALSE; + rasterDesc.DepthBias = 0; + rasterDesc.SlopeScaledDepthBias = 0; + rasterDesc.DepthBiasClamp = 0; + rasterDesc.DepthClipEnable = FALSE; + rasterDesc.MultisampleEnable = FALSE; + rasterDesc.AntialiasedLineEnable = FALSE; + + D3D12_BLEND_DESC blendDesc{}; + blendDesc.RenderTarget[0].BlendEnable = FALSE; + blendDesc.RenderTarget[0].SrcBlend = D3D12_BLEND_ONE; + blendDesc.RenderTarget[0].DestBlend = D3D12_BLEND_ZERO; + blendDesc.RenderTarget[0].BlendOp = D3D12_BLEND_OP_ADD; + blendDesc.RenderTarget[0].SrcBlendAlpha = D3D12_BLEND_ONE; + blendDesc.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_ZERO; + blendDesc.RenderTarget[0].BlendOpAlpha = D3D12_BLEND_OP_ADD; + blendDesc.RenderTarget[0].RenderTargetWriteMask = + D3D12_COLOR_WRITE_ENABLE_ALL; + + D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {}; + psoDesc.InputLayout = {layoutDesc, _countof(layoutDesc)}; + psoDesc.pRootSignature = m_rootSignature.Get(); + psoDesc.VS = {shader::tess::vert::g_main, + std::size(shader::tess::vert::g_main)}; + psoDesc.PS = {shader::tess::frag::g_main, + std::size(shader::tess::frag::g_main)}; + psoDesc.RasterizerState = rasterDesc; + psoDesc.BlendState = blendDesc; + psoDesc.DepthStencilState.DepthEnable = FALSE; + psoDesc.DepthStencilState.StencilEnable = FALSE; + psoDesc.SampleMask = UINT_MAX; + psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; + psoDesc.NumRenderTargets = 1; + psoDesc.RTVFormats[0] = DXGI_FORMAT_R32G32B32A32_UINT; + psoDesc.SampleDesc.Count = 1; + + VERIFY_OK(device()->CreateGraphicsPipelineState( + &psoDesc, + IID_PPV_ARGS(&m_tesselationPipeline))); +} + +void D3D12PipelineManager::compileGradientPipeline() +{ + + D3D12_INPUT_ELEMENT_DESC layoutDesc = { + GLSL_a_span, + 0, + DXGI_FORMAT_R32G32B32A32_UINT, + 0, + 0, + D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA, + 1}; + + D3D12_RASTERIZER_DESC rasterDesc = {}; + rasterDesc.FillMode = D3D12_FILL_MODE_SOLID; + rasterDesc.CullMode = D3D12_CULL_MODE_BACK; + rasterDesc.FrontCounterClockwise = FALSE; + rasterDesc.DepthBias = 0; + rasterDesc.SlopeScaledDepthBias = 0; + rasterDesc.DepthBiasClamp = 0; + rasterDesc.DepthClipEnable = FALSE; + rasterDesc.MultisampleEnable = FALSE; + rasterDesc.AntialiasedLineEnable = FALSE; + + D3D12_BLEND_DESC blendDesc{}; + blendDesc.RenderTarget[0].BlendEnable = FALSE; + blendDesc.RenderTarget[0].SrcBlend = D3D12_BLEND_ONE; + blendDesc.RenderTarget[0].DestBlend = D3D12_BLEND_ZERO; + blendDesc.RenderTarget[0].BlendOp = D3D12_BLEND_OP_ADD; + blendDesc.RenderTarget[0].SrcBlendAlpha = D3D12_BLEND_ONE; + blendDesc.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_ZERO; + blendDesc.RenderTarget[0].BlendOpAlpha = D3D12_BLEND_OP_ADD; + blendDesc.RenderTarget[0].RenderTargetWriteMask = + D3D12_COLOR_WRITE_ENABLE_ALL; + + D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {}; + psoDesc.InputLayout = {&layoutDesc, 1}; + psoDesc.pRootSignature = m_rootSignature.Get(); + psoDesc.VS = {shader::grad::vert::g_main, + std::size(shader::grad::vert::g_main)}; + psoDesc.PS = {shader::grad::frag::g_main, + std::size(shader::grad::frag::g_main)}; + psoDesc.RasterizerState = rasterDesc; + psoDesc.BlendState = blendDesc; + psoDesc.DepthStencilState.DepthEnable = FALSE; + psoDesc.DepthStencilState.StencilEnable = FALSE; + psoDesc.SampleMask = UINT_MAX; + psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; + psoDesc.NumRenderTargets = 1; + psoDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM; + psoDesc.SampleDesc.Count = 1; + + VERIFY_OK(device()->CreateGraphicsPipelineState( + &psoDesc, + IID_PPV_ARGS(&m_gradientPipeline))); +} + +void D3D12PipelineManager::compileAtlasPipeline() +{ + + D3D12_INPUT_ELEMENT_DESC layoutDesc[2]; + layoutDesc[0] = {GLSL_a_patchVertexData, + 0, + DXGI_FORMAT_R32G32B32A32_FLOAT, + PATCH_VERTEX_DATA_SLOT, + D3D12_APPEND_ALIGNED_ELEMENT, + D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, + 0}; + layoutDesc[1] = {GLSL_a_mirroredVertexData, + 0, + DXGI_FORMAT_R32G32B32A32_FLOAT, + PATCH_VERTEX_DATA_SLOT, + D3D12_APPEND_ALIGNED_ELEMENT, + D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, + 0}; + + D3D12_RASTERIZER_DESC rasterDesc = {}; + rasterDesc.FillMode = D3D12_FILL_MODE_SOLID; + rasterDesc.CullMode = D3D12_CULL_MODE_BACK; + rasterDesc.FrontCounterClockwise = FALSE; + rasterDesc.DepthBias = 0; + rasterDesc.SlopeScaledDepthBias = 0; + rasterDesc.DepthBiasClamp = 0; + rasterDesc.DepthClipEnable = FALSE; + rasterDesc.MultisampleEnable = FALSE; + rasterDesc.AntialiasedLineEnable = FALSE; + + D3D12_BLEND_DESC blendDesc{}; + blendDesc.RenderTarget[0].BlendEnable = TRUE; + blendDesc.RenderTarget[0].SrcBlend = D3D12_BLEND_ONE; + blendDesc.RenderTarget[0].DestBlend = D3D12_BLEND_ONE; + blendDesc.RenderTarget[0].BlendOp = D3D12_BLEND_OP_MAX; + blendDesc.RenderTarget[0].SrcBlendAlpha = D3D12_BLEND_ONE; + blendDesc.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_ONE; + blendDesc.RenderTarget[0].BlendOpAlpha = D3D12_BLEND_OP_MAX; + blendDesc.RenderTarget[0].RenderTargetWriteMask = + D3D12_COLOR_WRITE_ENABLE_ALL; + + D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {}; + psoDesc.InputLayout = {layoutDesc, 2}; + psoDesc.pRootSignature = m_rootSignature.Get(); + psoDesc.VS = {shader::atlas::vert::g_main, + std::size(shader::atlas::vert::g_main)}; + psoDesc.PS = {shader::atlas::stroke::g_main, + std::size(shader::atlas::stroke::g_main)}; + psoDesc.RasterizerState = rasterDesc; + psoDesc.BlendState = blendDesc; + psoDesc.DepthStencilState.DepthEnable = FALSE; + psoDesc.DepthStencilState.StencilEnable = FALSE; + psoDesc.SampleMask = UINT_MAX; + psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; + psoDesc.NumRenderTargets = 1; + psoDesc.RTVFormats[0] = DXGI_FORMAT_R32_FLOAT; + psoDesc.SampleDesc.Count = 1; + + VERIFY_OK(device()->CreateGraphicsPipelineState( + &psoDesc, + IID_PPV_ARGS(&m_atlasStrokePipeline))); + + psoDesc.BlendState.RenderTarget[0].BlendOp = D3D12_BLEND_OP_ADD; + psoDesc.BlendState.RenderTarget[0].BlendOpAlpha = D3D12_BLEND_OP_ADD; + + psoDesc.PS = {shader::atlas::fill::g_main, + std::size(shader::atlas::fill::g_main)}; + + VERIFY_OK(device()->CreateGraphicsPipelineState( + &psoDesc, + IID_PPV_ARGS(&m_atlasFillPipeline))); +} +} // namespace rive::gpu \ No newline at end of file diff --git a/third_party/rive_renderer/source/d3d12/d3d12_utils.cpp b/third_party/rive_renderer/source/d3d12/d3d12_utils.cpp new file mode 100644 index 0000000..62f4063 --- /dev/null +++ b/third_party/rive_renderer/source/d3d12/d3d12_utils.cpp @@ -0,0 +1,638 @@ +/* + * Copyright 2025 Rive + */ +#include "rive/renderer/d3d12/d3d12_utils.hpp" + +namespace rive::gpu +{ +void print_sig_descriptor(LPCVOID data, SIZE_T size) +{ + ComPtr descS; + D3D12CreateRootSignatureDeserializer(data, size, IID_PPV_ARGS(&descS)); + auto desc = descS->GetRootSignatureDesc(); + printf("desc {\n"); + for (size_t i = 0; i < desc->NumParameters; ++i) + { + const char* type; + switch (desc->pParameters[i].ParameterType) + { + case D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE: + type = "table"; + break; + case D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS: + type = "constant"; + break; + case D3D12_ROOT_PARAMETER_TYPE_CBV: + type = "cbv"; + break; + case D3D12_ROOT_PARAMETER_TYPE_SRV: + type = "srv"; + break; + case D3D12_ROOT_PARAMETER_TYPE_UAV: + type = "uav"; + break; + default: + type = "unkown"; + } + + printf("root desc name %s\n", type); + } + printf("}\n"); +} +#if defined(DEBUG) +void SetName(D3D12Resource* pObject, LPCWSTR name) { pObject->SetName(name); } +#else +void printDescriptor(LPCVOID data, SIZE_T size) {} +void SetName(ID3D12Object*, LPCWSTR) {} +#endif + +D3D12DescriptorHeap::D3D12DescriptorHeap(rcp manager, + ID3D12Device* device, + UINT numDescriptors, + D3D12_DESCRIPTOR_HEAP_TYPE type, + D3D12_DESCRIPTOR_HEAP_FLAGS flags) : + GPUResource(std::move(manager)), +#ifndef NDEBUG + m_type(type), + m_flags(flags), +#endif + m_heapDescriptorSize(device->GetDescriptorHandleIncrementSize(type)) +{ + D3D12_DESCRIPTOR_HEAP_DESC desc = {}; + desc.Type = type; + desc.NumDescriptors = numDescriptors; + desc.Flags = flags; + + VERIFY_OK(device->CreateDescriptorHeap(&desc, IID_PPV_ARGS(&m_heap))); +} + +void D3D12DescriptorHeap::markSamplerToIndex(ID3D12Device* device, + const D3D12_SAMPLER_DESC& desc, + UINT index) +{ + assert(m_type == D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER); + + CD3DX12_CPU_DESCRIPTOR_HANDLE samplerHandle( + m_heap->GetCPUDescriptorHandleForHeapStart(), + index, + m_heapDescriptorSize); + + device->CreateSampler(&desc, samplerHandle); +} + +void D3D12DescriptorHeap::markCbvToIndex(ID3D12Device* device, + D3D12Buffer* resource, + UINT index, + UINT sizeInBytes, + SIZE_T offset) +{ + assert(m_type == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); + + D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc; + cbvDesc.SizeInBytes = sizeInBytes; + cbvDesc.BufferLocation = + resource->resource()->GetGPUVirtualAddress() + offset; + + CD3DX12_CPU_DESCRIPTOR_HANDLE cbvHandle( + m_heap->GetCPUDescriptorHandleForHeapStart(), + index, + m_heapDescriptorSize); + + device->CreateConstantBufferView(&cbvDesc, cbvHandle); +} + +void D3D12DescriptorHeap::markSrvToIndex(ID3D12Device* device, + D3D12Buffer* resource, + UINT index, + UINT numElements, + UINT elementByteStride, + UINT64 firstElement) +{ + assert(m_type == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); + + D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; + + srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; + srvDesc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER; + srvDesc.Buffer.FirstElement = firstElement; + srvDesc.Buffer.NumElements = numElements; + srvDesc.Buffer.StructureByteStride = elementByteStride; + srvDesc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_NONE; + srvDesc.Format = resource->desc().Format; + + CD3DX12_CPU_DESCRIPTOR_HANDLE srvHandle( + m_heap->GetCPUDescriptorHandleForHeapStart(), + index, + m_heapDescriptorSize); + + device->CreateShaderResourceView(resource->resource(), &srvDesc, srvHandle); +} + +void D3D12DescriptorHeap::markUavToIndex(ID3D12Device* device, + D3D12Buffer* resource, + DXGI_FORMAT format, + UINT index, + UINT numElements, + UINT elementByteStride) +{ + assert(m_type == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); + + D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {}; + + uavDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER; + uavDesc.Buffer.CounterOffsetInBytes = 0; + uavDesc.Buffer.FirstElement = 0; + uavDesc.Buffer.NumElements = numElements; + uavDesc.Buffer.StructureByteStride = elementByteStride; + uavDesc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_NONE; + uavDesc.Format = format; + + CD3DX12_CPU_DESCRIPTOR_HANDLE uavHandle( + m_heap->GetCPUDescriptorHandleForHeapStart(), + index, + m_heapDescriptorSize); + + device->CreateUnorderedAccessView(resource->resource(), + nullptr, + &uavDesc, + uavHandle); +} + +void D3D12DescriptorHeap::markSrvToIndex(ID3D12Device* device, + D3D12Texture* resource, + UINT index) +{ + assert(m_type == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); + + D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; + + srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; + srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; + srvDesc.Texture2D.MipLevels = resource->desc().MipLevels; + srvDesc.Texture2D.PlaneSlice = 0; + srvDesc.Format = resource->desc().Format; + + CD3DX12_CPU_DESCRIPTOR_HANDLE srvHandle( + m_heap->GetCPUDescriptorHandleForHeapStart(), + index, + m_heapDescriptorSize); + + device->CreateShaderResourceView(resource->resource(), &srvDesc, srvHandle); +} + +void D3D12DescriptorHeap::markSrvToIndex(ID3D12Device* device, + D3D12TextureArray* resource, + UINT index) +{ + assert(m_type == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); + + D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; + + srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; + srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1DARRAY; + srvDesc.Texture1DArray.MipLevels = resource->desc().MipLevels; + srvDesc.Texture1DArray.ArraySize = resource->length(); + srvDesc.Texture1DArray.FirstArraySlice = 0; + srvDesc.Format = resource->desc().Format; + + CD3DX12_CPU_DESCRIPTOR_HANDLE srvHandle( + m_heap->GetCPUDescriptorHandleForHeapStart(), + index, + m_heapDescriptorSize); + + device->CreateShaderResourceView(resource->resource(), &srvDesc, srvHandle); +} + +void D3D12DescriptorHeap::markUavToIndex(ID3D12Device* device, + D3D12Texture* resource, + DXGI_FORMAT format, + UINT index) +{ + assert(m_type == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); + + D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {}; + + uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D; + uavDesc.Texture2D.MipSlice = 0; + uavDesc.Texture2D.PlaneSlice = 0; + uavDesc.Format = format; + + CD3DX12_CPU_DESCRIPTOR_HANDLE uavHandle( + m_heap->GetCPUDescriptorHandleForHeapStart(), + index, + m_heapDescriptorSize); + + device->CreateUnorderedAccessView(resource->resource(), + nullptr, + &uavDesc, + uavHandle); +} + +void D3D12DescriptorHeap::markRtvToIndex(ID3D12Device* device, + D3D12Texture* resource, + UINT index) +{ + assert(m_type == D3D12_DESCRIPTOR_HEAP_TYPE_RTV); + + D3D12_RENDER_TARGET_VIEW_DESC RTVDesc = {}; + RTVDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D; + RTVDesc.Texture2D.MipSlice = 0; + + CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle( + m_heap->GetCPUDescriptorHandleForHeapStart(), + index, + m_heapDescriptorSize); + device->CreateRenderTargetView(resource->resource(), &RTVDesc, rtvHandle); +} + +D3D12Resource::D3D12Resource(rcp manager, + ComPtr resource, + D3D12_RESOURCE_STATES initialState) : + GPUResource(std::move(manager)), + m_resource(resource), + m_lastState(initialState), + m_desc(m_resource->GetDesc()), + m_heapPropeties(D3D12_HEAP_TYPE_DEFAULT), + m_heapFlags(D3D12_HEAP_FLAG_NONE) +{} + +D3D12Resource::D3D12Resource(rcp manager, + ID3D12Device* device, + D3D12_RESOURCE_STATES initialState, + D3D12_HEAP_FLAGS heapFlags, + const D3D12_RESOURCE_DESC& resourceDesc, + const D3D12_CLEAR_VALUE* clearValue) : + GPUResource(std::move(manager)), + m_lastState(initialState), + m_desc(std::move(resourceDesc)), + m_heapFlags(heapFlags) +{ + m_heapPropeties = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT); + VERIFY_OK(device->CreateCommittedResource(&m_heapPropeties, + heapFlags, + &m_desc, + m_lastState, + clearValue, + IID_PPV_ARGS(&m_resource))); +} + +D3D12Resource::D3D12Resource(rcp manager, + ID3D12Device* device, + D3D12_RESOURCE_STATES initialState, + D3D12_HEAP_FLAGS heapFlags, + CD3DX12_HEAP_PROPERTIES heapPropeties, + const D3D12_RESOURCE_DESC& desc, + const D3D12_CLEAR_VALUE* clearValue) : + GPUResource(std::move(manager)), + m_lastState(initialState), + m_desc(std::move(desc)), + m_heapPropeties(heapPropeties), + m_heapFlags(heapFlags) +{ + VERIFY_OK(device->CreateCommittedResource(&m_heapPropeties, + heapFlags, + &m_desc, + m_lastState, + clearValue, + IID_PPV_ARGS(&m_resource))); +} + +void* D3D12Buffer::map() +{ + assert(m_sizeInBytes); + assert(!m_isMapped); + assert(m_heapPropeties.IsCPUAccessible()); + void* data = nullptr; + VERIFY_OK(m_resource->Map(0, nullptr, &data)); +#ifndef NDEBUG + m_isMapped = true; +#endif + return data; +} + +void D3D12Buffer::unmap() +{ + assert(m_isMapped); + assert(m_heapPropeties.IsCPUAccessible()); + m_resource->Unmap(0, nullptr); +#ifndef NDEBUG + m_isMapped = false; +#endif +} + +D3D12VolatileBuffer::D3D12VolatileBuffer(rcp manager, + UINT initialSize, + D3D12_RESOURCE_FLAGS bindFlags, + D3D12_HEAP_FLAGS heapFlags) : + GPUResource(std::move(manager)), + m_bindFlags(bindFlags), + m_heapFlags(heapFlags) +{ + assert(initialSize > 0); + resizeBuffers(initialSize); +} + +D3D12ResourceManager* D3D12VolatileBuffer::d3d() const +{ + return static_cast(m_manager.get()); +} + +void D3D12VolatileBuffer::sync(ID3D12GraphicsCommandList* cmdList, + UINT64 offsetBytes) +{ + assert(m_uploadBuffer->sizeInBytes() == m_gpuBuffer->sizeInBytes()); + sync(cmdList, offsetBytes, m_uploadBuffer->sizeInBytes()); +} + +void D3D12VolatileBuffer::sync(ID3D12GraphicsCommandList* cmdList, + UINT64 offsetBytes, + UINT64 bytesToSync) +{ + assert(bytesToSync); + d3d()->transition(cmdList, + m_gpuBuffer.get(), + D3D12_RESOURCE_STATE_COPY_DEST); + + cmdList->CopyBufferRegion(m_gpuBuffer->resource(), + 0, + m_uploadBuffer->resource(), + offsetBytes, + bytesToSync); + d3d()->transition(cmdList, m_gpuBuffer.get(), D3D12_RESOURCE_STATE_COMMON); +} + +void D3D12VolatileBuffer::syncToBuffer(ID3D12GraphicsCommandList* cmdList, + D3D12Buffer* buffer, + UINT64 offsetBytes, + UINT64 bytesToSync) const +{ + assert(buffer->sizeInBytes() >= bytesToSync); + + cmdList->CopyBufferRegion(buffer->resource(), + 0, + m_uploadBuffer->resource(), + offsetBytes, + bytesToSync); +} + +void D3D12VolatileBuffer::resizeBuffers(UINT newSize) +{ + m_uploadBuffer = d3d()->makeUploadBuffer(newSize, + D3D12_RESOURCE_FLAG_NONE, + D3D12_RESOURCE_STATE_COPY_SOURCE); + m_gpuBuffer = d3d()->makeBuffer(newSize, + m_bindFlags, + D3D12_RESOURCE_STATE_COMMON, + m_heapFlags); +} + +rcp D3D12ResourceManager::makeBuffer( + UINT size, + D3D12_RESOURCE_FLAGS bindFlags, + D3D12_RESOURCE_STATES initialState, + D3D12_HEAP_FLAGS heapFlags) +{ + auto desc = CD3DX12_RESOURCE_DESC::Buffer(size); + return make_rcp(ref_rcp(this), + m_device.Get(), + initialState, + heapFlags, + size, + desc); +} + +rcp D3D12ResourceManager::makeUploadBuffer( + UINT size, + D3D12_RESOURCE_FLAGS bindFlags, + D3D12_RESOURCE_STATES initialState, + D3D12_HEAP_FLAGS heapFlags) +{ + auto desc = CD3DX12_RESOURCE_DESC::Buffer(size); + + return make_rcp( + ref_rcp(this), + m_device.Get(), + initialState, + heapFlags, + CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), + size, + desc); +} + +rcp D3D12ResourceManager::makeVolatileBuffer( + UINT size, + D3D12_RESOURCE_FLAGS bindFlags, + D3D12_HEAP_FLAGS heapFlags) +{ + return make_rcp(ref_rcp(this), + size, + bindFlags, + heapFlags); +} + +rcp D3D12ResourceManager::makeHeap( + UINT numDescriptors, + D3D12_DESCRIPTOR_HEAP_TYPE type, + D3D12_DESCRIPTOR_HEAP_FLAGS flags) +{ + return make_rcp(ref_rcp(this), + m_device.Get(), + numDescriptors, + type, + flags); +} + +rcp D3D12ResourceManager::make1DTextureArray( + UINT width, + UINT16 length, + UINT mipLevelCount, + DXGI_FORMAT format, + D3D12_RESOURCE_FLAGS bindFlags, + D3D12_RESOURCE_STATES initialState, + D3D12_HEAP_FLAGS heapFlags) +{ + D3D12_RESOURCE_DESC desc = CD3DX12_RESOURCE_DESC::Tex1D(format, + width, + length, + mipLevelCount, + bindFlags); + return make_rcp(ref_rcp(this), + m_device.Get(), + initialState, + heapFlags, + desc); +} + +rcp D3D12ResourceManager::make2DTexture( + UINT width, + UINT height, + UINT mipLevelCount, + DXGI_FORMAT format, + D3D12_RESOURCE_FLAGS bindFlags, + D3D12_RESOURCE_STATES initialState, + D3D12_HEAP_FLAGS heapFlags, + const D3D12_CLEAR_VALUE* clearValue) +{ + D3D12_RESOURCE_DESC desc = CD3DX12_RESOURCE_DESC::Tex2D(format, + width, + height, + 1, + mipLevelCount, + 1, + 0, + bindFlags); + + return make_rcp(ref_rcp(this), + m_device.Get(), + initialState, + heapFlags, + desc, + clearValue); +} + +rcp D3D12ResourceManager::makeExternalTexture( + ComPtr externalTexture, + D3D12_RESOURCE_STATES lastState) +{ + return make_rcp(ref_rcp(this), externalTexture, lastState); +} + +void D3D12ResourceManager::transition(ID3D12GraphicsCommandList* cmdList, + D3D12Resource* resource, + D3D12_RESOURCE_STATES toState) +{ + assert(resource->m_lastState != toState); + + auto barrier = CD3DX12_RESOURCE_BARRIER::Transition(resource->resource(), + resource->m_lastState, + toState); + cmdList->ResourceBarrier(1, &barrier); + resource->m_lastState = toState; +} + +void D3D12ResourceManager::clearUAV(ID3D12GraphicsCommandList* cmdList, + ID3D12Resource* resource, + CD3DX12_GPU_DESCRIPTOR_HANDLE& gpuHandle, + CD3DX12_CPU_DESCRIPTOR_HANDLE& cpuHandle, + const UINT clearColor[4], + bool needsBarrier) +{ + if (needsBarrier) + { + D3D12_RESOURCE_BARRIER barriers[] = { + CD3DX12_RESOURCE_BARRIER::UAV(resource)}; + + cmdList->ResourceBarrier(1, barriers); + } + + cmdList->ClearUnorderedAccessViewUint(gpuHandle, + cpuHandle, + resource, + clearColor, + 0, + nullptr); + + if (needsBarrier) + { + D3D12_RESOURCE_BARRIER barriers[] = { + CD3DX12_RESOURCE_BARRIER::UAV(resource)}; + + cmdList->ResourceBarrier(1, barriers); + } +} + +void D3D12ResourceManager::clearUAV(ID3D12GraphicsCommandList* cmdList, + ID3D12Resource* resource, + CD3DX12_GPU_DESCRIPTOR_HANDLE& gpuHandle, + CD3DX12_CPU_DESCRIPTOR_HANDLE& cpuHandle, + const float clearColor[4], + bool needsBarrier) +{ + if (needsBarrier) + { + D3D12_RESOURCE_BARRIER barriers[] = { + CD3DX12_RESOURCE_BARRIER::UAV(resource)}; + + cmdList->ResourceBarrier(1, barriers); + } + + cmdList->ClearUnorderedAccessViewFloat(gpuHandle, + cpuHandle, + resource, + clearColor, + 0, + nullptr); + + if (needsBarrier) + { + D3D12_RESOURCE_BARRIER barriers[] = { + CD3DX12_RESOURCE_BARRIER::UAV(resource)}; + + cmdList->ResourceBarrier(1, barriers); + } +} + +D3D12VolatileBufferPool::D3D12VolatileBufferPool( + rcp manager, + UINT alignment, + UINT size) : + GPUResourcePool(std::move(manager), MAX_POOL_SIZE), + m_targetSize(std::max(size, m_alignment)), + m_alignment(alignment) +{} + +inline D3D12ResourceManager* D3D12VolatileBufferPool::d3d() const +{ + return static_cast(m_manager.get()); +} + +void D3D12VolatileBufferPool::setTargetSize(size_t size) +{ + m_targetSize = std::max(static_cast(size), m_alignment); + assert(m_targetSize % m_alignment == 0); +} + +rcp D3D12VolatileBufferPool::acquire() +{ + auto buffer = + static_rcp_cast(GPUResourcePool::acquire()); + if (buffer == nullptr) + { + buffer = d3d()->makeVolatileBuffer(m_targetSize); + } + else if (buffer->sizeInBytes() != m_targetSize) + { + buffer->resizeBuffers(m_targetSize); + } + return buffer; +} + +D3D12DescriptorHeapPool::D3D12DescriptorHeapPool( + rcp manager, + UINT numDescriptors, + D3D12_DESCRIPTOR_HEAP_TYPE type, + D3D12_DESCRIPTOR_HEAP_FLAGS flags) : + GPUResourcePool(std::move(manager), MAX_POOL_SIZE), + m_numDescriptors(numDescriptors), + m_type(type), + m_flags(flags) +{} + +rcp D3D12DescriptorHeapPool::acquire() +{ + auto heap = + static_rcp_cast(GPUResourcePool::acquire()); + if (heap == nullptr) + { + heap = d3d()->makeHeap(m_numDescriptors, m_type, m_flags); + } + + return heap; +} + +inline D3D12ResourceManager* D3D12DescriptorHeapPool::d3d() const +{ + return static_cast(m_manager.get()); +} + +}; // namespace rive::gpu \ No newline at end of file diff --git a/third_party/rive_renderer/source/d3d12/render_context_d3d12_impl.cpp b/third_party/rive_renderer/source/d3d12/render_context_d3d12_impl.cpp new file mode 100644 index 0000000..42a2271 --- /dev/null +++ b/third_party/rive_renderer/source/d3d12/render_context_d3d12_impl.cpp @@ -0,0 +1,1673 @@ +/* + * Copyright 2025 Rive + */ + +#include "rive/renderer/d3d12/render_context_d3d12_impl.hpp" +#include "rive/renderer/d3d/d3d_constants.hpp" +// needed for root sig and heap constants +#include "shaders/d3d/root.sig" + +#ifdef RIVE_DECODERS +#include "rive/decoders/bitmap_decoder.hpp" +#endif + +#include +#include + +#include +// this is defined here instead of root_sig becaise the gpu does not care about +// the number of rtvs this is gradient, tess, atlas and color +static constexpr UINT NUM_RTV_HEAP_DESCRIPTORS = 4; +namespace rive::gpu +{ + +static constexpr D3D12_FILTER filter_for_sampler_options(ImageFilter option) +{ + switch (option) + { + case ImageFilter::trilinear: + return D3D12_FILTER_COMPARISON_MIN_MAG_MIP_LINEAR; + case ImageFilter::nearest: + return D3D12_FILTER_COMPARISON_MIN_MAG_MIP_POINT; + } + + RIVE_UNREACHABLE(); + return D3D12_FILTER_COMPARISON_MIN_MAG_MIP_LINEAR; +}; + +static constexpr D3D12_TEXTURE_ADDRESS_MODE address_mode_for_sampler_option( + ImageWrap option) +{ + switch (option) + { + case ImageWrap::clamp: + return D3D12_TEXTURE_ADDRESS_MODE_CLAMP; + case ImageWrap::repeat: + return D3D12_TEXTURE_ADDRESS_MODE_WRAP; + case ImageWrap::mirror: + return D3D12_TEXTURE_ADDRESS_MODE_MIRROR; + } + + RIVE_UNREACHABLE(); + return D3D12_TEXTURE_ADDRESS_MODE_CLAMP; +} + +void RenderContextD3D12Impl::blitSubRect(ID3D12GraphicsCommandList* cmdList, + D3D12Texture* dst, + D3D12Texture* src, + const IAABB& rect) +{ + D3D12_BOX updateBox = { + static_cast(rect.left), + static_cast(rect.top), + 0, + static_cast(rect.right), + static_cast(rect.bottom), + 1, + }; + + D3D12_TEXTURE_COPY_LOCATION dstLoc; + dstLoc.SubresourceIndex = 0; + dstLoc.pResource = dst->resource(); + dstLoc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; + + D3D12_TEXTURE_COPY_LOCATION srcLoc; + srcLoc.SubresourceIndex = 0; + srcLoc.pResource = src->resource(); + srcLoc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; + + m_resourceManager->transition(cmdList, + src, + D3D12_RESOURCE_STATE_COPY_SOURCE); + m_resourceManager->transition(cmdList, dst, D3D12_RESOURCE_STATE_COPY_DEST); + cmdList->CopyTextureRegion(&dstLoc, + updateBox.left, + updateBox.top, + 0, + &srcLoc, + &updateBox); + + // we don't untransition here because we don't + // know what we want it to be, so instead we just always transition before + // use +} + +class TextureD3D12Impl : public Texture +{ +public: + TextureD3D12Impl(D3D12ResourceManager* manager, + UINT width, + UINT height, + UINT mipLevel, + const uint8_t imageDataRGBA[]) : + Texture(width, height), + m_gpuTexture(manager->make2DTexture(width, + height, + mipLevel, + DXGI_FORMAT_R8G8B8A8_UNORM, + D3D12_RESOURCE_FLAG_NONE, + D3D12_RESOURCE_STATE_COPY_DEST)) + { + D3D12_SUBRESOURCE_DATA srcData; + srcData.pData = imageDataRGBA; + srcData.RowPitch = width * 4; + srcData.SlicePitch = srcData.RowPitch * height; + + UINT numRows; + UINT64 rowSizeInBtes; + UINT64 totalBytes; + auto desc = m_gpuTexture->resource()->GetDesc(); + manager->device()->GetCopyableFootprints(&desc, + 0, + 1, + 0, + &m_uploadFootprint, + &numRows, + &rowSizeInBtes, + &totalBytes); + + m_uploadBuffer = manager->makeUploadBuffer( + static_cast(totalBytes) + + D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT); + + D3D12_MEMCPY_DEST DestData = { + m_uploadBuffer->map(), + m_uploadFootprint.Footprint.RowPitch, + SIZE_T(m_uploadFootprint.Footprint.RowPitch * numRows)}; + + MemcpySubresource(&DestData, + &srcData, + static_cast(rowSizeInBtes), + numRows, + m_uploadFootprint.Footprint.Depth); + } + + D3D12Texture* synchronize(ID3D12GraphicsCommandList* copyList, + ID3D12GraphicsCommandList* cmdList, + D3D12ResourceManager* manager) const + { + if (m_uploadBuffer) + { + const CD3DX12_TEXTURE_COPY_LOCATION dst(m_gpuTexture->resource(), + 0); + const CD3DX12_TEXTURE_COPY_LOCATION src(m_uploadBuffer->resource(), + m_uploadFootprint); + + copyList->CopyTextureRegion(&dst, 0, 0, 0, &src, nullptr); + + manager->transition(cmdList, + m_gpuTexture.get(), + D3D12_RESOURCE_STATE_GENERIC_READ); + + m_uploadBuffer = nullptr; + } + + return m_gpuTexture.get(); + } + + D3D12Texture* resource() const { return m_gpuTexture.get(); } + +private: + mutable rcp m_uploadBuffer; + const rcp m_gpuTexture; + D3D12_PLACED_SUBRESOURCE_FOOTPRINT m_uploadFootprint; +}; + +class RenderBufferD3D12Impl + : public LITE_RTTI_OVERRIDE(RenderBuffer, RenderBufferD3D12Impl) +{ +public: + RenderBufferD3D12Impl(D3D12ResourceManager* manager, + RenderBufferType renderBufferType, + RenderBufferFlags renderBufferFlags, + size_t sizeInBytes) : + lite_rtti_override(renderBufferType, renderBufferFlags, sizeInBytes), + m_gpuBuffer(manager->makeBuffer(static_cast(sizeInBytes), + D3D12_RESOURCE_FLAG_NONE, + D3D12_RESOURCE_STATE_COMMON)) + { + m_uploadBuffer = + manager->makeUploadBuffer(static_cast(sizeInBytes)); + + if (flags() & RenderBufferFlags::mappedOnceAtInitialization) + { + mappedOnceMempry = m_uploadBuffer->map(); + } + } + + D3D12Buffer* sync(ID3D12GraphicsCommandList* cmdList) + { + if (needsUpload) + { + needsUpload = false; + assert(m_uploadBuffer->sizeInBytes() == m_gpuBuffer->sizeInBytes()); + cmdList->CopyBufferRegion(m_gpuBuffer->resource(), + 0, + m_uploadBuffer->resource(), + 0, + m_uploadBuffer->sizeInBytes()); + + const auto barrier = CD3DX12_RESOURCE_BARRIER::Transition( + m_gpuBuffer->resource(), + D3D12_RESOURCE_STATE_COPY_DEST, + D3D12_RESOURCE_STATE_COMMON); + + cmdList->ResourceBarrier(1, &barrier); + if (flags() & RenderBufferFlags::mappedOnceAtInitialization) + { + m_uploadBuffer = nullptr; + } + } + + return m_gpuBuffer.get(); + } + +protected: + void* onMap() override + { + assert(m_uploadBuffer); + needsUpload = true; + if (flags() & RenderBufferFlags::mappedOnceAtInitialization) + { + assert(mappedOnceMempry); + return mappedOnceMempry; + } + else + { + return m_uploadBuffer->map(); + } + } + + void onUnmap() override + { + assert(m_uploadBuffer); + if (flags() & RenderBufferFlags::mappedOnceAtInitialization) + { + assert(mappedOnceMempry); + m_uploadBuffer->unmap(); + mappedOnceMempry = nullptr; + } + else + { + m_uploadBuffer->unmap(); + } + } + +private: + rcp m_uploadBuffer; + const rcp m_gpuBuffer; + void* mappedOnceMempry = nullptr; + + bool needsUpload = false; +}; + +RenderTargetD3D12::RenderTargetD3D12(RenderContextD3D12Impl* impl, + int width, + int height) : + RenderTarget(width, height), + m_manager(impl->manager()), + m_gpuSupportsTypedUAVLoadStore( + impl->d3dCapabilities().supportsTypedUAVLoadStore) +{} + +void RenderTargetD3D12::setTargetTexture(rcp tex) +{ + if (tex && tex->resource()) + { + D3D12_RESOURCE_DESC desc = tex->desc(); +#ifdef DEBUG + assert(desc.Width == width()); + assert(desc.Height == height()); + assert(desc.Format == DXGI_FORMAT_R8G8B8A8_UNORM || + desc.Format == DXGI_FORMAT_B8G8R8A8_UNORM || + desc.Format == DXGI_FORMAT_R8G8B8A8_TYPELESS || + desc.Format == DXGI_FORMAT_B8G8R8A8_TYPELESS); +#endif + m_targetTextureSupportsUAV = + (desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS) && + m_gpuSupportsTypedUAVLoadStore; + m_targetFormat = desc.Format; + } + else + { + m_targetTextureSupportsUAV = false; + } + + m_targetTexture = std::move(tex); + SNAME_D3D12_OBJECT(m_targetTexture, "color"); +} + +void RenderTargetD3D12::setTargetTexture(ComPtr tex) +{ + if (tex) + { + D3D12_RESOURCE_DESC desc = tex->GetDesc(); +#ifdef DEBUG + assert(desc.Width == width()); + assert(desc.Height == height()); + assert(desc.Format == DXGI_FORMAT_R8G8B8A8_UNORM || + desc.Format == DXGI_FORMAT_B8G8R8A8_UNORM || + desc.Format == DXGI_FORMAT_R8G8B8A8_TYPELESS || + desc.Format == DXGI_FORMAT_B8G8R8A8_TYPELESS); +#endif + m_targetTextureSupportsUAV = + (desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS) && + m_gpuSupportsTypedUAVLoadStore; + m_targetFormat = desc.Format; + } + else + { + m_targetTextureSupportsUAV = false; + } + + m_targetTexture = + m_manager->makeExternalTexture(tex, D3D12_RESOURCE_STATE_PRESENT); + SNAME_D3D12_OBJECT(m_targetTexture, "color"); +} + +D3D12Texture* RenderTargetD3D12::offscreenTexture() +{ + if (!m_offscreenTexture) + { + m_offscreenTexture = + m_manager->make2DTexture(width(), + height(), + 1, + DXGI_FORMAT_R8G8B8A8_TYPELESS, + D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS, + D3D12_RESOURCE_STATE_UNORDERED_ACCESS, + D3D12_HEAP_FLAG_ALLOW_SHADER_ATOMICS); + SNAME_D3D12_OBJECT(m_offscreenTexture, "offscreenColor"); + } + return m_offscreenTexture.get(); +} + +void RenderTargetD3D12::markTargetUAV(D3D12DescriptorHeap* heap) +{ + assert(m_targetTexture); + D3D12Texture* targetTexture = m_targetTexture.get(); + if (!m_targetTextureSupportsUAV) + { + targetTexture = offscreenTexture(); + } + + if (auto& uavTexture = + m_targetTextureSupportsUAV ? m_targetTexture : m_offscreenTexture) + { + DXGI_FORMAT targetUavFormat; + switch (m_targetFormat) + { + case DXGI_FORMAT_R8G8B8A8_UNORM: + case DXGI_FORMAT_R8G8B8A8_TYPELESS: + targetUavFormat = m_gpuSupportsTypedUAVLoadStore + ? DXGI_FORMAT_R8G8B8A8_UNORM + : DXGI_FORMAT_R32_UINT; + break; + case DXGI_FORMAT_B8G8R8A8_UNORM: + case DXGI_FORMAT_B8G8R8A8_TYPELESS: + targetUavFormat = m_gpuSupportsTypedUAVLoadStore + ? DXGI_FORMAT_B8G8R8A8_UNORM + : DXGI_FORMAT_R32_UINT; + break; + default: + RIVE_UNREACHABLE(); + } + + heap->markUavToIndex(m_manager->device(), + targetTexture, + targetUavFormat, + ATOMIC_COLOR_HEAP_OFFSET); + } +} + +void RenderTargetD3D12::markClipUAV(D3D12DescriptorHeap* heap) +{ + if (m_clipTexture == nullptr) + { + m_clipTexture = + m_manager->make2DTexture(width(), + height(), + 1, + DXGI_FORMAT_R32_UINT, + D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS, + D3D12_RESOURCE_STATE_UNORDERED_ACCESS); + SNAME_D3D12_OBJECT(m_clipTexture, "clip"); + } + assert(m_clipTexture); + heap->markUavToIndex(m_manager->device(), + m_clipTexture.get(), + DXGI_FORMAT_R32_UINT, + ATOMIC_CLIP_HEAP_OFFSET); +} + +void RenderTargetD3D12::markScratchColorUAV(D3D12DescriptorHeap* heap) +{ + // checks and makes texture + if (!m_scratchColorTexture) + { + m_scratchColorTexture = + m_manager->make2DTexture(width(), + height(), + 1, + DXGI_FORMAT_R8G8B8A8_TYPELESS, + D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS, + D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, + D3D12_HEAP_FLAG_ALLOW_SHADER_ATOMICS); + SNAME_D3D12_OBJECT(m_scratchColorTexture, "scratchColor"); + } + + assert(m_scratchColorTexture); + heap->markUavToIndex(m_manager->device(), + m_scratchColorTexture.get(), + m_gpuSupportsTypedUAVLoadStore + ? DXGI_FORMAT_R8G8B8A8_UNORM + : DXGI_FORMAT_R32_UINT, + ATOMIC_SCRATCH_COLOR_HEAP_OFFSET); +} + +void RenderTargetD3D12::markCoverageUAV(D3D12DescriptorHeap* heap) +{ + if (m_coverageTexture == nullptr) + { + m_coverageTexture = + m_manager->make2DTexture(width(), + height(), + 1, + DXGI_FORMAT_R32_UINT, + D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS, + D3D12_RESOURCE_STATE_UNORDERED_ACCESS); + + SNAME_D3D12_OBJECT(m_coverageTexture, "coverage"); + } + heap->markUavToIndex(m_manager->device(), + m_coverageTexture.get(), + DXGI_FORMAT_R32_UINT, + ATOMIC_COVERAGE_HEAP_OFFSET); +} + +std::unique_ptr RenderContextD3D12Impl::MakeContext( + ComPtr device, + ID3D12GraphicsCommandList* copyCommandList, + const D3DContextOptions& contextOptions) +{ + D3DCapabilities d3dCapabilities; + D3D12_FEATURE_DATA_D3D12_OPTIONS d3d12Options; + + if (SUCCEEDED(device->CheckFeatureSupport( + D3D12_FEATURE_D3D12_OPTIONS, + &d3d12Options, + sizeof(D3D12_FEATURE_DATA_D3D12_OPTIONS)))) + { + d3dCapabilities.supportsRasterizerOrderedViews = + d3d12Options.ROVsSupported; + if (d3d12Options.TypedUAVLoadAdditionalFormats) + { + // TypedUAVLoadAdditionalFormats is true. Now check if we can + // both load and store all formats used by Rive (currently only + // RGBA8 and BGRA8): + // https://learn.microsoft.com/en-us/windows/win32/direct3d11/typed-unordered-access-view-loads. + auto check_typed_uav_load = [device](DXGI_FORMAT format) { + D3D12_FEATURE_DATA_FORMAT_SUPPORT d3d12Format{}; + d3d12Format.Format = format; + if (SUCCEEDED(device->CheckFeatureSupport( + D3D12_FEATURE_FORMAT_SUPPORT, + &d3d12Format, + sizeof(d3d12Format)))) + { + constexpr UINT loadStoreFlags = + D3D12_FORMAT_SUPPORT2_UAV_TYPED_LOAD | + D3D12_FORMAT_SUPPORT2_UAV_TYPED_STORE; + return (d3d12Format.Support2 & loadStoreFlags) == + loadStoreFlags; + } + return false; + }; + + d3dCapabilities.supportsTypedUAVLoadStore = + check_typed_uav_load(DXGI_FORMAT_R8G8B8A8_UNORM) && + check_typed_uav_load(DXGI_FORMAT_B8G8R8A8_UNORM); + + // Check if we can use HLSL minimum precision types (e.g. min16int) + d3dCapabilities.supportsMin16Precision = + d3d12Options.MinPrecisionSupport & + D3D12_SHADER_MIN_PRECISION_SUPPORT_16_BIT; + } + } + + if (contextOptions.disableRasterizerOrderedViews) + { + d3dCapabilities.supportsRasterizerOrderedViews = false; + } + if (contextOptions.disableTypedUAVLoadStore) + { + d3dCapabilities.supportsTypedUAVLoadStore = false; + } + + d3dCapabilities.isIntel = contextOptions.isIntel; + + auto renderContextImpl = std::unique_ptr( + new RenderContextD3D12Impl(device, copyCommandList, d3dCapabilities)); + return std::make_unique(std::move(renderContextImpl)); +} + +RenderContextD3D12Impl::RenderContextD3D12Impl( + ComPtr device, + ID3D12GraphicsCommandList* copyCommandList, + const D3DCapabilities& capabilities) : + m_device(device), + m_capabilities(capabilities), + m_pipelineManager(device, capabilities), + m_resourceManager(make_rcp(device)), + m_flushUniformBufferPool(m_resourceManager, sizeof(FlushUniforms)), + m_imageDrawUniformBufferPool(m_resourceManager, sizeof(ImageDrawUniforms)), + m_pathBufferPool(m_resourceManager), + m_paintBufferPool(m_resourceManager), + m_paintAuxBufferPool(m_resourceManager), + m_contourBufferPool(m_resourceManager), + m_gradSpanBufferPool(m_resourceManager), + m_tessSpanBufferPool(m_resourceManager), + m_triangleBufferPool(m_resourceManager), + // this is 64kb which is the smallest heap that can be sent to gpu + m_srvUavCbvHeapPool(m_resourceManager, + MAX_DESCRIPTOR_HEAPS_PER_FLUSH, + D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, + D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE), + m_cpuSrvUavCbvHeapPool(m_resourceManager, + NUM_SRV_UAV_HEAP_DESCRIPTORS, + D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, + D3D12_DESCRIPTOR_HEAP_FLAG_NONE), + m_samplerHeapPool(m_resourceManager, + MAX_DESCRIPTOR_SAMPLER_HEAPS_PER_FLUSH, + D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, + D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE) +{ + + m_platformFeatures.clipSpaceBottomUp = true; + m_platformFeatures.framebufferBottomUp = false; + m_platformFeatures.supportsRasterOrdering = + m_capabilities.supportsRasterizerOrderedViews; + m_platformFeatures.supportsFragmentShaderAtomics = true; + m_platformFeatures.maxTextureSize = D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION; + + m_rtvHeap = m_resourceManager->makeHeap(NUM_RTV_HEAP_DESCRIPTORS, + D3D12_DESCRIPTOR_HEAP_TYPE_RTV, + D3D12_DESCRIPTOR_HEAP_FLAG_NONE); + + m_pipelineManager.compileGradientPipeline(); + m_pipelineManager.compileTesselationPipeline(); + m_pipelineManager.compileAtlasPipeline(); + + m_linearSampler.Filter = D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT; + m_linearSampler.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP; + m_linearSampler.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP; + m_linearSampler.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP; + m_linearSampler.MipLODBias = 0.0f; + m_linearSampler.MaxAnisotropy = 1; + m_linearSampler.ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER; + m_linearSampler.MinLOD = 0; + m_linearSampler.MaxLOD = 0; + + for (int i = 0; i < ImageSampler::MAX_SAMPLER_PERMUTATIONS; ++i) + { + auto wrapX = ImageSampler::GetWrapXOptionFromKey(i); + auto wrapY = ImageSampler::GetWrapYOptionFromKey(i); + auto filter = ImageSampler::GetFilterOptionFromKey(i); + + m_imageSamplers[i].Filter = filter_for_sampler_options(filter); + m_imageSamplers[i].AddressU = address_mode_for_sampler_option(wrapX); + m_imageSamplers[i].AddressV = address_mode_for_sampler_option(wrapY); + m_imageSamplers[i].AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP; + m_imageSamplers[i].MipLODBias = 0.0f; + m_imageSamplers[i].MaxAnisotropy = 1; + m_imageSamplers[i].ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER; + m_imageSamplers[i].MinLOD = 0; + // this should be D3D12_FLOAT32_MAX but currently we don't generate mips + m_imageSamplers[i].MaxLOD = 0; + } + + PatchVertex patchVertices[kPatchVertexBufferCount]; + uint16_t patchIndices[kPatchIndexBufferCount]; + + GeneratePatchBufferData(patchVertices, patchIndices); + + // advance to ensure that safe frame does not equal current frame so that + // our temp upload buffers do not get released automatically + m_resourceManager->advanceFrameNumber(1, 0); + + m_pathPatchVertexBuffer = + m_resourceManager->makeImmutableBuffer<>(copyCommandList, + patchVertices); + NAME_D3D12_OBJECT(m_pathPatchVertexBuffer); + m_pathPatchIndexBuffer = + m_resourceManager->makeImmutableBuffer<>(copyCommandList, patchIndices); + NAME_D3D12_OBJECT(m_pathPatchIndexBuffer); + m_tessSpanIndexBuffer = + m_resourceManager->makeImmutableBuffer<>(copyCommandList, + kTessSpanIndices); + NAME_D3D12_OBJECT(m_tessSpanIndexBuffer); + m_imageRectVertexBuffer = + m_resourceManager->makeImmutableBuffer<>(copyCommandList, + kImageRectVertices); + NAME_D3D12_OBJECT(m_imageRectVertexBuffer); + m_imageRectIndexBuffer = + m_resourceManager->makeImmutableBuffer<>(copyCommandList, + kImageRectIndices); + NAME_D3D12_OBJECT(m_imageRectIndexBuffer); + m_featherTexture = + m_resourceManager->make1DTextureArray(GAUSSIAN_TABLE_SIZE, + FEATHER_TEXTURE_1D_ARRAY_LENGTH, + 1, + DXGI_FORMAT_R16_FLOAT, + D3D12_RESOURCE_FLAG_NONE, + D3D12_RESOURCE_STATE_COPY_DEST); + NAME_D3D12_OBJECT(m_featherTexture); + auto featherUploadBuffer = m_resourceManager->makeUploadBuffer( + sizeof(gpu::g_inverseGaussianIntegralTableF16) * 2); + + D3D12_SUBRESOURCE_DATA updateData; + updateData.pData = g_gaussianIntegralTableF16; + updateData.RowPitch = sizeof(g_gaussianIntegralTableF16); + updateData.SlicePitch = updateData.RowPitch; + + UpdateSubresources(copyCommandList, + m_featherTexture->resource(), + featherUploadBuffer->resource(), + 0, + 0, + 1, + &updateData); + + D3D12_SUBRESOURCE_DATA updateData2; + updateData2.pData = g_inverseGaussianIntegralTableF16; + updateData2.RowPitch = sizeof(g_inverseGaussianIntegralTableF16); + updateData2.SlicePitch = updateData.RowPitch; + + UpdateSubresources(copyCommandList, + m_featherTexture->resource(), + featherUploadBuffer->resource(), + sizeof(gpu::g_gaussianIntegralTableF16), + 1, + 1, + &updateData2); + + m_resourceManager->transition(copyCommandList, + m_featherTexture.get(), + D3D12_RESOURCE_STATE_COMMON); +} + +rcp RenderContextD3D12Impl::makeRenderBuffer( + RenderBufferType type, + RenderBufferFlags flags, + size_t size) +{ + return make_rcp(m_resourceManager.get(), + type, + flags, + size); +} + +rcp RenderContextD3D12Impl::makeImageTexture( + uint32_t width, + uint32_t height, + uint32_t mipLevelCount, + const uint8_t imageDataRGBAPremul[]) +{ + return make_rcp(m_resourceManager.get(), + width, + height, + mipLevelCount, + imageDataRGBAPremul); +} + +void rive::gpu::RenderContextD3D12Impl::resizeGradientTexture(uint32_t width, + uint32_t height) +{ + if (width == 0 || height == 0) + { + m_gradientTexture = nullptr; + } + else + { + m_gradientTexture = m_resourceManager->make2DTexture( + width, + height, + 1, + DXGI_FORMAT_R8G8B8A8_UNORM, + D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET); + // these can be done here since they arent recycled every frame + m_rtvHeap->markRtvToIndex(m_device.Get(), + m_gradientTexture.get(), + GRAD_RTV_HEAP_OFFSET); + SNAME_D3D12_OBJECT(m_gradientTexture, "gradient"); + } +} + +void rive::gpu::RenderContextD3D12Impl::resizeTessellationTexture( + uint32_t width, + uint32_t height) +{ + if (width == 0 || height == 0) + { + m_tesselationTexture = nullptr; + } + else + { + + m_tesselationTexture = m_resourceManager->make2DTexture( + width, + height, + 1, + DXGI_FORMAT_R32G32B32A32_UINT, + D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET); + // these can be done here since they arent recycled every frame + m_rtvHeap->markRtvToIndex(m_device.Get(), + m_tesselationTexture.get(), + TESS_RTV_HEAP_OFFSET); + SNAME_D3D12_OBJECT(m_tesselationTexture, "tesselation"); + } +} + +void rive::gpu::RenderContextD3D12Impl::resizeAtlasTexture(uint32_t width, + uint32_t height) +{ + if (width == 0 || height == 0) + { + m_atlasTexture = nullptr; + } + else + { + + D3D12_CLEAR_VALUE clear{DXGI_FORMAT_R32_FLOAT, {}}; + + m_atlasTexture = m_resourceManager->make2DTexture( + width, + height, + 1, + DXGI_FORMAT_R32_FLOAT, + D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET, + D3D12_RESOURCE_STATE_COMMON, + D3D12_HEAP_FLAG_NONE, + &clear); + // these can be done here since they arent recycled every frame + m_rtvHeap->markRtvToIndex(m_device.Get(), + m_atlasTexture.get(), + ATLAS_RTV_HEAP_OFFSET); + SNAME_D3D12_OBJECT(m_atlasTexture, "atlas"); + } +} + +void RenderContextD3D12Impl::prepareToFlush(uint64_t nextFrameNumber, + uint64_t safeFrameNumber) +{ + // These should all have gotten recycled at the end of the last frame. + assert(m_flushUniformBuffer == nullptr); + assert(m_imageDrawUniformBuffer == nullptr); + assert(m_pathBuffer == nullptr); + assert(m_paintBuffer == nullptr); + assert(m_paintAuxBuffer == nullptr); + assert(m_contourBuffer == nullptr); + assert(m_gradSpanBuffer == nullptr); + assert(m_tessSpanBuffer == nullptr); + assert(m_triangleBuffer == nullptr); + + assert(m_srvUavCbvHeap == nullptr); + assert(m_cpuSrvUavCbvHeap == nullptr); + assert(m_samplerHeap == nullptr); + + // Advance the context frame and delete resources that are no longer + // referenced by in-flight command buffers. + m_resourceManager->advanceFrameNumber(nextFrameNumber, safeFrameNumber); + + // Acquire buffers for the flush. + m_flushUniformBuffer = m_flushUniformBufferPool.acquire(); + m_imageDrawUniformBuffer = m_imageDrawUniformBufferPool.acquire(); + m_pathBuffer = m_pathBufferPool.acquire(); + m_paintBuffer = m_paintBufferPool.acquire(); + m_paintAuxBuffer = m_paintAuxBufferPool.acquire(); + m_contourBuffer = m_contourBufferPool.acquire(); + m_gradSpanBuffer = m_gradSpanBufferPool.acquire(); + m_tessSpanBuffer = m_tessSpanBufferPool.acquire(); + m_triangleBuffer = m_triangleBufferPool.acquire(); + + m_srvUavCbvHeap = m_srvUavCbvHeapPool.acquire(); + m_cpuSrvUavCbvHeap = m_cpuSrvUavCbvHeapPool.acquire(); + m_samplerHeap = m_samplerHeapPool.acquire(); + + VNAME_D3D12_OBJECT(m_flushUniformBuffer); + VNAME_D3D12_OBJECT(m_imageDrawUniformBuffer); + VNAME_D3D12_OBJECT(m_pathBuffer); + VNAME_D3D12_OBJECT(m_paintBuffer); + VNAME_D3D12_OBJECT(m_paintAuxBuffer); + VNAME_D3D12_OBJECT(m_contourBuffer); + VNAME_D3D12_OBJECT(m_gradSpanBuffer); + VNAME_D3D12_OBJECT(m_tessSpanBuffer); + VNAME_D3D12_OBJECT(m_triangleBuffer); + + m_isFirstFlushOfFrame = true; + + m_heapDescriptorOffset = 0; + m_samplerHeapDescriptorOffset = IMAGE_SAMPLER_HEAP_OFFSET; + m_lastDynamicSampler = ImageSampler::LinearClamp(); +} + +void RenderContextD3D12Impl::flush(const FlushDescriptor& desc) +{ + CommandLists* commandLists = + static_cast(desc.externalCommandBuffer); + assert(commandLists); + + auto copyCmdList = commandLists->copyComandList; + auto cmdList = commandLists->directComandList; + // it's ok but less efficient to use one command list for everything + // and a copy command list may not be guaranteed on certain platforms + if (!copyCmdList) + copyCmdList = cmdList; + assert(copyCmdList); + assert(cmdList); + + // this assert doesn't take into account any potential images + // there is no way to currently know how many we have though so we have to + // just do this and assert the image index later + if (m_heapDescriptorOffset + NUM_SRV_UAV_HEAP_DESCRIPTORS >= + MAX_DESCRIPTOR_HEAPS_PER_FLUSH) + { + fprintf(stderr, + "heap descriptor ran out of room ! heapOffset %i maxHeap %i\n", + m_heapDescriptorOffset, + MAX_DESCRIPTOR_HEAPS_PER_FLUSH); + assert(false); + return; + } + + auto renderTarget = static_cast(desc.renderTarget); + + auto width = renderTarget->width(); + auto height = renderTarget->height(); + + auto targetTexture = renderTarget->targetTexture(); + + // offset for where to start writing image descriptors into the heap + // on every frame but the first, that is just the number of dynamic + // descriptors the first frame though we need to move it the entire length + // of descriptors over + UINT64 imageDescriptorOffset = NUM_DYNAMIC_SRV_HEAP_DESCRIPTORS; + if (m_isFirstFlushOfFrame) + { + m_isFirstFlushOfFrame = false; + + // the -1 is because this size includes the image descriptor itself + // note we could just use IMAGE_HEAP_OFFSET_START but i thought this + // was more readable for someone who hasn't seen this code before + imageDescriptorOffset = (NUM_SRV_UAV_HEAP_DESCRIPTORS - 1); + // sync everything first logical flush, + // copies are slow, so do it all at once + m_flushUniformBuffer->sync(copyCmdList, 0); + m_imageDrawUniformBuffer->sync(copyCmdList, 0); + if (desc.pathCount > 0) + { + m_pathBuffer->sync(copyCmdList, 0); + m_paintBuffer->sync(copyCmdList, 0); + m_paintAuxBuffer->sync(copyCmdList, 0); + } + if (desc.contourCount > 0) + { + m_contourBuffer->sync(copyCmdList, 0); + } + + if (desc.tessVertexSpanCount) + { + m_tessSpanBuffer->sync(copyCmdList, 0); + } + + if (desc.gradSpanCount) + { + m_gradSpanBuffer->sync(copyCmdList, 0); + } + + if (desc.hasTriangleVertices) + { + m_triangleBuffer->sync(copyCmdList, 0); + } + + // mark all UAVS, thse only need to happen the fist time since they + // won't change per logical flush + + renderTarget->markClipUAV(m_cpuSrvUavCbvHeap.get()); + renderTarget->markCoverageUAV(m_cpuSrvUavCbvHeap.get()); + renderTarget->markTargetUAV(m_cpuSrvUavCbvHeap.get()); + renderTarget->markScratchColorUAV(m_cpuSrvUavCbvHeap.get()); + m_rtvHeap->markRtvToIndex(m_device.Get(), + targetTexture, + TARGET_RTV_HEAP_OFFSET); + // mark all the texture srvs, these also only need to be done once per + // flush since the texture aren't re created per logical flush + if (m_gradientTexture) + { + m_cpuSrvUavCbvHeap->markSrvToIndex(m_device.Get(), + m_gradientTexture.get(), + GRAD_IMAGE_HEAP_OFFSET); + } + if (m_tesselationTexture) + { + m_cpuSrvUavCbvHeap->markSrvToIndex(m_device.Get(), + m_tesselationTexture.get(), + TESS_IMAGE_HEAP_OFFSET); + } + if (m_atlasTexture) + { + m_cpuSrvUavCbvHeap->markSrvToIndex(m_device.Get(), + m_atlasTexture.get(), + ATLAS_IMAGE_HEAP_OFFSET); + } + assert(m_featherTexture); + m_cpuSrvUavCbvHeap->markSrvToIndex(m_device.Get(), + m_featherTexture.get(), + FEATHER_IMAGE_HEAP_OFFSET); + + // do this only once. + m_pipelineManager.setRootSig(cmdList); + + ID3D12DescriptorHeap* ppHeaps[] = {m_srvUavCbvHeap->heap(), + m_samplerHeap->heap()}; + // copy the static descriptors + m_device->CopyDescriptorsSimple( + NUM_STATIC_SRV_UAV_HEAP_DESCRIPTORS, + m_srvUavCbvHeap->cpuHandleForUpload( + STATIC_SRV_UAV_HEAP_DESCRIPTOPR_START), + m_cpuSrvUavCbvHeap->cpuHandleForIndex( + STATIC_SRV_UAV_HEAP_DESCRIPTOPR_START), + D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); + + // this is extremely expensive as it causes a fence on some hardware + // (nvidia) so we do this only once per flush + // some api's may potentially expose a global heap to use, if so, we + // should use that one instead. but that will have to be addressed once + // we start integrating + cmdList->SetDescriptorHeaps(_countof(ppHeaps), ppHeaps); + + // setup samplers, these don't change, + // image sampler will eventually but for now keep it here + m_samplerHeap->markSamplerToIndex(m_device.Get(), + m_linearSampler, + TESS_SAMPLER_HEAP_OFFSET); + m_samplerHeap->markSamplerToIndex(m_device.Get(), + m_linearSampler, + GRAD_SAMPLER_HEAP_OFFSET); + m_samplerHeap->markSamplerToIndex(m_device.Get(), + m_linearSampler, + FEATHER_SAMPLER_HEAP_OFFSET); + m_samplerHeap->markSamplerToIndex(m_device.Get(), + m_linearSampler, + ATLAS_SAMPLER_HEAP_OFFSET); + + // this SHOULD be m_mipSampler but we don't currently generate mips + m_samplerHeap->markSamplerToIndex(m_device.Get(), + m_linearSampler, + IMAGE_SAMPLER_HEAP_OFFSET); + + cmdList->SetGraphicsRootDescriptorTable( + STATIC_SRV_SIG_INDEX, + m_srvUavCbvHeap->gpuHandleForIndex( + STATIC_SRV_UAV_HEAP_DESCRIPTOPR_START)); + + cmdList->SetGraphicsRootDescriptorTable( + UAV_SIG_INDEX, + m_srvUavCbvHeap->gpuHandleForIndex(UAV_START_HEAP_INDEX)); + + cmdList->SetGraphicsRootDescriptorTable( + SAMPLER_SIG_INDEX, + m_samplerHeap->gpuHandleForIndex(0)); + + cmdList->SetGraphicsRootDescriptorTable( + DYNAMIC_SAMPLER_SIG_INDEX, + m_samplerHeap->gpuHandleForIndex(IMAGE_SAMPLER_HEAP_OFFSET)); + } + + // note that flush could have been left a heap but it would be pointless + // since it would have been a heap size of 1, so instead we bind to as a + // root constant buffer view instead + cmdList->SetGraphicsRootConstantBufferView( + FLUSH_UNIFORM_BUFFFER_SIG_INDEX, + m_flushUniformBuffer->resource()->getGPUVirtualAddress() + + desc.flushUniformDataOffsetInBytes); + + if (desc.pathCount > 0) + { + m_cpuSrvUavCbvHeap->markSrvToIndex(m_device.Get(), + m_pathBuffer->resource(), + PATH_BUFFER_HEAP_OFFSET, + desc.pathCount, + sizeof(PathData), + desc.firstPath); + + m_cpuSrvUavCbvHeap->markSrvToIndex(m_device.Get(), + m_paintBuffer->resource(), + PAINT_BUFFER_HEAP_OFFSET, + desc.pathCount, + sizeof(PaintData), + desc.firstPaint); + + m_cpuSrvUavCbvHeap->markSrvToIndex(m_device.Get(), + m_paintAuxBuffer->resource(), + PAINT_AUX_BUFFER_HEAP_OFFSET, + desc.pathCount, + sizeof(PaintAuxData), + desc.firstPaintAux); + } + + if (desc.contourCount > 0) + { + m_cpuSrvUavCbvHeap->markSrvToIndex(m_device.Get(), + m_contourBuffer->resource(), + CONTOUR_BUFFER_HEAP_OFFSET, + desc.contourCount, + sizeof(ContourData), + desc.firstContour); + } + + // copy to gpu heap + m_device->CopyDescriptorsSimple( + NUM_DYNAMIC_SRV_HEAP_DESCRIPTORS, + m_srvUavCbvHeap->cpuHandleForUpload( + m_heapDescriptorOffset + DYNAMIC_SRV_UAV_HEAP_DESCRIPTOPR_START), + m_cpuSrvUavCbvHeap->cpuHandleForIndex( + DYNAMIC_SRV_UAV_HEAP_DESCRIPTOPR_START), + D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); + + cmdList->SetGraphicsRootDescriptorTable( + DYNAMIC_SRV_SIG_INDEX, + m_srvUavCbvHeap->gpuHandleForIndex( + m_heapDescriptorOffset + DYNAMIC_SRV_UAV_HEAP_DESCRIPTOPR_START)); + + if (desc.gradSpanCount) + { + + CD3DX12_VIEWPORT viewport(0.0f, + 0.0f, + static_cast(kGradTextureWidth), + static_cast(desc.gradDataHeight)); + CD3DX12_RECT scissorRect(0, + 0, + static_cast(kGradTextureWidth), + static_cast(desc.gradDataHeight)); + + m_resourceManager->transition(cmdList, + m_gradientTexture.get(), + D3D12_RESOURCE_STATE_RENDER_TARGET); + + auto rtvHandle = m_rtvHeap->cpuHandleForIndex(GRAD_RTV_HEAP_OFFSET); + + cmdList->OMSetRenderTargets(1, &rtvHandle, FALSE, nullptr); + + cmdList->RSSetViewports(1, &viewport); + cmdList->RSSetScissorRects(1, &scissorRect); + + auto view = m_gradSpanBuffer->resource()->vertexBufferView( + 0, + sizeof(GradientSpan)); + + cmdList->IASetVertexBuffers(0, 1, &view); + + m_pipelineManager.setGradientPipeline(cmdList); + + cmdList->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + + cmdList->SetGraphicsRoot32BitConstant( + VERTEX_DRAW_UNIFORM_SIG_INDEX, + math::lossless_numeric_cast(desc.firstGradSpan), + 0); + + cmdList->DrawInstanced( + gpu::GRAD_SPAN_TRI_STRIP_VERTEX_COUNT, + desc.gradSpanCount, + 0, + math::lossless_numeric_cast(desc.firstGradSpan)); + + m_resourceManager->transition(cmdList, + m_gradientTexture.get(), + D3D12_RESOURCE_STATE_GENERIC_READ); + + cmdList->OMSetRenderTargets(0, nullptr, FALSE, nullptr); + } + + if (desc.tessVertexSpanCount) + { + m_resourceManager->transition(cmdList, + m_tesselationTexture.get(), + D3D12_RESOURCE_STATE_RENDER_TARGET); + + auto rtvHandle = m_rtvHeap->cpuHandleForIndex(TESS_RTV_HEAP_OFFSET); + + cmdList->OMSetRenderTargets(1, &rtvHandle, FALSE, nullptr); + + CD3DX12_VIEWPORT viewport(0.0f, + 0.0f, + static_cast(kTessTextureWidth), + static_cast(desc.tessDataHeight)); + CD3DX12_RECT scissorRect(0, + 0, + static_cast(kTessTextureWidth), + static_cast(desc.tessDataHeight)); + + cmdList->RSSetViewports(1, &viewport); + cmdList->RSSetScissorRects(1, &scissorRect); + + cmdList->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + + auto VBView = m_tessSpanBuffer->resource()->vertexBufferView( + sizeof(TessVertexSpan)); + + auto IBView = + m_tessSpanIndexBuffer->indexBufferView(0, sizeof(kTessSpanIndices)); + + cmdList->IASetVertexBuffers(0, 1, &VBView); + cmdList->IASetIndexBuffer(&IBView); + + m_pipelineManager.setTesselationPipeline(cmdList); + + cmdList->DrawIndexedInstanced( + std::size(gpu::kTessSpanIndices), + desc.tessVertexSpanCount, + 0, + 0, + math::lossless_numeric_cast(desc.firstTessVertexSpan)); + + cmdList->OMSetRenderTargets(0, nullptr, FALSE, nullptr); + + m_resourceManager->transition(cmdList, + m_tesselationTexture.get(), + D3D12_RESOURCE_STATE_GENERIC_READ); + } + + D3D12_VERTEX_BUFFER_VIEW NULL_VIEW; + NULL_VIEW.BufferLocation = 0; + NULL_VIEW.SizeInBytes = 0; + NULL_VIEW.StrideInBytes = 0; + + D3D12_VERTEX_BUFFER_VIEW vertexBuffers[3] = { + m_pathPatchVertexBuffer->vertexBufferView(0, + kPatchVertexBufferCount, + sizeof(PatchVertex)), + desc.hasTriangleVertices + ? m_triangleBuffer->resource()->vertexBufferView( + 0, + sizeof(TriangleVertex)) + : NULL_VIEW, + m_imageRectVertexBuffer->vertexBufferView(0, + std::size(kImageRectVertices), + sizeof(ImageRectVertex))}; + + static_assert(PATCH_VERTEX_DATA_SLOT == 0); + static_assert(TRIANGLE_VERTEX_DATA_SLOT == 1); + static_assert(IMAGE_RECT_VERTEX_DATA_SLOT == 2); + cmdList->IASetVertexBuffers(0, 3, vertexBuffers); + + if ((desc.atlasFillBatchCount | desc.atlasStrokeBatchCount) != 0) + { + m_resourceManager->transition(cmdList, + m_atlasTexture.get(), + D3D12_RESOURCE_STATE_RENDER_TARGET); + + auto rtvHandle = m_rtvHeap->cpuHandleForIndex(ATLAS_RTV_HEAP_OFFSET); + cmdList->OMSetRenderTargets(1, &rtvHandle, FALSE, nullptr); + + float clearZero[4]{}; + cmdList->ClearRenderTargetView(rtvHandle, clearZero, 0, nullptr); + + CD3DX12_VIEWPORT viewport(0.0f, + 0.0f, + static_cast(desc.atlasContentWidth), + static_cast(desc.atlasContentHeight)); + + cmdList->RSSetViewports(1, &viewport); + cmdList->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + auto IBV = m_pathPatchIndexBuffer->indexBufferView(); + cmdList->IASetIndexBuffer(&IBV); + if (desc.atlasFillBatchCount != 0) + { + m_pipelineManager.setAtlasFillPipeline(cmdList); + + for (size_t i = 0; i < desc.atlasFillBatchCount; ++i) + { + const gpu::AtlasDrawBatch& fillBatch = desc.atlasFillBatches[i]; + CD3DX12_RECT scissorRect(fillBatch.scissor.left, + fillBatch.scissor.top, + fillBatch.scissor.right, + fillBatch.scissor.bottom); + cmdList->RSSetScissorRects(1, &scissorRect); + cmdList->SetGraphicsRoot32BitConstant( + VERTEX_DRAW_UNIFORM_SIG_INDEX, + fillBatch.basePatch, + 0); + cmdList->DrawIndexedInstanced( + kMidpointFanCenterAAPatchIndexCount, + fillBatch.patchCount, + kMidpointFanCenterAAPatchBaseIndex, + 0, + fillBatch.basePatch); + } + } + + if (desc.atlasStrokeBatchCount != 0) + { + m_pipelineManager.setAtlasStrokePipeline(cmdList); + + for (size_t i = 0; i < desc.atlasStrokeBatchCount; ++i) + { + const gpu::AtlasDrawBatch& strokeBatch = + desc.atlasStrokeBatches[i]; + CD3DX12_RECT scissorRect(strokeBatch.scissor.left, + strokeBatch.scissor.top, + strokeBatch.scissor.right, + strokeBatch.scissor.bottom); + cmdList->RSSetScissorRects(1, &scissorRect); + cmdList->SetGraphicsRoot32BitConstant( + VERTEX_DRAW_UNIFORM_SIG_INDEX, + strokeBatch.basePatch, + 0); + cmdList->DrawIndexedInstanced( + gpu::kMidpointFanPatchBorderIndexCount, + strokeBatch.patchCount, + gpu::kMidpointFanPatchBaseIndex, + 0, + strokeBatch.basePatch); + } + } + m_resourceManager->transition(cmdList, + m_atlasTexture.get(), + D3D12_RESOURCE_STATE_GENERIC_READ); + + cmdList->OMSetRenderTargets(0, nullptr, FALSE, nullptr); + } + + CD3DX12_VIEWPORT viewport(0.0f, + 0.0f, + static_cast(width), + static_cast(height)); + CD3DX12_RECT scissorRect(desc.renderTargetUpdateBounds.left, + desc.renderTargetUpdateBounds.top, + desc.renderTargetUpdateBounds.right, + desc.renderTargetUpdateBounds.bottom); + cmdList->RSSetViewports(1, &viewport); + cmdList->RSSetScissorRects(1, &scissorRect); + + // Setup and clear the PLS textures. + + if (desc.atomicFixedFunctionColorOutput) + { + m_resourceManager->transition(cmdList, + targetTexture, + D3D12_RESOURCE_STATE_RENDER_TARGET); + + auto rtvHandle = m_rtvHeap->cpuHandleForIndex(TARGET_RTV_HEAP_OFFSET); + cmdList->OMSetRenderTargets(1, &rtvHandle, FALSE, nullptr); + + if (desc.colorLoadAction == gpu::LoadAction::clear) + { + float clearColor4f[4]; + UnpackColorToRGBA32FPremul(desc.colorClearValue, clearColor4f); + cmdList->ClearRenderTargetView(rtvHandle, clearColor4f, 0, nullptr); + } + } + else // !desc.atomicFixedFunctionColorOutput + { + if (renderTarget->targetTextureSupportsUAV()) + { + m_resourceManager->transition( + cmdList, + targetTexture, + D3D12_RESOURCE_STATE_UNORDERED_ACCESS); + } + + if (desc.colorLoadAction == gpu::LoadAction::clear) + { + auto tex = renderTarget->targetTextureSupportsUAV() + ? renderTarget->targetTexture()->resource() + : renderTarget->offscreenTexture()->resource(); + + if (m_capabilities.supportsTypedUAVLoadStore) + { + float clearColor4f[4]; + UnpackColorToRGBA32FPremul(desc.colorClearValue, clearColor4f); + + auto gpuHandle = m_srvUavCbvHeap->gpuHandleForIndex( + ATOMIC_COLOR_HEAP_OFFSET); + auto cpuHandle = m_cpuSrvUavCbvHeap->cpuHandleForIndex( + ATOMIC_COLOR_HEAP_OFFSET); + m_resourceManager->clearUAV(cmdList, + tex, + gpuHandle, + cpuHandle, + clearColor4f, + desc.interlockMode == + InterlockMode::atomics); + } + else + { + UINT clearColorui[4] = { + gpu::SwizzleRiveColorToRGBAPremul(desc.colorClearValue)}; + + auto gpuHandle = m_srvUavCbvHeap->gpuHandleForIndex( + ATOMIC_COLOR_HEAP_OFFSET); + auto cpuHandle = m_cpuSrvUavCbvHeap->cpuHandleForIndex( + ATOMIC_COLOR_HEAP_OFFSET); + + m_resourceManager->clearUAV(cmdList, + tex, + gpuHandle, + cpuHandle, + clearColorui, + desc.interlockMode == + InterlockMode::atomics); + } + } + if (desc.colorLoadAction == gpu::LoadAction::preserveRenderTarget && + !renderTarget->targetTextureSupportsUAV()) + { + auto offscreenTex = renderTarget->offscreenTexture(); + blitSubRect(cmdList, + offscreenTex, + renderTarget->targetTexture(), + desc.renderTargetUpdateBounds); + + m_resourceManager->transition( + cmdList, + offscreenTex, + D3D12_RESOURCE_STATE_UNORDERED_ACCESS); + } + } + + bool renderPassHasCoalescedResolveAndTransfer = + desc.interlockMode == gpu::InterlockMode::atomics && + !desc.atomicFixedFunctionColorOutput && + !renderTarget->targetTextureSupportsUAV(); + + if (desc.combinedShaderFeatures & gpu::ShaderFeatures::ENABLE_CLIPPING) + { + constexpr static UINT kZero[4]{}; + auto gpuHandle = + m_srvUavCbvHeap->gpuHandleForIndex(ATOMIC_CLIP_HEAP_OFFSET); + auto cpuHandle = + m_cpuSrvUavCbvHeap->cpuHandleForIndex(ATOMIC_CLIP_HEAP_OFFSET); + m_resourceManager->clearUAV(cmdList, + renderTarget->clip()->resource(), + gpuHandle, + cpuHandle, + kZero, + desc.interlockMode == + InterlockMode::atomics); + } + // always clear coverage + { + UINT coverageClear[4]{desc.coverageClearValue}; + auto gpuHandle = + m_srvUavCbvHeap->gpuHandleForIndex(ATOMIC_COVERAGE_HEAP_OFFSET); + auto cpuHandle = + m_cpuSrvUavCbvHeap->cpuHandleForIndex(ATOMIC_COVERAGE_HEAP_OFFSET); + + m_resourceManager->clearUAV(cmdList, + renderTarget->coverage()->resource(), + gpuHandle, + cpuHandle, + coverageClear, + desc.interlockMode == + InterlockMode::atomics); + } + + if (renderPassHasCoalescedResolveAndTransfer) + { + m_resourceManager->transition(cmdList, + targetTexture, + D3D12_RESOURCE_STATE_RENDER_TARGET); + + auto rtvHandle = m_rtvHeap->cpuHandleForIndex(TARGET_RTV_HEAP_OFFSET); + cmdList->OMSetRenderTargets(1, &rtvHandle, FALSE, nullptr); + } + + m_heapDescriptorOffset += imageDescriptorOffset; + + for (const DrawBatch& batch : *desc.drawList) + { + assert(batch.elementCount != 0); + + DrawType drawType = batch.drawType; + auto shaderFeatures = desc.interlockMode == gpu::InterlockMode::atomics + ? desc.combinedShaderFeatures + : batch.shaderFeatures; + auto shaderMiscFlags = batch.shaderMiscFlags; + if (drawType == gpu::DrawType::atomicResolve && + renderPassHasCoalescedResolveAndTransfer) + { + shaderMiscFlags |= + gpu::ShaderMiscFlags::coalescedResolveAndTransfer; + } + if (desc.atomicFixedFunctionColorOutput) + { + shaderMiscFlags |= gpu::ShaderMiscFlags::fixedFunctionColorOutput; + } + if (desc.interlockMode == gpu::InterlockMode::rasterOrdering && + (batch.drawContents & gpu::DrawContents::clockwiseFill)) + { + shaderMiscFlags |= gpu::ShaderMiscFlags::clockwiseFill; + } + + auto pipeline = + m_pipelineManager.getDrawPipelineState(drawType, + shaderFeatures, + desc.interlockMode, + shaderMiscFlags); + cmdList->SetPipelineState(pipeline); + + // all atomic barriers are the same for dx12 + if (batch.barriers & + (BarrierFlags::plsAtomicPreResolve | BarrierFlags::plsAtomic)) + { + assert(desc.interlockMode == gpu::InterlockMode::atomics); + auto target = renderTarget->targetTextureSupportsUAV() + ? renderTarget->targetTexture() + : renderTarget->offscreenTexture(); + + D3D12_RESOURCE_BARRIER barriers[] = { + CD3DX12_RESOURCE_BARRIER::UAV( + renderTarget->coverage()->resource()), + CD3DX12_RESOURCE_BARRIER::UAV(target->resource()), + CD3DX12_RESOURCE_BARRIER::UAV( + renderTarget->clip()->resource())}; + + cmdList->ResourceBarrier( + desc.combinedShaderFeatures & + gpu::ShaderFeatures::ENABLE_CLIPPING + ? 3 + : 2, + barriers); + } + + if (auto imageTextureD3D12 = + static_cast(batch.imageTexture)) + { + auto imageTexture = + imageTextureD3D12->synchronize(copyCmdList, + cmdList, + m_resourceManager.get()); + RNAME_D3D12_OBJECT(imageTexture, m_heapDescriptorOffset); + if (m_heapDescriptorOffset >= MAX_DESCRIPTOR_HEAPS_PER_FLUSH) + { + fprintf(stderr, + "heap descriptor ran out of room ! heapOffset %i " + "maxHeap %i\n", + m_heapDescriptorOffset, + MAX_DESCRIPTOR_HEAPS_PER_FLUSH); + assert(false); + // break out of loop and let transitions happen + break; + } + m_srvUavCbvHeap->markSrvToIndex(m_device.Get(), + imageTexture, + m_heapDescriptorOffset); + cmdList->SetGraphicsRootDescriptorTable( + IMAGE_SIG_INDEX, + m_srvUavCbvHeap->gpuHandleForIndex(m_heapDescriptorOffset)); + ++m_heapDescriptorOffset; + + // we want to update this as little as possible, so only set it if + // it's changed + if (m_lastDynamicSampler != batch.imageSampler) + { + if (++m_samplerHeapDescriptorOffset >= + MAX_DESCRIPTOR_SAMPLER_HEAPS_PER_FLUSH) + { + auto oldHeap = m_samplerHeap; + m_samplerHeap = m_samplerHeapPool.acquire(); + m_samplerHeapDescriptorOffset = IMAGE_SAMPLER_HEAP_OFFSET; + // copy the imutable sampelrs to the new heap + m_device->CopyDescriptorsSimple( + IMAGE_SAMPLER_HEAP_OFFSET, + m_samplerHeap->cpuHandleForUpload(0), + oldHeap->cpuHandleForUpload(0), + D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER); + + ID3D12DescriptorHeap* ppHeaps[] = {m_srvUavCbvHeap->heap(), + m_samplerHeap->heap()}; + + cmdList->SetDescriptorHeaps(_countof(ppHeaps), ppHeaps); + } + + m_samplerHeap->markSamplerToIndex( + m_device.Get(), + m_imageSamplers[batch.imageSampler.asKey()], + m_samplerHeapDescriptorOffset); + + cmdList->SetGraphicsRootDescriptorTable( + DYNAMIC_SAMPLER_SIG_INDEX, + m_samplerHeap->gpuHandleForIndex( + m_samplerHeapDescriptorOffset)); + + m_lastDynamicSampler = batch.imageSampler; + } + } + + switch (drawType) + { + case DrawType::midpointFanPatches: + case DrawType::midpointFanCenterAAPatches: + case DrawType::outerCurvePatches: + { + cmdList->IASetPrimitiveTopology( + D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + auto IBV = m_pathPatchIndexBuffer->indexBufferView(); + cmdList->IASetIndexBuffer(&IBV); + cmdList->SetGraphicsRoot32BitConstant( + VERTEX_DRAW_UNIFORM_SIG_INDEX, + batch.baseElement, + 0); + cmdList->DrawIndexedInstanced(PatchIndexCount(drawType), + batch.elementCount, + PatchBaseIndex(drawType), + 0, + batch.baseElement); + break; + } + case DrawType::interiorTriangulation: + case DrawType::atlasBlit: + { + cmdList->IASetPrimitiveTopology( + D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + cmdList->DrawInstanced(batch.elementCount, + 1, + batch.baseElement, + 0); + break; + } + case DrawType::imageRect: + { + cmdList->IASetPrimitiveTopology( + D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + auto IBV = m_imageRectIndexBuffer->indexBufferView(); + cmdList->IASetIndexBuffer(&IBV); + + cmdList->SetGraphicsRootConstantBufferView( + IMAGE_UNIFORM_BUFFFER_SIG_INDEX, + m_imageDrawUniformBuffer->resource() + ->getGPUVirtualAddress() + + batch.imageDrawDataOffset); + + cmdList->DrawIndexedInstanced(std::size(gpu::kImageRectIndices), + 1, + 0, + 0, + 0); + break; + } + case DrawType::imageMesh: + { + LITE_RTTI_CAST_OR_BREAK(vertexBuffer, + RenderBufferD3D12Impl*, + batch.vertexBuffer); + LITE_RTTI_CAST_OR_BREAK(uvBuffer, + RenderBufferD3D12Impl*, + batch.uvBuffer); + LITE_RTTI_CAST_OR_BREAK(indexBuffer, + RenderBufferD3D12Impl*, + batch.indexBuffer); + + auto vBuffer = vertexBuffer->sync(copyCmdList); + auto uBuffer = uvBuffer->sync(copyCmdList); + auto iBuffer = indexBuffer->sync(copyCmdList); + + D3D12_VERTEX_BUFFER_VIEW imageMeshBuffers[] = { + vBuffer->vertexBufferView(0, sizeof(Vec2D)), + uBuffer->vertexBufferView(0, sizeof(Vec2D))}; + cmdList->IASetVertexBuffers(IMAGE_MESH_VERTEX_DATA_SLOT, + 2, + imageMeshBuffers); + static_assert(IMAGE_MESH_UV_DATA_SLOT == + IMAGE_MESH_VERTEX_DATA_SLOT + 1); + cmdList->IASetPrimitiveTopology( + D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + auto IBV = iBuffer->indexBufferView(); + cmdList->IASetIndexBuffer(&IBV); + + cmdList->SetGraphicsRootConstantBufferView( + IMAGE_UNIFORM_BUFFFER_SIG_INDEX, + m_imageDrawUniformBuffer->resource() + ->getGPUVirtualAddress() + + batch.imageDrawDataOffset); + + cmdList->DrawIndexedInstanced(batch.elementCount, + 1, + batch.baseElement, + 0, + 0); + break; + } + case DrawType::atomicResolve: + assert(desc.interlockMode == gpu::InterlockMode::atomics); + cmdList->IASetPrimitiveTopology( + D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + cmdList->DrawInstanced(4, 1, 0, 0); + break; + case DrawType::atomicInitialize: + case DrawType::msaaStrokes: + case DrawType::msaaMidpointFanBorrowedCoverage: + case DrawType::msaaMidpointFans: + case DrawType::msaaMidpointFanStencilReset: + case DrawType::msaaMidpointFanPathsStencil: + case DrawType::msaaMidpointFanPathsCover: + case DrawType::msaaOuterCubics: + case DrawType::msaaStencilClipReset: + RIVE_UNREACHABLE(); + } + } + + if (desc.interlockMode == gpu::InterlockMode::rasterOrdering && + !renderTarget->targetTextureSupportsUAV()) + { + // We rendered to an offscreen UAV and did not resolve to the + // renderTarget. Copy back to the main target. + assert(!desc.atomicFixedFunctionColorOutput); + assert(!renderPassHasCoalescedResolveAndTransfer); + blitSubRect(cmdList, + renderTarget->targetTexture(), + renderTarget->offscreenTexture(), + desc.renderTargetUpdateBounds); + + m_resourceManager->transition(cmdList, + targetTexture, + D3D12_RESOURCE_STATE_COMMON); + + // we create the offscreen texture in UAV state and always assume it is + // in it. so put it back + m_resourceManager->transition(cmdList, + renderTarget->offscreenTexture(), + D3D12_RESOURCE_STATE_UNORDERED_ACCESS); + } + + if (desc.atomicFixedFunctionColorOutput || + renderPassHasCoalescedResolveAndTransfer || + (renderTarget->targetTextureSupportsUAV() && + !desc.atomicFixedFunctionColorOutput)) + { + m_resourceManager->transition(cmdList, + targetTexture, + D3D12_RESOURCE_STATE_COMMON); + } +} + +void RenderContextD3D12Impl::postFlush(const RenderContext::FlushResources&) +{ + // Recycle buffers. + m_flushUniformBufferPool.recycle(std::move(m_flushUniformBuffer)); + m_imageDrawUniformBufferPool.recycle(std::move(m_imageDrawUniformBuffer)); + m_pathBufferPool.recycle(std::move(m_pathBuffer)); + m_paintBufferPool.recycle(std::move(m_paintBuffer)); + m_paintAuxBufferPool.recycle(std::move(m_paintAuxBuffer)); + m_contourBufferPool.recycle(std::move(m_contourBuffer)); + m_gradSpanBufferPool.recycle(std::move(m_gradSpanBuffer)); + m_tessSpanBufferPool.recycle(std::move(m_tessSpanBuffer)); + m_triangleBufferPool.recycle(std::move(m_triangleBuffer)); + + m_srvUavCbvHeapPool.recycle(std::move(m_srvUavCbvHeap)); + m_cpuSrvUavCbvHeapPool.recycle(std::move(m_cpuSrvUavCbvHeap)); + m_samplerHeapPool.recycle(std::move(m_samplerHeap)); +} +}; // namespace rive::gpu \ No newline at end of file diff --git a/third_party/rive_renderer/source/draw.cpp b/third_party/rive_renderer/source/draw.cpp new file mode 100644 index 0000000..66aacb9 --- /dev/null +++ b/third_party/rive_renderer/source/draw.cpp @@ -0,0 +1,2552 @@ +/* + * Copyright 2023 Rive + */ + +#include "rive/renderer/draw.hpp" + +#include "gr_inner_fan_triangulator.hpp" +#include "rive_render_path.hpp" +#include "rive_render_paint.hpp" +#include "rive/math/bezier_utils.hpp" +#include "rive/math/wangs_formula.hpp" +#include "rive/renderer/texture.hpp" +#include "gradient.hpp" +#include "shaders/constants.glsl" + +namespace rive::gpu +{ +namespace +{ +// The final segment in an outerCurve patch is a bowtie join. +constexpr static size_t kJoinSegmentCount = 1; +constexpr static size_t kPatchSegmentCountExcludingJoin = + kOuterCurvePatchSegmentSpan - kJoinSegmentCount; + +// Maximum # of outerCurve patches a curve on the path can be subdivided into. +constexpr static size_t kMaxCurveSubdivisions = + (kMaxParametricSegments + kPatchSegmentCountExcludingJoin - 1) / + kPatchSegmentCountExcludingJoin; + +static uint32_t find_outer_cubic_subdivision_count( + const Vec2D pts[], + const wangs_formula::VectorXform& vectorXform) +{ + float numSubdivisions = + ceilf(wangs_formula::cubic(pts, kParametricPrecision, vectorXform) * + (1.f / kPatchSegmentCountExcludingJoin)); + return static_cast( + math::clamp(numSubdivisions, 1, kMaxCurveSubdivisions)); +} + +constexpr static int NUM_SEGMENTS_IN_MITER_OR_BEVEL_JOIN = 5; +constexpr static int STROKE_OR_FEATHER_STYLE_FLAG = 8; +constexpr static int ROUND_JOIN_STYLE_FLAG = STROKE_OR_FEATHER_STYLE_FLAG << 1; +RIVE_ALWAYS_INLINE constexpr int style_flags(bool isStrokeOrFeather, + bool roundJoinStroked) +{ + int styleFlags = (isStrokeOrFeather << 3) | (roundJoinStroked << 4); + assert(bool(styleFlags & STROKE_OR_FEATHER_STYLE_FLAG) == + isStrokeOrFeather); + assert(bool(styleFlags & ROUND_JOIN_STYLE_FLAG) == roundJoinStroked); + return styleFlags; +} + +// Switching on a StyledVerb reduces "if (stroked)" branching and makes the code +// cleaner. +enum class StyledVerb +{ + filledMove = static_cast(PathVerb::move), + strokedMove = + STROKE_OR_FEATHER_STYLE_FLAG | static_cast(PathVerb::move), + roundJoinStrokedMove = STROKE_OR_FEATHER_STYLE_FLAG | + ROUND_JOIN_STYLE_FLAG | + static_cast(PathVerb::move), + + filledLine = static_cast(PathVerb::line), + strokedLine = + STROKE_OR_FEATHER_STYLE_FLAG | static_cast(PathVerb::line), + roundJoinStrokedLine = STROKE_OR_FEATHER_STYLE_FLAG | + ROUND_JOIN_STYLE_FLAG | + static_cast(PathVerb::line), + + filledQuad = static_cast(PathVerb::quad), + strokedQuad = + STROKE_OR_FEATHER_STYLE_FLAG | static_cast(PathVerb::quad), + roundJoinStrokedQuad = STROKE_OR_FEATHER_STYLE_FLAG | + ROUND_JOIN_STYLE_FLAG | + static_cast(PathVerb::quad), + + filledCubic = static_cast(PathVerb::cubic), + strokedCubic = + STROKE_OR_FEATHER_STYLE_FLAG | static_cast(PathVerb::cubic), + roundJoinStrokedCubic = STROKE_OR_FEATHER_STYLE_FLAG | + ROUND_JOIN_STYLE_FLAG | + static_cast(PathVerb::cubic), + + filledClose = static_cast(PathVerb::close), + strokedClose = + STROKE_OR_FEATHER_STYLE_FLAG | static_cast(PathVerb::close), + roundJoinStrokedClose = STROKE_OR_FEATHER_STYLE_FLAG | + ROUND_JOIN_STYLE_FLAG | + static_cast(PathVerb::close), +}; +RIVE_ALWAYS_INLINE constexpr StyledVerb styled_verb(PathVerb verb, + int styleFlags) +{ + return static_cast(styleFlags | static_cast(verb)); +} + +// When chopping strokes, switching on a "chop_key" reduces "if (areCusps)" +// branching and makes the code cleaner. +RIVE_ALWAYS_INLINE constexpr uint8_t chop_key(bool areCusps, uint8_t numChops) +{ + return (numChops << 1) | static_cast(areCusps); +} +RIVE_ALWAYS_INLINE constexpr uint8_t cusp_chop_key(uint8_t n) +{ + return chop_key(true, n); +} +RIVE_ALWAYS_INLINE constexpr uint8_t simple_chop_key(uint8_t n) +{ + return chop_key(false, n); +} + +// Produces a cubic equivalent to the given line, for which Wang's formula also +// returns 1. +RIVE_ALWAYS_INLINE std::array convert_line_to_cubic( + const Vec2D line[2]) +{ + float4 endPts = simd::load4f(line); + float4 controlPts = simd::mix(endPts, endPts.zwxy, float4(1 / 3.f)); + std::array cubic; + cubic[0] = line[0]; + simd::store(&cubic[1], controlPts); + cubic[3] = line[1]; + return cubic; +} +RIVE_ALWAYS_INLINE std::array convert_line_to_cubic(Vec2D p0, + Vec2D p1) +{ + Vec2D line[2] = {p0, p1}; + return convert_line_to_cubic(line); +} + +// Chops a cubic into 2 * n + 1 segments, surrounding each cusp. The resulting +// cubics will be visually equivalent to the original when stroked, but the cusp +// won't have artifacts when rendered using the parametric/polar sorting +// algorithm. +// +// The size of dst[] must be 6 * n + 4 Vec2Ds. +static void chop_cubic_around_cusps(const Vec2D p[4], + Vec2D dst[/*6 * n + 4*/], + const float cuspT[], + int n, + float matrixMaxScale) +{ + float t[4]; + assert(n * 2 <= std::size(t)); + // Generate chop points straddling each cusp with padding. This creates + // buffer space around the cusp that protects against fp32 precision issues. + for (int i = 0; i < n; ++i) + { + // If the cusps are extremely close together, don't allow the straddle + // points to cross. + float minT = i == 0 ? 0.f : (cuspT[i - 1] + cuspT[i]) * .5f; + float maxT = i + 1 == n ? 1.f : (cuspT[i + 1] + cuspT[i]) * .5f; + t[i * 2 + 0] = fmaxf(cuspT[i] - math::EPSILON, minT); + t[i * 2 + 1] = fminf(cuspT[i] + math::EPSILON, maxT); + } + math::chop_cubic_at(p, dst, t, n * 2); + for (int i = 0; i < n; ++i) + { + // Find the three chops at this cusp. + Vec2D* chops = dst + i * 6; + // Correct the chops to fall on the actual cusp point. + Vec2D cusp = math::eval_cubic_at(p, cuspT[i]); + chops[3] = chops[6] = cusp; + // The only purpose of the middle cubic is to capture the cusp's + // 180-degree rotation. Implement it as a sub-pixel 180-degree pivot. + Vec2D pivot = (chops[2] + chops[7]) * .5f; + pivot = (cusp - pivot).normalized() / + (matrixMaxScale * kPolarPrecision * 2) + + cusp; + chops[4] = chops[5] = pivot; + } +} + +// Finds the starting tangent in a contour composed of the points [pts, end). If +// all points are equal, generates a tangent pointing horizontally to the right. +static Vec2D find_starting_tangent(const Vec2D pts[], const Vec2D* end) +{ + assert(end > pts); + const Vec2D p0 = pts[0]; + while (++pts < end) + { + Vec2D p = *pts; + if (p != p0) + { + return p - p0; + } + } + return {1, 0}; +} + +// Finds the ending tangent in a contour composed of the points [pts, end). If +// all points are equal, generates a tangent pointing horizontally to the left. +static Vec2D find_ending_tangent(const Vec2D pts[], const Vec2D* end) +{ + assert(end > pts); + const Vec2D endpoint = end[-1]; + while (--end > pts) + { + Vec2D p = end[-1]; + if (p != endpoint) + { + return endpoint - p; + } + } + return {-1, 0}; +} + +static Vec2D find_join_tangent_full_impl(const Vec2D* joinPoint, + const Vec2D* end, + bool closed, + const Vec2D* p0) +{ + // Find the first point in the contour not equal to *joinPoint and return + // the difference. RawPath should have discarded empty verbs, so this should + // be a fast operation. + for (const Vec2D* p = joinPoint + 1; p != end; ++p) + { + if (*p != *joinPoint) + { + return *p - *joinPoint; + } + } + if (closed) + { + for (const Vec2D* p = p0; p != joinPoint; ++p) + { + if (*p != *joinPoint) + { + return *p - *joinPoint; + } + } + } + // This should never be reached because RawPath discards empty verbs. + RIVE_UNREACHABLE(); +} + +RIVE_ALWAYS_INLINE Vec2D find_join_tangent(const Vec2D* joinPoint, + const Vec2D* end, + bool closed, + const Vec2D* p0) +{ + // Quick early out for inlining and branch prediction: The next point in the + // contour is almost always the point that determines the join tangent. + const Vec2D* nextPoint = joinPoint + 1; + nextPoint = nextPoint != end ? nextPoint : p0; + Vec2D tangent = *nextPoint - *joinPoint; + return tangent != Vec2D{0, 0} + ? tangent + : find_join_tangent_full_impl(joinPoint, end, closed, p0); +} + +// Should an empty stroke emit round caps, square caps, or none? +// +// Just pick the cap type that makes the most sense for a contour that animates +// from non-empty to empty: +// +// * A non-closed contour with round caps and a CLOSED contour with round +// JOINS both converge to a +// circle when animated to empty. +// => round caps on the empty contour. +// +// * A non-closed contour with square caps converges to a square (albeit with +// potential rotation +// that is lost when the contour becomes empty). +// => square caps on the empty contour. +// +// * A closed contour with miter JOINS converges to... some sort of polygon +// with pointy corners. +// ~=> square caps on the empty contour. +// +// * All other contours converge to nothing. +// => butt caps on the empty contour, which are ignored. +// +static StrokeCap empty_stroke_cap(bool closed, StrokeJoin join, StrokeCap cap) +{ + if (closed) + { + switch (join) + { + case StrokeJoin::round: + return StrokeCap::round; + case StrokeJoin::miter: + return StrokeCap::square; + case StrokeJoin::bevel: + return StrokeCap::butt; + } + } + return cap; +} + +RIVE_ALWAYS_INLINE bool is_final_verb_of_contour(const RawPath::Iter& iter, + const RawPath::Iter& end) +{ + return iter.rawVerbsPtr() + 1 == end.rawVerbsPtr(); +} + +RIVE_ALWAYS_INLINE uint32_t join_type_flags(StrokeJoin join) +{ + switch (join) + { + case StrokeJoin::miter: + return MITER_REVERT_JOIN_CONTOUR_FLAG; + case StrokeJoin::round: + return ROUND_JOIN_CONTOUR_FLAG; + case StrokeJoin::bevel: + return BEVEL_JOIN_CONTOUR_FLAG; + } + RIVE_UNREACHABLE(); +} + +inline float find_feather_radius(float paintFeather) +{ + // Blur magnitudes in design tools are customarily the width of two standard + // deviations, or, the length of the range -1stddev .. +1stddev. + return paintFeather * (FEATHER_TEXTURE_STDDEVS / 2); +} + +inline float find_atlas_feather_scale_factor(float featherRadius, + float matrixMaxScale) +{ + // In practice, and with "gaussian -> linear -> gaussian" filtering, we + // never need to render a blur with a radius larger than 16 pixels. After + // this point, we can just scale it up to whatever resolution it needs to be + // displayed at. + return 16.f / fmaxf(featherRadius * matrixMaxScale, 16); +} + +static uint32_t feather_join_segment_count(float polarSegmentsPerRadian) +{ + uint32_t n = + static_cast(ceilf(polarSegmentsPerRadian * math::PI)) + + FEATHER_JOIN_HELPER_SEGMENT_COUNT; + n = std::max(n, FEATHER_JOIN_MIN_SEGMENT_COUNT); + // FEATHER_POLAR_SEGMENT_MIN_ANGLE should limit n long before we reach + // kMaxPolarSegments. + assert(n < gpu::kMaxPolarSegments); + return n; +} +} // namespace + +Draw::Draw(IAABB pixelBounds, + const Mat2D& matrix, + BlendMode blendMode, + rcp imageTexture, + ImageSampler imageSampler, + Type type) : + m_imageTextureRef(imageTexture.release()), + m_imageSampler(imageSampler), + m_pixelBounds(pixelBounds), + m_matrix(matrix), + m_blendMode(blendMode), + m_type(type) + +{ + if (m_blendMode != BlendMode::srcOver) + { + m_drawContents |= gpu::DrawContents::advancedBlend; + } +} + +void Draw::setClipID(uint32_t clipID) +{ + m_clipID = clipID; + + // For clipUpdates, m_clipID refers to the ID we are writing to the stencil + // buffer (NOT the ID we are clipping against). It therefore doesn't affect + // the activeClip flag in that case. + if (!(m_drawContents & gpu::DrawContents::clipUpdate)) + { + if (m_clipID != 0) + { + m_drawContents |= gpu::DrawContents::activeClip; + } + else + { + m_drawContents &= ~gpu::DrawContents::activeClip; + } + } +} + +void Draw::releaseRefs() { safe_unref(m_imageTextureRef); } + +PathDraw::CoverageType PathDraw::SelectCoverageType( + const RiveRenderPaint* paint, + float matrixMaxScale, + const gpu::PlatformFeatures& platformFeatures, + gpu::InterlockMode interlockMode) +{ + if (paint->getFeather() != 0) + { + if (platformFeatures.alwaysFeatherToAtlas || + interlockMode == gpu::InterlockMode::msaa || + // Always switch to the atlas once we can render quarter-resultion. + find_atlas_feather_scale_factor( + find_feather_radius(paint->getFeather()), + matrixMaxScale) <= .5f) + { + return CoverageType::atlas; + } + } + if (interlockMode == gpu::InterlockMode::msaa) + { + return CoverageType::msaa; + } + if (interlockMode == gpu::InterlockMode::clockwiseAtomic) + { + return CoverageType::clockwiseAtomic; + } + return CoverageType::pixelLocalStorage; +} + +DrawUniquePtr PathDraw::Make(RenderContext* context, + const Mat2D& matrix, + rcp path, + FillRule fillRule, + const RiveRenderPaint* paint, + RawPath* scratchPath) +{ + assert(path != nullptr); + assert(paint != nullptr); + + CoverageType coverageType = + SelectCoverageType(paint, + matrix.findMaxScale(), + context->platformFeatures(), + context->frameInterlockMode()); + + // Compute the screen-space bounding box. + AABB mappedBounds; + if (context->frameInterlockMode() == gpu::InterlockMode::rasterOrdering && + coverageType != CoverageType::atlas) + { + // In rasterOrdering mode we can use a looser bounding box since we + // don't do reordering. + mappedBounds = matrix.mapBoundingBox(path->getBounds()); + } + else + { + // Otherwise find a tight bounding box in order to maximize reordering. + mappedBounds = + matrix.mapBoundingBox(path->getRawPath().points().data(), + path->getRawPath().points().count()); + } + assert(mappedBounds.width() >= 0); + assert(mappedBounds.height() >= 0); + if (paint->getIsStroked() || paint->getFeather() != 0) + { + // Outset the path's bounding box to account for stroking & feathering. + float outset = 0; + if (paint->getIsStroked()) + { + outset = paint->getThickness() * .5f; + if (paint->getJoin() == StrokeJoin::miter) + { + // Miter joins may be longer than the stroke radius. + outset *= RIVE_MITER_LIMIT; + } + else if (paint->getCap() == StrokeCap::square) + { + // The diagonal of a square cap is longer than the stroke + // radius. + outset *= math::SQRT2; + } + } + if (paint->getFeather() != 0) + { + outset += find_feather_radius(paint->getFeather()); + } + AABB strokePixelOutset = matrix.mapBoundingBox({0, 0, outset, outset}); + // Add an extra pixel to the stroke outset radius to account for: + // * Butt caps and bevel joins bleed out 1/2 AA width. + // * With Manhattan sytle AA, an AA width can be as large as sqrt(2). + // * The diagonal of that sqrt(2)/2 bleed is 1px in length. + mappedBounds = mappedBounds.outset(strokePixelOutset.width() + 1, + strokePixelOutset.height() + 1); + } + + IAABB pixelBounds = mappedBounds.roundOut(); + bool doTriangulation = false; + const AABB& localBounds = path->getBounds(); + if (context->isOutsideCurrentFrame(pixelBounds)) + { + return DrawUniquePtr(); + } + if (!paint->getIsStroked() && paint->getFeather() == 0) + { + // Use interior triangulation to draw filled paths if they're large + // enough to benefit from it. + // + // FIXME! Implement interior triangulation for feathers. + // + // FIXME! Implement interior triangulation in msaa mode. + if (context->frameInterlockMode() != gpu::InterlockMode::msaa && + path->getRawPath().verbs().count() < 1000 && + gpu::find_transformed_area(localBounds, matrix) > 512.f * 512.f) + { + doTriangulation = true; + } + } + + auto draw = context->make(pixelBounds, + matrix, + std::move(path), + fillRule, + paint, + coverageType, + context->frameDescriptor()); + if (doTriangulation) + { + draw->initForInteriorTriangulation( + context, + scratchPath, + localBounds.width() > localBounds.height() + ? PathDraw::TriangulatorAxis::horizontal + : PathDraw::TriangulatorAxis::vertical); + } + else + { + draw->initForMidpointFan(context, paint); + } + + return DrawUniquePtr(draw); +} + +PathDraw::PathDraw(IAABB pixelBounds, + const Mat2D& matrix, + rcp path, + FillRule initialFillRule, + const RiveRenderPaint* paint, + CoverageType coverageType, + const RenderContext::FrameDescriptor& frameDesc) : + Draw(pixelBounds, + matrix, + paint->getBlendMode(), + ref_rcp(paint->getImageTexture()), + paint->getImageSampler(), + Type::path), + m_pathRef(path.release()), + m_pathFillRule(frameDesc.clockwiseFillOverride ? FillRule::clockwise + : initialFillRule), + m_gradientRef(safe_ref(paint->getGradient())), + m_paintType(paint->getType()), + m_coverageType(coverageType) +{ + assert(m_pathRef != nullptr); + assert(!m_pathRef->getRawPath().empty()); + assert(paint != nullptr); + + if (paint->getIsOpaque()) + { + m_drawContents |= gpu::DrawContents::opaquePaint; + } + + if (paint->getFeather() != 0) + { + m_featherRadius = find_feather_radius(paint->getFeather()); + assert(!std::isnan(m_featherRadius)); // These should get culled in + // RiveRenderer::drawPath(). + assert(m_featherRadius > 0); + } + + if (paint->getIsStroked()) + { + m_strokeRadius = paint->getThickness() * .5f; + // Ensure stroke radius is nonzero. (In PLS, zero radius means the path + // is filled.) + m_strokeRadius = + fmaxf(m_strokeRadius, std::numeric_limits::min()); + assert(!std::isnan(m_strokeRadius)); // These should get culled in + // RiveRenderer::drawPath(). + assert(m_strokeRadius > 0); + } + + // For atlased paths, m_drawContents refers to the rectangle being drawn + // into the main render target, not the step that generates the atlas mask. + if (m_coverageType != CoverageType::atlas) + { + if (isStroke()) + { + m_drawContents |= gpu::DrawContents::stroke; + } + else + { + if (m_featherRadius) + { + m_drawContents |= gpu::DrawContents::featheredFill; + } + if (initialFillRule == FillRule::clockwise || + frameDesc.clockwiseFillOverride) + { + m_drawContents |= gpu::DrawContents::clockwiseFill; + } + else if (initialFillRule == FillRule::nonZero) + { + m_drawContents |= gpu::DrawContents::nonZeroFill; + } + else if (initialFillRule == FillRule::evenOdd) + { + m_drawContents |= gpu::DrawContents::evenOddFill; + } + } + } + + if (paint->getType() == gpu::PaintType::clipUpdate) + { + m_drawContents |= gpu::DrawContents::clipUpdate; + if (paint->getSimpleValue().outerClipID != 0) + { + m_drawContents |= gpu::DrawContents::activeClip; + } + } + + if (isStroke()) + { + // Stroke triangles are always forward. + m_contourDirections = gpu::ContourDirections::forward; + } + else if (initialFillRule == FillRule::clockwise) + { + // Clockwise paths need to be reversed when the matrix is left-handed, + // so that the intended forward triangles remain clockwise. + float det = matrix.xx() * matrix.yy() - matrix.yx() * matrix.xy(); + if (det < 0) + { + m_contourDirections = + m_coverageType == CoverageType::msaa + ? gpu::ContourDirections::reverse + : gpu::ContourDirections::forwardThenReverse; + m_contourFlags |= NEGATE_PATH_FILL_COVERAGE_FLAG; // ignored by msaa + } + else + { + m_contourDirections = + m_coverageType == CoverageType::msaa + ? gpu::ContourDirections::forward + : gpu::ContourDirections::reverseThenForward; + } + } + else if (m_coverageType != CoverageType::msaa) + { + // atomic and rasterOrdering fills need reverse AND forward triangles. + if (frameDesc.clockwiseFillOverride && + !m_pathRef->isClockwiseDominant(matrix)) + { + // For clockwiseFill, this is also our opportunity to logically + // reverse the winding of the path, if it is predominantly + // counterclockwise. + m_contourDirections = gpu::ContourDirections::forwardThenReverse; + m_contourFlags |= NEGATE_PATH_FILL_COVERAGE_FLAG; + } + else + { + m_contourDirections = gpu::ContourDirections::reverseThenForward; + } + } + else + { + if (initialFillRule == FillRule::nonZero || + frameDesc.clockwiseFillOverride) + { + // Emit "nonZero" msaa fills in a direction such that the dominant + // triangle winding area is always clockwise. This maximizes pixel + // throughput since we will draw counterclockwise triangles twice + // and clockwise only once. + m_contourDirections = m_pathRef->isClockwiseDominant(matrix) + ? gpu::ContourDirections::forward + : gpu::ContourDirections::reverse; + } + else + { + // "evenOdd" msaa fills just get drawn twice, so any direction is + // fine. + m_contourDirections = gpu::ContourDirections::forward; + } + } + + m_simplePaintValue = paint->getSimpleValue(); + + if (m_coverageType == CoverageType::atlas) + { + // Reserve two triangles for our on-screen rectangle that reads coverage + // from the atlas. + m_resourceCounts.maxTriangleVertexCount = 6; + } + + RIVE_DEBUG_CODE(m_pathRef->lockRawPathMutations();) + RIVE_DEBUG_CODE(m_rawPathMutationID = m_pathRef->getRawPathMutationID();) + assert(isStroke() == (strokeRadius() > 0)); + assert(isFeatheredFill() == (!isStroke() && featherRadius() > 0)); + assert(!isFeatheredFill() || featherRadius() > 0); +} + +void PathDraw::releaseRefs() +{ + Draw::releaseRefs(); + RIVE_DEBUG_CODE(m_pathRef->unlockRawPathMutations();) + m_pathRef->unref(); + safe_unref(m_gradientRef); +} + +void PathDraw::initForMidpointFan(RenderContext* context, + const RiveRenderPaint* paint) +{ + // Only call init() once. + assert((m_resourceCounts.midpointFanTessVertexCount | + m_resourceCounts.outerCubicTessVertexCount) == 0); + + if (isStrokeOrFeather()) + { + m_strokeMatrixMaxScale = m_matrix.findMaxScale(); + + float r_ = 0; + if (m_featherRadius != 0) + { + r_ = m_featherRadius * m_strokeMatrixMaxScale; + + // Inverse of 1/calc_polar_segments_per_radian at + // FEATHER_MIN_POLAR_SEGMENT_ANGLE. + // + // i.e., 1 / calc_polar_segments_per_radian( + // FEATHER_MIN_POLAR_SEGMENT_ANGLE) == + // FEATHER_MAX_SCREEN_SPACE_RADIUS + // + constexpr static float FEATHER_MAX_SCREEN_SPACE_RADIUS = + 1 / (kPolarPrecision * + (1 - COS_FEATHER_POLAR_SEGMENT_MIN_ANGLE_OVER_2)); + assert(math::nearly_equal( + 1 / math::calc_polar_segments_per_radian( + FEATHER_MAX_SCREEN_SPACE_RADIUS), + gpu::FEATHER_POLAR_SEGMENT_MIN_ANGLE)); + + // r_ is used to calculate how many polar segments are needed. Limit + // r_ for large feathers. (See FEATHER_POLAR_SEGMENT_MIN_ANGLE.) + r_ = std::min(r_, FEATHER_MAX_SCREEN_SPACE_RADIUS); + } + if (isStroke()) + { + r_ += m_strokeRadius * m_strokeMatrixMaxScale; + } + m_polarSegmentsPerRadian = + math::calc_polar_segments_per_radian(r_); + + m_strokeJoin = paint->getJoin(); + m_strokeCap = paint->getCap(); + } + + // Count up how much temporary storage this function will need to reserve in + // CPU buffers. + const RawPath& rawPath = m_pathRef->getRawPath(); + size_t contourCount = rawPath.countMoveTos(); + assert(contourCount != 0); + + m_contours = reinterpret_cast( + context->perFrameAllocator().alloc(sizeof(ContourInfo) * contourCount)); + + size_t maxStrokedCurvesBeforeChops = 0; + size_t maxCurves = 0; + size_t maxRotations = 0; + // Reserve enough space to record all the info we might need for this path. + assert(rawPath.verbs()[0] == PathVerb::move); + // Every path has at least 1 (non-cubic) move. + size_t pathMaxLinesOrCurvesBeforeChops = rawPath.verbs().size() - 1; + // Stroked cubics can be chopped into a maximum of 5 segments. + size_t pathMaxLinesOrCurvesAfterChops = + isStrokeOrFeather() ? pathMaxLinesOrCurvesBeforeChops * 5 + : pathMaxLinesOrCurvesBeforeChops; + maxCurves += pathMaxLinesOrCurvesAfterChops; + if (isStrokeOrFeather()) + { + maxStrokedCurvesBeforeChops += pathMaxLinesOrCurvesBeforeChops; + maxRotations += pathMaxLinesOrCurvesAfterChops; + if (m_strokeJoin == StrokeJoin::round) + { + // If the stroke has round joins, we also record the rotations + // between (pre-chopped) joins in order to calculate how many + // vertices are in each round join. + maxRotations += pathMaxLinesOrCurvesBeforeChops; + } + } + + // Each stroked curve will record the number of chops it requires (either 0, + // 1, or 2). + size_t maxChops = maxStrokedCurvesBeforeChops; + // We only chop into this queue if a cubic has one chop. More chops in a + // single cubic are rare and require a lot of memory, so if a cubic needs + // more chops we just re-chop the second time around. The maximum size this + // queue would need is therefore enough to chop each cubic once, or 5 + // internal points per chop. + size_t maxChopVertices = maxStrokedCurvesBeforeChops * 5; + // +3 for each contour because we align each contour's curves and rotations + // on multiples of 4. + size_t maxPaddedRotations = + isStrokeOrFeather() ? maxRotations + contourCount * 3 : 0; + size_t maxPaddedCurves = maxCurves + contourCount * 3; + + // Reserve intermediate space for the polar segment counts of each curve and + // round join. + if (isStrokeOrFeather()) + { + m_numChops.reset(context->numChopsAllocator(), maxChops); + m_chopVertices.reset(context->chopVerticesAllocator(), maxChopVertices); + m_tangentPairs = + context->tangentPairsAllocator().alloc(maxPaddedRotations); + m_polarSegmentCounts = + context->polarSegmentCountsAllocator().alloc(maxPaddedRotations); + } + m_parametricSegmentCounts = + context->parametricSegmentCountsAllocator().alloc(maxPaddedCurves); + + float parametricPrecision = gpu::kParametricPrecision; + if (m_featherRadius > 1) + { + // Once the blur radius is above ~50 pixels, we don't have to tessellate + // within 1/4px of the edge anymore. + // At this point, tessellate within strokeRadius/200 pixels of the edge. + // (parametricPrecision == 1/tolerance.) + parametricPrecision = + std::min(parametricPrecision * 100.f / + (m_featherRadius * m_strokeMatrixMaxScale), + parametricPrecision); + } + + size_t lineCount = 0; + size_t unpaddedCurveCount = 0; + size_t unpaddedRotationCount = 0; + size_t emptyStrokeCountForCaps = 0; + + // Iteration pass 1: Collect information on contour and curves counts for + // every path in the batch, and begin counting tessellated vertices. + size_t contourIdx = 0; + size_t curveIdx = 0; + // We measure rotations on both curves and round joins. + size_t rotationIdx = 0; + bool roundJoinStroked = isStroke() && m_strokeJoin == StrokeJoin::round; + wangs_formula::VectorXform vectorXform(m_matrix); + RawPath::Iter startOfContour = rawPath.begin(); + RawPath::Iter end = rawPath.end(); + // Original number of lines and curves, before chopping. + int preChopVerbCount = 0; + Vec2D endpointsSum{}; + bool closed = !isStroke(); + Vec2D lastTangent = {0, 1}; + Vec2D firstTangent = {0, 1}; + size_t roundJoinCount = 0; + size_t contourFirstCurveIdx = curveIdx; + assert(contourFirstCurveIdx % 4 == 0); + size_t contourFirstRotationIdx = rotationIdx; + assert(contourFirstRotationIdx % 4 == 0); + auto finishAndAppendContour = [&](RawPath::Iter iter) { + if (closed) + { + Vec2D finalPtInContour = iter.rawPtsPtr()[-1]; + // Bit-cast to uint64_t because we don't want the special equality + // rules for NaN. If we're empty or otherwise return back to p0, we + // want to detect this, regardless of whether there are NaN values. + if (math::bit_cast(startOfContour.movePt()) != + math::bit_cast(finalPtInContour)) + { + assert(preChopVerbCount > 0); + if (roundJoinStroked) + { + // Round join before implicit closing line. + Vec2D tangent = startOfContour.movePt() - finalPtInContour; + assert(rotationIdx < maxPaddedRotations); + m_tangentPairs[rotationIdx++] = {lastTangent, tangent}; + lastTangent = tangent; + ++roundJoinCount; + } + ++lineCount; // Implicit closing line. + // The first point in the contour hasn't gotten + // counted yet. + ++preChopVerbCount; + endpointsSum += startOfContour.movePt(); + } + if (roundJoinStroked && preChopVerbCount != 0) + { + // Round join back to the beginning of the contour. + assert(rotationIdx < maxPaddedRotations); + m_tangentPairs[rotationIdx++] = {lastTangent, firstTangent}; + ++roundJoinCount; + } + } + size_t strokeJoinCount = preChopVerbCount; + if (!closed) + { + strokeJoinCount = std::max(strokeJoinCount, 1) - 1; + } + assert(contourIdx < contourCount); + m_contours[contourIdx++] = { + iter, + lineCount, + contourFirstCurveIdx, + curveIdx, + contourFirstRotationIdx, + rotationIdx, + isStroke() ? Vec2D() : endpointsSum * (1.f / preChopVerbCount), + closed, + strokeJoinCount, + 0, // strokeCapSegmentCount + 0, // paddingVertexCount + RIVE_DEBUG_CODE(0) // tessVertexCount + }; + unpaddedCurveCount += curveIdx - contourFirstCurveIdx; + contourFirstCurveIdx = curveIdx = + math::round_up_to_multiple_of<4>(curveIdx); + unpaddedRotationCount += rotationIdx - contourFirstRotationIdx; + contourFirstRotationIdx = rotationIdx = + math::round_up_to_multiple_of<4>(rotationIdx); + }; + const int styleFlags = style_flags(isStrokeOrFeather(), roundJoinStroked); + for (RawPath::Iter iter = startOfContour; iter != end; ++iter) + { + switch (styled_verb(iter.verb(), styleFlags)) + { + case StyledVerb::roundJoinStrokedMove: + case StyledVerb::strokedMove: + case StyledVerb::filledMove: + if (iter != startOfContour) + { + finishAndAppendContour(iter); + startOfContour = iter; + } + preChopVerbCount = 0; + endpointsSum = {0, 0}; + closed = !isStroke(); + lastTangent = {0, 1}; + firstTangent = {0, 1}; + roundJoinCount = 0; + break; + case StyledVerb::roundJoinStrokedClose: + case StyledVerb::strokedClose: + case StyledVerb::filledClose: + assert(iter != startOfContour); + closed = true; + break; + case StyledVerb::roundJoinStrokedLine: + { + const Vec2D* p = iter.linePts(); + Vec2D tangent = p[1] - p[0]; + if (preChopVerbCount == 0) + { + firstTangent = tangent; + } + else + { + assert(rotationIdx < maxPaddedRotations); + m_tangentPairs[rotationIdx++] = {lastTangent, tangent}; + ++roundJoinCount; + } + lastTangent = tangent; + [[fallthrough]]; + } + case StyledVerb::strokedLine: + case StyledVerb::filledLine: + { + const Vec2D* p = iter.linePts(); + ++preChopVerbCount; + endpointsSum += p[1]; + ++lineCount; + break; + } + case StyledVerb::roundJoinStrokedQuad: + case StyledVerb::strokedQuad: + case StyledVerb::filledQuad: + RIVE_UNREACHABLE(); + break; + case StyledVerb::roundJoinStrokedCubic: + { + const Vec2D* p = iter.cubicPts(); + Vec2D unchoppedTangents[2]; + math::find_cubic_tangents(p, unchoppedTangents); + if (preChopVerbCount == 0) + { + firstTangent = unchoppedTangents[0]; + } + else + { + assert(rotationIdx < maxPaddedRotations); + m_tangentPairs[rotationIdx++] = {lastTangent, + unchoppedTangents[0]}; + ++roundJoinCount; + } + lastTangent = unchoppedTangents[1]; + [[fallthrough]]; + } + case StyledVerb::strokedCubic: + { + const Vec2D* p = iter.cubicPts(); + ++preChopVerbCount; + endpointsSum += p[3]; + // Chop strokes into sections that do not inflect (i.e, are + // convex), and do not rotate more than 180 degrees. This is + // required by the GPU parametric/polar sorter. + float t[2]; + bool areCusps = false; + uint8_t numChops = + isStroke() + ? math::find_cubic_convex_180_chops(p, t, &areCusps) + : 0; // Feathers already got chopped. + uint8_t chopKey = chop_key(areCusps, numChops); + m_numChops.push_back(chopKey); + Vec2D localChopBuffer[16]; + switch (chopKey) + { + case cusp_chop_key(2): // 2 cusps + case cusp_chop_key(1): // 1 cusp + // We have to chop carefully around stroked cusps in + // order to avoid rendering artifacts. Luckily, cusps + // are extremely rare in real-world content. + m_chopVertices.push_back() = {t[0], t[1]}; + chop_cubic_around_cusps(p, + localChopBuffer, + t, + numChops, + m_strokeMatrixMaxScale); + p = localChopBuffer; + numChops *= 2; + break; + case simple_chop_key(2): // 2 non-cusp chops + m_chopVertices.push_back() = {t[0], t[1]}; + math::chop_cubic_at(p, localChopBuffer, t[0], t[1]); + p = localChopBuffer; + break; + case simple_chop_key(1): // 1 non-cusp chop + { + math::chop_cubic_at(p, localChopBuffer, t[0]); + p = localChopBuffer; + memcpy(m_chopVertices.push_back_n(5), + p + 1, + sizeof(Vec2D) * 5); + break; + } + } + // Calculate segment counts for each chopped section + // independently. + for (const Vec2D* end = p + numChops * 3 + 3; p != end; + p += 3, ++curveIdx, ++rotationIdx) + { + float n4 = wangs_formula::cubic_pow4(p, + parametricPrecision, + vectorXform); + // Record n^4 for now. This will get resolved later. + assert(curveIdx < maxPaddedCurves); + RIVE_INLINE_MEMCPY(m_parametricSegmentCounts + curveIdx, + &n4, + sizeof(uint32_t)); + assert(rotationIdx < maxPaddedRotations); + if (isStroke()) + { + math::find_cubic_tangents( + p, + m_tangentPairs[rotationIdx].data()); + } + else + { + // FIXME: Feathered fills don't have polar segments for + // now, but we're leaving space for them in + // m_tangentPairs because we will convert them to use a + // similar concept of "polar joins" once we move them + // onto the GPU. + m_tangentPairs[rotationIdx] = {Vec2D{0, 1}, + Vec2D{0, 1}}; + } + } + break; + } + case StyledVerb::filledCubic: + { + const Vec2D* p = iter.cubicPts(); + ++preChopVerbCount; + endpointsSum += p[3]; + float n4 = wangs_formula::cubic_pow4(p, + parametricPrecision, + vectorXform); + // Record n^4 for now. This will get resolved later. + assert(curveIdx < maxPaddedCurves); + RIVE_INLINE_MEMCPY(m_parametricSegmentCounts + curveIdx++, + &n4, + sizeof(uint32_t)); + break; + } + } + } + if (startOfContour != end) + { + finishAndAppendContour(end); + } + assert(contourIdx == contourCount); + assert(contourCount > 0); + assert(curveIdx <= maxPaddedCurves); + assert(rotationIdx <= maxPaddedRotations); + // Because we write parametric segment counts in batches of 4. + assert(curveIdx % 4 == 0); + // Because we write polar segment counts in batches of 4. + assert(rotationIdx % 4 == 0); + assert(isStrokeOrFeather() || maxPaddedRotations == 0); + assert(isStrokeOrFeather() || rotationIdx == 0); + + // Return any data we conservatively allocated but did not use. + if (isStrokeOrFeather()) + { + m_numChops.shrinkToFit(context->numChopsAllocator(), maxChops); + m_chopVertices.shrinkToFit(context->chopVerticesAllocator(), + maxChopVertices); + context->tangentPairsAllocator().rewindLastAllocation( + maxPaddedRotations - rotationIdx); + context->polarSegmentCountsAllocator().rewindLastAllocation( + maxPaddedRotations - rotationIdx); + } + context->parametricSegmentCountsAllocator().rewindLastAllocation( + maxPaddedCurves - curveIdx); + + // Iteration pass 2: Finish calculating the numbers of tessellation segments + // in each contour, using SIMD. + size_t contourFirstLineIdx = 0; + size_t tessVertexCount = 0; + for (size_t i = 0; i < contourCount; ++i) + { + ContourInfo* contour = &m_contours[i]; + size_t contourLineCount = contour->endLineIdx - contourFirstLineIdx; + uint32_t contourVertexCount = math::lossless_numeric_cast( + contourLineCount * 2); // Each line tessellates to 2 vertices. + uint4 mergedTessVertexSums4 = 0; + + // Finish calculating and counting parametric segments for each curve. + size_t j; + for (j = contour->firstCurveIdx; j < contour->endCurveIdx; j += 4) + { + // Curves recorded their segment counts raised to the 4th power. Now + // find their roots and convert to integers in batches of 4. + assert(j + 4 <= curveIdx); + float4 n = simd::load4f(m_parametricSegmentCounts + j); + n = simd::ceil(simd::sqrt(simd::sqrt(n))); + n = simd::clamp(n, float4(1), float4(kMaxParametricSegments)); + uint4 n_ = simd::cast(n); + assert(j + 4 <= curveIdx); + simd::store(m_parametricSegmentCounts + j, n_); + mergedTessVertexSums4 += n_; + } + // We counted in batches of 4. Undo the values we counted from beyond + // the end of the path. + while (j-- > contour->endCurveIdx) + { + contourVertexCount -= m_parametricSegmentCounts[j]; + } + + if (isStrokeOrFeather()) + { + // Finish calculating and counting polar segments for each stroked + // curve and round join. + for (j = contour->firstRotationIdx; j < contour->endRotationIdx; + j += 4) + { + // Measure the rotations of curves in batches of 4. + assert(j + 4 <= rotationIdx); + + float4 tx0, ty0, tx1, ty1; + std::tie(tx0, ty0, tx1, ty1) = + simd::load4x4f(&m_tangentPairs[j][0].x); + + float4 numer = tx0 * tx1 + ty0 * ty1; + float4 denom_pow2 = + (tx0 * tx0 + ty0 * ty0) * (tx1 * tx1 + ty1 * ty1); + float4 cosTheta = numer / simd::sqrt(denom_pow2); + cosTheta = simd::clamp(cosTheta, float4(-1), float4(1)); + float4 theta = simd::fast_acos(cosTheta); + // Find polar segment counts from the rotation angles. + float4 n = simd::ceil(theta * m_polarSegmentsPerRadian); + n = simd::clamp(n, float4(1), float4(kMaxPolarSegments)); + uint4 n_ = simd::cast(n); + assert(j + 4 <= rotationIdx); + simd::store(m_polarSegmentCounts + j, n_); + // Polar and parametric segments share the first and final + // vertices. Therefore: + // + // parametricVertexCount = parametricSegmentCount + 1 + // + // polarVertexCount = polarVertexCount + 1 + // + // mergedVertexCount + // = parametricVertexCount + polarVertexCount - 2 + // = parametricSegmentCount + 1 + polarSegmentCount + 1 - 2 + // = parametricSegmentCount + polarSegmentCount + // + mergedTessVertexSums4 += n_; + } + + // We counted in batches of 4. Undo the values we counted from + // beyond the end of the path. + while (j-- > contour->endRotationIdx) + { + contourVertexCount -= m_polarSegmentCounts[j]; + } + + // Count joins. + if (!isStroke()) + { + assert(isFeatheredFill()); + uint32_t numSegmentsInFeatherJoin = + feather_join_segment_count(m_polarSegmentsPerRadian); + contourVertexCount += + contour->strokeJoinCount * (numSegmentsInFeatherJoin - 1); + } + else if (m_strokeJoin == StrokeJoin::round) + { + // Round joins share their beginning and ending vertices with + // the curve on either side. Therefore, the number of vertices + // we need to allocate for a round join is "joinSegmentCount - + // 1". Do all the -1's here. + contourVertexCount -= contour->strokeJoinCount; + } + else + { + // The shader needs 3 segments for each miter and bevel join + // (which translates to two interior vertices, since joins share + // their beginning and ending vertices with the curve on either + // side). + contourVertexCount += contour->strokeJoinCount * + (NUM_SEGMENTS_IN_MITER_OR_BEVEL_JOIN - 1); + } + + // Count stroke caps, if any. + bool empty = contour->endLineIdx == contourFirstLineIdx && + contour->endCurveIdx == contour->firstCurveIdx; + StrokeCap cap; + bool needsCaps = false; + if (!empty) + { + cap = m_strokeCap; + needsCaps = !contour->closed; + } + else if (isStroke()) + { + cap = empty_stroke_cap(contour->closed, + m_strokeJoin, + m_strokeCap); + needsCaps = cap != StrokeCap::butt; // Ignore butt caps when the + // contour is empty. + } + if (needsCaps) + { + // We emulate stroke caps as 180-degree joins. + if (cap == StrokeCap::round) + { + // Round caps rotate 180 degrees. + float strokeCapSegmentCount = + ceilf(m_polarSegmentsPerRadian * math::PI); + // +2 because round caps emulated as joins need to emit + // vertices at T=0 and T=1, unlike normal round joins. + strokeCapSegmentCount += 2; + // Make sure not to exceed kMaxPolarSegments. + strokeCapSegmentCount = + fminf(strokeCapSegmentCount, kMaxPolarSegments); + contour->strokeCapSegmentCount = + static_cast(strokeCapSegmentCount); + } + else + { + contour->strokeCapSegmentCount = + NUM_SEGMENTS_IN_MITER_OR_BEVEL_JOIN; + } + // PLS expects all patches to have >0 tessellation vertices, so + // for the case of an empty patch with a stroke cap, + // contour->strokeCapSegmentCount can't be zero. Also, + // pushContourToRenderContext() uses "strokeCapSegmentCount != + // 0" to tell if it needs stroke caps. + assert(contour->strokeCapSegmentCount >= 2); + // As long as a contour isn't empty, we can tack the end cap + // onto the join section of the final curve in the stroke. + // Otherwise, we need to introduce 0-tessellation-segment curves + // with non-empty joins to carry the caps. + emptyStrokeCountForCaps += empty ? 2 : 1; + contourVertexCount += (contour->strokeCapSegmentCount - 1) * 2; + } + } + else + { + // Fills don't have polar segments: + // + // mergedVertexCount = parametricVertexCount = + // parametricSegmentCount + 1 + // + // Just collect the +1 for each non-stroked curve. + size_t contourCurveCount = + contour->endCurveIdx - contour->firstCurveIdx; + contourVertexCount += contourCurveCount; + } + contourVertexCount += simd::reduce_add(mergedTessVertexSums4); + + // Add padding vertices until the number of tessellation vertices in the + // contour is an exact multiple of kMidpointFanPatchSegmentSpan. This + // ensures that patch boundaries align with contour boundaries. + contour->paddingVertexCount = + math::padding_to_align_up( + contourVertexCount); + contourVertexCount += contour->paddingVertexCount; + assert(contourVertexCount % kMidpointFanPatchSegmentSpan == 0); + RIVE_DEBUG_CODE(contour->tessVertexCount = contourVertexCount;) + + tessVertexCount += contourVertexCount; + contourFirstLineIdx = contour->endLineIdx; + } + + assert(contourFirstLineIdx == lineCount); + RIVE_DEBUG_CODE(m_pendingLineCount = lineCount); + RIVE_DEBUG_CODE(m_pendingCurveCount = unpaddedCurveCount); + RIVE_DEBUG_CODE(m_pendingRotationCount = unpaddedRotationCount); + RIVE_DEBUG_CODE(m_pendingEmptyStrokeCountForCaps = emptyStrokeCountForCaps); + + if (tessVertexCount > 0) + { + m_resourceCounts.pathCount = 1; + m_resourceCounts.contourCount = contourCount; + // maxTessellatedSegmentCount does not get doubled when we emit both + // forward and mirrored contours because the forward and mirrored pair + // both get packed into a single gpu::TessVertexSpan. + m_resourceCounts.maxTessellatedSegmentCount = + lineCount + unpaddedCurveCount + emptyStrokeCountForCaps; + m_resourceCounts.midpointFanTessVertexCount = + gpu::ContourDirectionsAreDoubleSided(m_contourDirections) + ? tessVertexCount * 2 + : tessVertexCount; + } +} + +void PathDraw::initForInteriorTriangulation(RenderContext* context, + RawPath* scratchPath, + TriangulatorAxis triangulatorAxis) +{ + assert(simd::all(m_resourceCounts.toVec() == 0)); // Only call init() once. + assert(!isStrokeOrFeather()); + assert(m_strokeRadius == 0); + + // Every path has at least 1 (non-cubic) move. + size_t originalNumChopsSize = m_pathRef->getRawPath().verbs().size() - 1; + m_numChops.reset(context->numChopsAllocator(), originalNumChopsSize); + iterateInteriorTriangulation( + InteriorTriangulationOp::countDataAndTriangulate, + &context->perFrameAllocator(), + scratchPath, + triangulatorAxis, + nullptr); + m_numChops.shrinkToFit(context->numChopsAllocator(), originalNumChopsSize); +} + +bool PathDraw::allocateResources(RenderContext::LogicalFlush* flush) +{ + const RenderContext::FrameDescriptor& frameDesc = flush->frameDescriptor(); + + // Allocate a gradient if needed. Do this first since it's more expensive to + // fail after setting up an atlas draw than a gradient draw. + if (m_gradientRef != nullptr && + !flush->allocateGradient(m_gradientRef, + &m_simplePaintValue.colorRampLocation)) + { + return false; + } + + // Allocate a coverage buffer range or atlas region if needed. + if (m_coverageType == CoverageType::atlas || + m_coverageType == CoverageType::clockwiseAtomic) + { + constexpr static int PADDING = 2; + + // We don't need any coverage space for areas outside the viewport. + // TODO: Account for active clips as well once we have the info. + IAABB renderTargetBounds = { + 0, + 0, + static_cast(frameDesc.renderTargetWidth), + static_cast(frameDesc.renderTargetHeight), + }; + IAABB visibleBounds = renderTargetBounds.intersect(m_pixelBounds); + + if (m_coverageType == CoverageType::atlas) + { + const float scaleFactor = + find_atlas_feather_scale_factor(m_featherRadius, + m_strokeMatrixMaxScale); + auto w = static_cast( + ceilf(visibleBounds.width() * scaleFactor)); + auto h = static_cast( + ceilf(visibleBounds.height() * scaleFactor)); + uint16_t x, y; + if (!flush->allocateAtlasDraw(this, + w, + h, + PADDING, + &x, + &y, + &m_atlasScissor)) + { + return false; // There wasn't room for our path in the atlas. + } + m_atlasTransform.scaleFactor = scaleFactor; + m_atlasTransform.translateX = x - visibleBounds.left * scaleFactor; + m_atlasTransform.translateY = y - visibleBounds.top * scaleFactor; + m_atlasScissorEnabled = visibleBounds != m_pixelBounds; + } + else + { + // Round up width and height to multiples of 32 for tiling. + uint32_t coverageWidth = math::round_up_to_multiple_of<32>( + visibleBounds.width() + PADDING * 2); + uint32_t coverageHeight = math::round_up_to_multiple_of<32>( + visibleBounds.height() + PADDING * 2); + + // Get our coverage allocation. + size_t offset = flush->allocateCoverageBufferRange(coverageHeight * + coverageWidth); + if (offset == -1) + { + return false; // There wasn't room for our coverage buffer. + } + m_coverageBufferRange.offset = + math::lossless_numeric_cast(offset); + m_coverageBufferRange.pitch = coverageWidth; + m_coverageBufferRange.offsetX = -visibleBounds.left + PADDING; + m_coverageBufferRange.offsetY = -visibleBounds.top + PADDING; + } + } + return true; +} + +void PathDraw::countSubpasses() +{ + m_subpassCount = 1; + m_prepassCount = 0; + + switch (m_coverageType) + { + case CoverageType::pixelLocalStorage: + case CoverageType::atlas: + m_subpassCount = 1; + break; + + case CoverageType::clockwiseAtomic: + if (!isStroke()) + { + m_prepassCount = 1; // Borrowed coverage. + } + m_subpassCount = 1; + break; + + case CoverageType::msaa: + { + if (isStroke()) + { + m_subpassCount = 1; // Strokes can be rendered in a single pass. + } + else if ((m_drawContents & gpu::kNestedClipUpdateMask) == + gpu::kNestedClipUpdateMask) + { + // Nested clip updates only have a stencil pass. (The reset is + // handled by a separate msaaStencilClipReset draw.) + m_subpassCount = 1; + } + else if (m_drawContents & gpu::DrawContents::evenOddFill) + { + m_subpassCount = 2; // MSAA "slow" path: stencil-then-cover. + } + else + { + // MSAA "fast" path: (effectively) single pass rendering. + m_subpassCount = 3; + } + if (isOpaque()) + { + const bool usesClipping = + m_drawContents & (gpu::DrawContents::activeClip | + gpu::DrawContents::clipUpdate); + if (!usesClipping) + { + // Render this path front-to-back instead of back-to-front. + assert(m_prepassCount == 0); + m_prepassCount = m_subpassCount; + m_subpassCount = 0; + } + } + } + } + + if (m_triangulator != nullptr) + { + // Each tessellation draw has a corresponding interior triangles draw. + m_prepassCount *= 2; + m_subpassCount *= 2; + } +} + +void PathDraw::pushToRenderContext(RenderContext::LogicalFlush* flush, + int subpassIndex) +{ + // Make sure the rawPath in our path reference hasn't changed since we began + // holding! + assert(m_rawPathMutationID == m_pathRef->getRawPathMutationID()); + assert(!m_pathRef->getRawPath().empty()); + + assert(m_resourceCounts.outerCubicTessVertexCount == 0 || + m_resourceCounts.midpointFanTessVertexCount == 0); + uint32_t tessVertexCount = math::lossless_numeric_cast( + m_resourceCounts.outerCubicTessVertexCount | + m_resourceCounts.midpointFanTessVertexCount); + if (tessVertexCount == 0) + { + return; + } + + if (m_pathID == 0) + { + // Reserve our pathID and write out a path record. + m_pathID = flush->pushPath(this); + } + + switch (m_coverageType) + { + case CoverageType::pixelLocalStorage: + { + if (subpassIndex == 0) + { + // Tessellation (midpoint fan or outer cubic). + uint32_t tessLocation = + allocateTessellationVertices(flush, tessVertexCount); + pushTessellationData(flush, tessVertexCount, tessLocation); + pushTessellationDraw(flush, tessVertexCount, tessLocation); + } + else + { + // Interior triangles. + assert(m_triangulator != nullptr); + assert(subpassIndex == 1); + RIVE_DEBUG_CODE(m_numInteriorTriangleVerticesPushed +=) + flush->pushInteriorTriangulationDraw(this, + m_pathID, + gpu::WindingFaces::all); + assert(m_numInteriorTriangleVerticesPushed <= + m_triangulator->maxVertexCount()); + } + break; + } + + case CoverageType::clockwiseAtomic: + if (!isStroke()) + { + // The subpass and prepass each emit half the vertices. + assert(m_prepassCount == m_subpassCount); + assert(tessVertexCount % 2 == 0); + tessVertexCount /= 2; + } + switch (subpassIndex) + { + case -1: // Tessellation (borrowed, midpointFan or outerCubic). + assert(!isStroke()); + m_prepassTessLocation = + allocateTessellationVertices(flush, tessVertexCount); + pushTessellationDraw( + flush, + tessVertexCount, + m_prepassTessLocation, + gpu::ShaderMiscFlags::borrowedCoveragePrepass); + break; + + case 0: // Tessellation (midpointFan or outerCubic). + { + uint32_t tessLocation = + allocateTessellationVertices(flush, tessVertexCount); + pushTessellationData(flush, tessVertexCount, tessLocation); + pushTessellationDraw(flush, tessVertexCount, tessLocation); + break; + } + + case -2: // Interior triangles (borrowed). + case 1: // Interior triangles. + assert(!isStroke()); + assert(m_triangulator != nullptr); + RIVE_DEBUG_CODE(m_numInteriorTriangleVerticesPushed +=) + flush->pushInteriorTriangulationDraw( + this, + m_pathID, + subpassIndex < 0 ? gpu::WindingFaces::negative + : gpu::WindingFaces::positive, + subpassIndex < 0 + ? gpu::ShaderMiscFlags::borrowedCoveragePrepass + : gpu::ShaderMiscFlags::none); + assert(m_numInteriorTriangleVerticesPushed <= + m_triangulator->maxVertexCount()); + break; + + default: + RIVE_UNREACHABLE(); + } + break; + + case CoverageType::msaa: + { + assert(m_prepassCount == 0 || m_subpassCount == 0); + int passCount = m_prepassCount | m_subpassCount; + int passIdx = subpassIndex + m_prepassCount; + if (passIdx == 0) + { + m_msaaTessLocation = + allocateTessellationVertices(flush, tessVertexCount); + pushTessellationData(flush, + tessVertexCount, + m_msaaTessLocation); + } + constexpr static gpu::DrawType MSAA_FILL_TYPES[][3] = { + // Nested clip update (passCount == 1; the reset is handled by a + // separate msaaStencilClipReset draw.) + { + gpu::DrawType::msaaMidpointFanPathsStencil, + }, + + // Slow path (passCount == 2): stencil-then-cover + { + gpu::DrawType::msaaMidpointFanPathsStencil, + gpu::DrawType::msaaMidpointFanPathsCover, + }, + + // Fast path (passCount == 3): (mostly) single pass rendering. + { + gpu::DrawType::msaaMidpointFanBorrowedCoverage, + gpu::DrawType::msaaMidpointFans, + gpu::DrawType::msaaMidpointFanStencilReset, + }, + }; + assert(passCount <= 3); + assert(passIdx < passCount); + gpu::DrawType msaaDrawType = + isStroke() ? gpu::DrawType::msaaStrokes + : MSAA_FILL_TYPES[passCount - 1][passIdx]; + flush->pushMidpointFanDraw(this, + msaaDrawType, + tessVertexCount, + m_msaaTessLocation); + break; + } + + case CoverageType::atlas: + // Atlas draws only have one subpass -- the rectangular blit from + // the atlas to the screen. The step that renders coverage to the + // offscreen atlas is handled separately, outside the subpass + // system. + assert(subpassIndex == 0); + flush->pushAtlasBlit(this, m_pathID); + break; + } +} + +void PathDraw::pushTessellationDraw(RenderContext::LogicalFlush* flush, + uint32_t tessVertexCount, + uint32_t tessLocation, + gpu::ShaderMiscFlags shaderMiscFlags) +{ + if (m_triangulator != nullptr) + { + assert(!isStroke()); + flush->pushOuterCubicsDraw(this, + gpu::DrawType::outerCurvePatches, + tessVertexCount, + tessLocation, + shaderMiscFlags); + } + else + { + flush->pushMidpointFanDraw( + this, + isFeatheredFill() ? gpu::DrawType::midpointFanCenterAAPatches + : gpu::DrawType::midpointFanPatches, + tessVertexCount, + tessLocation, + shaderMiscFlags); + } +} + +void PathDraw::pushAtlasTessellation(RenderContext::LogicalFlush* flush, + uint32_t* tessVertexCount, + uint32_t* tessBaseVertex) +{ + assert(m_coverageType == CoverageType::atlas); + assert(m_resourceCounts.outerCubicTessVertexCount == 0 || + m_resourceCounts.midpointFanTessVertexCount == 0); + + *tessVertexCount = math::lossless_numeric_cast( + m_resourceCounts.outerCubicTessVertexCount | + m_resourceCounts.midpointFanTessVertexCount); + + if (*tessVertexCount == 0) + { + assert(m_pathID == 0); + return; + } + + *tessBaseVertex = allocateTessellationVertices(flush, *tessVertexCount); + pushTessellationData(flush, *tessVertexCount, *tessBaseVertex); +} + +void PathDraw::pushTessellationData(RenderContext::LogicalFlush* flush, + uint32_t tessVertexCount, + uint32_t tessLocation) +{ + // Determine where to fill in forward and mirrored tessellations. + uint32_t forwardTessVertexCount, forwardTessLocation, + mirroredTessVertexCount, mirroredTessLocation; + switch (m_contourDirections) + { + case gpu::ContourDirections::forward: + forwardTessVertexCount = tessVertexCount; + forwardTessLocation = tessLocation; + mirroredTessLocation = mirroredTessVertexCount = 0; + break; + case gpu::ContourDirections::reverse: + forwardTessVertexCount = forwardTessLocation = 0; + mirroredTessVertexCount = tessVertexCount; + mirroredTessLocation = tessLocation + tessVertexCount; + break; + case gpu::ContourDirections::reverseThenForward: + if (m_coverageType == CoverageType::clockwiseAtomic && !isStroke()) + { + // The tessellation for borrowed coverage was allocated at a + // different location than the forward tessellation, both with + // "tessVertexCount" vertices. + assert(m_prepassTessLocation != 0); // With padding, this will + // only be zero if it wasn't + // initialized. + forwardTessVertexCount = mirroredTessVertexCount = + tessVertexCount; + forwardTessLocation = tessLocation; + mirroredTessLocation = m_prepassTessLocation + tessVertexCount; + } + else + { + // The reverse and forward tessellations are allocated + // contiguously, with a combined vertex count of + // "tessVertexCount". (tessVertexCount/2 vertices each.) + assert(tessVertexCount % 2 == 0); + forwardTessVertexCount = mirroredTessVertexCount = + tessVertexCount / 2; + forwardTessLocation = mirroredTessLocation = + tessLocation + tessVertexCount / 2; + } + break; + case gpu::ContourDirections::forwardThenReverse: + if (m_coverageType == CoverageType::clockwiseAtomic && !isStroke()) + { + // The tessellation for borrowed coverage was allocated at a + // different location than the forward tessellation, both with + // "tessVertexCount" vertices. + assert(m_prepassTessLocation != 0); // With padding, this will + // only be zero if it wasn't + // initialized. + forwardTessVertexCount = mirroredTessVertexCount = + tessVertexCount; + forwardTessLocation = m_prepassTessLocation; + mirroredTessLocation = tessLocation + tessVertexCount; + } + else + { + // The reverse and forward tessellations are allocated + // contiguously, with a combined vertex count of + // "tessVertexCount". (tessVertexCount/2 vertices each.) + assert(tessVertexCount % 2 == 0); + forwardTessVertexCount = mirroredTessVertexCount = + tessVertexCount / 2; + forwardTessLocation = tessLocation; + mirroredTessLocation = tessLocation + tessVertexCount; + } + break; + } + + // Write out the TessVertexSpans and path contours. + RenderContext::TessellationWriter tessWriter(flush, + m_pathID, + m_contourDirections, + forwardTessVertexCount, + forwardTessLocation, + mirroredTessVertexCount, + mirroredTessLocation); + + if (m_triangulator != nullptr) + { + iterateInteriorTriangulation( + InteriorTriangulationOp::pushOuterCubicTessellationData, + nullptr, + nullptr, + TriangulatorAxis::dontCare, + &tessWriter); + } + else + { + pushMidpointFanTessellationData(&tessWriter); + } +} + +void PathDraw::pushMidpointFanTessellationData( + RenderContext::TessellationWriter* tessWriter) +{ + const RawPath& rawPath = m_pathRef->getRawPath(); + RawPath::Iter startOfContour = rawPath.begin(); + for (size_t i = 0; i < m_resourceCounts.contourCount; ++i) + { + // Push a contour and curve records. + const ContourInfo& contour = m_contours[i]; + assert(startOfContour.verb() == PathVerb::move); + assert(isStroke() || contour.closed); // Fills are always closed. + RIVE_DEBUG_CODE(m_pendingStrokeJoinCount = + isStrokeOrFeather() ? contour.strokeJoinCount : 0;) + RIVE_DEBUG_CODE(m_pendingStrokeCapCount = + contour.strokeCapSegmentCount != 0 ? 2 : 0;) + + const Vec2D* pts = startOfContour.rawPtsPtr(); + size_t curveIdx = contour.firstCurveIdx; + size_t rotationIdx = contour.firstRotationIdx; + const RawPath::Iter end = contour.endOfContour; + uint32_t joinTypeFlags = 0; + bool roundJoinStroked = false; + // Emit a starting cap before the next cubic? + bool needsFirstEmulatedCapAsJoin = false; + uint32_t emulatedCapAsJoinFlags = 0; + if (isStrokeOrFeather()) + { + joinTypeFlags = isStroke() ? join_type_flags(m_strokeJoin) + : FEATHER_JOIN_CONTOUR_FLAG; + roundJoinStroked = joinTypeFlags == ROUND_JOIN_CONTOUR_FLAG; + if (contour.strokeCapSegmentCount != 0) + { + StrokeCap cap = + !contour.closed + ? m_strokeCap + : empty_stroke_cap(true, m_strokeJoin, m_strokeCap); + switch (cap) + { + case StrokeCap::butt: + emulatedCapAsJoinFlags = BEVEL_JOIN_CONTOUR_FLAG; + break; + case StrokeCap::square: + emulatedCapAsJoinFlags = MITER_CLIP_JOIN_CONTOUR_FLAG; + break; + case StrokeCap::round: + emulatedCapAsJoinFlags = ROUND_JOIN_CONTOUR_FLAG; + break; + } + emulatedCapAsJoinFlags |= EMULATED_STROKE_CAP_CONTOUR_FLAG; + needsFirstEmulatedCapAsJoin = true; + } + } + + // Make a data record for this current contour on the GPU. + uint32_t contourIDWithFlags = + m_contourFlags | + tessWriter->pushContour(contour.midpoint, + isStroke(), + contour.closed, + contour.paddingVertexCount); + + // When we don't have round joins, the number of segments per join is + // constant. (Round joins have a variable number of segments per join, + // depending on the angle.) + uint32_t numSegmentsInNotRoundJoin; + if (isFeatheredFill()) + { + numSegmentsInNotRoundJoin = + feather_join_segment_count(m_polarSegmentsPerRadian); + } + else + { + numSegmentsInNotRoundJoin = NUM_SEGMENTS_IN_MITER_OR_BEVEL_JOIN; + } + + // Convert all curves in the contour to cubics and push them to the GPU. + const int styleFlags = + style_flags(isStrokeOrFeather(), roundJoinStroked); + Vec2D joinTangent = {0, 1}; + int joinSegmentCount = 1; + Vec2D implicitClose[2]; // In case we need an implicit closing line. + for (auto iter = startOfContour; iter != end; ++iter) + { + StyledVerb styledVerb = styled_verb(iter.verb(), styleFlags); + switch (styledVerb) + { + case StyledVerb::filledMove: + case StyledVerb::strokedMove: + case StyledVerb::roundJoinStrokedMove: + implicitClose[1] = iter.movePt(); // In case we need an + // implicit closing line. + break; + case StyledVerb::filledClose: + case StyledVerb::strokedClose: + case StyledVerb::roundJoinStrokedClose: + assert(contour.closed); + break; + case StyledVerb::roundJoinStrokedLine: + { + if (contour.closed || !is_final_verb_of_contour(iter, end)) + { + joinTangent = m_tangentPairs[rotationIdx][1]; + joinSegmentCount = m_polarSegmentCounts[rotationIdx]; + ++rotationIdx; + RIVE_DEBUG_CODE(--m_pendingRotationCount;) + RIVE_DEBUG_CODE(--m_pendingStrokeJoinCount;) + } + else + { + // End with a 180-degree join that looks like the stroke + // cap. + joinTangent = + -find_ending_tangent(pts, end.rawPtsPtr()); + joinTypeFlags = emulatedCapAsJoinFlags; + joinSegmentCount = contour.strokeCapSegmentCount; + RIVE_DEBUG_CODE(--m_pendingStrokeCapCount;) + } + goto line_common; + } + case StyledVerb::strokedLine: + if (contour.closed || !is_final_verb_of_contour(iter, end)) + { + joinTangent = find_join_tangent(iter.linePts() + 1, + end.rawPtsPtr(), + contour.closed, + pts); + joinSegmentCount = numSegmentsInNotRoundJoin; + RIVE_DEBUG_CODE(--m_pendingStrokeJoinCount;) + } + else + { + // End with a 180-degree join that looks like the stroke + // cap. + joinTangent = + -find_ending_tangent(pts, end.rawPtsPtr()); + joinTypeFlags = emulatedCapAsJoinFlags; + joinSegmentCount = contour.strokeCapSegmentCount; + RIVE_DEBUG_CODE(--m_pendingStrokeCapCount;) + } + [[fallthrough]]; + case StyledVerb::filledLine: + line_common: + { + std::array cubic = + convert_line_to_cubic(iter.linePts()); + if (needsFirstEmulatedCapAsJoin) + { + // Emulate the start cap as a 180-degree join before the + // first stroke. + pushEmulatedStrokeCapAsJoinBeforeCubic( + tessWriter, + cubic.data(), + contour.strokeCapSegmentCount, + contourIDWithFlags | emulatedCapAsJoinFlags); + needsFirstEmulatedCapAsJoin = false; + } + tessWriter->pushCubic(cubic.data(), + m_contourDirections, + joinTangent, + 1, + 1, + joinSegmentCount, + contourIDWithFlags | joinTypeFlags); + RIVE_DEBUG_CODE(--m_pendingLineCount;) + break; + } + case StyledVerb::roundJoinStrokedQuad: + case StyledVerb::strokedQuad: + case StyledVerb::filledQuad: + RIVE_UNREACHABLE(); + break; + case StyledVerb::roundJoinStrokedCubic: + case StyledVerb::strokedCubic: + { + const Vec2D* p = iter.cubicPts(); + uint8_t chopKey = m_numChops.pop_front(); + uint8_t numChops = 0; + Vec2D localChopBuffer[16]; + switch (chopKey) + { + case cusp_chop_key(2): // 2 cusps + case cusp_chop_key(1): // 1 cusp + // We have to chop carefully around stroked cusps in + // order to avoid rendering artifacts. Luckily, + // cusps are extremely rare in real-world content. + chop_cubic_around_cusps( + p, + localChopBuffer, + &m_chopVertices.pop_front().x, + chopKey >> 1, + m_strokeMatrixMaxScale); + p = localChopBuffer; + // The bottom bit of chopKey is 1, meaning + // "areCusps". Clearing the bottom bit leaves + // "numChops * 2", which is the number of chops a + // cusp needs! + numChops = chopKey ^ 1; + break; + + case simple_chop_key(2): // 2 non-cusp chops + { + // Curves that need 2 chops are rare in real-world + // content. Just re-chop the curve this time around + // as well. + auto [t0, t1] = m_chopVertices.pop_front(); + math::chop_cubic_at(p, localChopBuffer, t0, t1); + p = localChopBuffer; + numChops = 2; + break; + } + case simple_chop_key(1): // 1 non-cusp chop + // Single-chop curves were saved in the + // m_chopVertices queue. + localChopBuffer[0] = p[0]; + memcpy(localChopBuffer + 1, + m_chopVertices.pop_front_n(5), + sizeof(Vec2D) * 5); + localChopBuffer[6] = p[3]; + p = localChopBuffer; + numChops = 1; + break; + } + if (needsFirstEmulatedCapAsJoin) + { + // Emulate the start cap as a 180-degree join before the + // first stroke. + pushEmulatedStrokeCapAsJoinBeforeCubic( + tessWriter, + p, + contour.strokeCapSegmentCount, + contourIDWithFlags | emulatedCapAsJoinFlags); + needsFirstEmulatedCapAsJoin = false; + } + // Push chops before the final one. + for (size_t end = curveIdx + numChops; curveIdx != end; + ++curveIdx, ++rotationIdx, p += 3) + { + uint32_t parametricSegmentCount = + m_parametricSegmentCounts[curveIdx]; + uint32_t polarSegmentCount = + m_polarSegmentCounts[rotationIdx]; + tessWriter->pushCubic(p, + m_contourDirections, + joinTangent, + parametricSegmentCount, + polarSegmentCount, + 1, + contourIDWithFlags | + joinTypeFlags); + RIVE_DEBUG_CODE(--m_pendingCurveCount;) + RIVE_DEBUG_CODE(--m_pendingRotationCount;) + } + // Push the final chop, with a join. + uint32_t parametricSegmentCount = + m_parametricSegmentCounts[curveIdx++]; + uint32_t polarSegmentCount = + m_polarSegmentCounts[rotationIdx++]; + RIVE_DEBUG_CODE(--m_pendingRotationCount;) + if (contour.closed || !is_final_verb_of_contour(iter, end)) + { + if (styledVerb == StyledVerb::roundJoinStrokedCubic) + { + joinTangent = m_tangentPairs[rotationIdx][1]; + joinSegmentCount = + m_polarSegmentCounts[rotationIdx]; + ++rotationIdx; + RIVE_DEBUG_CODE(--m_pendingRotationCount;) + } + else + { + joinTangent = find_join_tangent(iter.cubicPts() + 3, + end.rawPtsPtr(), + contour.closed, + pts); + joinSegmentCount = numSegmentsInNotRoundJoin; + } + RIVE_DEBUG_CODE(--m_pendingStrokeJoinCount;) + } + else + { + // End with a 180-degree join that looks like the stroke + // cap. + joinTangent = + -find_ending_tangent(pts, end.rawPtsPtr()); + joinTypeFlags = emulatedCapAsJoinFlags; + joinSegmentCount = contour.strokeCapSegmentCount; + RIVE_DEBUG_CODE(--m_pendingStrokeCapCount;) + } + tessWriter->pushCubic(p, + m_contourDirections, + joinTangent, + parametricSegmentCount, + polarSegmentCount, + joinSegmentCount, + contourIDWithFlags | joinTypeFlags); + RIVE_DEBUG_CODE(--m_pendingCurveCount;) + break; + } + case StyledVerb::filledCubic: + { + uint32_t parametricSegmentCount = + m_parametricSegmentCounts[curveIdx++]; + tessWriter->pushCubic(iter.cubicPts(), + m_contourDirections, + Vec2D{}, + parametricSegmentCount, + 1, + 1, + contourIDWithFlags); + RIVE_DEBUG_CODE(--m_pendingCurveCount;) + break; + } + } + } + + if (needsFirstEmulatedCapAsJoin) + { + // The contour was empty. Emit both caps on p0. + Vec2D p0 = pts[0], left = {p0.x - 1, p0.y}, + right = {p0.x + 1, p0.y}; + pushEmulatedStrokeCapAsJoinBeforeCubic( + tessWriter, + std::array{p0, right, right, right}.data(), + contour.strokeCapSegmentCount, + contourIDWithFlags | emulatedCapAsJoinFlags); + pushEmulatedStrokeCapAsJoinBeforeCubic( + tessWriter, + std::array{p0, left, left, left}.data(), + contour.strokeCapSegmentCount, + contourIDWithFlags | emulatedCapAsJoinFlags); + } + else if (contour.closed) + { + implicitClose[0] = end.rawPtsPtr()[-1]; + // Bit-cast to uint64_t because we don't want the special equality + // rules for NaN. If we're empty or otherwise return back to p0, we + // want to detect this, regardless of whether there are NaN values. + if (math::bit_cast(implicitClose[0]) != + math::bit_cast(implicitClose[1])) + { + // Draw a line back to the beginning of the contour. + std::array cubic = + convert_line_to_cubic(implicitClose); + // Closing join back to the beginning of the contour. + if (roundJoinStroked) + { + joinTangent = m_tangentPairs[rotationIdx][1]; + joinSegmentCount = m_polarSegmentCounts[rotationIdx]; + ++rotationIdx; + RIVE_DEBUG_CODE(--m_pendingRotationCount;) + RIVE_DEBUG_CODE(--m_pendingStrokeJoinCount;) + } + else if (isStrokeOrFeather()) + { + joinTangent = find_starting_tangent(pts, end.rawPtsPtr()); + joinSegmentCount = numSegmentsInNotRoundJoin; + RIVE_DEBUG_CODE(--m_pendingStrokeJoinCount;) + } + tessWriter->pushCubic(cubic.data(), + m_contourDirections, + joinTangent, + 1, + 1, + joinSegmentCount, + contourIDWithFlags | joinTypeFlags); + RIVE_DEBUG_CODE(--m_pendingLineCount;) + } + } + + assert(curveIdx == contour.endCurveIdx); + assert(rotationIdx == contour.endRotationIdx); + + assert(m_pendingStrokeJoinCount == 0); + assert(m_pendingStrokeCapCount == 0); + startOfContour = contour.endOfContour; + } + + // Make sure we only pushed the amount of data we reserved. + assert(m_pendingLineCount == 0); + assert(m_pendingCurveCount == 0); + assert(m_pendingRotationCount == 0); + assert(m_pendingEmptyStrokeCountForCaps == 0); +} + +void PathDraw::pushEmulatedStrokeCapAsJoinBeforeCubic( + RenderContext::TessellationWriter* tessWriter, + const Vec2D cubic[], + uint32_t strokeCapSegmentCount, + uint32_t contourIDWithFlags) +{ + // Reverse the cubic and push it with zero parametric and polar segments, + // and a 180-degree join tangent. This results in a solitary join, + // positioned immediately before the provided cubic, that looks like the + // desired stroke cap. + assert(strokeCapSegmentCount >= 2); + tessWriter->pushCubic( + std::array{cubic[3], cubic[2], cubic[1], cubic[0]}.data(), + m_contourDirections, + math::find_cubic_tan0(cubic), + 0, + 0, + strokeCapSegmentCount, + contourIDWithFlags); + RIVE_DEBUG_CODE(--m_pendingStrokeCapCount;) + RIVE_DEBUG_CODE(--m_pendingEmptyStrokeCountForCaps;) +} + +void PathDraw::iterateInteriorTriangulation( + InteriorTriangulationOp op, + TrivialBlockAllocator* allocator, + RawPath* scratchPath, + TriangulatorAxis triangulatorAxis, + RenderContext::TessellationWriter* tessWriter) +{ + Vec2D chops[kMaxCurveSubdivisions * 3 + 1]; + const RawPath& rawPath = m_pathRef->getRawPath(); + assert(!rawPath.empty()); + wangs_formula::VectorXform vectorXform(m_matrix); + size_t patchCount = 0; + size_t contourCount = 0; + Vec2D p0 = {0, 0}; + if (op == InteriorTriangulationOp::countDataAndTriangulate) + { + scratchPath->rewind(); + } + // Used with InteriorTriangulationOp::pushOuterCubicData. + uint32_t contourIDWithFlags = 0; + for (const auto [verb, pts] : rawPath) + { + switch (verb) + { + case PathVerb::move: + if (contourCount != 0 && pts[-1] != p0) + { + if (op == + InteriorTriangulationOp::pushOuterCubicTessellationData) + { + tessWriter->pushCubic( + convert_line_to_cubic(pts[-1], p0).data(), + m_contourDirections, + {0, 0}, + kPatchSegmentCountExcludingJoin, + 1, + kJoinSegmentCount, + contourIDWithFlags | + CULL_EXCESS_TESSELLATION_SEGMENTS_CONTOUR_FLAG); + } + ++patchCount; + } + if (op == InteriorTriangulationOp::countDataAndTriangulate) + { + scratchPath->move(pts[0]); + } + else + { + contourIDWithFlags = + m_contourFlags | + tessWriter->pushContour({0, 0}, + isStroke(), + /*closed=*/true, + 0); + } + p0 = pts[0]; + ++contourCount; + break; + case PathVerb::line: + if (op == InteriorTriangulationOp::countDataAndTriangulate) + { + scratchPath->line(pts[1]); + } + else + { + tessWriter->pushCubic( + convert_line_to_cubic(pts).data(), + m_contourDirections, + {0, 0}, + kPatchSegmentCountExcludingJoin, + 1, + kJoinSegmentCount, + contourIDWithFlags | + CULL_EXCESS_TESSELLATION_SEGMENTS_CONTOUR_FLAG); + } + ++patchCount; + break; + case PathVerb::quad: + RIVE_UNREACHABLE(); + case PathVerb::cubic: + { + uint32_t numSubdivisions; + if (op == InteriorTriangulationOp::countDataAndTriangulate) + { + numSubdivisions = + find_outer_cubic_subdivision_count(pts, vectorXform); + m_numChops.push_back(numSubdivisions); + } + else + { + numSubdivisions = m_numChops.pop_front(); + } + if (numSubdivisions == 1) + { + if (op == InteriorTriangulationOp::countDataAndTriangulate) + { + scratchPath->line(pts[3]); + } + else + { + tessWriter->pushCubic( + pts, + m_contourDirections, + {0, 0}, + kPatchSegmentCountExcludingJoin, + 1, + kJoinSegmentCount, + contourIDWithFlags | + CULL_EXCESS_TESSELLATION_SEGMENTS_CONTOUR_FLAG); + } + } + else + { + // Passing nullptr for the 'tValues' causes it to chop the + // cubic uniformly in T. + math::chop_cubic_at(pts, + chops, + nullptr, + numSubdivisions - 1); + const Vec2D* chop = chops; + for (size_t i = 0; i < numSubdivisions; ++i) + { + if (op == + InteriorTriangulationOp::countDataAndTriangulate) + { + scratchPath->line(chop[3]); + } + else + { + tessWriter->pushCubic( + chop, + m_contourDirections, + {0, 0}, + kPatchSegmentCountExcludingJoin, + 1, + kJoinSegmentCount, + contourIDWithFlags | + CULL_EXCESS_TESSELLATION_SEGMENTS_CONTOUR_FLAG); + } + chop += 3; + } + } + patchCount += numSubdivisions; + break; + } + case PathVerb::close: + break; + } + } + Vec2D lastPt = rawPath.points().back(); + if (contourCount != 0 && lastPt != p0) + { + if (op == InteriorTriangulationOp::pushOuterCubicTessellationData) + { + tessWriter->pushCubic( + convert_line_to_cubic(lastPt, p0).data(), + m_contourDirections, + {0, 0}, + kPatchSegmentCountExcludingJoin, + 1, + kJoinSegmentCount, + contourIDWithFlags | + CULL_EXCESS_TESSELLATION_SEGMENTS_CONTOUR_FLAG); + } + ++patchCount; + } + + if (op == InteriorTriangulationOp::countDataAndTriangulate) + { + assert(m_triangulator == nullptr); + assert(triangulatorAxis != TriangulatorAxis::dontCare); + m_triangulator = allocator->make( + *scratchPath, + m_matrix, + triangulatorAxis == TriangulatorAxis::horizontal + ? GrTriangulator::Comparator::Direction::kHorizontal + : GrTriangulator::Comparator::Direction::kVertical, + // clockwise and nonZero paths both get triangulated as nonZero, + // because clockwise fill still needs the backwards triangles for + // borrowed coverage. + m_pathFillRule == FillRule::evenOdd ? FillRule::evenOdd + : FillRule::nonZero, + allocator); + float matrixDeterminant = + m_matrix[0] * m_matrix[3] - m_matrix[2] * m_matrix[1]; + if ((matrixDeterminant < 0) != + static_cast(m_contourFlags & NEGATE_PATH_FILL_COVERAGE_FLAG)) + { + m_triangulator->negateWinding(); + } + // We also draw each "grout" triangle using an outerCubic patch. + patchCount += m_triangulator->groutList().count(); + + if (patchCount > 0) + { + m_resourceCounts.pathCount = 1; + m_resourceCounts.contourCount = contourCount; + // maxTessellatedSegmentCount does not get doubled when we emit both + // forward and mirrored contours because the forward and mirrored + // pair both get packed into a single gpu::TessVertexSpan. + m_resourceCounts.maxTessellatedSegmentCount = patchCount; + // outerCubic patches emit their tessellated geometry twice: once + // forward and once mirrored. + m_resourceCounts.outerCubicTessVertexCount = + gpu::ContourDirectionsAreDoubleSided(m_contourDirections) + ? patchCount * kOuterCurvePatchSegmentSpan * 2 + : patchCount * kOuterCurvePatchSegmentSpan; + m_resourceCounts.maxTriangleVertexCount += + m_triangulator->maxVertexCount(); + } + } + else + { + assert(m_triangulator != nullptr); + // Submit grout triangles, retrofitted into outerCubic patches. + for (auto* node = m_triangulator->groutList().head(); node; + node = node->fNext) + { + Vec2D triangleAsCubic[4] = {node->fPts[0], + node->fPts[1], + {0, 0}, + node->fPts[2]}; + tessWriter->pushCubic(triangleAsCubic, + m_contourDirections, + {0, 0}, + kPatchSegmentCountExcludingJoin, + 1, + kJoinSegmentCount, + contourIDWithFlags | + RETROFITTED_TRIANGLE_CONTOUR_FLAG); + ++patchCount; + } + assert(contourCount == m_resourceCounts.contourCount); + assert(patchCount == m_resourceCounts.maxTessellatedSegmentCount); + assert(patchCount * kOuterCurvePatchSegmentSpan * 2 == + m_resourceCounts.outerCubicTessVertexCount || + patchCount * kOuterCurvePatchSegmentSpan == + m_resourceCounts.outerCubicTessVertexCount); + } +} + +ImageRectDraw::ImageRectDraw(RenderContext* context, + IAABB pixelBounds, + const Mat2D& matrix, + BlendMode blendMode, + rcp imageTexture, + const ImageSampler imageSampler, + float opacity) : + Draw(pixelBounds, + matrix, + blendMode, + std::move(imageTexture), + imageSampler, + Type::imageRect), + m_opacity(opacity) +{ + // If we support image paints for paths, the client should draw a + // rectangular path with an image paint instead of using this draw. + assert(!context->frameSupportsImagePaintForPaths()); + m_resourceCounts.imageDrawCount = 1; +} + +void ImageRectDraw::pushToRenderContext(RenderContext::LogicalFlush* flush, + int subpassIndex) +{ + assert(subpassIndex == 0); + flush->pushImageRectDraw(this); +} + +ImageMeshDraw::ImageMeshDraw(IAABB pixelBounds, + const Mat2D& matrix, + BlendMode blendMode, + rcp imageTexture, + const ImageSampler imageSampler, + rcp vertexBuffer, + rcp uvBuffer, + rcp indexBuffer, + uint32_t indexCount, + float opacity) : + Draw(pixelBounds, + matrix, + blendMode, + std::move(imageTexture), + + imageSampler, + Type::imageMesh), + m_vertexBufferRef(vertexBuffer.release()), + m_uvBufferRef(uvBuffer.release()), + m_indexBufferRef(indexBuffer.release()), + m_indexCount(indexCount), + m_opacity(opacity) +{ + assert(m_vertexBufferRef != nullptr); + assert(m_uvBufferRef != nullptr); + assert(m_indexBufferRef != nullptr); + m_resourceCounts.imageDrawCount = 1; +} + +void ImageMeshDraw::pushToRenderContext(RenderContext::LogicalFlush* flush, + int subpassIndex) +{ + assert(subpassIndex == 0); + flush->pushImageMeshDraw(this); +} + +void ImageMeshDraw::releaseRefs() +{ + Draw::releaseRefs(); + m_vertexBufferRef->unref(); + m_uvBufferRef->unref(); + m_indexBufferRef->unref(); +} + +StencilClipReset::StencilClipReset(RenderContext* context, + uint32_t previousClipID, + gpu::DrawContents previousClipDrawContents, + ResetAction resetAction) : + Draw(context->getClipContentBounds(previousClipID), + Mat2D(), + BlendMode::srcOver, + nullptr, + ImageSampler::LinearClamp(), + Type::stencilClipReset), + m_previousClipID(previousClipID) +{ + constexpr static gpu::DrawContents FILL_RULE_FLAGS = + gpu::DrawContents::nonZeroFill | gpu::DrawContents::evenOddFill | + gpu::DrawContents::clockwiseFill; + m_drawContents |= previousClipDrawContents & FILL_RULE_FLAGS; + switch (resetAction) + { + case ResetAction::intersectPreviousClip: + m_drawContents |= gpu::DrawContents::activeClip; + [[fallthrough]]; + case ResetAction::clearPreviousClip: + m_drawContents |= gpu::DrawContents::clipUpdate; + break; + } + m_resourceCounts.maxTriangleVertexCount = 6; +} + +void StencilClipReset::pushToRenderContext(RenderContext::LogicalFlush* flush, + int subpassIndex) +{ + assert(subpassIndex == 0); + flush->pushStencilClipResetDraw(this); +} +} // namespace rive::gpu diff --git a/third_party/rive_renderer/source/generated/shaders/advanced_blend.exports.h b/third_party/rive_renderer/source/generated/shaders/advanced_blend.exports.h new file mode 100644 index 0000000..7d86e26 --- /dev/null +++ b/third_party/rive_renderer/source/generated/shaders/advanced_blend.exports.h @@ -0,0 +1,208 @@ +#pragma once + +#define GLSL_ATLAS_BLIT "CB" +#define GLSL_ATLAS_BLIT_raw CB +#define GLSL_ATLAS_FEATHERED_FILL "QE" +#define GLSL_ATLAS_FEATHERED_FILL_raw QE +#define GLSL_ATLAS_FEATHERED_STROKE "SE" +#define GLSL_ATLAS_FEATHERED_STROKE_raw SE +#define GLSL_BASE_INSTANCE_UNIFORM_NAME "ED" +#define GLSL_BASE_INSTANCE_UNIFORM_NAME_raw ED +#define GLSL_BORROWED_COVERAGE_PREPASS "OC" +#define GLSL_BORROWED_COVERAGE_PREPASS_raw OC +#define GLSL_CLEAR_CLIP "OE" +#define GLSL_CLEAR_CLIP_raw OE +#define GLSL_CLEAR_COLOR "RD" +#define GLSL_CLEAR_COLOR_raw RD +#define GLSL_CLEAR_COVERAGE "NE" +#define GLSL_CLEAR_COVERAGE_raw NE +#define GLSL_CLOCKWISE_FILL "AD" +#define GLSL_CLOCKWISE_FILL_raw AD +#define GLSL_COALESCED_PLS_RESOLVE_AND_TRANSFER "LC" +#define GLSL_COALESCED_PLS_RESOLVE_AND_TRANSFER_raw LC +#define GLSL_COLOR_PLANE_IDX_OVERRIDE "LD" +#define GLSL_COLOR_PLANE_IDX_OVERRIDE_raw LD +#define GLSL_DISABLE_SHADER_STORAGE_BUFFERS "FE" +#define GLSL_DISABLE_SHADER_STORAGE_BUFFERS_raw FE +#define GLSL_DRAW_IMAGE "UC" +#define GLSL_DRAW_IMAGE_raw UC +#define GLSL_DRAW_IMAGE_MESH "UD" +#define GLSL_DRAW_IMAGE_MESH_raw UD +#define GLSL_DRAW_IMAGE_RECT "TC" +#define GLSL_DRAW_IMAGE_RECT_raw TC +#define GLSL_DRAW_INTERIOR_TRIANGLES "GB" +#define GLSL_DRAW_INTERIOR_TRIANGLES_raw GB +#define GLSL_DRAW_PATH "KC" +#define GLSL_DRAW_PATH_raw KC +#define GLSL_DRAW_RENDER_TARGET_UPDATE_BOUNDS "VD" +#define GLSL_DRAW_RENDER_TARGET_UPDATE_BOUNDS_raw VD +#define GLSL_ENABLE_ADVANCED_BLEND "FB" +#define GLSL_ENABLE_ADVANCED_BLEND_raw FB +#define GLSL_ENABLE_CLIPPING "T" +#define GLSL_ENABLE_CLIPPING_raw T +#define GLSL_ENABLE_CLIP_RECT "BB" +#define GLSL_ENABLE_CLIP_RECT_raw BB +#define GLSL_ENABLE_EVEN_ODD "IC" +#define GLSL_ENABLE_EVEN_ODD_raw IC +#define GLSL_ENABLE_FEATHER "EB" +#define GLSL_ENABLE_FEATHER_raw EB +#define GLSL_ENABLE_HSL_BLEND_MODES "XB" +#define GLSL_ENABLE_HSL_BLEND_MODES_raw XB +#define GLSL_ENABLE_INSTANCE_INDEX "OD" +#define GLSL_ENABLE_INSTANCE_INDEX_raw OD +#define GLSL_ENABLE_KHR_BLEND "KD" +#define GLSL_ENABLE_KHR_BLEND_raw KD +#define GLSL_ENABLE_MIN_16_PRECISION "PD" +#define GLSL_ENABLE_MIN_16_PRECISION_raw PD +#define GLSL_ENABLE_NESTED_CLIPPING "CD" +#define GLSL_ENABLE_NESTED_CLIPPING_raw CD +#define GLSL_ENABLE_RASTERIZER_ORDERED_VIEWS "QD" +#define GLSL_ENABLE_RASTERIZER_ORDERED_VIEWS_raw QD +#define GLSL_ENABLE_TYPED_UAV_LOAD_STORE "FC" +#define GLSL_ENABLE_TYPED_UAV_LOAD_STORE_raw FC +#define GLSL_FIXED_FUNCTION_COLOR_OUTPUT "QB" +#define GLSL_FIXED_FUNCTION_COLOR_OUTPUT_raw QB +#define GLSL_FRAGMENT "HB" +#define GLSL_FRAGMENT_raw HB +#define GLSL_FRAMEBUFFER_BOTTOM_UP "DE" +#define GLSL_FRAMEBUFFER_BOTTOM_UP_raw DE +#define GLSL_FlushUniforms "VB" +#define GLSL_FlushUniforms_raw VB +#define GLSL_GLSL_VERSION "WB" +#define GLSL_GLSL_VERSION_raw WB +#define GLSL_INITIALIZE_PLS "WD" +#define GLSL_INITIALIZE_PLS_raw WD +#define GLSL_ImageDrawUniforms "EC" +#define GLSL_ImageDrawUniforms_raw EC +#define GLSL_LOAD_COLOR "TD" +#define GLSL_LOAD_COLOR_raw TD +#define GLSL_OPTIONALLY_FLAT "OB" +#define GLSL_OPTIONALLY_FLAT_raw OB +#define GLSL_PLS_BLEND_SRC_OVER "ZB" +#define GLSL_PLS_BLEND_SRC_OVER_raw ZB +#define GLSL_PLS_IMPL_ANGLE "_EXPORTED_PLS_IMPL_ANGLE" +#define GLSL_PLS_IMPL_ANGLE_raw _EXPORTED_PLS_IMPL_ANGLE +#define GLSL_PLS_IMPL_DEVICE_BUFFER "LE" +#define GLSL_PLS_IMPL_DEVICE_BUFFER_raw LE +#define GLSL_PLS_IMPL_DEVICE_BUFFER_RASTER_ORDERED "ME" +#define GLSL_PLS_IMPL_DEVICE_BUFFER_RASTER_ORDERED_raw ME +#define GLSL_PLS_IMPL_EXT_NATIVE "GE" +#define GLSL_PLS_IMPL_EXT_NATIVE_raw GE +#define GLSL_PLS_IMPL_FRAMEBUFFER_FETCH "HE" +#define GLSL_PLS_IMPL_FRAMEBUFFER_FETCH_raw HE +#define GLSL_PLS_IMPL_NONE "KE" +#define GLSL_PLS_IMPL_NONE_raw KE +#define GLSL_PLS_IMPL_STORAGE_TEXTURE "IE" +#define GLSL_PLS_IMPL_STORAGE_TEXTURE_raw IE +#define GLSL_PLS_IMPL_SUBPASS_LOAD "JE" +#define GLSL_PLS_IMPL_SUBPASS_LOAD_raw JE +#define GLSL_POST_INVERT_Y "EE" +#define GLSL_POST_INVERT_Y_raw EE +#define GLSL_RENDER_MODE_MSAA "DB" +#define GLSL_RENDER_MODE_MSAA_raw DB +#define GLSL_RESOLVE_PLS "HC" +#define GLSL_RESOLVE_PLS_raw HC +#define GLSL_STORE_COLOR "FD" +#define GLSL_STORE_COLOR_raw FD +#define GLSL_STORE_COLOR_CLEAR "XD" +#define GLSL_STORE_COLOR_CLEAR_raw XD +#define GLSL_SWIZZLE_COLOR_BGRA_TO_RGBA "YD" +#define GLSL_SWIZZLE_COLOR_BGRA_TO_RGBA_raw YD +#define GLSL_TARGET_VULKAN "CC" +#define GLSL_TARGET_VULKAN_raw CC +#define GLSL_TESS_TEXTURE_FLOATING_POINT "CE" +#define GLSL_TESS_TEXTURE_FLOATING_POINT_raw CE +#define GLSL_USE_TEXEL_FETCH_WITH_FRAG_COORD "NC" +#define GLSL_USE_TEXEL_FETCH_WITH_FRAG_COORD_raw NC +#define GLSL_USING_PLS_STORAGE_TEXTURES "DD" +#define GLSL_USING_PLS_STORAGE_TEXTURES_raw DD +#define GLSL_VERTEX "AB" +#define GLSL_VERTEX_raw AB +#define GLSL_VULKAN_VENDOR_ID "BD" +#define GLSL_VULKAN_VENDOR_ID_raw BD +#define GLSL_a_args "RB" +#define GLSL_a_args_raw RB +#define GLSL_a_color0 "YC" +#define GLSL_a_color0_raw YC +#define GLSL_a_color1 "ZC" +#define GLSL_a_color1_raw ZC +#define GLSL_a_contourIDWithFlags "JD" +#define GLSL_a_contourIDWithFlags_raw JD +#define GLSL_a_imageRectVertex "YB" +#define GLSL_a_imageRectVertex_raw YB +#define GLSL_a_joinTan_and_ys "GC" +#define GLSL_a_joinTan_and_ys_raw GC +#define GLSL_a_mirroredVertexData "MB" +#define GLSL_a_mirroredVertexData_raw MB +#define GLSL_a_p0p1_ "RC" +#define GLSL_a_p0p1__raw RC +#define GLSL_a_p2p3_ "SC" +#define GLSL_a_p2p3__raw SC +#define GLSL_a_patchVertexData "LB" +#define GLSL_a_patchVertexData_raw LB +#define GLSL_a_position "SB" +#define GLSL_a_position_raw SB +#define GLSL_a_reflectionX0X1 "HD" +#define GLSL_a_reflectionX0X1_raw HD +#define GLSL_a_segmentCounts "ID" +#define GLSL_a_segmentCounts_raw ID +#define GLSL_a_span "AC" +#define GLSL_a_span_raw AC +#define GLSL_a_spanX "WC" +#define GLSL_a_spanX_raw WC +#define GLSL_a_texCoord "TB" +#define GLSL_a_texCoord_raw TB +#define GLSL_a_triangleVertex "IB" +#define GLSL_a_triangleVertex_raw IB +#define GLSL_a_x0x1 "GD" +#define GLSL_a_x0x1_raw GD +#define GLSL_a_yWithFlags "XC" +#define GLSL_a_yWithFlags_raw XC +#define GLSL_atlasFillFragmentMain "RE" +#define GLSL_atlasFillFragmentMain_raw RE +#define GLSL_atlasStrokeFragmentMain "TE" +#define GLSL_atlasStrokeFragmentMain_raw TE +#define GLSL_atlasTexture "ND" +#define GLSL_atlasTexture_raw ND +#define GLSL_atlasVertexMain "PE" +#define GLSL_atlasVertexMain_raw PE +#define GLSL_blitFragmentMain "MD" +#define GLSL_blitFragmentMain_raw MD +#define GLSL_blitVertexMain "ZD" +#define GLSL_blitVertexMain_raw ZD +#define GLSL_clearColor "SD" +#define GLSL_clearColor_raw SD +#define GLSL_colorRampFragmentMain "BE" +#define GLSL_colorRampFragmentMain_raw BE +#define GLSL_colorRampVertexMain "AE" +#define GLSL_colorRampVertexMain_raw AE +#define GLSL_contourBuffer "QC" +#define GLSL_contourBuffer_raw QC +#define GLSL_drawFragmentMain "NB" +#define GLSL_drawFragmentMain_raw NB +#define GLSL_drawVertexMain "PB" +#define GLSL_drawVertexMain_raw PB +#define GLSL_dstColorTexture "PC" +#define GLSL_dstColorTexture_raw PC +#define GLSL_featherTexture "JC" +#define GLSL_featherTexture_raw JC +#define GLSL_gradTexture "MC" +#define GLSL_gradTexture_raw MC +#define GLSL_imageTexture "UB" +#define GLSL_imageTexture_raw UB +#define GLSL_paintAuxBuffer "KB" +#define GLSL_paintAuxBuffer_raw KB +#define GLSL_paintBuffer "DC" +#define GLSL_paintBuffer_raw DC +#define GLSL_pathBuffer "JB" +#define GLSL_pathBuffer_raw JB +#define GLSL_sourceTexture "VC" +#define GLSL_sourceTexture_raw VC +#define GLSL_stencilVertexMain "UE" +#define GLSL_stencilVertexMain_raw UE +#define GLSL_tessVertexTexture "BC" +#define GLSL_tessVertexTexture_raw BC +#define GLSL_tessellateFragmentMain "WE" +#define GLSL_tessellateFragmentMain_raw WE +#define GLSL_tessellateVertexMain "VE" +#define GLSL_tessellateVertexMain_raw VE diff --git a/third_party/rive_renderer/source/generated/shaders/advanced_blend.glsl.hpp b/third_party/rive_renderer/source/generated/shaders/advanced_blend.glsl.hpp new file mode 100644 index 0000000..68a781c --- /dev/null +++ b/third_party/rive_renderer/source/generated/shaders/advanced_blend.glsl.hpp @@ -0,0 +1,32 @@ +#pragma once + +#include "advanced_blend.exports.h" + +namespace rive { +namespace gpu { +namespace glsl { +const char advanced_blend[] = R"===(#ifdef HB +#ifdef KD +layout( +#ifdef XB +blend_support_all_equations +#else +blend_support_multiply,blend_support_screen,blend_support_overlay,blend_support_darken,blend_support_lighten,blend_support_colordodge,blend_support_colorburn,blend_support_hardlight,blend_support_softlight,blend_support_difference,blend_support_exclusion +#endif +)out; +#endif +#ifdef FB +#ifdef XB +g V7(A B0){return min(min(B0.x,B0.y),B0.z);}g N9(A B0){return max(max(B0.x,B0.y),B0.z);}g W7(A B0){return dot(B0,K0(.30,.59,.11));}g O9(A B0){return N9(B0)-V7(B0);}A kc(A j){g p3=W7(j);g P9=V7(j);g Q9=N9(j);if(P9<.0)j=p3+((j-p3)*p3)/(p3-P9);if(Q9>1.)j=p3+((j-p3)*(1.-p3))/(Q9-p3);return j;}A X7(A L4,A Y7){g lc=W7(L4);g mc=W7(Y7);g nc=mc-lc;A j=L4+K0(nc);return kc(j);}A R9(A L4,A oc,A Y7){g pc=V7(L4);g S9=O9(L4);g qc=O9(oc);A j;if(S9>.0){j=(L4-pc)*qc/S9;}else{j=K0(.0);}return X7(j,Y7);} +#endif +A rc(A e0,i X0,a0 Z7){A h0=Y3(X0);A L0;switch(Z7){case sc:L0=e0.xyz*h0.xyz;break;case tc:L0=e0.xyz+h0.xyz-e0.xyz*h0.xyz;break;case uc:{for(int C=0;C<3;++C){if(h0[C]<=.5)L0[C]=2.*e0[C]*h0[C];else L0[C]=1.-2.*(1.-e0[C])*(1.-h0[C]);}break;}case vc:L0=min(e0.xyz,h0.xyz);break;case wc:L0=max(e0.xyz,h0.xyz);break;case xc:{X0.xyz=clamp(X0.xyz,K0(.0),X0.www);A T9=clamp(1.-e0,K0(.0),K0(1.))*X0.w;L0=mix(min(K0(1.),X0.xyz/T9),sign(X0.xyz),equal(T9,K0(.0)));break;}case zc:{e0=clamp(e0,K0(.0),K0(1.));X0.xyz=clamp(X0.xyz,K0(.0),X0.www);if(X0.w==.0)X0.w=1.;A U9=X0.w-X0.xyz;L0=1.-mix(min(K0(1.),U9/(e0*X0.w)),sign(U9),equal(e0,K0(.0)));break;}case Ac:{for(int C=0;C<3;++C){if(e0[C]<=.5)L0[C]=2.*e0[C]*h0[C];else L0[C]=1.-2.*(1.-e0[C])*(1.-h0[C]);}break;}case Bc:{for(int C=0;C<3;++C){if(e0[C]<=0.5)L0[C]=h0[C]-(1.-2.*e0[C])*h0[C]*(1.-h0[C]);else if(h0[C]<=.25)L0[C]=h0[C]+(2.*e0[C]-1.)*h0[C]*((16.*h0[C]-12.)*h0[C]+3.);else L0[C]=h0[C]+(2.*e0[C]-1.)*(sqrt(h0[C])-h0[C]);}break;}case Cc:L0=abs(h0.xyz-e0.xyz);break;case Dc:L0=e0.xyz+h0.xyz-2.*e0.xyz*h0.xyz;break; +#ifdef XB +case Ec:if(XB){e0.xyz=clamp(e0.xyz,K0(.0),K0(1.));L0=R9(e0.xyz,h0.xyz,h0.xyz);}break;case Fc:if(XB){e0.xyz=clamp(e0.xyz,K0(.0),K0(1.));L0=R9(h0.xyz,e0.xyz,h0.xyz);}break;case Gc:if(XB){e0.xyz=clamp(e0.xyz,K0(.0),K0(1.));L0=X7(e0.xyz,h0.xyz);}break;case Hc:if(XB){e0.xyz=clamp(e0.xyz,K0(.0),K0(1.));L0=X7(h0.xyz,e0.xyz);}break; +#endif +}return L0;}d A M4(A e0,i X0,a0 Z7){A L0=rc(e0,X0,Z7);G z5=Z3(X0.w,1.-X0.w);return C0(Ic(L0,e0),z5);} +#endif +#endif +)==="; +} // namespace glsl +} // namespace gpu +} // namespace rive \ No newline at end of file diff --git a/third_party/rive_renderer/source/generated/shaders/advanced_blend.minified.glsl b/third_party/rive_renderer/source/generated/shaders/advanced_blend.minified.glsl new file mode 100644 index 0000000..532ab9e --- /dev/null +++ b/third_party/rive_renderer/source/generated/shaders/advanced_blend.minified.glsl @@ -0,0 +1,21 @@ +#ifdef FRAGMENT +#ifdef ENABLE_KHR_BLEND +layout( +#ifdef ENABLE_HSL_BLEND_MODES +blend_support_all_equations +#else +blend_support_multiply,blend_support_screen,blend_support_overlay,blend_support_darken,blend_support_lighten,blend_support_colordodge,blend_support_colorburn,blend_support_hardlight,blend_support_softlight,blend_support_difference,blend_support_exclusion +#endif +)out; +#endif +#ifdef ENABLE_ADVANCED_BLEND +#ifdef ENABLE_HSL_BLEND_MODES +g V7(A B0){return min(min(B0.x,B0.y),B0.z);}g N9(A B0){return max(max(B0.x,B0.y),B0.z);}g W7(A B0){return dot(B0,K0(.30,.59,.11));}g O9(A B0){return N9(B0)-V7(B0);}A kc(A j){g p3=W7(j);g P9=V7(j);g Q9=N9(j);if(P9<.0)j=p3+((j-p3)*p3)/(p3-P9);if(Q9>1.)j=p3+((j-p3)*(1.-p3))/(Q9-p3);return j;}A X7(A L4,A Y7){g lc=W7(L4);g mc=W7(Y7);g nc=mc-lc;A j=L4+K0(nc);return kc(j);}A R9(A L4,A oc,A Y7){g pc=V7(L4);g S9=O9(L4);g qc=O9(oc);A j;if(S9>.0){j=(L4-pc)*qc/S9;}else{j=K0(.0);}return X7(j,Y7);} +#endif +A rc(A e0,i X0,a0 Z7){A h0=Y3(X0);A L0;switch(Z7){case sc:L0=e0.xyz*h0.xyz;break;case tc:L0=e0.xyz+h0.xyz-e0.xyz*h0.xyz;break;case uc:{for(int C=0;C<3;++C){if(h0[C]<=.5)L0[C]=2.*e0[C]*h0[C];else L0[C]=1.-2.*(1.-e0[C])*(1.-h0[C]);}break;}case vc:L0=min(e0.xyz,h0.xyz);break;case wc:L0=max(e0.xyz,h0.xyz);break;case xc:{X0.xyz=clamp(X0.xyz,K0(.0),X0.www);A T9=clamp(1.-e0,K0(.0),K0(1.))*X0.w;L0=mix(min(K0(1.),X0.xyz/T9),sign(X0.xyz),equal(T9,K0(.0)));break;}case zc:{e0=clamp(e0,K0(.0),K0(1.));X0.xyz=clamp(X0.xyz,K0(.0),X0.www);if(X0.w==.0)X0.w=1.;A U9=X0.w-X0.xyz;L0=1.-mix(min(K0(1.),U9/(e0*X0.w)),sign(U9),equal(e0,K0(.0)));break;}case Ac:{for(int C=0;C<3;++C){if(e0[C]<=.5)L0[C]=2.*e0[C]*h0[C];else L0[C]=1.-2.*(1.-e0[C])*(1.-h0[C]);}break;}case Bc:{for(int C=0;C<3;++C){if(e0[C]<=0.5)L0[C]=h0[C]-(1.-2.*e0[C])*h0[C]*(1.-h0[C]);else if(h0[C]<=.25)L0[C]=h0[C]+(2.*e0[C]-1.)*h0[C]*((16.*h0[C]-12.)*h0[C]+3.);else L0[C]=h0[C]+(2.*e0[C]-1.)*(sqrt(h0[C])-h0[C]);}break;}case Cc:L0=abs(h0.xyz-e0.xyz);break;case Dc:L0=e0.xyz+h0.xyz-2.*e0.xyz*h0.xyz;break; +#ifdef ENABLE_HSL_BLEND_MODES +case Ec:if(ENABLE_HSL_BLEND_MODES){e0.xyz=clamp(e0.xyz,K0(.0),K0(1.));L0=R9(e0.xyz,h0.xyz,h0.xyz);}break;case Fc:if(ENABLE_HSL_BLEND_MODES){e0.xyz=clamp(e0.xyz,K0(.0),K0(1.));L0=R9(h0.xyz,e0.xyz,h0.xyz);}break;case Gc:if(ENABLE_HSL_BLEND_MODES){e0.xyz=clamp(e0.xyz,K0(.0),K0(1.));L0=X7(e0.xyz,h0.xyz);}break;case Hc:if(ENABLE_HSL_BLEND_MODES){e0.xyz=clamp(e0.xyz,K0(.0),K0(1.));L0=X7(h0.xyz,e0.xyz);}break; +#endif +}return L0;}d A M4(A e0,i X0,a0 Z7){A L0=rc(e0,X0,Z7);G z5=Z3(X0.w,1.-X0.w);return C0(Ic(L0,e0),z5);} +#endif +#endif diff --git a/third_party/rive_renderer/source/generated/shaders/atomic_draw.exports.h b/third_party/rive_renderer/source/generated/shaders/atomic_draw.exports.h new file mode 100644 index 0000000..7d86e26 --- /dev/null +++ b/third_party/rive_renderer/source/generated/shaders/atomic_draw.exports.h @@ -0,0 +1,208 @@ +#pragma once + +#define GLSL_ATLAS_BLIT "CB" +#define GLSL_ATLAS_BLIT_raw CB +#define GLSL_ATLAS_FEATHERED_FILL "QE" +#define GLSL_ATLAS_FEATHERED_FILL_raw QE +#define GLSL_ATLAS_FEATHERED_STROKE "SE" +#define GLSL_ATLAS_FEATHERED_STROKE_raw SE +#define GLSL_BASE_INSTANCE_UNIFORM_NAME "ED" +#define GLSL_BASE_INSTANCE_UNIFORM_NAME_raw ED +#define GLSL_BORROWED_COVERAGE_PREPASS "OC" +#define GLSL_BORROWED_COVERAGE_PREPASS_raw OC +#define GLSL_CLEAR_CLIP "OE" +#define GLSL_CLEAR_CLIP_raw OE +#define GLSL_CLEAR_COLOR "RD" +#define GLSL_CLEAR_COLOR_raw RD +#define GLSL_CLEAR_COVERAGE "NE" +#define GLSL_CLEAR_COVERAGE_raw NE +#define GLSL_CLOCKWISE_FILL "AD" +#define GLSL_CLOCKWISE_FILL_raw AD +#define GLSL_COALESCED_PLS_RESOLVE_AND_TRANSFER "LC" +#define GLSL_COALESCED_PLS_RESOLVE_AND_TRANSFER_raw LC +#define GLSL_COLOR_PLANE_IDX_OVERRIDE "LD" +#define GLSL_COLOR_PLANE_IDX_OVERRIDE_raw LD +#define GLSL_DISABLE_SHADER_STORAGE_BUFFERS "FE" +#define GLSL_DISABLE_SHADER_STORAGE_BUFFERS_raw FE +#define GLSL_DRAW_IMAGE "UC" +#define GLSL_DRAW_IMAGE_raw UC +#define GLSL_DRAW_IMAGE_MESH "UD" +#define GLSL_DRAW_IMAGE_MESH_raw UD +#define GLSL_DRAW_IMAGE_RECT "TC" +#define GLSL_DRAW_IMAGE_RECT_raw TC +#define GLSL_DRAW_INTERIOR_TRIANGLES "GB" +#define GLSL_DRAW_INTERIOR_TRIANGLES_raw GB +#define GLSL_DRAW_PATH "KC" +#define GLSL_DRAW_PATH_raw KC +#define GLSL_DRAW_RENDER_TARGET_UPDATE_BOUNDS "VD" +#define GLSL_DRAW_RENDER_TARGET_UPDATE_BOUNDS_raw VD +#define GLSL_ENABLE_ADVANCED_BLEND "FB" +#define GLSL_ENABLE_ADVANCED_BLEND_raw FB +#define GLSL_ENABLE_CLIPPING "T" +#define GLSL_ENABLE_CLIPPING_raw T +#define GLSL_ENABLE_CLIP_RECT "BB" +#define GLSL_ENABLE_CLIP_RECT_raw BB +#define GLSL_ENABLE_EVEN_ODD "IC" +#define GLSL_ENABLE_EVEN_ODD_raw IC +#define GLSL_ENABLE_FEATHER "EB" +#define GLSL_ENABLE_FEATHER_raw EB +#define GLSL_ENABLE_HSL_BLEND_MODES "XB" +#define GLSL_ENABLE_HSL_BLEND_MODES_raw XB +#define GLSL_ENABLE_INSTANCE_INDEX "OD" +#define GLSL_ENABLE_INSTANCE_INDEX_raw OD +#define GLSL_ENABLE_KHR_BLEND "KD" +#define GLSL_ENABLE_KHR_BLEND_raw KD +#define GLSL_ENABLE_MIN_16_PRECISION "PD" +#define GLSL_ENABLE_MIN_16_PRECISION_raw PD +#define GLSL_ENABLE_NESTED_CLIPPING "CD" +#define GLSL_ENABLE_NESTED_CLIPPING_raw CD +#define GLSL_ENABLE_RASTERIZER_ORDERED_VIEWS "QD" +#define GLSL_ENABLE_RASTERIZER_ORDERED_VIEWS_raw QD +#define GLSL_ENABLE_TYPED_UAV_LOAD_STORE "FC" +#define GLSL_ENABLE_TYPED_UAV_LOAD_STORE_raw FC +#define GLSL_FIXED_FUNCTION_COLOR_OUTPUT "QB" +#define GLSL_FIXED_FUNCTION_COLOR_OUTPUT_raw QB +#define GLSL_FRAGMENT "HB" +#define GLSL_FRAGMENT_raw HB +#define GLSL_FRAMEBUFFER_BOTTOM_UP "DE" +#define GLSL_FRAMEBUFFER_BOTTOM_UP_raw DE +#define GLSL_FlushUniforms "VB" +#define GLSL_FlushUniforms_raw VB +#define GLSL_GLSL_VERSION "WB" +#define GLSL_GLSL_VERSION_raw WB +#define GLSL_INITIALIZE_PLS "WD" +#define GLSL_INITIALIZE_PLS_raw WD +#define GLSL_ImageDrawUniforms "EC" +#define GLSL_ImageDrawUniforms_raw EC +#define GLSL_LOAD_COLOR "TD" +#define GLSL_LOAD_COLOR_raw TD +#define GLSL_OPTIONALLY_FLAT "OB" +#define GLSL_OPTIONALLY_FLAT_raw OB +#define GLSL_PLS_BLEND_SRC_OVER "ZB" +#define GLSL_PLS_BLEND_SRC_OVER_raw ZB +#define GLSL_PLS_IMPL_ANGLE "_EXPORTED_PLS_IMPL_ANGLE" +#define GLSL_PLS_IMPL_ANGLE_raw _EXPORTED_PLS_IMPL_ANGLE +#define GLSL_PLS_IMPL_DEVICE_BUFFER "LE" +#define GLSL_PLS_IMPL_DEVICE_BUFFER_raw LE +#define GLSL_PLS_IMPL_DEVICE_BUFFER_RASTER_ORDERED "ME" +#define GLSL_PLS_IMPL_DEVICE_BUFFER_RASTER_ORDERED_raw ME +#define GLSL_PLS_IMPL_EXT_NATIVE "GE" +#define GLSL_PLS_IMPL_EXT_NATIVE_raw GE +#define GLSL_PLS_IMPL_FRAMEBUFFER_FETCH "HE" +#define GLSL_PLS_IMPL_FRAMEBUFFER_FETCH_raw HE +#define GLSL_PLS_IMPL_NONE "KE" +#define GLSL_PLS_IMPL_NONE_raw KE +#define GLSL_PLS_IMPL_STORAGE_TEXTURE "IE" +#define GLSL_PLS_IMPL_STORAGE_TEXTURE_raw IE +#define GLSL_PLS_IMPL_SUBPASS_LOAD "JE" +#define GLSL_PLS_IMPL_SUBPASS_LOAD_raw JE +#define GLSL_POST_INVERT_Y "EE" +#define GLSL_POST_INVERT_Y_raw EE +#define GLSL_RENDER_MODE_MSAA "DB" +#define GLSL_RENDER_MODE_MSAA_raw DB +#define GLSL_RESOLVE_PLS "HC" +#define GLSL_RESOLVE_PLS_raw HC +#define GLSL_STORE_COLOR "FD" +#define GLSL_STORE_COLOR_raw FD +#define GLSL_STORE_COLOR_CLEAR "XD" +#define GLSL_STORE_COLOR_CLEAR_raw XD +#define GLSL_SWIZZLE_COLOR_BGRA_TO_RGBA "YD" +#define GLSL_SWIZZLE_COLOR_BGRA_TO_RGBA_raw YD +#define GLSL_TARGET_VULKAN "CC" +#define GLSL_TARGET_VULKAN_raw CC +#define GLSL_TESS_TEXTURE_FLOATING_POINT "CE" +#define GLSL_TESS_TEXTURE_FLOATING_POINT_raw CE +#define GLSL_USE_TEXEL_FETCH_WITH_FRAG_COORD "NC" +#define GLSL_USE_TEXEL_FETCH_WITH_FRAG_COORD_raw NC +#define GLSL_USING_PLS_STORAGE_TEXTURES "DD" +#define GLSL_USING_PLS_STORAGE_TEXTURES_raw DD +#define GLSL_VERTEX "AB" +#define GLSL_VERTEX_raw AB +#define GLSL_VULKAN_VENDOR_ID "BD" +#define GLSL_VULKAN_VENDOR_ID_raw BD +#define GLSL_a_args "RB" +#define GLSL_a_args_raw RB +#define GLSL_a_color0 "YC" +#define GLSL_a_color0_raw YC +#define GLSL_a_color1 "ZC" +#define GLSL_a_color1_raw ZC +#define GLSL_a_contourIDWithFlags "JD" +#define GLSL_a_contourIDWithFlags_raw JD +#define GLSL_a_imageRectVertex "YB" +#define GLSL_a_imageRectVertex_raw YB +#define GLSL_a_joinTan_and_ys "GC" +#define GLSL_a_joinTan_and_ys_raw GC +#define GLSL_a_mirroredVertexData "MB" +#define GLSL_a_mirroredVertexData_raw MB +#define GLSL_a_p0p1_ "RC" +#define GLSL_a_p0p1__raw RC +#define GLSL_a_p2p3_ "SC" +#define GLSL_a_p2p3__raw SC +#define GLSL_a_patchVertexData "LB" +#define GLSL_a_patchVertexData_raw LB +#define GLSL_a_position "SB" +#define GLSL_a_position_raw SB +#define GLSL_a_reflectionX0X1 "HD" +#define GLSL_a_reflectionX0X1_raw HD +#define GLSL_a_segmentCounts "ID" +#define GLSL_a_segmentCounts_raw ID +#define GLSL_a_span "AC" +#define GLSL_a_span_raw AC +#define GLSL_a_spanX "WC" +#define GLSL_a_spanX_raw WC +#define GLSL_a_texCoord "TB" +#define GLSL_a_texCoord_raw TB +#define GLSL_a_triangleVertex "IB" +#define GLSL_a_triangleVertex_raw IB +#define GLSL_a_x0x1 "GD" +#define GLSL_a_x0x1_raw GD +#define GLSL_a_yWithFlags "XC" +#define GLSL_a_yWithFlags_raw XC +#define GLSL_atlasFillFragmentMain "RE" +#define GLSL_atlasFillFragmentMain_raw RE +#define GLSL_atlasStrokeFragmentMain "TE" +#define GLSL_atlasStrokeFragmentMain_raw TE +#define GLSL_atlasTexture "ND" +#define GLSL_atlasTexture_raw ND +#define GLSL_atlasVertexMain "PE" +#define GLSL_atlasVertexMain_raw PE +#define GLSL_blitFragmentMain "MD" +#define GLSL_blitFragmentMain_raw MD +#define GLSL_blitVertexMain "ZD" +#define GLSL_blitVertexMain_raw ZD +#define GLSL_clearColor "SD" +#define GLSL_clearColor_raw SD +#define GLSL_colorRampFragmentMain "BE" +#define GLSL_colorRampFragmentMain_raw BE +#define GLSL_colorRampVertexMain "AE" +#define GLSL_colorRampVertexMain_raw AE +#define GLSL_contourBuffer "QC" +#define GLSL_contourBuffer_raw QC +#define GLSL_drawFragmentMain "NB" +#define GLSL_drawFragmentMain_raw NB +#define GLSL_drawVertexMain "PB" +#define GLSL_drawVertexMain_raw PB +#define GLSL_dstColorTexture "PC" +#define GLSL_dstColorTexture_raw PC +#define GLSL_featherTexture "JC" +#define GLSL_featherTexture_raw JC +#define GLSL_gradTexture "MC" +#define GLSL_gradTexture_raw MC +#define GLSL_imageTexture "UB" +#define GLSL_imageTexture_raw UB +#define GLSL_paintAuxBuffer "KB" +#define GLSL_paintAuxBuffer_raw KB +#define GLSL_paintBuffer "DC" +#define GLSL_paintBuffer_raw DC +#define GLSL_pathBuffer "JB" +#define GLSL_pathBuffer_raw JB +#define GLSL_sourceTexture "VC" +#define GLSL_sourceTexture_raw VC +#define GLSL_stencilVertexMain "UE" +#define GLSL_stencilVertexMain_raw UE +#define GLSL_tessVertexTexture "BC" +#define GLSL_tessVertexTexture_raw BC +#define GLSL_tessellateFragmentMain "WE" +#define GLSL_tessellateFragmentMain_raw WE +#define GLSL_tessellateVertexMain "VE" +#define GLSL_tessellateVertexMain_raw VE diff --git a/third_party/rive_renderer/source/generated/shaders/atomic_draw.glsl.hpp b/third_party/rive_renderer/source/generated/shaders/atomic_draw.glsl.hpp new file mode 100644 index 0000000..c123d58 --- /dev/null +++ b/third_party/rive_renderer/source/generated/shaders/atomic_draw.glsl.hpp @@ -0,0 +1,389 @@ +#pragma once + +#include "atomic_draw.exports.h" + +namespace rive { +namespace gpu { +namespace glsl { +const char atomic_draw[] = R"===(#ifdef KC +#ifdef AB +U0(f0)i0(0,f,LB);i0(1,f,MB);V0 +#endif +o1 +#ifdef EB +n0 H(0,f,D); +#else +n0 H(0,G,D); +#endif +L2 H(1,a0,j0);p1 +#ifdef AB +q1(PB,f0,B,n,K){l0(n,B,LB,f);l0(n,B,MB,f); +#ifdef EB +L(D,f); +#else +L(D,G); +#endif +L(j0,a0);f Q;uint R;c J;f O;if(E6(LB,MB,K,R,J,O Y1)){ +#ifdef EB +D=O; +#else +D.xy=F6(O.xy); +#endif +j0=Q1(R);Q=F2(J);}else{Q=f(q.C1,q.C1,q.C1,q.C1);}P(D);P(j0);h1(Q);} +#endif +#endif +#ifdef GB +#ifdef AB +U0(f0)i0(0,a4,IB);V0 +#endif +o1 +#ifdef CB +n0 H(0,c,Q0); +#else +OB H(0,g,i1); +#endif +L2 H(1,a0,j0);p1 +#ifdef AB +q1(PB,f0,B,n,K){l0(n,B,IB,Z); +#ifdef CB +L(Q0,c); +#else +L(i1,g); +#endif +L(j0,a0);uint R;c J; +#ifdef CB +J=a8(IB,R,Q0 Y1); +#else +J=c8(IB,R,i1 Y1); +#endif +j0=Q1(R);f Q=F2(J); +#ifdef CB +P(Q0); +#else +P(i1); +#endif +P(j0);h1(Q);} +#endif +#endif +#ifdef TC +#ifdef AB +U0(f0)i0(0,f,YB);V0 +#endif +o1 n0 H(0,c,q0);n0 H(1,g,c4); +#ifdef BB +n0 H(2,f,R0); +#endif +p1 +#ifdef AB +G6(PB,f0,B,n,K){l0(n,B,YB,f);L(q0,c);L(c4,g); +#ifdef BB +L(R0,f); +#endif +bool d8=YB.z==.0||YB.w==.0;c4=d8?.0:1.;c J=YB.xy;S D0=D1(m0.H6);S A5=transpose(inverse(D0));if(!d8){float e8=q3*f8(A5[1])/dot(D0[1],A5[1]);if(e8>=.5){J.x=.5;c4*=d4(.5/e8);}else{J.x+=e8*YB.z;}float g8=q3*f8(A5[0])/dot(D0[0],A5[0]);if(g8>=.5){J.y=.5;c4*=d4(.5/g8);}else{J.y+=g8*YB.w;}}q0=J;J=C0(D0,J)+m0.S0;if(d8){c e4=C0(A5,YB.zw);e4*=f8(e4)/dot(e4,e4);J+=q3*e4;} +#ifdef BB +if(BB){R0=I6(D1(m0.R1),m0.Z1,J);} +#endif +f Q=F2(J);P(q0);P(c4); +#ifdef BB +P(R0); +#endif +h1(Q);} +#endif +#elif defined(UD) +#ifdef AB +U0(a2)i0(0,c,SB);V0 U0(v2)i0(1,c,TB);V0 +#endif +o1 n0 H(0,c,q0); +#ifdef BB +n0 H(1,f,R0); +#endif +p1 +#ifdef AB +N4(PB,a2,c2,v2,w2,n){l0(n,c2,SB,c);l0(n,w2,TB,c);L(q0,c); +#ifdef BB +L(R0,f); +#endif +S D0=D1(m0.H6);c J=C0(D0,SB)+m0.S0;q0=TB; +#ifdef BB +if(BB){R0=I6(D1(m0.R1),m0.Z1,J);} +#endif +f Q=F2(J);P(q0); +#ifdef BB +P(R0); +#endif +h1(Q);} +#endif +#endif +#ifdef VD +#ifdef AB +U0(f0)V0 +#endif +o1 p1 +#ifdef AB +q1(PB,f0,B,n,K){c0 S1;S1.x=(n&1)==0?q.J6.x:q.J6.z;S1.y=(n&2)==0?q.J6.y:q.J6.w;f Q=F2(c(S1));h1(Q);} +#endif +#endif +#ifdef UC +#endif +#ifdef HB +x2 +#ifndef QB +#ifdef LD +#define h8 LD +#else +#define h8 i8 +#endif +#ifdef LC +O4(h8,H0); +#else +M0(h8,H0); +#endif +#endif +#ifdef ZB +#define r3 i +#define j8 I0 +#define K6 E1(.0) +#define V9(m) ((m).w!=.0) +#ifdef T +#ifndef HC +M0(B5,r1); +#else +O4(B5,r1); +#endif +#endif +#else +#define r3 uint +#define K6 0u +#define j8 j1 +#define V9(m) ((m)!=0u) +#ifdef T +Y0(B5,r1); +#endif +#endif +f4(k8,v3);y2 w3 g4(l8,W9,DC);h4(m8,X9,KB);x3 d uint Jc(float x){return uint(round(x*n8+o8));}d g L6(uint x){return d4(float(x)*Y9+(-o8*Y9));} +#ifdef T +d void Z9(uint Z0,r3 I1,i4(g)E){ +#ifdef ZB +if(all(lessThan(abs(I1.xy-unpackUnorm4x8(Z0).xy),Z3(.25/255.))))E=min(E,I1.z);else E=.0; +#else +if(Z0==I1>>16)E=min(E,unpackHalf2x16(I1).x);else E=.0; +#endif +} +#endif +d void M6(uint R,g F1,k1(i)U +#if defined(T)&&!defined(HC) +,i4(r3)a1 +#endif +C5 y3){N0 F0=k4(DC,R);g E=F1;if((F0.x&(Kc|p8))!=0u){E=abs(E); +#ifdef IC +if(IC&&(F0.x&p8)!=0u){E=1.-abs(fract(E*.5)*2.+-1.);} +#endif +}E=clamp(E,v1(.0),v1(1.)); +#ifdef T +if(T){uint Z0=F0.x>>16u;if(Z0!=0u){Z9(Z0,j8(r1),E);}} +#endif +#ifdef BB +if(BB&&(F0.x&Lc)!=0u){S D0=D1(w0(KB,R*4u+2u));f S0=w0(KB,R*4u+3u);c Mc=C0(D0,y0)+S0.xy;G aa=F6(abs(Mc)*S0.zw-S0.zw);g l4=clamp(min(aa.x,aa.y)+.5,.0,1.);E=min(E,l4);} +#endif +uint J1=F0.x&0xfu;if(J1<=q8){U=unpackUnorm4x8(F0.y); +#ifdef T +if(T&&J1==N6){ +#ifndef HC +#ifdef ZB +a1.xy=U.zw;a1.z=E;a1.w=1.; +#else +a1=F0.y|packHalf2x16(Z3(E,.0)); +#endif +#endif +U=E1(.0);} +#endif +}else{S D0=D1(w0(KB,R*4u));f S0=w0(KB,R*4u+1u);c G2=C0(D0,y0)+S0.xy;float t=J1==O6?G2.x:length(G2);t=clamp(t,.0,1.);float x=t*S0.z+S0.w;float y=uintBitsToFloat(F0.y);U=T1(MC,r8,c(x,y),.0);}U.w*=E; +#if!defined(QB)&&defined(FB) +a0 z3;if(FB&&U.w!=.0&&(z3=Q1((F0.x>>4)&0xfu))!=0u){i w1=I0(H0);U.xyz=M4(U.xyz,w1,z3);} +#endif +#ifndef ZB +U.xyz*=U.w; +#endif +} +#if!defined(QB)&&!defined(LC) +d void P6(i U y3){ +#ifndef ZB +if(U.w==.0)return;float D5=1.-U.w;if(D5!=.0)U+=I0(H0)*D5; +#endif +T0(H0,U);} +#endif +#if defined(T)&&!defined(HC) +d void v8(r3 a1 y3){ +#ifdef ZB +T0(r1,a1); +#else +if(a1!=0u)l1(r1,a1); +#endif +} +#endif +#ifdef QB +#define E5 A3 +#define ca F5 +#define Q4 P4 +#else +#define E5 z2 +#define ca R4 +#define Q4 M2 +#endif +#ifdef KC +E5(NB){ +#ifdef EB +N(D,f); +#else +N(D,G); +#endif +N(j0,a0);g Q6; +#ifdef EB +if(EB&&w8(D)){Q6=R6(D x1);}else if(EB&&S6(D)){Q6=S4(D x1);}else +#endif +{Q6=min(min(v1(D.x),abs(v1(D.y))),v1(1.));}i U=E1(.0); +#ifdef T +r3 a1=K6; +#endif +uint T6=Jc(Q6);uint da=(ea(j0)<>T4);if(N2==j0){if(!U6(D)){T6+=U1-max(da,U1);T6-=x8;H5(v3,T6);}}else{g F1=L6(U1&V6);M6(N2,F1,U +#ifdef T +,a1 +#endif +Y2 G1);} +#ifdef QB +K1=U; +#else +P6(U G1); +#endif +#ifdef T +v8(a1 G1); +#endif +Q4} +#endif +#ifdef GB +E5(NB){ +#ifdef CB +N(Q0,c); +#else +N(i1,g); +#endif +N(j0,a0);uint U1=m4(v3);a0 N2=Q1(U1>>T4);uint y8; +#ifndef CB +if(N2==j0){y8=U1;}else +#endif +{y8=(ea(j0)<>T4);g z8=L6(U1&V6);i U; +#ifdef T +r3 a1=K6; +#endif +M6(N2,z8,U +#ifdef T +,a1 +#endif +Y2 G1); +#ifdef ZB +U.xyz*=U.w; +#endif +#ifdef T +if(T&&m0.Z0!=0u){r3 I1=V9(a1)?a1:j8(r1);Z9(m0.Z0,I1,W4);} +#endif +#if!defined(QB)&&defined(FB) +if(FB&&m0.z3!=B8){i w1=I0(H0)*(1.-U.w)+U;V4.xyz=M4(Y3(V4),w1,Q1(m0.z3))*V4.w;} +#endif +V4*=W4*d4(m0.H2);U=U*(1.-V4.w)+V4; +#ifdef QB +K1=U; +#else +P6(U G1); +#endif +#ifdef T +v8(a1 G1); +#endif +n4(v3,x8);Q4} +#endif +#ifdef WD +E5(NB){ +#ifdef XD +T0(H0,unpackUnorm4x8(q.Oc)); +#endif +#ifdef YD +i j=I0(H0);T0(H0,j.zyxw); +#endif +n4(v3,q.Pc); +#ifdef T +if(T){l1(r1,0u);} +#endif +#ifdef QB +discard; +#endif +Q4} +#endif +#ifdef HC +#ifdef LC +A3(NB) +#else +E5(NB) +#endif +{uint U1=m4(v3);g F1=L6(U1&V6);a0 N2=Q1(U1>>T4);i U;M6(N2,F1,U Y2 G1); +#ifdef LC +#ifdef ZB +U.xyz*=U.w; +#endif +float D5=1.-U.w;if(D5!=.0)U+=I0(H0)*D5;K1=U;P4 +#else +#ifdef QB +K1=U; +#else +P6(U G1); +#endif +Q4 +#endif +} +#endif +#endif +)==="; +} // namespace glsl +} // namespace gpu +} // namespace rive \ No newline at end of file diff --git a/third_party/rive_renderer/source/generated/shaders/atomic_draw.minified.glsl b/third_party/rive_renderer/source/generated/shaders/atomic_draw.minified.glsl new file mode 100644 index 0000000..107cf0c --- /dev/null +++ b/third_party/rive_renderer/source/generated/shaders/atomic_draw.minified.glsl @@ -0,0 +1,378 @@ +#ifdef DRAW_PATH +#ifdef VERTEX +U0(f0)i0(0,f,LB);i0(1,f,MB);V0 +#endif +o1 +#ifdef ENABLE_FEATHER +n0 H(0,f,D); +#else +n0 H(0,G,D); +#endif +L2 H(1,a0,j0);p1 +#ifdef VERTEX +q1(PB,f0,B,n,K){l0(n,B,LB,f);l0(n,B,MB,f); +#ifdef ENABLE_FEATHER +L(D,f); +#else +L(D,G); +#endif +L(j0,a0);f Q;uint R;c J;f O;if(E6(LB,MB,K,R,J,O Y1)){ +#ifdef ENABLE_FEATHER +D=O; +#else +D.xy=F6(O.xy); +#endif +j0=Q1(R);Q=F2(J);}else{Q=f(q.C1,q.C1,q.C1,q.C1);}P(D);P(j0);h1(Q);} +#endif +#endif +#ifdef DRAW_INTERIOR_TRIANGLES +#ifdef VERTEX +U0(f0)i0(0,a4,IB);V0 +#endif +o1 +#ifdef ATLAS_BLIT +n0 H(0,c,Q0); +#else +OPTIONALLY_FLAT H(0,g,i1); +#endif +L2 H(1,a0,j0);p1 +#ifdef VERTEX +q1(PB,f0,B,n,K){l0(n,B,IB,Z); +#ifdef ATLAS_BLIT +L(Q0,c); +#else +L(i1,g); +#endif +L(j0,a0);uint R;c J; +#ifdef ATLAS_BLIT +J=a8(IB,R,Q0 Y1); +#else +J=c8(IB,R,i1 Y1); +#endif +j0=Q1(R);f Q=F2(J); +#ifdef ATLAS_BLIT +P(Q0); +#else +P(i1); +#endif +P(j0);h1(Q);} +#endif +#endif +#ifdef DRAW_IMAGE_RECT +#ifdef VERTEX +U0(f0)i0(0,f,YB);V0 +#endif +o1 n0 H(0,c,q0);n0 H(1,g,c4); +#ifdef ENABLE_CLIP_RECT +n0 H(2,f,R0); +#endif +p1 +#ifdef VERTEX +G6(PB,f0,B,n,K){l0(n,B,YB,f);L(q0,c);L(c4,g); +#ifdef ENABLE_CLIP_RECT +L(R0,f); +#endif +bool d8=YB.z==.0||YB.w==.0;c4=d8?.0:1.;c J=YB.xy;S D0=D1(m0.H6);S A5=transpose(inverse(D0));if(!d8){float e8=q3*f8(A5[1])/dot(D0[1],A5[1]);if(e8>=.5){J.x=.5;c4*=d4(.5/e8);}else{J.x+=e8*YB.z;}float g8=q3*f8(A5[0])/dot(D0[0],A5[0]);if(g8>=.5){J.y=.5;c4*=d4(.5/g8);}else{J.y+=g8*YB.w;}}q0=J;J=C0(D0,J)+m0.S0;if(d8){c e4=C0(A5,YB.zw);e4*=f8(e4)/dot(e4,e4);J+=q3*e4;} +#ifdef ENABLE_CLIP_RECT +if(ENABLE_CLIP_RECT){R0=I6(D1(m0.R1),m0.Z1,J);} +#endif +f Q=F2(J);P(q0);P(c4); +#ifdef ENABLE_CLIP_RECT +P(R0); +#endif +h1(Q);} +#endif +#elif defined(DRAW_IMAGE_MESH) +#ifdef VERTEX +U0(a2)i0(0,c,SB);V0 U0(v2)i0(1,c,TB);V0 +#endif +o1 n0 H(0,c,q0); +#ifdef ENABLE_CLIP_RECT +n0 H(1,f,R0); +#endif +p1 +#ifdef VERTEX +N4(PB,a2,c2,v2,w2,n){l0(n,c2,SB,c);l0(n,w2,TB,c);L(q0,c); +#ifdef ENABLE_CLIP_RECT +L(R0,f); +#endif +S D0=D1(m0.H6);c J=C0(D0,SB)+m0.S0;q0=TB; +#ifdef ENABLE_CLIP_RECT +if(ENABLE_CLIP_RECT){R0=I6(D1(m0.R1),m0.Z1,J);} +#endif +f Q=F2(J);P(q0); +#ifdef ENABLE_CLIP_RECT +P(R0); +#endif +h1(Q);} +#endif +#endif +#ifdef DRAW_RENDER_TARGET_UPDATE_BOUNDS +#ifdef VERTEX +U0(f0)V0 +#endif +o1 p1 +#ifdef VERTEX +q1(PB,f0,B,n,K){c0 S1;S1.x=(n&1)==0?q.J6.x:q.J6.z;S1.y=(n&2)==0?q.J6.y:q.J6.w;f Q=F2(c(S1));h1(Q);} +#endif +#endif +#ifdef DRAW_IMAGE +#endif +#ifdef FRAGMENT +x2 +#ifndef FIXED_FUNCTION_COLOR_OUTPUT +#ifdef COLOR_PLANE_IDX_OVERRIDE +#define h8 COLOR_PLANE_IDX_OVERRIDE +#else +#define h8 i8 +#endif +#ifdef COALESCED_PLS_RESOLVE_AND_TRANSFER +O4(h8,H0); +#else +M0(h8,H0); +#endif +#endif +#ifdef PLS_BLEND_SRC_OVER +#define r3 i +#define j8 I0 +#define K6 E1(.0) +#define V9(m) ((m).w!=.0) +#ifdef ENABLE_CLIPPING +#ifndef RESOLVE_PLS +M0(B5,r1); +#else +O4(B5,r1); +#endif +#endif +#else +#define r3 uint +#define K6 0u +#define j8 j1 +#define V9(m) ((m)!=0u) +#ifdef ENABLE_CLIPPING +Y0(B5,r1); +#endif +#endif +f4(k8,v3);y2 w3 g4(l8,W9,DC);h4(m8,X9,KB);x3 d uint Jc(float x){return uint(round(x*n8+o8));}d g L6(uint x){return d4(float(x)*Y9+(-o8*Y9));} +#ifdef ENABLE_CLIPPING +d void Z9(uint Z0,r3 I1,i4(g)E){ +#ifdef PLS_BLEND_SRC_OVER +if(all(lessThan(abs(I1.xy-unpackUnorm4x8(Z0).xy),Z3(.25/255.))))E=min(E,I1.z);else E=.0; +#else +if(Z0==I1>>16)E=min(E,unpackHalf2x16(I1).x);else E=.0; +#endif +} +#endif +d void M6(uint R,g F1,k1(i)U +#if defined(ENABLE_CLIPPING)&&!defined(RESOLVE_PLS) +,i4(r3)a1 +#endif +C5 y3){N0 F0=k4(DC,R);g E=F1;if((F0.x&(Kc|p8))!=0u){E=abs(E); +#ifdef ENABLE_EVEN_ODD +if(ENABLE_EVEN_ODD&&(F0.x&p8)!=0u){E=1.-abs(fract(E*.5)*2.+-1.);} +#endif +}E=clamp(E,v1(.0),v1(1.)); +#ifdef ENABLE_CLIPPING +if(ENABLE_CLIPPING){uint Z0=F0.x>>16u;if(Z0!=0u){Z9(Z0,j8(r1),E);}} +#endif +#ifdef ENABLE_CLIP_RECT +if(ENABLE_CLIP_RECT&&(F0.x&Lc)!=0u){S D0=D1(w0(KB,R*4u+2u));f S0=w0(KB,R*4u+3u);c Mc=C0(D0,y0)+S0.xy;G aa=F6(abs(Mc)*S0.zw-S0.zw);g l4=clamp(min(aa.x,aa.y)+.5,.0,1.);E=min(E,l4);} +#endif +uint J1=F0.x&0xfu;if(J1<=q8){U=unpackUnorm4x8(F0.y); +#ifdef ENABLE_CLIPPING +if(ENABLE_CLIPPING&&J1==N6){ +#ifndef RESOLVE_PLS +#ifdef PLS_BLEND_SRC_OVER +a1.xy=U.zw;a1.z=E;a1.w=1.; +#else +a1=F0.y|packHalf2x16(Z3(E,.0)); +#endif +#endif +U=E1(.0);} +#endif +}else{S D0=D1(w0(KB,R*4u));f S0=w0(KB,R*4u+1u);c G2=C0(D0,y0)+S0.xy;float t=J1==O6?G2.x:length(G2);t=clamp(t,.0,1.);float x=t*S0.z+S0.w;float y=uintBitsToFloat(F0.y);U=T1(MC,r8,c(x,y),.0);}U.w*=E; +#if!defined(FIXED_FUNCTION_COLOR_OUTPUT)&&defined(ENABLE_ADVANCED_BLEND) +a0 z3;if(ENABLE_ADVANCED_BLEND&&U.w!=.0&&(z3=Q1((F0.x>>4)&0xfu))!=0u){i w1=I0(H0);U.xyz=M4(U.xyz,w1,z3);} +#endif +#ifndef PLS_BLEND_SRC_OVER +U.xyz*=U.w; +#endif +} +#if!defined(FIXED_FUNCTION_COLOR_OUTPUT)&&!defined(COALESCED_PLS_RESOLVE_AND_TRANSFER) +d void P6(i U y3){ +#ifndef PLS_BLEND_SRC_OVER +if(U.w==.0)return;float D5=1.-U.w;if(D5!=.0)U+=I0(H0)*D5; +#endif +T0(H0,U);} +#endif +#if defined(ENABLE_CLIPPING)&&!defined(RESOLVE_PLS) +d void v8(r3 a1 y3){ +#ifdef PLS_BLEND_SRC_OVER +T0(r1,a1); +#else +if(a1!=0u)l1(r1,a1); +#endif +} +#endif +#ifdef FIXED_FUNCTION_COLOR_OUTPUT +#define E5 A3 +#define ca F5 +#define Q4 P4 +#else +#define E5 z2 +#define ca R4 +#define Q4 M2 +#endif +#ifdef DRAW_PATH +E5(NB){ +#ifdef ENABLE_FEATHER +N(D,f); +#else +N(D,G); +#endif +N(j0,a0);g Q6; +#ifdef ENABLE_FEATHER +if(ENABLE_FEATHER&&w8(D)){Q6=R6(D x1);}else if(ENABLE_FEATHER&&S6(D)){Q6=S4(D x1);}else +#endif +{Q6=min(min(v1(D.x),abs(v1(D.y))),v1(1.));}i U=E1(.0); +#ifdef ENABLE_CLIPPING +r3 a1=K6; +#endif +uint T6=Jc(Q6);uint da=(ea(j0)<>T4);if(N2==j0){if(!U6(D)){T6+=U1-max(da,U1);T6-=x8;H5(v3,T6);}}else{g F1=L6(U1&V6);M6(N2,F1,U +#ifdef ENABLE_CLIPPING +,a1 +#endif +Y2 G1);} +#ifdef FIXED_FUNCTION_COLOR_OUTPUT +K1=U; +#else +P6(U G1); +#endif +#ifdef ENABLE_CLIPPING +v8(a1 G1); +#endif +Q4} +#endif +#ifdef DRAW_INTERIOR_TRIANGLES +E5(NB){ +#ifdef ATLAS_BLIT +N(Q0,c); +#else +N(i1,g); +#endif +N(j0,a0);uint U1=m4(v3);a0 N2=Q1(U1>>T4);uint y8; +#ifndef ATLAS_BLIT +if(N2==j0){y8=U1;}else +#endif +{y8=(ea(j0)<>T4);g z8=L6(U1&V6);i U; +#ifdef ENABLE_CLIPPING +r3 a1=K6; +#endif +M6(N2,z8,U +#ifdef ENABLE_CLIPPING +,a1 +#endif +Y2 G1); +#ifdef PLS_BLEND_SRC_OVER +U.xyz*=U.w; +#endif +#ifdef ENABLE_CLIPPING +if(ENABLE_CLIPPING&&m0.Z0!=0u){r3 I1=V9(a1)?a1:j8(r1);Z9(m0.Z0,I1,W4);} +#endif +#if!defined(FIXED_FUNCTION_COLOR_OUTPUT)&&defined(ENABLE_ADVANCED_BLEND) +if(ENABLE_ADVANCED_BLEND&&m0.z3!=B8){i w1=I0(H0)*(1.-U.w)+U;V4.xyz=M4(Y3(V4),w1,Q1(m0.z3))*V4.w;} +#endif +V4*=W4*d4(m0.H2);U=U*(1.-V4.w)+V4; +#ifdef FIXED_FUNCTION_COLOR_OUTPUT +K1=U; +#else +P6(U G1); +#endif +#ifdef ENABLE_CLIPPING +v8(a1 G1); +#endif +n4(v3,x8);Q4} +#endif +#ifdef INITIALIZE_PLS +E5(NB){ +#ifdef STORE_COLOR_CLEAR +T0(H0,unpackUnorm4x8(q.Oc)); +#endif +#ifdef SWIZZLE_COLOR_BGRA_TO_RGBA +i j=I0(H0);T0(H0,j.zyxw); +#endif +n4(v3,q.Pc); +#ifdef ENABLE_CLIPPING +if(ENABLE_CLIPPING){l1(r1,0u);} +#endif +#ifdef FIXED_FUNCTION_COLOR_OUTPUT +discard; +#endif +Q4} +#endif +#ifdef RESOLVE_PLS +#ifdef COALESCED_PLS_RESOLVE_AND_TRANSFER +A3(NB) +#else +E5(NB) +#endif +{uint U1=m4(v3);g F1=L6(U1&V6);a0 N2=Q1(U1>>T4);i U;M6(N2,F1,U Y2 G1); +#ifdef COALESCED_PLS_RESOLVE_AND_TRANSFER +#ifdef PLS_BLEND_SRC_OVER +U.xyz*=U.w; +#endif +float D5=1.-U.w;if(D5!=.0)U+=I0(H0)*D5;K1=U;P4 +#else +#ifdef FIXED_FUNCTION_COLOR_OUTPUT +K1=U; +#else +P6(U G1); +#endif +Q4 +#endif +} +#endif +#endif diff --git a/third_party/rive_renderer/source/generated/shaders/bezier_utils.exports.h b/third_party/rive_renderer/source/generated/shaders/bezier_utils.exports.h new file mode 100644 index 0000000..7d86e26 --- /dev/null +++ b/third_party/rive_renderer/source/generated/shaders/bezier_utils.exports.h @@ -0,0 +1,208 @@ +#pragma once + +#define GLSL_ATLAS_BLIT "CB" +#define GLSL_ATLAS_BLIT_raw CB +#define GLSL_ATLAS_FEATHERED_FILL "QE" +#define GLSL_ATLAS_FEATHERED_FILL_raw QE +#define GLSL_ATLAS_FEATHERED_STROKE "SE" +#define GLSL_ATLAS_FEATHERED_STROKE_raw SE +#define GLSL_BASE_INSTANCE_UNIFORM_NAME "ED" +#define GLSL_BASE_INSTANCE_UNIFORM_NAME_raw ED +#define GLSL_BORROWED_COVERAGE_PREPASS "OC" +#define GLSL_BORROWED_COVERAGE_PREPASS_raw OC +#define GLSL_CLEAR_CLIP "OE" +#define GLSL_CLEAR_CLIP_raw OE +#define GLSL_CLEAR_COLOR "RD" +#define GLSL_CLEAR_COLOR_raw RD +#define GLSL_CLEAR_COVERAGE "NE" +#define GLSL_CLEAR_COVERAGE_raw NE +#define GLSL_CLOCKWISE_FILL "AD" +#define GLSL_CLOCKWISE_FILL_raw AD +#define GLSL_COALESCED_PLS_RESOLVE_AND_TRANSFER "LC" +#define GLSL_COALESCED_PLS_RESOLVE_AND_TRANSFER_raw LC +#define GLSL_COLOR_PLANE_IDX_OVERRIDE "LD" +#define GLSL_COLOR_PLANE_IDX_OVERRIDE_raw LD +#define GLSL_DISABLE_SHADER_STORAGE_BUFFERS "FE" +#define GLSL_DISABLE_SHADER_STORAGE_BUFFERS_raw FE +#define GLSL_DRAW_IMAGE "UC" +#define GLSL_DRAW_IMAGE_raw UC +#define GLSL_DRAW_IMAGE_MESH "UD" +#define GLSL_DRAW_IMAGE_MESH_raw UD +#define GLSL_DRAW_IMAGE_RECT "TC" +#define GLSL_DRAW_IMAGE_RECT_raw TC +#define GLSL_DRAW_INTERIOR_TRIANGLES "GB" +#define GLSL_DRAW_INTERIOR_TRIANGLES_raw GB +#define GLSL_DRAW_PATH "KC" +#define GLSL_DRAW_PATH_raw KC +#define GLSL_DRAW_RENDER_TARGET_UPDATE_BOUNDS "VD" +#define GLSL_DRAW_RENDER_TARGET_UPDATE_BOUNDS_raw VD +#define GLSL_ENABLE_ADVANCED_BLEND "FB" +#define GLSL_ENABLE_ADVANCED_BLEND_raw FB +#define GLSL_ENABLE_CLIPPING "T" +#define GLSL_ENABLE_CLIPPING_raw T +#define GLSL_ENABLE_CLIP_RECT "BB" +#define GLSL_ENABLE_CLIP_RECT_raw BB +#define GLSL_ENABLE_EVEN_ODD "IC" +#define GLSL_ENABLE_EVEN_ODD_raw IC +#define GLSL_ENABLE_FEATHER "EB" +#define GLSL_ENABLE_FEATHER_raw EB +#define GLSL_ENABLE_HSL_BLEND_MODES "XB" +#define GLSL_ENABLE_HSL_BLEND_MODES_raw XB +#define GLSL_ENABLE_INSTANCE_INDEX "OD" +#define GLSL_ENABLE_INSTANCE_INDEX_raw OD +#define GLSL_ENABLE_KHR_BLEND "KD" +#define GLSL_ENABLE_KHR_BLEND_raw KD +#define GLSL_ENABLE_MIN_16_PRECISION "PD" +#define GLSL_ENABLE_MIN_16_PRECISION_raw PD +#define GLSL_ENABLE_NESTED_CLIPPING "CD" +#define GLSL_ENABLE_NESTED_CLIPPING_raw CD +#define GLSL_ENABLE_RASTERIZER_ORDERED_VIEWS "QD" +#define GLSL_ENABLE_RASTERIZER_ORDERED_VIEWS_raw QD +#define GLSL_ENABLE_TYPED_UAV_LOAD_STORE "FC" +#define GLSL_ENABLE_TYPED_UAV_LOAD_STORE_raw FC +#define GLSL_FIXED_FUNCTION_COLOR_OUTPUT "QB" +#define GLSL_FIXED_FUNCTION_COLOR_OUTPUT_raw QB +#define GLSL_FRAGMENT "HB" +#define GLSL_FRAGMENT_raw HB +#define GLSL_FRAMEBUFFER_BOTTOM_UP "DE" +#define GLSL_FRAMEBUFFER_BOTTOM_UP_raw DE +#define GLSL_FlushUniforms "VB" +#define GLSL_FlushUniforms_raw VB +#define GLSL_GLSL_VERSION "WB" +#define GLSL_GLSL_VERSION_raw WB +#define GLSL_INITIALIZE_PLS "WD" +#define GLSL_INITIALIZE_PLS_raw WD +#define GLSL_ImageDrawUniforms "EC" +#define GLSL_ImageDrawUniforms_raw EC +#define GLSL_LOAD_COLOR "TD" +#define GLSL_LOAD_COLOR_raw TD +#define GLSL_OPTIONALLY_FLAT "OB" +#define GLSL_OPTIONALLY_FLAT_raw OB +#define GLSL_PLS_BLEND_SRC_OVER "ZB" +#define GLSL_PLS_BLEND_SRC_OVER_raw ZB +#define GLSL_PLS_IMPL_ANGLE "_EXPORTED_PLS_IMPL_ANGLE" +#define GLSL_PLS_IMPL_ANGLE_raw _EXPORTED_PLS_IMPL_ANGLE +#define GLSL_PLS_IMPL_DEVICE_BUFFER "LE" +#define GLSL_PLS_IMPL_DEVICE_BUFFER_raw LE +#define GLSL_PLS_IMPL_DEVICE_BUFFER_RASTER_ORDERED "ME" +#define GLSL_PLS_IMPL_DEVICE_BUFFER_RASTER_ORDERED_raw ME +#define GLSL_PLS_IMPL_EXT_NATIVE "GE" +#define GLSL_PLS_IMPL_EXT_NATIVE_raw GE +#define GLSL_PLS_IMPL_FRAMEBUFFER_FETCH "HE" +#define GLSL_PLS_IMPL_FRAMEBUFFER_FETCH_raw HE +#define GLSL_PLS_IMPL_NONE "KE" +#define GLSL_PLS_IMPL_NONE_raw KE +#define GLSL_PLS_IMPL_STORAGE_TEXTURE "IE" +#define GLSL_PLS_IMPL_STORAGE_TEXTURE_raw IE +#define GLSL_PLS_IMPL_SUBPASS_LOAD "JE" +#define GLSL_PLS_IMPL_SUBPASS_LOAD_raw JE +#define GLSL_POST_INVERT_Y "EE" +#define GLSL_POST_INVERT_Y_raw EE +#define GLSL_RENDER_MODE_MSAA "DB" +#define GLSL_RENDER_MODE_MSAA_raw DB +#define GLSL_RESOLVE_PLS "HC" +#define GLSL_RESOLVE_PLS_raw HC +#define GLSL_STORE_COLOR "FD" +#define GLSL_STORE_COLOR_raw FD +#define GLSL_STORE_COLOR_CLEAR "XD" +#define GLSL_STORE_COLOR_CLEAR_raw XD +#define GLSL_SWIZZLE_COLOR_BGRA_TO_RGBA "YD" +#define GLSL_SWIZZLE_COLOR_BGRA_TO_RGBA_raw YD +#define GLSL_TARGET_VULKAN "CC" +#define GLSL_TARGET_VULKAN_raw CC +#define GLSL_TESS_TEXTURE_FLOATING_POINT "CE" +#define GLSL_TESS_TEXTURE_FLOATING_POINT_raw CE +#define GLSL_USE_TEXEL_FETCH_WITH_FRAG_COORD "NC" +#define GLSL_USE_TEXEL_FETCH_WITH_FRAG_COORD_raw NC +#define GLSL_USING_PLS_STORAGE_TEXTURES "DD" +#define GLSL_USING_PLS_STORAGE_TEXTURES_raw DD +#define GLSL_VERTEX "AB" +#define GLSL_VERTEX_raw AB +#define GLSL_VULKAN_VENDOR_ID "BD" +#define GLSL_VULKAN_VENDOR_ID_raw BD +#define GLSL_a_args "RB" +#define GLSL_a_args_raw RB +#define GLSL_a_color0 "YC" +#define GLSL_a_color0_raw YC +#define GLSL_a_color1 "ZC" +#define GLSL_a_color1_raw ZC +#define GLSL_a_contourIDWithFlags "JD" +#define GLSL_a_contourIDWithFlags_raw JD +#define GLSL_a_imageRectVertex "YB" +#define GLSL_a_imageRectVertex_raw YB +#define GLSL_a_joinTan_and_ys "GC" +#define GLSL_a_joinTan_and_ys_raw GC +#define GLSL_a_mirroredVertexData "MB" +#define GLSL_a_mirroredVertexData_raw MB +#define GLSL_a_p0p1_ "RC" +#define GLSL_a_p0p1__raw RC +#define GLSL_a_p2p3_ "SC" +#define GLSL_a_p2p3__raw SC +#define GLSL_a_patchVertexData "LB" +#define GLSL_a_patchVertexData_raw LB +#define GLSL_a_position "SB" +#define GLSL_a_position_raw SB +#define GLSL_a_reflectionX0X1 "HD" +#define GLSL_a_reflectionX0X1_raw HD +#define GLSL_a_segmentCounts "ID" +#define GLSL_a_segmentCounts_raw ID +#define GLSL_a_span "AC" +#define GLSL_a_span_raw AC +#define GLSL_a_spanX "WC" +#define GLSL_a_spanX_raw WC +#define GLSL_a_texCoord "TB" +#define GLSL_a_texCoord_raw TB +#define GLSL_a_triangleVertex "IB" +#define GLSL_a_triangleVertex_raw IB +#define GLSL_a_x0x1 "GD" +#define GLSL_a_x0x1_raw GD +#define GLSL_a_yWithFlags "XC" +#define GLSL_a_yWithFlags_raw XC +#define GLSL_atlasFillFragmentMain "RE" +#define GLSL_atlasFillFragmentMain_raw RE +#define GLSL_atlasStrokeFragmentMain "TE" +#define GLSL_atlasStrokeFragmentMain_raw TE +#define GLSL_atlasTexture "ND" +#define GLSL_atlasTexture_raw ND +#define GLSL_atlasVertexMain "PE" +#define GLSL_atlasVertexMain_raw PE +#define GLSL_blitFragmentMain "MD" +#define GLSL_blitFragmentMain_raw MD +#define GLSL_blitVertexMain "ZD" +#define GLSL_blitVertexMain_raw ZD +#define GLSL_clearColor "SD" +#define GLSL_clearColor_raw SD +#define GLSL_colorRampFragmentMain "BE" +#define GLSL_colorRampFragmentMain_raw BE +#define GLSL_colorRampVertexMain "AE" +#define GLSL_colorRampVertexMain_raw AE +#define GLSL_contourBuffer "QC" +#define GLSL_contourBuffer_raw QC +#define GLSL_drawFragmentMain "NB" +#define GLSL_drawFragmentMain_raw NB +#define GLSL_drawVertexMain "PB" +#define GLSL_drawVertexMain_raw PB +#define GLSL_dstColorTexture "PC" +#define GLSL_dstColorTexture_raw PC +#define GLSL_featherTexture "JC" +#define GLSL_featherTexture_raw JC +#define GLSL_gradTexture "MC" +#define GLSL_gradTexture_raw MC +#define GLSL_imageTexture "UB" +#define GLSL_imageTexture_raw UB +#define GLSL_paintAuxBuffer "KB" +#define GLSL_paintAuxBuffer_raw KB +#define GLSL_paintBuffer "DC" +#define GLSL_paintBuffer_raw DC +#define GLSL_pathBuffer "JB" +#define GLSL_pathBuffer_raw JB +#define GLSL_sourceTexture "VC" +#define GLSL_sourceTexture_raw VC +#define GLSL_stencilVertexMain "UE" +#define GLSL_stencilVertexMain_raw UE +#define GLSL_tessVertexTexture "BC" +#define GLSL_tessVertexTexture_raw BC +#define GLSL_tessellateFragmentMain "WE" +#define GLSL_tessellateFragmentMain_raw WE +#define GLSL_tessellateVertexMain "VE" +#define GLSL_tessellateVertexMain_raw VE diff --git a/third_party/rive_renderer/source/generated/shaders/bezier_utils.glsl.hpp b/third_party/rive_renderer/source/generated/shaders/bezier_utils.glsl.hpp new file mode 100644 index 0000000..9bcd819 --- /dev/null +++ b/third_party/rive_renderer/source/generated/shaders/bezier_utils.glsl.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include "bezier_utils.exports.h" + +namespace rive { +namespace gpu { +namespace glsl { +const char bezier_utils[] = R"===(#ifndef fa +#define fa f +#endif +#ifndef J5 +#define J5 c +#endif +d float C8(c k,c b){float Qc=dot(k,b);float ga=dot(k,k)*dot(b,b);return(ga==.0)?1.:clamp(Qc*inversesqrt(ga),-1.,1.);}d void Rc(c o0,c p0,c x0,c z0,k1(c)o,k1(c)r,k1(c)L1){L1=p0-o0;c K5=x0-p0;c X6=z0-o0;r=K5-L1;o=-3.*K5+X6;}d S D8(c o0,c p0,c x0,c z0){S t;t[0]=(any(notEqual(o0,p0))?p0:any(notEqual(p0,x0))?x0:z0)-o0;t[1]=z0-(any(notEqual(z0,x0))?x0:any(notEqual(x0,p0))?p0:o0);return t;}d float Sc(c o0,c p0,c x0,c z0,float c1,float Tc){c o,r,L1;Rc(o0,p0,x0,z0,o,r,L1);c L5=3.*(((o*c1)+2.*r)*c1+L1);float ha=length(L5);if(ha==.0){return.0;}L5*=1./ha;float Y6=2.*dot(o,L5);float M5=3.*(Y6*c1+4.*dot(r,L5))*c1+6.*dot(L1,L5);float E8=min(c1,1.-c1);float Uc=(Y6*E8*E8+M5)*E8;float ia=min(Tc,Uc*.9999);float A2;if(Y6==.0){A2=ia/M5;}else{float d0=1./Y6;float b=M5*d0,B0=-ia*d0;float N5=(-1./3.)*b,O5=.5*B0;float ja=O5*O5-N5*N5*N5;if(ja<.0){float Z6=sqrt(N5);float O0=acos(O5/(Z6*Z6*Z6));A2=-2.*Z6*cos(O0*(1./3.)+(-O2*2./3.));}else{float o=pow(abs(O5)+sqrt(ja),1./3.);if(O5<.0)o=-o;A2=o!=.0?o+N5/o:.0;}}A2=abs(A2);f t0011=c1+fa(-A2,-A2,A2,A2);f ka=(o.xyxy*t0011+2.*r.xyxy)*t0011+L1.xyxy;S d2=D8(o0,p0,x0,z0);c Vc=t0011.x<1e-3?d2[0]:ka.xy;c Wc=t0011.z>1.-1e-3?d2[1]:ka.zw;return acos(C8(Vc,Wc));}d float a7(float k,float b){k=b<.0?-k:k;b=abs(b);return k>.0?(kX4.y?P5.x:P5.y;return max(X4.x,X4.y); +#else +float pa=3.*D3;float r=-C3-D3;float L1=C3;float t=.5;for(int C=0;C<3;++C){float qa=pa*t;t=a7(qa*t-L1,2.*(qa+r));}F8=t;return abs(t*(t*(t*pa+3.*r)+3.*L1)); +#endif +} +)==="; +} // namespace glsl +} // namespace gpu +} // namespace rive \ No newline at end of file diff --git a/third_party/rive_renderer/source/generated/shaders/bezier_utils.minified.glsl b/third_party/rive_renderer/source/generated/shaders/bezier_utils.minified.glsl new file mode 100644 index 0000000..b1892ad --- /dev/null +++ b/third_party/rive_renderer/source/generated/shaders/bezier_utils.minified.glsl @@ -0,0 +1,13 @@ +#ifndef fa +#define fa f +#endif +#ifndef J5 +#define J5 c +#endif +d float C8(c k,c b){float Qc=dot(k,b);float ga=dot(k,k)*dot(b,b);return(ga==.0)?1.:clamp(Qc*inversesqrt(ga),-1.,1.);}d void Rc(c o0,c p0,c x0,c z0,k1(c)o,k1(c)r,k1(c)L1){L1=p0-o0;c K5=x0-p0;c X6=z0-o0;r=K5-L1;o=-3.*K5+X6;}d S D8(c o0,c p0,c x0,c z0){S t;t[0]=(any(notEqual(o0,p0))?p0:any(notEqual(p0,x0))?x0:z0)-o0;t[1]=z0-(any(notEqual(z0,x0))?x0:any(notEqual(x0,p0))?p0:o0);return t;}d float Sc(c o0,c p0,c x0,c z0,float c1,float Tc){c o,r,L1;Rc(o0,p0,x0,z0,o,r,L1);c L5=3.*(((o*c1)+2.*r)*c1+L1);float ha=length(L5);if(ha==.0){return.0;}L5*=1./ha;float Y6=2.*dot(o,L5);float M5=3.*(Y6*c1+4.*dot(r,L5))*c1+6.*dot(L1,L5);float E8=min(c1,1.-c1);float Uc=(Y6*E8*E8+M5)*E8;float ia=min(Tc,Uc*.9999);float A2;if(Y6==.0){A2=ia/M5;}else{float d0=1./Y6;float b=M5*d0,B0=-ia*d0;float N5=(-1./3.)*b,O5=.5*B0;float ja=O5*O5-N5*N5*N5;if(ja<.0){float Z6=sqrt(N5);float O0=acos(O5/(Z6*Z6*Z6));A2=-2.*Z6*cos(O0*(1./3.)+(-O2*2./3.));}else{float o=pow(abs(O5)+sqrt(ja),1./3.);if(O5<.0)o=-o;A2=o!=.0?o+N5/o:.0;}}A2=abs(A2);f t0011=c1+fa(-A2,-A2,A2,A2);f ka=(o.xyxy*t0011+2.*r.xyxy)*t0011+L1.xyxy;S d2=D8(o0,p0,x0,z0);c Vc=t0011.x<1e-3?d2[0]:ka.xy;c Wc=t0011.z>1.-1e-3?d2[1]:ka.zw;return acos(C8(Vc,Wc));}d float a7(float k,float b){k=b<.0?-k:k;b=abs(b);return k>.0?(kX4.y?P5.x:P5.y;return max(X4.x,X4.y); +#else +float pa=3.*D3;float r=-C3-D3;float L1=C3;float t=.5;for(int C=0;C<3;++C){float qa=pa*t;t=a7(qa*t-L1,2.*(qa+r));}F8=t;return abs(t*(t*(t*pa+3.*r)+3.*L1)); +#endif +} \ No newline at end of file diff --git a/third_party/rive_renderer/source/generated/shaders/blit_texture_as_draw.exports.h b/third_party/rive_renderer/source/generated/shaders/blit_texture_as_draw.exports.h new file mode 100644 index 0000000..7d86e26 --- /dev/null +++ b/third_party/rive_renderer/source/generated/shaders/blit_texture_as_draw.exports.h @@ -0,0 +1,208 @@ +#pragma once + +#define GLSL_ATLAS_BLIT "CB" +#define GLSL_ATLAS_BLIT_raw CB +#define GLSL_ATLAS_FEATHERED_FILL "QE" +#define GLSL_ATLAS_FEATHERED_FILL_raw QE +#define GLSL_ATLAS_FEATHERED_STROKE "SE" +#define GLSL_ATLAS_FEATHERED_STROKE_raw SE +#define GLSL_BASE_INSTANCE_UNIFORM_NAME "ED" +#define GLSL_BASE_INSTANCE_UNIFORM_NAME_raw ED +#define GLSL_BORROWED_COVERAGE_PREPASS "OC" +#define GLSL_BORROWED_COVERAGE_PREPASS_raw OC +#define GLSL_CLEAR_CLIP "OE" +#define GLSL_CLEAR_CLIP_raw OE +#define GLSL_CLEAR_COLOR "RD" +#define GLSL_CLEAR_COLOR_raw RD +#define GLSL_CLEAR_COVERAGE "NE" +#define GLSL_CLEAR_COVERAGE_raw NE +#define GLSL_CLOCKWISE_FILL "AD" +#define GLSL_CLOCKWISE_FILL_raw AD +#define GLSL_COALESCED_PLS_RESOLVE_AND_TRANSFER "LC" +#define GLSL_COALESCED_PLS_RESOLVE_AND_TRANSFER_raw LC +#define GLSL_COLOR_PLANE_IDX_OVERRIDE "LD" +#define GLSL_COLOR_PLANE_IDX_OVERRIDE_raw LD +#define GLSL_DISABLE_SHADER_STORAGE_BUFFERS "FE" +#define GLSL_DISABLE_SHADER_STORAGE_BUFFERS_raw FE +#define GLSL_DRAW_IMAGE "UC" +#define GLSL_DRAW_IMAGE_raw UC +#define GLSL_DRAW_IMAGE_MESH "UD" +#define GLSL_DRAW_IMAGE_MESH_raw UD +#define GLSL_DRAW_IMAGE_RECT "TC" +#define GLSL_DRAW_IMAGE_RECT_raw TC +#define GLSL_DRAW_INTERIOR_TRIANGLES "GB" +#define GLSL_DRAW_INTERIOR_TRIANGLES_raw GB +#define GLSL_DRAW_PATH "KC" +#define GLSL_DRAW_PATH_raw KC +#define GLSL_DRAW_RENDER_TARGET_UPDATE_BOUNDS "VD" +#define GLSL_DRAW_RENDER_TARGET_UPDATE_BOUNDS_raw VD +#define GLSL_ENABLE_ADVANCED_BLEND "FB" +#define GLSL_ENABLE_ADVANCED_BLEND_raw FB +#define GLSL_ENABLE_CLIPPING "T" +#define GLSL_ENABLE_CLIPPING_raw T +#define GLSL_ENABLE_CLIP_RECT "BB" +#define GLSL_ENABLE_CLIP_RECT_raw BB +#define GLSL_ENABLE_EVEN_ODD "IC" +#define GLSL_ENABLE_EVEN_ODD_raw IC +#define GLSL_ENABLE_FEATHER "EB" +#define GLSL_ENABLE_FEATHER_raw EB +#define GLSL_ENABLE_HSL_BLEND_MODES "XB" +#define GLSL_ENABLE_HSL_BLEND_MODES_raw XB +#define GLSL_ENABLE_INSTANCE_INDEX "OD" +#define GLSL_ENABLE_INSTANCE_INDEX_raw OD +#define GLSL_ENABLE_KHR_BLEND "KD" +#define GLSL_ENABLE_KHR_BLEND_raw KD +#define GLSL_ENABLE_MIN_16_PRECISION "PD" +#define GLSL_ENABLE_MIN_16_PRECISION_raw PD +#define GLSL_ENABLE_NESTED_CLIPPING "CD" +#define GLSL_ENABLE_NESTED_CLIPPING_raw CD +#define GLSL_ENABLE_RASTERIZER_ORDERED_VIEWS "QD" +#define GLSL_ENABLE_RASTERIZER_ORDERED_VIEWS_raw QD +#define GLSL_ENABLE_TYPED_UAV_LOAD_STORE "FC" +#define GLSL_ENABLE_TYPED_UAV_LOAD_STORE_raw FC +#define GLSL_FIXED_FUNCTION_COLOR_OUTPUT "QB" +#define GLSL_FIXED_FUNCTION_COLOR_OUTPUT_raw QB +#define GLSL_FRAGMENT "HB" +#define GLSL_FRAGMENT_raw HB +#define GLSL_FRAMEBUFFER_BOTTOM_UP "DE" +#define GLSL_FRAMEBUFFER_BOTTOM_UP_raw DE +#define GLSL_FlushUniforms "VB" +#define GLSL_FlushUniforms_raw VB +#define GLSL_GLSL_VERSION "WB" +#define GLSL_GLSL_VERSION_raw WB +#define GLSL_INITIALIZE_PLS "WD" +#define GLSL_INITIALIZE_PLS_raw WD +#define GLSL_ImageDrawUniforms "EC" +#define GLSL_ImageDrawUniforms_raw EC +#define GLSL_LOAD_COLOR "TD" +#define GLSL_LOAD_COLOR_raw TD +#define GLSL_OPTIONALLY_FLAT "OB" +#define GLSL_OPTIONALLY_FLAT_raw OB +#define GLSL_PLS_BLEND_SRC_OVER "ZB" +#define GLSL_PLS_BLEND_SRC_OVER_raw ZB +#define GLSL_PLS_IMPL_ANGLE "_EXPORTED_PLS_IMPL_ANGLE" +#define GLSL_PLS_IMPL_ANGLE_raw _EXPORTED_PLS_IMPL_ANGLE +#define GLSL_PLS_IMPL_DEVICE_BUFFER "LE" +#define GLSL_PLS_IMPL_DEVICE_BUFFER_raw LE +#define GLSL_PLS_IMPL_DEVICE_BUFFER_RASTER_ORDERED "ME" +#define GLSL_PLS_IMPL_DEVICE_BUFFER_RASTER_ORDERED_raw ME +#define GLSL_PLS_IMPL_EXT_NATIVE "GE" +#define GLSL_PLS_IMPL_EXT_NATIVE_raw GE +#define GLSL_PLS_IMPL_FRAMEBUFFER_FETCH "HE" +#define GLSL_PLS_IMPL_FRAMEBUFFER_FETCH_raw HE +#define GLSL_PLS_IMPL_NONE "KE" +#define GLSL_PLS_IMPL_NONE_raw KE +#define GLSL_PLS_IMPL_STORAGE_TEXTURE "IE" +#define GLSL_PLS_IMPL_STORAGE_TEXTURE_raw IE +#define GLSL_PLS_IMPL_SUBPASS_LOAD "JE" +#define GLSL_PLS_IMPL_SUBPASS_LOAD_raw JE +#define GLSL_POST_INVERT_Y "EE" +#define GLSL_POST_INVERT_Y_raw EE +#define GLSL_RENDER_MODE_MSAA "DB" +#define GLSL_RENDER_MODE_MSAA_raw DB +#define GLSL_RESOLVE_PLS "HC" +#define GLSL_RESOLVE_PLS_raw HC +#define GLSL_STORE_COLOR "FD" +#define GLSL_STORE_COLOR_raw FD +#define GLSL_STORE_COLOR_CLEAR "XD" +#define GLSL_STORE_COLOR_CLEAR_raw XD +#define GLSL_SWIZZLE_COLOR_BGRA_TO_RGBA "YD" +#define GLSL_SWIZZLE_COLOR_BGRA_TO_RGBA_raw YD +#define GLSL_TARGET_VULKAN "CC" +#define GLSL_TARGET_VULKAN_raw CC +#define GLSL_TESS_TEXTURE_FLOATING_POINT "CE" +#define GLSL_TESS_TEXTURE_FLOATING_POINT_raw CE +#define GLSL_USE_TEXEL_FETCH_WITH_FRAG_COORD "NC" +#define GLSL_USE_TEXEL_FETCH_WITH_FRAG_COORD_raw NC +#define GLSL_USING_PLS_STORAGE_TEXTURES "DD" +#define GLSL_USING_PLS_STORAGE_TEXTURES_raw DD +#define GLSL_VERTEX "AB" +#define GLSL_VERTEX_raw AB +#define GLSL_VULKAN_VENDOR_ID "BD" +#define GLSL_VULKAN_VENDOR_ID_raw BD +#define GLSL_a_args "RB" +#define GLSL_a_args_raw RB +#define GLSL_a_color0 "YC" +#define GLSL_a_color0_raw YC +#define GLSL_a_color1 "ZC" +#define GLSL_a_color1_raw ZC +#define GLSL_a_contourIDWithFlags "JD" +#define GLSL_a_contourIDWithFlags_raw JD +#define GLSL_a_imageRectVertex "YB" +#define GLSL_a_imageRectVertex_raw YB +#define GLSL_a_joinTan_and_ys "GC" +#define GLSL_a_joinTan_and_ys_raw GC +#define GLSL_a_mirroredVertexData "MB" +#define GLSL_a_mirroredVertexData_raw MB +#define GLSL_a_p0p1_ "RC" +#define GLSL_a_p0p1__raw RC +#define GLSL_a_p2p3_ "SC" +#define GLSL_a_p2p3__raw SC +#define GLSL_a_patchVertexData "LB" +#define GLSL_a_patchVertexData_raw LB +#define GLSL_a_position "SB" +#define GLSL_a_position_raw SB +#define GLSL_a_reflectionX0X1 "HD" +#define GLSL_a_reflectionX0X1_raw HD +#define GLSL_a_segmentCounts "ID" +#define GLSL_a_segmentCounts_raw ID +#define GLSL_a_span "AC" +#define GLSL_a_span_raw AC +#define GLSL_a_spanX "WC" +#define GLSL_a_spanX_raw WC +#define GLSL_a_texCoord "TB" +#define GLSL_a_texCoord_raw TB +#define GLSL_a_triangleVertex "IB" +#define GLSL_a_triangleVertex_raw IB +#define GLSL_a_x0x1 "GD" +#define GLSL_a_x0x1_raw GD +#define GLSL_a_yWithFlags "XC" +#define GLSL_a_yWithFlags_raw XC +#define GLSL_atlasFillFragmentMain "RE" +#define GLSL_atlasFillFragmentMain_raw RE +#define GLSL_atlasStrokeFragmentMain "TE" +#define GLSL_atlasStrokeFragmentMain_raw TE +#define GLSL_atlasTexture "ND" +#define GLSL_atlasTexture_raw ND +#define GLSL_atlasVertexMain "PE" +#define GLSL_atlasVertexMain_raw PE +#define GLSL_blitFragmentMain "MD" +#define GLSL_blitFragmentMain_raw MD +#define GLSL_blitVertexMain "ZD" +#define GLSL_blitVertexMain_raw ZD +#define GLSL_clearColor "SD" +#define GLSL_clearColor_raw SD +#define GLSL_colorRampFragmentMain "BE" +#define GLSL_colorRampFragmentMain_raw BE +#define GLSL_colorRampVertexMain "AE" +#define GLSL_colorRampVertexMain_raw AE +#define GLSL_contourBuffer "QC" +#define GLSL_contourBuffer_raw QC +#define GLSL_drawFragmentMain "NB" +#define GLSL_drawFragmentMain_raw NB +#define GLSL_drawVertexMain "PB" +#define GLSL_drawVertexMain_raw PB +#define GLSL_dstColorTexture "PC" +#define GLSL_dstColorTexture_raw PC +#define GLSL_featherTexture "JC" +#define GLSL_featherTexture_raw JC +#define GLSL_gradTexture "MC" +#define GLSL_gradTexture_raw MC +#define GLSL_imageTexture "UB" +#define GLSL_imageTexture_raw UB +#define GLSL_paintAuxBuffer "KB" +#define GLSL_paintAuxBuffer_raw KB +#define GLSL_paintBuffer "DC" +#define GLSL_paintBuffer_raw DC +#define GLSL_pathBuffer "JB" +#define GLSL_pathBuffer_raw JB +#define GLSL_sourceTexture "VC" +#define GLSL_sourceTexture_raw VC +#define GLSL_stencilVertexMain "UE" +#define GLSL_stencilVertexMain_raw UE +#define GLSL_tessVertexTexture "BC" +#define GLSL_tessVertexTexture_raw BC +#define GLSL_tessellateFragmentMain "WE" +#define GLSL_tessellateFragmentMain_raw WE +#define GLSL_tessellateVertexMain "VE" +#define GLSL_tessellateVertexMain_raw VE diff --git a/third_party/rive_renderer/source/generated/shaders/blit_texture_as_draw.glsl.hpp b/third_party/rive_renderer/source/generated/shaders/blit_texture_as_draw.glsl.hpp new file mode 100644 index 0000000..dd4a8bd --- /dev/null +++ b/third_party/rive_renderer/source/generated/shaders/blit_texture_as_draw.glsl.hpp @@ -0,0 +1,36 @@ +#pragma once + +#include "blit_texture_as_draw.exports.h" + +namespace rive { +namespace gpu { +namespace glsl { +const char blit_texture_as_draw[] = R"===(o1 +#ifndef NC +n0 H(0,c,q0); +#endif +p1 +#ifdef AB +P2 Q2 E3 F3 q1(ZD,f0,B,n,K){c S1;S1.x=(n&1)==0?-1.:1.;S1.y=(n&2)==0?-1.:1.; +#ifndef NC +L(q0,c);q0.x=S1.x*.5+.5;q0.y=S1.y*-.5+.5;P(q0); +#endif +f Q=f(S1,0,1);h1(Q);} +#endif +#ifdef HB +R2 C2(0,0,VC);S2 +#ifndef NC +p4 G3(0,Yc)q4 +#endif +e2(i,MD){i G8; +#ifndef NC +N(q0,c);G8=T1(VC,Yc,q0,.0); +#else +G8=d1(VC,c0(floor(y0.xy))); +#endif +f2(G8);} +#endif +)==="; +} // namespace glsl +} // namespace gpu +} // namespace rive \ No newline at end of file diff --git a/third_party/rive_renderer/source/generated/shaders/blit_texture_as_draw.minified.glsl b/third_party/rive_renderer/source/generated/shaders/blit_texture_as_draw.minified.glsl new file mode 100644 index 0000000..87edbae --- /dev/null +++ b/third_party/rive_renderer/source/generated/shaders/blit_texture_as_draw.minified.glsl @@ -0,0 +1,25 @@ +o1 +#ifndef USE_TEXEL_FETCH_WITH_FRAG_COORD +n0 H(0,c,q0); +#endif +p1 +#ifdef VERTEX +P2 Q2 E3 F3 q1(ZD,f0,B,n,K){c S1;S1.x=(n&1)==0?-1.:1.;S1.y=(n&2)==0?-1.:1.; +#ifndef USE_TEXEL_FETCH_WITH_FRAG_COORD +L(q0,c);q0.x=S1.x*.5+.5;q0.y=S1.y*-.5+.5;P(q0); +#endif +f Q=f(S1,0,1);h1(Q);} +#endif +#ifdef FRAGMENT +R2 C2(0,0,VC);S2 +#ifndef USE_TEXEL_FETCH_WITH_FRAG_COORD +p4 G3(0,Yc)q4 +#endif +e2(i,MD){i G8; +#ifndef USE_TEXEL_FETCH_WITH_FRAG_COORD +N(q0,c);G8=T1(VC,Yc,q0,.0); +#else +G8=d1(VC,c0(floor(y0.xy))); +#endif +f2(G8);} +#endif diff --git a/third_party/rive_renderer/source/generated/shaders/color_ramp.exports.h b/third_party/rive_renderer/source/generated/shaders/color_ramp.exports.h new file mode 100644 index 0000000..7d86e26 --- /dev/null +++ b/third_party/rive_renderer/source/generated/shaders/color_ramp.exports.h @@ -0,0 +1,208 @@ +#pragma once + +#define GLSL_ATLAS_BLIT "CB" +#define GLSL_ATLAS_BLIT_raw CB +#define GLSL_ATLAS_FEATHERED_FILL "QE" +#define GLSL_ATLAS_FEATHERED_FILL_raw QE +#define GLSL_ATLAS_FEATHERED_STROKE "SE" +#define GLSL_ATLAS_FEATHERED_STROKE_raw SE +#define GLSL_BASE_INSTANCE_UNIFORM_NAME "ED" +#define GLSL_BASE_INSTANCE_UNIFORM_NAME_raw ED +#define GLSL_BORROWED_COVERAGE_PREPASS "OC" +#define GLSL_BORROWED_COVERAGE_PREPASS_raw OC +#define GLSL_CLEAR_CLIP "OE" +#define GLSL_CLEAR_CLIP_raw OE +#define GLSL_CLEAR_COLOR "RD" +#define GLSL_CLEAR_COLOR_raw RD +#define GLSL_CLEAR_COVERAGE "NE" +#define GLSL_CLEAR_COVERAGE_raw NE +#define GLSL_CLOCKWISE_FILL "AD" +#define GLSL_CLOCKWISE_FILL_raw AD +#define GLSL_COALESCED_PLS_RESOLVE_AND_TRANSFER "LC" +#define GLSL_COALESCED_PLS_RESOLVE_AND_TRANSFER_raw LC +#define GLSL_COLOR_PLANE_IDX_OVERRIDE "LD" +#define GLSL_COLOR_PLANE_IDX_OVERRIDE_raw LD +#define GLSL_DISABLE_SHADER_STORAGE_BUFFERS "FE" +#define GLSL_DISABLE_SHADER_STORAGE_BUFFERS_raw FE +#define GLSL_DRAW_IMAGE "UC" +#define GLSL_DRAW_IMAGE_raw UC +#define GLSL_DRAW_IMAGE_MESH "UD" +#define GLSL_DRAW_IMAGE_MESH_raw UD +#define GLSL_DRAW_IMAGE_RECT "TC" +#define GLSL_DRAW_IMAGE_RECT_raw TC +#define GLSL_DRAW_INTERIOR_TRIANGLES "GB" +#define GLSL_DRAW_INTERIOR_TRIANGLES_raw GB +#define GLSL_DRAW_PATH "KC" +#define GLSL_DRAW_PATH_raw KC +#define GLSL_DRAW_RENDER_TARGET_UPDATE_BOUNDS "VD" +#define GLSL_DRAW_RENDER_TARGET_UPDATE_BOUNDS_raw VD +#define GLSL_ENABLE_ADVANCED_BLEND "FB" +#define GLSL_ENABLE_ADVANCED_BLEND_raw FB +#define GLSL_ENABLE_CLIPPING "T" +#define GLSL_ENABLE_CLIPPING_raw T +#define GLSL_ENABLE_CLIP_RECT "BB" +#define GLSL_ENABLE_CLIP_RECT_raw BB +#define GLSL_ENABLE_EVEN_ODD "IC" +#define GLSL_ENABLE_EVEN_ODD_raw IC +#define GLSL_ENABLE_FEATHER "EB" +#define GLSL_ENABLE_FEATHER_raw EB +#define GLSL_ENABLE_HSL_BLEND_MODES "XB" +#define GLSL_ENABLE_HSL_BLEND_MODES_raw XB +#define GLSL_ENABLE_INSTANCE_INDEX "OD" +#define GLSL_ENABLE_INSTANCE_INDEX_raw OD +#define GLSL_ENABLE_KHR_BLEND "KD" +#define GLSL_ENABLE_KHR_BLEND_raw KD +#define GLSL_ENABLE_MIN_16_PRECISION "PD" +#define GLSL_ENABLE_MIN_16_PRECISION_raw PD +#define GLSL_ENABLE_NESTED_CLIPPING "CD" +#define GLSL_ENABLE_NESTED_CLIPPING_raw CD +#define GLSL_ENABLE_RASTERIZER_ORDERED_VIEWS "QD" +#define GLSL_ENABLE_RASTERIZER_ORDERED_VIEWS_raw QD +#define GLSL_ENABLE_TYPED_UAV_LOAD_STORE "FC" +#define GLSL_ENABLE_TYPED_UAV_LOAD_STORE_raw FC +#define GLSL_FIXED_FUNCTION_COLOR_OUTPUT "QB" +#define GLSL_FIXED_FUNCTION_COLOR_OUTPUT_raw QB +#define GLSL_FRAGMENT "HB" +#define GLSL_FRAGMENT_raw HB +#define GLSL_FRAMEBUFFER_BOTTOM_UP "DE" +#define GLSL_FRAMEBUFFER_BOTTOM_UP_raw DE +#define GLSL_FlushUniforms "VB" +#define GLSL_FlushUniforms_raw VB +#define GLSL_GLSL_VERSION "WB" +#define GLSL_GLSL_VERSION_raw WB +#define GLSL_INITIALIZE_PLS "WD" +#define GLSL_INITIALIZE_PLS_raw WD +#define GLSL_ImageDrawUniforms "EC" +#define GLSL_ImageDrawUniforms_raw EC +#define GLSL_LOAD_COLOR "TD" +#define GLSL_LOAD_COLOR_raw TD +#define GLSL_OPTIONALLY_FLAT "OB" +#define GLSL_OPTIONALLY_FLAT_raw OB +#define GLSL_PLS_BLEND_SRC_OVER "ZB" +#define GLSL_PLS_BLEND_SRC_OVER_raw ZB +#define GLSL_PLS_IMPL_ANGLE "_EXPORTED_PLS_IMPL_ANGLE" +#define GLSL_PLS_IMPL_ANGLE_raw _EXPORTED_PLS_IMPL_ANGLE +#define GLSL_PLS_IMPL_DEVICE_BUFFER "LE" +#define GLSL_PLS_IMPL_DEVICE_BUFFER_raw LE +#define GLSL_PLS_IMPL_DEVICE_BUFFER_RASTER_ORDERED "ME" +#define GLSL_PLS_IMPL_DEVICE_BUFFER_RASTER_ORDERED_raw ME +#define GLSL_PLS_IMPL_EXT_NATIVE "GE" +#define GLSL_PLS_IMPL_EXT_NATIVE_raw GE +#define GLSL_PLS_IMPL_FRAMEBUFFER_FETCH "HE" +#define GLSL_PLS_IMPL_FRAMEBUFFER_FETCH_raw HE +#define GLSL_PLS_IMPL_NONE "KE" +#define GLSL_PLS_IMPL_NONE_raw KE +#define GLSL_PLS_IMPL_STORAGE_TEXTURE "IE" +#define GLSL_PLS_IMPL_STORAGE_TEXTURE_raw IE +#define GLSL_PLS_IMPL_SUBPASS_LOAD "JE" +#define GLSL_PLS_IMPL_SUBPASS_LOAD_raw JE +#define GLSL_POST_INVERT_Y "EE" +#define GLSL_POST_INVERT_Y_raw EE +#define GLSL_RENDER_MODE_MSAA "DB" +#define GLSL_RENDER_MODE_MSAA_raw DB +#define GLSL_RESOLVE_PLS "HC" +#define GLSL_RESOLVE_PLS_raw HC +#define GLSL_STORE_COLOR "FD" +#define GLSL_STORE_COLOR_raw FD +#define GLSL_STORE_COLOR_CLEAR "XD" +#define GLSL_STORE_COLOR_CLEAR_raw XD +#define GLSL_SWIZZLE_COLOR_BGRA_TO_RGBA "YD" +#define GLSL_SWIZZLE_COLOR_BGRA_TO_RGBA_raw YD +#define GLSL_TARGET_VULKAN "CC" +#define GLSL_TARGET_VULKAN_raw CC +#define GLSL_TESS_TEXTURE_FLOATING_POINT "CE" +#define GLSL_TESS_TEXTURE_FLOATING_POINT_raw CE +#define GLSL_USE_TEXEL_FETCH_WITH_FRAG_COORD "NC" +#define GLSL_USE_TEXEL_FETCH_WITH_FRAG_COORD_raw NC +#define GLSL_USING_PLS_STORAGE_TEXTURES "DD" +#define GLSL_USING_PLS_STORAGE_TEXTURES_raw DD +#define GLSL_VERTEX "AB" +#define GLSL_VERTEX_raw AB +#define GLSL_VULKAN_VENDOR_ID "BD" +#define GLSL_VULKAN_VENDOR_ID_raw BD +#define GLSL_a_args "RB" +#define GLSL_a_args_raw RB +#define GLSL_a_color0 "YC" +#define GLSL_a_color0_raw YC +#define GLSL_a_color1 "ZC" +#define GLSL_a_color1_raw ZC +#define GLSL_a_contourIDWithFlags "JD" +#define GLSL_a_contourIDWithFlags_raw JD +#define GLSL_a_imageRectVertex "YB" +#define GLSL_a_imageRectVertex_raw YB +#define GLSL_a_joinTan_and_ys "GC" +#define GLSL_a_joinTan_and_ys_raw GC +#define GLSL_a_mirroredVertexData "MB" +#define GLSL_a_mirroredVertexData_raw MB +#define GLSL_a_p0p1_ "RC" +#define GLSL_a_p0p1__raw RC +#define GLSL_a_p2p3_ "SC" +#define GLSL_a_p2p3__raw SC +#define GLSL_a_patchVertexData "LB" +#define GLSL_a_patchVertexData_raw LB +#define GLSL_a_position "SB" +#define GLSL_a_position_raw SB +#define GLSL_a_reflectionX0X1 "HD" +#define GLSL_a_reflectionX0X1_raw HD +#define GLSL_a_segmentCounts "ID" +#define GLSL_a_segmentCounts_raw ID +#define GLSL_a_span "AC" +#define GLSL_a_span_raw AC +#define GLSL_a_spanX "WC" +#define GLSL_a_spanX_raw WC +#define GLSL_a_texCoord "TB" +#define GLSL_a_texCoord_raw TB +#define GLSL_a_triangleVertex "IB" +#define GLSL_a_triangleVertex_raw IB +#define GLSL_a_x0x1 "GD" +#define GLSL_a_x0x1_raw GD +#define GLSL_a_yWithFlags "XC" +#define GLSL_a_yWithFlags_raw XC +#define GLSL_atlasFillFragmentMain "RE" +#define GLSL_atlasFillFragmentMain_raw RE +#define GLSL_atlasStrokeFragmentMain "TE" +#define GLSL_atlasStrokeFragmentMain_raw TE +#define GLSL_atlasTexture "ND" +#define GLSL_atlasTexture_raw ND +#define GLSL_atlasVertexMain "PE" +#define GLSL_atlasVertexMain_raw PE +#define GLSL_blitFragmentMain "MD" +#define GLSL_blitFragmentMain_raw MD +#define GLSL_blitVertexMain "ZD" +#define GLSL_blitVertexMain_raw ZD +#define GLSL_clearColor "SD" +#define GLSL_clearColor_raw SD +#define GLSL_colorRampFragmentMain "BE" +#define GLSL_colorRampFragmentMain_raw BE +#define GLSL_colorRampVertexMain "AE" +#define GLSL_colorRampVertexMain_raw AE +#define GLSL_contourBuffer "QC" +#define GLSL_contourBuffer_raw QC +#define GLSL_drawFragmentMain "NB" +#define GLSL_drawFragmentMain_raw NB +#define GLSL_drawVertexMain "PB" +#define GLSL_drawVertexMain_raw PB +#define GLSL_dstColorTexture "PC" +#define GLSL_dstColorTexture_raw PC +#define GLSL_featherTexture "JC" +#define GLSL_featherTexture_raw JC +#define GLSL_gradTexture "MC" +#define GLSL_gradTexture_raw MC +#define GLSL_imageTexture "UB" +#define GLSL_imageTexture_raw UB +#define GLSL_paintAuxBuffer "KB" +#define GLSL_paintAuxBuffer_raw KB +#define GLSL_paintBuffer "DC" +#define GLSL_paintBuffer_raw DC +#define GLSL_pathBuffer "JB" +#define GLSL_pathBuffer_raw JB +#define GLSL_sourceTexture "VC" +#define GLSL_sourceTexture_raw VC +#define GLSL_stencilVertexMain "UE" +#define GLSL_stencilVertexMain_raw UE +#define GLSL_tessVertexTexture "BC" +#define GLSL_tessVertexTexture_raw BC +#define GLSL_tessellateFragmentMain "WE" +#define GLSL_tessellateFragmentMain_raw WE +#define GLSL_tessellateVertexMain "VE" +#define GLSL_tessellateVertexMain_raw VE diff --git a/third_party/rive_renderer/source/generated/shaders/color_ramp.glsl.hpp b/third_party/rive_renderer/source/generated/shaders/color_ramp.glsl.hpp new file mode 100644 index 0000000..f826bd8 --- /dev/null +++ b/third_party/rive_renderer/source/generated/shaders/color_ramp.glsl.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include "color_ramp.exports.h" + +namespace rive { +namespace gpu { +namespace glsl { +const char color_ramp[] = R"===(#ifdef AB +U0(f0) +#ifdef H8 +i0(0,uint,WC);i0(1,uint,XC);i0(2,uint,YC);i0(3,uint,ZC); +#else +i0(0,M,AC); +#endif +V0 +#endif +o1 n0 H(0,i,Q5);p1 +#ifdef AB +P2 Q2 E3 F3 i Zc(uint j){return ra((M(j,j,j,j)>>M(16,8,0,24))&0xffu)/255.;}q1(AE,f0,B,n,K){ +#ifdef H8 +l0(K,B,WC,uint);l0(K,B,XC,uint);l0(K,B,YC,uint);l0(K,B,ZC,uint);M AC=M(WC,XC,YC,ZC); +#else +l0(K,B,AC,M); +#endif +L(Q5,i);int c7=n>>1;float x=float(c7<=1?AC.x&0xffffu:AC.x>>16)/65536.;float I8=(n&1)==0?.0:1.;if(q.sa<.0){I8=1.-I8;}uint R5=AC.y;float y=float(R5&~ad)+I8;if((R5&ta)!=0u&&c7==0){if((R5&J8)!=0u)x=.0;else x-=ua;}if((R5&va)!=0u&&c7==3){if((R5&J8)!=0u)x=1.;else x+=ua;}Q5=Zc(c7<=1?AC.z:AC.w);f Q=d7(c(x,y),2.,q.sa);P(Q5);h1(Q);} +#endif +#ifdef HB +R2 S2 e2(i,BE){N(Q5,i);f2(Q5);} +#endif +)==="; +} // namespace glsl +} // namespace gpu +} // namespace rive \ No newline at end of file diff --git a/third_party/rive_renderer/source/generated/shaders/color_ramp.minified.glsl b/third_party/rive_renderer/source/generated/shaders/color_ramp.minified.glsl new file mode 100644 index 0000000..3a81006 --- /dev/null +++ b/third_party/rive_renderer/source/generated/shaders/color_ramp.minified.glsl @@ -0,0 +1,22 @@ +#ifdef VERTEX +U0(f0) +#ifdef H8 +i0(0,uint,WC);i0(1,uint,XC);i0(2,uint,YC);i0(3,uint,ZC); +#else +i0(0,M,AC); +#endif +V0 +#endif +o1 n0 H(0,i,Q5);p1 +#ifdef VERTEX +P2 Q2 E3 F3 i Zc(uint j){return ra((M(j,j,j,j)>>M(16,8,0,24))&0xffu)/255.;}q1(AE,f0,B,n,K){ +#ifdef H8 +l0(K,B,WC,uint);l0(K,B,XC,uint);l0(K,B,YC,uint);l0(K,B,ZC,uint);M AC=M(WC,XC,YC,ZC); +#else +l0(K,B,AC,M); +#endif +L(Q5,i);int c7=n>>1;float x=float(c7<=1?AC.x&0xffffu:AC.x>>16)/65536.;float I8=(n&1)==0?.0:1.;if(q.sa<.0){I8=1.-I8;}uint R5=AC.y;float y=float(R5&~ad)+I8;if((R5&ta)!=0u&&c7==0){if((R5&J8)!=0u)x=.0;else x-=ua;}if((R5&va)!=0u&&c7==3){if((R5&J8)!=0u)x=1.;else x+=ua;}Q5=Zc(c7<=1?AC.z:AC.w);f Q=d7(c(x,y),2.,q.sa);P(Q5);h1(Q);} +#endif +#ifdef FRAGMENT +R2 S2 e2(i,BE){N(Q5,i);f2(Q5);} +#endif diff --git a/third_party/rive_renderer/source/generated/shaders/common.exports.h b/third_party/rive_renderer/source/generated/shaders/common.exports.h new file mode 100644 index 0000000..7d86e26 --- /dev/null +++ b/third_party/rive_renderer/source/generated/shaders/common.exports.h @@ -0,0 +1,208 @@ +#pragma once + +#define GLSL_ATLAS_BLIT "CB" +#define GLSL_ATLAS_BLIT_raw CB +#define GLSL_ATLAS_FEATHERED_FILL "QE" +#define GLSL_ATLAS_FEATHERED_FILL_raw QE +#define GLSL_ATLAS_FEATHERED_STROKE "SE" +#define GLSL_ATLAS_FEATHERED_STROKE_raw SE +#define GLSL_BASE_INSTANCE_UNIFORM_NAME "ED" +#define GLSL_BASE_INSTANCE_UNIFORM_NAME_raw ED +#define GLSL_BORROWED_COVERAGE_PREPASS "OC" +#define GLSL_BORROWED_COVERAGE_PREPASS_raw OC +#define GLSL_CLEAR_CLIP "OE" +#define GLSL_CLEAR_CLIP_raw OE +#define GLSL_CLEAR_COLOR "RD" +#define GLSL_CLEAR_COLOR_raw RD +#define GLSL_CLEAR_COVERAGE "NE" +#define GLSL_CLEAR_COVERAGE_raw NE +#define GLSL_CLOCKWISE_FILL "AD" +#define GLSL_CLOCKWISE_FILL_raw AD +#define GLSL_COALESCED_PLS_RESOLVE_AND_TRANSFER "LC" +#define GLSL_COALESCED_PLS_RESOLVE_AND_TRANSFER_raw LC +#define GLSL_COLOR_PLANE_IDX_OVERRIDE "LD" +#define GLSL_COLOR_PLANE_IDX_OVERRIDE_raw LD +#define GLSL_DISABLE_SHADER_STORAGE_BUFFERS "FE" +#define GLSL_DISABLE_SHADER_STORAGE_BUFFERS_raw FE +#define GLSL_DRAW_IMAGE "UC" +#define GLSL_DRAW_IMAGE_raw UC +#define GLSL_DRAW_IMAGE_MESH "UD" +#define GLSL_DRAW_IMAGE_MESH_raw UD +#define GLSL_DRAW_IMAGE_RECT "TC" +#define GLSL_DRAW_IMAGE_RECT_raw TC +#define GLSL_DRAW_INTERIOR_TRIANGLES "GB" +#define GLSL_DRAW_INTERIOR_TRIANGLES_raw GB +#define GLSL_DRAW_PATH "KC" +#define GLSL_DRAW_PATH_raw KC +#define GLSL_DRAW_RENDER_TARGET_UPDATE_BOUNDS "VD" +#define GLSL_DRAW_RENDER_TARGET_UPDATE_BOUNDS_raw VD +#define GLSL_ENABLE_ADVANCED_BLEND "FB" +#define GLSL_ENABLE_ADVANCED_BLEND_raw FB +#define GLSL_ENABLE_CLIPPING "T" +#define GLSL_ENABLE_CLIPPING_raw T +#define GLSL_ENABLE_CLIP_RECT "BB" +#define GLSL_ENABLE_CLIP_RECT_raw BB +#define GLSL_ENABLE_EVEN_ODD "IC" +#define GLSL_ENABLE_EVEN_ODD_raw IC +#define GLSL_ENABLE_FEATHER "EB" +#define GLSL_ENABLE_FEATHER_raw EB +#define GLSL_ENABLE_HSL_BLEND_MODES "XB" +#define GLSL_ENABLE_HSL_BLEND_MODES_raw XB +#define GLSL_ENABLE_INSTANCE_INDEX "OD" +#define GLSL_ENABLE_INSTANCE_INDEX_raw OD +#define GLSL_ENABLE_KHR_BLEND "KD" +#define GLSL_ENABLE_KHR_BLEND_raw KD +#define GLSL_ENABLE_MIN_16_PRECISION "PD" +#define GLSL_ENABLE_MIN_16_PRECISION_raw PD +#define GLSL_ENABLE_NESTED_CLIPPING "CD" +#define GLSL_ENABLE_NESTED_CLIPPING_raw CD +#define GLSL_ENABLE_RASTERIZER_ORDERED_VIEWS "QD" +#define GLSL_ENABLE_RASTERIZER_ORDERED_VIEWS_raw QD +#define GLSL_ENABLE_TYPED_UAV_LOAD_STORE "FC" +#define GLSL_ENABLE_TYPED_UAV_LOAD_STORE_raw FC +#define GLSL_FIXED_FUNCTION_COLOR_OUTPUT "QB" +#define GLSL_FIXED_FUNCTION_COLOR_OUTPUT_raw QB +#define GLSL_FRAGMENT "HB" +#define GLSL_FRAGMENT_raw HB +#define GLSL_FRAMEBUFFER_BOTTOM_UP "DE" +#define GLSL_FRAMEBUFFER_BOTTOM_UP_raw DE +#define GLSL_FlushUniforms "VB" +#define GLSL_FlushUniforms_raw VB +#define GLSL_GLSL_VERSION "WB" +#define GLSL_GLSL_VERSION_raw WB +#define GLSL_INITIALIZE_PLS "WD" +#define GLSL_INITIALIZE_PLS_raw WD +#define GLSL_ImageDrawUniforms "EC" +#define GLSL_ImageDrawUniforms_raw EC +#define GLSL_LOAD_COLOR "TD" +#define GLSL_LOAD_COLOR_raw TD +#define GLSL_OPTIONALLY_FLAT "OB" +#define GLSL_OPTIONALLY_FLAT_raw OB +#define GLSL_PLS_BLEND_SRC_OVER "ZB" +#define GLSL_PLS_BLEND_SRC_OVER_raw ZB +#define GLSL_PLS_IMPL_ANGLE "_EXPORTED_PLS_IMPL_ANGLE" +#define GLSL_PLS_IMPL_ANGLE_raw _EXPORTED_PLS_IMPL_ANGLE +#define GLSL_PLS_IMPL_DEVICE_BUFFER "LE" +#define GLSL_PLS_IMPL_DEVICE_BUFFER_raw LE +#define GLSL_PLS_IMPL_DEVICE_BUFFER_RASTER_ORDERED "ME" +#define GLSL_PLS_IMPL_DEVICE_BUFFER_RASTER_ORDERED_raw ME +#define GLSL_PLS_IMPL_EXT_NATIVE "GE" +#define GLSL_PLS_IMPL_EXT_NATIVE_raw GE +#define GLSL_PLS_IMPL_FRAMEBUFFER_FETCH "HE" +#define GLSL_PLS_IMPL_FRAMEBUFFER_FETCH_raw HE +#define GLSL_PLS_IMPL_NONE "KE" +#define GLSL_PLS_IMPL_NONE_raw KE +#define GLSL_PLS_IMPL_STORAGE_TEXTURE "IE" +#define GLSL_PLS_IMPL_STORAGE_TEXTURE_raw IE +#define GLSL_PLS_IMPL_SUBPASS_LOAD "JE" +#define GLSL_PLS_IMPL_SUBPASS_LOAD_raw JE +#define GLSL_POST_INVERT_Y "EE" +#define GLSL_POST_INVERT_Y_raw EE +#define GLSL_RENDER_MODE_MSAA "DB" +#define GLSL_RENDER_MODE_MSAA_raw DB +#define GLSL_RESOLVE_PLS "HC" +#define GLSL_RESOLVE_PLS_raw HC +#define GLSL_STORE_COLOR "FD" +#define GLSL_STORE_COLOR_raw FD +#define GLSL_STORE_COLOR_CLEAR "XD" +#define GLSL_STORE_COLOR_CLEAR_raw XD +#define GLSL_SWIZZLE_COLOR_BGRA_TO_RGBA "YD" +#define GLSL_SWIZZLE_COLOR_BGRA_TO_RGBA_raw YD +#define GLSL_TARGET_VULKAN "CC" +#define GLSL_TARGET_VULKAN_raw CC +#define GLSL_TESS_TEXTURE_FLOATING_POINT "CE" +#define GLSL_TESS_TEXTURE_FLOATING_POINT_raw CE +#define GLSL_USE_TEXEL_FETCH_WITH_FRAG_COORD "NC" +#define GLSL_USE_TEXEL_FETCH_WITH_FRAG_COORD_raw NC +#define GLSL_USING_PLS_STORAGE_TEXTURES "DD" +#define GLSL_USING_PLS_STORAGE_TEXTURES_raw DD +#define GLSL_VERTEX "AB" +#define GLSL_VERTEX_raw AB +#define GLSL_VULKAN_VENDOR_ID "BD" +#define GLSL_VULKAN_VENDOR_ID_raw BD +#define GLSL_a_args "RB" +#define GLSL_a_args_raw RB +#define GLSL_a_color0 "YC" +#define GLSL_a_color0_raw YC +#define GLSL_a_color1 "ZC" +#define GLSL_a_color1_raw ZC +#define GLSL_a_contourIDWithFlags "JD" +#define GLSL_a_contourIDWithFlags_raw JD +#define GLSL_a_imageRectVertex "YB" +#define GLSL_a_imageRectVertex_raw YB +#define GLSL_a_joinTan_and_ys "GC" +#define GLSL_a_joinTan_and_ys_raw GC +#define GLSL_a_mirroredVertexData "MB" +#define GLSL_a_mirroredVertexData_raw MB +#define GLSL_a_p0p1_ "RC" +#define GLSL_a_p0p1__raw RC +#define GLSL_a_p2p3_ "SC" +#define GLSL_a_p2p3__raw SC +#define GLSL_a_patchVertexData "LB" +#define GLSL_a_patchVertexData_raw LB +#define GLSL_a_position "SB" +#define GLSL_a_position_raw SB +#define GLSL_a_reflectionX0X1 "HD" +#define GLSL_a_reflectionX0X1_raw HD +#define GLSL_a_segmentCounts "ID" +#define GLSL_a_segmentCounts_raw ID +#define GLSL_a_span "AC" +#define GLSL_a_span_raw AC +#define GLSL_a_spanX "WC" +#define GLSL_a_spanX_raw WC +#define GLSL_a_texCoord "TB" +#define GLSL_a_texCoord_raw TB +#define GLSL_a_triangleVertex "IB" +#define GLSL_a_triangleVertex_raw IB +#define GLSL_a_x0x1 "GD" +#define GLSL_a_x0x1_raw GD +#define GLSL_a_yWithFlags "XC" +#define GLSL_a_yWithFlags_raw XC +#define GLSL_atlasFillFragmentMain "RE" +#define GLSL_atlasFillFragmentMain_raw RE +#define GLSL_atlasStrokeFragmentMain "TE" +#define GLSL_atlasStrokeFragmentMain_raw TE +#define GLSL_atlasTexture "ND" +#define GLSL_atlasTexture_raw ND +#define GLSL_atlasVertexMain "PE" +#define GLSL_atlasVertexMain_raw PE +#define GLSL_blitFragmentMain "MD" +#define GLSL_blitFragmentMain_raw MD +#define GLSL_blitVertexMain "ZD" +#define GLSL_blitVertexMain_raw ZD +#define GLSL_clearColor "SD" +#define GLSL_clearColor_raw SD +#define GLSL_colorRampFragmentMain "BE" +#define GLSL_colorRampFragmentMain_raw BE +#define GLSL_colorRampVertexMain "AE" +#define GLSL_colorRampVertexMain_raw AE +#define GLSL_contourBuffer "QC" +#define GLSL_contourBuffer_raw QC +#define GLSL_drawFragmentMain "NB" +#define GLSL_drawFragmentMain_raw NB +#define GLSL_drawVertexMain "PB" +#define GLSL_drawVertexMain_raw PB +#define GLSL_dstColorTexture "PC" +#define GLSL_dstColorTexture_raw PC +#define GLSL_featherTexture "JC" +#define GLSL_featherTexture_raw JC +#define GLSL_gradTexture "MC" +#define GLSL_gradTexture_raw MC +#define GLSL_imageTexture "UB" +#define GLSL_imageTexture_raw UB +#define GLSL_paintAuxBuffer "KB" +#define GLSL_paintAuxBuffer_raw KB +#define GLSL_paintBuffer "DC" +#define GLSL_paintBuffer_raw DC +#define GLSL_pathBuffer "JB" +#define GLSL_pathBuffer_raw JB +#define GLSL_sourceTexture "VC" +#define GLSL_sourceTexture_raw VC +#define GLSL_stencilVertexMain "UE" +#define GLSL_stencilVertexMain_raw UE +#define GLSL_tessVertexTexture "BC" +#define GLSL_tessVertexTexture_raw BC +#define GLSL_tessellateFragmentMain "WE" +#define GLSL_tessellateFragmentMain_raw WE +#define GLSL_tessellateVertexMain "VE" +#define GLSL_tessellateVertexMain_raw VE diff --git a/third_party/rive_renderer/source/generated/shaders/common.glsl.hpp b/third_party/rive_renderer/source/generated/shaders/common.glsl.hpp new file mode 100644 index 0000000..46ae032 --- /dev/null +++ b/third_party/rive_renderer/source/generated/shaders/common.glsl.hpp @@ -0,0 +1,62 @@ +#pragma once + +#include "common.exports.h" + +namespace rive { +namespace gpu { +namespace glsl { +const char common[] = R"===(#define O2 3.14159265359 +#define e7 6.28318530718 +#define S5 1.57079632679 +#ifndef DB +#define q3 float(.5) +#else +#define q3 float(.0) +#endif +#define F2(l) d7(l,q.bd,q.cd) +#ifdef CE +#define wa(g0,e,a) r4(g0,e,a) +#define H3 f +#define K8(m) m +#define Y4(m) m +#define L8(m) uintBitsToFloat(m) +#define v4(m) floatBitsToUint(m) +#else +#define wa(g0,e,a) I3(g0,e,a) +#define H3 M +#define K8(m) floatBitsToUint(m) +#define Y4(m) uintBitsToFloat(m) +#define L8(m) m +#define v4(m) m +#endif +#define J3(m) T5(JC,M8,m,xa,float(xa),.0).x +#define Z4(m) T5(JC,M8,m,ya,float(ya),.0).x +#ifdef za +d g d4(float x){return x;}d g f7(uint x){return float(x);}d g dd(a0 x){return float(x);}d g N8(int x){return float(x);}d i I5(f xyzw){return xyzw;}d G F6(c xy){return xy;}d i ra(M xyzw){return vec4(xyzw);}d a0 O8(g x){return uint(x);}d a0 Q1(uint x){return x;} +#else +d g d4(float x){return(g)x;}d g f7(uint x){return(g)x;}d g dd(a0 x){return(g)x;}d g N8(int x){return(g)x;}d i I5(f xyzw){return(i)xyzw;}d G F6(c xy){return(G)xy;}d i ra(M xyzw){return(i)xyzw;}d a0 O8(g x){return(a0)x;}d a0 Q1(uint x){return(a0)x;} +#endif +d g v1(g x){return x;}d G Z3(G xy){return xy;}d G Z3(g x,g y){G V;V.x=x,V.y=y;return V;}d G Z3(g x){G V;V.x=x,V.y=x;return V;}d c J5(float x){return c(x,x);}d A K0(g x,g y,g z){A V;V.x=x,V.y=y,V.z=z;return V;}d A K0(g x){A V;V.x=x,V.y=x,V.z=x;return V;}d i E1(g x,g y,g z,g w){i V;V.x=x,V.y=y,V.z=z,V.w=w;return V;}d i E1(A xyz,g w){i V;V.xyz=xyz;V.w=w;return V;}d i E1(g x){i V;V.x=x,V.y=x,V.z=x,V.w=x;return V;}d a5 ed(bool b){return a5(b,b);}d U5 qf(A k,A b,A B0){U5 V;V[0]=k;V[1]=b;V[2]=B0;return V;}d V5 Ic(A k,A b){V5 V;V[0]=k;V[1]=b;return V;}d S D1(f x){return S(x.xy,x.zw);}d uint ea(a0 x){return x;}d uint Aa(uint Y){return(Y&fd)-1u;}d c c5(c k,c b,float t){return(b-k)*t+k;}d g g7(uint Ba,uint d5){return Ba==0u?.0:unpackHalf2x16((Ba+gd)*d5).x;}d float Ca(c M1){M1=normalize(M1);float O0=acos(clamp(M1.x,-1.,1.));return M1.y>=.0?O0:-O0;}d i rf(i j){return E1(j.xyz*j.w,j.w);}d A Y3(i P8){return P8.xyz*(P8.w!=.0?1./P8.w:.0);}d g A8(i Da){G Ea=min(Da.xy,Da.zw);g hd=min(Ea.x,Ea.y);return hd;}d float f8(c x){return abs(x.x)+abs(x.y);} +#ifndef UNIFORM_DEFINITIONS_AUTO_GENERATED +e5(K3,VB)float sa;float Fa;float bd;float cd;uint Ga;uint id;uint Oc;uint Pc;h7 J6;c U4;c Ha;uint Z2;uint d5;float C1;uint jd;W5(q) +#endif +#ifdef AB +d f d7(c Ia,float kd,float Ja){return f(Ia.x*kd-1.,Ia.y*Ja-sign(Ja),0.,1.);} +#ifndef DB +d f I6(S R1,c Z1,c Q8){c R8=abs(R1[0])+abs(R1[1]);if(R8.x!=.0&&R8.y!=.0){c d0=1./R8;c w4=C0(R1,Q8)+Z1;const float ld=.5;return f(w4,-w4)*d0.xyxy+d0.xyxy+ld;}else{return Z1.xyxy;}} +#else +d float S8(uint X5){return 1.-float(X5)*(2./32768.);} +#ifdef BB +d void Ka(S R1,c Z1,c Q8){if(R1!=S(0)){c w4=C0(R1,Q8)+Z1.xy;gl_ClipDistance[0]=w4.x+1.;gl_ClipDistance[1]=w4.y+1.;gl_ClipDistance[2]=1.-w4.x;gl_ClipDistance[3]=1.-w4.y;}else{gl_ClipDistance[0]=gl_ClipDistance[1]=gl_ClipDistance[2]=gl_ClipDistance[3]=Z1.x-.5;}} +#endif +#endif +#endif +#ifdef UC +#ifndef UNIFORM_DEFINITIONS_AUTO_GENERATED +e5(f5,EC)f H6;c S0;float H2;float sf;f R1;c Z1;uint Z0;uint z3;uint X5;W5(m0) +#endif +#endif +)==="; +} // namespace glsl +} // namespace gpu +} // namespace rive \ No newline at end of file diff --git a/third_party/rive_renderer/source/generated/shaders/common.minified.glsl b/third_party/rive_renderer/source/generated/shaders/common.minified.glsl new file mode 100644 index 0000000..8be32e1 --- /dev/null +++ b/third_party/rive_renderer/source/generated/shaders/common.minified.glsl @@ -0,0 +1,51 @@ +#define O2 3.14159265359 +#define e7 6.28318530718 +#define S5 1.57079632679 +#ifndef RENDER_MODE_MSAA +#define q3 float(.5) +#else +#define q3 float(.0) +#endif +#define F2(l) d7(l,q.bd,q.cd) +#ifdef TESS_TEXTURE_FLOATING_POINT +#define wa(g0,e,a) r4(g0,e,a) +#define H3 f +#define K8(m) m +#define Y4(m) m +#define L8(m) uintBitsToFloat(m) +#define v4(m) floatBitsToUint(m) +#else +#define wa(g0,e,a) I3(g0,e,a) +#define H3 M +#define K8(m) floatBitsToUint(m) +#define Y4(m) uintBitsToFloat(m) +#define L8(m) m +#define v4(m) m +#endif +#define J3(m) T5(JC,M8,m,xa,float(xa),.0).x +#define Z4(m) T5(JC,M8,m,ya,float(ya),.0).x +#ifdef za +d g d4(float x){return x;}d g f7(uint x){return float(x);}d g dd(a0 x){return float(x);}d g N8(int x){return float(x);}d i I5(f xyzw){return xyzw;}d G F6(c xy){return xy;}d i ra(M xyzw){return vec4(xyzw);}d a0 O8(g x){return uint(x);}d a0 Q1(uint x){return x;} +#else +d g d4(float x){return(g)x;}d g f7(uint x){return(g)x;}d g dd(a0 x){return(g)x;}d g N8(int x){return(g)x;}d i I5(f xyzw){return(i)xyzw;}d G F6(c xy){return(G)xy;}d i ra(M xyzw){return(i)xyzw;}d a0 O8(g x){return(a0)x;}d a0 Q1(uint x){return(a0)x;} +#endif +d g v1(g x){return x;}d G Z3(G xy){return xy;}d G Z3(g x,g y){G V;V.x=x,V.y=y;return V;}d G Z3(g x){G V;V.x=x,V.y=x;return V;}d c J5(float x){return c(x,x);}d A K0(g x,g y,g z){A V;V.x=x,V.y=y,V.z=z;return V;}d A K0(g x){A V;V.x=x,V.y=x,V.z=x;return V;}d i E1(g x,g y,g z,g w){i V;V.x=x,V.y=y,V.z=z,V.w=w;return V;}d i E1(A xyz,g w){i V;V.xyz=xyz;V.w=w;return V;}d i E1(g x){i V;V.x=x,V.y=x,V.z=x,V.w=x;return V;}d a5 ed(bool b){return a5(b,b);}d U5 qf(A k,A b,A B0){U5 V;V[0]=k;V[1]=b;V[2]=B0;return V;}d V5 Ic(A k,A b){V5 V;V[0]=k;V[1]=b;return V;}d S D1(f x){return S(x.xy,x.zw);}d uint ea(a0 x){return x;}d uint Aa(uint Y){return(Y&fd)-1u;}d c c5(c k,c b,float t){return(b-k)*t+k;}d g g7(uint Ba,uint d5){return Ba==0u?.0:unpackHalf2x16((Ba+gd)*d5).x;}d float Ca(c M1){M1=normalize(M1);float O0=acos(clamp(M1.x,-1.,1.));return M1.y>=.0?O0:-O0;}d i rf(i j){return E1(j.xyz*j.w,j.w);}d A Y3(i P8){return P8.xyz*(P8.w!=.0?1./P8.w:.0);}d g A8(i Da){G Ea=min(Da.xy,Da.zw);g hd=min(Ea.x,Ea.y);return hd;}d float f8(c x){return abs(x.x)+abs(x.y);} +#ifndef UNIFORM_DEFINITIONS_AUTO_GENERATED +e5(K3,VB)float sa;float Fa;float bd;float cd;uint Ga;uint id;uint Oc;uint Pc;h7 J6;c U4;c Ha;uint Z2;uint d5;float C1;uint jd;W5(q) +#endif +#ifdef VERTEX +d f d7(c Ia,float kd,float Ja){return f(Ia.x*kd-1.,Ia.y*Ja-sign(Ja),0.,1.);} +#ifndef RENDER_MODE_MSAA +d f I6(S R1,c Z1,c Q8){c R8=abs(R1[0])+abs(R1[1]);if(R8.x!=.0&&R8.y!=.0){c d0=1./R8;c w4=C0(R1,Q8)+Z1;const float ld=.5;return f(w4,-w4)*d0.xyxy+d0.xyxy+ld;}else{return Z1.xyxy;}} +#else +d float S8(uint X5){return 1.-float(X5)*(2./32768.);} +#ifdef ENABLE_CLIP_RECT +d void Ka(S R1,c Z1,c Q8){if(R1!=S(0)){c w4=C0(R1,Q8)+Z1.xy;gl_ClipDistance[0]=w4.x+1.;gl_ClipDistance[1]=w4.y+1.;gl_ClipDistance[2]=1.-w4.x;gl_ClipDistance[3]=1.-w4.y;}else{gl_ClipDistance[0]=gl_ClipDistance[1]=gl_ClipDistance[2]=gl_ClipDistance[3]=Z1.x-.5;}} +#endif +#endif +#endif +#ifdef DRAW_IMAGE +#ifndef UNIFORM_DEFINITIONS_AUTO_GENERATED +e5(f5,EC)f H6;c S0;float H2;float sf;f R1;c Z1;uint Z0;uint z3;uint X5;W5(m0) +#endif +#endif diff --git a/third_party/rive_renderer/source/generated/shaders/constants.exports.h b/third_party/rive_renderer/source/generated/shaders/constants.exports.h new file mode 100644 index 0000000..7d86e26 --- /dev/null +++ b/third_party/rive_renderer/source/generated/shaders/constants.exports.h @@ -0,0 +1,208 @@ +#pragma once + +#define GLSL_ATLAS_BLIT "CB" +#define GLSL_ATLAS_BLIT_raw CB +#define GLSL_ATLAS_FEATHERED_FILL "QE" +#define GLSL_ATLAS_FEATHERED_FILL_raw QE +#define GLSL_ATLAS_FEATHERED_STROKE "SE" +#define GLSL_ATLAS_FEATHERED_STROKE_raw SE +#define GLSL_BASE_INSTANCE_UNIFORM_NAME "ED" +#define GLSL_BASE_INSTANCE_UNIFORM_NAME_raw ED +#define GLSL_BORROWED_COVERAGE_PREPASS "OC" +#define GLSL_BORROWED_COVERAGE_PREPASS_raw OC +#define GLSL_CLEAR_CLIP "OE" +#define GLSL_CLEAR_CLIP_raw OE +#define GLSL_CLEAR_COLOR "RD" +#define GLSL_CLEAR_COLOR_raw RD +#define GLSL_CLEAR_COVERAGE "NE" +#define GLSL_CLEAR_COVERAGE_raw NE +#define GLSL_CLOCKWISE_FILL "AD" +#define GLSL_CLOCKWISE_FILL_raw AD +#define GLSL_COALESCED_PLS_RESOLVE_AND_TRANSFER "LC" +#define GLSL_COALESCED_PLS_RESOLVE_AND_TRANSFER_raw LC +#define GLSL_COLOR_PLANE_IDX_OVERRIDE "LD" +#define GLSL_COLOR_PLANE_IDX_OVERRIDE_raw LD +#define GLSL_DISABLE_SHADER_STORAGE_BUFFERS "FE" +#define GLSL_DISABLE_SHADER_STORAGE_BUFFERS_raw FE +#define GLSL_DRAW_IMAGE "UC" +#define GLSL_DRAW_IMAGE_raw UC +#define GLSL_DRAW_IMAGE_MESH "UD" +#define GLSL_DRAW_IMAGE_MESH_raw UD +#define GLSL_DRAW_IMAGE_RECT "TC" +#define GLSL_DRAW_IMAGE_RECT_raw TC +#define GLSL_DRAW_INTERIOR_TRIANGLES "GB" +#define GLSL_DRAW_INTERIOR_TRIANGLES_raw GB +#define GLSL_DRAW_PATH "KC" +#define GLSL_DRAW_PATH_raw KC +#define GLSL_DRAW_RENDER_TARGET_UPDATE_BOUNDS "VD" +#define GLSL_DRAW_RENDER_TARGET_UPDATE_BOUNDS_raw VD +#define GLSL_ENABLE_ADVANCED_BLEND "FB" +#define GLSL_ENABLE_ADVANCED_BLEND_raw FB +#define GLSL_ENABLE_CLIPPING "T" +#define GLSL_ENABLE_CLIPPING_raw T +#define GLSL_ENABLE_CLIP_RECT "BB" +#define GLSL_ENABLE_CLIP_RECT_raw BB +#define GLSL_ENABLE_EVEN_ODD "IC" +#define GLSL_ENABLE_EVEN_ODD_raw IC +#define GLSL_ENABLE_FEATHER "EB" +#define GLSL_ENABLE_FEATHER_raw EB +#define GLSL_ENABLE_HSL_BLEND_MODES "XB" +#define GLSL_ENABLE_HSL_BLEND_MODES_raw XB +#define GLSL_ENABLE_INSTANCE_INDEX "OD" +#define GLSL_ENABLE_INSTANCE_INDEX_raw OD +#define GLSL_ENABLE_KHR_BLEND "KD" +#define GLSL_ENABLE_KHR_BLEND_raw KD +#define GLSL_ENABLE_MIN_16_PRECISION "PD" +#define GLSL_ENABLE_MIN_16_PRECISION_raw PD +#define GLSL_ENABLE_NESTED_CLIPPING "CD" +#define GLSL_ENABLE_NESTED_CLIPPING_raw CD +#define GLSL_ENABLE_RASTERIZER_ORDERED_VIEWS "QD" +#define GLSL_ENABLE_RASTERIZER_ORDERED_VIEWS_raw QD +#define GLSL_ENABLE_TYPED_UAV_LOAD_STORE "FC" +#define GLSL_ENABLE_TYPED_UAV_LOAD_STORE_raw FC +#define GLSL_FIXED_FUNCTION_COLOR_OUTPUT "QB" +#define GLSL_FIXED_FUNCTION_COLOR_OUTPUT_raw QB +#define GLSL_FRAGMENT "HB" +#define GLSL_FRAGMENT_raw HB +#define GLSL_FRAMEBUFFER_BOTTOM_UP "DE" +#define GLSL_FRAMEBUFFER_BOTTOM_UP_raw DE +#define GLSL_FlushUniforms "VB" +#define GLSL_FlushUniforms_raw VB +#define GLSL_GLSL_VERSION "WB" +#define GLSL_GLSL_VERSION_raw WB +#define GLSL_INITIALIZE_PLS "WD" +#define GLSL_INITIALIZE_PLS_raw WD +#define GLSL_ImageDrawUniforms "EC" +#define GLSL_ImageDrawUniforms_raw EC +#define GLSL_LOAD_COLOR "TD" +#define GLSL_LOAD_COLOR_raw TD +#define GLSL_OPTIONALLY_FLAT "OB" +#define GLSL_OPTIONALLY_FLAT_raw OB +#define GLSL_PLS_BLEND_SRC_OVER "ZB" +#define GLSL_PLS_BLEND_SRC_OVER_raw ZB +#define GLSL_PLS_IMPL_ANGLE "_EXPORTED_PLS_IMPL_ANGLE" +#define GLSL_PLS_IMPL_ANGLE_raw _EXPORTED_PLS_IMPL_ANGLE +#define GLSL_PLS_IMPL_DEVICE_BUFFER "LE" +#define GLSL_PLS_IMPL_DEVICE_BUFFER_raw LE +#define GLSL_PLS_IMPL_DEVICE_BUFFER_RASTER_ORDERED "ME" +#define GLSL_PLS_IMPL_DEVICE_BUFFER_RASTER_ORDERED_raw ME +#define GLSL_PLS_IMPL_EXT_NATIVE "GE" +#define GLSL_PLS_IMPL_EXT_NATIVE_raw GE +#define GLSL_PLS_IMPL_FRAMEBUFFER_FETCH "HE" +#define GLSL_PLS_IMPL_FRAMEBUFFER_FETCH_raw HE +#define GLSL_PLS_IMPL_NONE "KE" +#define GLSL_PLS_IMPL_NONE_raw KE +#define GLSL_PLS_IMPL_STORAGE_TEXTURE "IE" +#define GLSL_PLS_IMPL_STORAGE_TEXTURE_raw IE +#define GLSL_PLS_IMPL_SUBPASS_LOAD "JE" +#define GLSL_PLS_IMPL_SUBPASS_LOAD_raw JE +#define GLSL_POST_INVERT_Y "EE" +#define GLSL_POST_INVERT_Y_raw EE +#define GLSL_RENDER_MODE_MSAA "DB" +#define GLSL_RENDER_MODE_MSAA_raw DB +#define GLSL_RESOLVE_PLS "HC" +#define GLSL_RESOLVE_PLS_raw HC +#define GLSL_STORE_COLOR "FD" +#define GLSL_STORE_COLOR_raw FD +#define GLSL_STORE_COLOR_CLEAR "XD" +#define GLSL_STORE_COLOR_CLEAR_raw XD +#define GLSL_SWIZZLE_COLOR_BGRA_TO_RGBA "YD" +#define GLSL_SWIZZLE_COLOR_BGRA_TO_RGBA_raw YD +#define GLSL_TARGET_VULKAN "CC" +#define GLSL_TARGET_VULKAN_raw CC +#define GLSL_TESS_TEXTURE_FLOATING_POINT "CE" +#define GLSL_TESS_TEXTURE_FLOATING_POINT_raw CE +#define GLSL_USE_TEXEL_FETCH_WITH_FRAG_COORD "NC" +#define GLSL_USE_TEXEL_FETCH_WITH_FRAG_COORD_raw NC +#define GLSL_USING_PLS_STORAGE_TEXTURES "DD" +#define GLSL_USING_PLS_STORAGE_TEXTURES_raw DD +#define GLSL_VERTEX "AB" +#define GLSL_VERTEX_raw AB +#define GLSL_VULKAN_VENDOR_ID "BD" +#define GLSL_VULKAN_VENDOR_ID_raw BD +#define GLSL_a_args "RB" +#define GLSL_a_args_raw RB +#define GLSL_a_color0 "YC" +#define GLSL_a_color0_raw YC +#define GLSL_a_color1 "ZC" +#define GLSL_a_color1_raw ZC +#define GLSL_a_contourIDWithFlags "JD" +#define GLSL_a_contourIDWithFlags_raw JD +#define GLSL_a_imageRectVertex "YB" +#define GLSL_a_imageRectVertex_raw YB +#define GLSL_a_joinTan_and_ys "GC" +#define GLSL_a_joinTan_and_ys_raw GC +#define GLSL_a_mirroredVertexData "MB" +#define GLSL_a_mirroredVertexData_raw MB +#define GLSL_a_p0p1_ "RC" +#define GLSL_a_p0p1__raw RC +#define GLSL_a_p2p3_ "SC" +#define GLSL_a_p2p3__raw SC +#define GLSL_a_patchVertexData "LB" +#define GLSL_a_patchVertexData_raw LB +#define GLSL_a_position "SB" +#define GLSL_a_position_raw SB +#define GLSL_a_reflectionX0X1 "HD" +#define GLSL_a_reflectionX0X1_raw HD +#define GLSL_a_segmentCounts "ID" +#define GLSL_a_segmentCounts_raw ID +#define GLSL_a_span "AC" +#define GLSL_a_span_raw AC +#define GLSL_a_spanX "WC" +#define GLSL_a_spanX_raw WC +#define GLSL_a_texCoord "TB" +#define GLSL_a_texCoord_raw TB +#define GLSL_a_triangleVertex "IB" +#define GLSL_a_triangleVertex_raw IB +#define GLSL_a_x0x1 "GD" +#define GLSL_a_x0x1_raw GD +#define GLSL_a_yWithFlags "XC" +#define GLSL_a_yWithFlags_raw XC +#define GLSL_atlasFillFragmentMain "RE" +#define GLSL_atlasFillFragmentMain_raw RE +#define GLSL_atlasStrokeFragmentMain "TE" +#define GLSL_atlasStrokeFragmentMain_raw TE +#define GLSL_atlasTexture "ND" +#define GLSL_atlasTexture_raw ND +#define GLSL_atlasVertexMain "PE" +#define GLSL_atlasVertexMain_raw PE +#define GLSL_blitFragmentMain "MD" +#define GLSL_blitFragmentMain_raw MD +#define GLSL_blitVertexMain "ZD" +#define GLSL_blitVertexMain_raw ZD +#define GLSL_clearColor "SD" +#define GLSL_clearColor_raw SD +#define GLSL_colorRampFragmentMain "BE" +#define GLSL_colorRampFragmentMain_raw BE +#define GLSL_colorRampVertexMain "AE" +#define GLSL_colorRampVertexMain_raw AE +#define GLSL_contourBuffer "QC" +#define GLSL_contourBuffer_raw QC +#define GLSL_drawFragmentMain "NB" +#define GLSL_drawFragmentMain_raw NB +#define GLSL_drawVertexMain "PB" +#define GLSL_drawVertexMain_raw PB +#define GLSL_dstColorTexture "PC" +#define GLSL_dstColorTexture_raw PC +#define GLSL_featherTexture "JC" +#define GLSL_featherTexture_raw JC +#define GLSL_gradTexture "MC" +#define GLSL_gradTexture_raw MC +#define GLSL_imageTexture "UB" +#define GLSL_imageTexture_raw UB +#define GLSL_paintAuxBuffer "KB" +#define GLSL_paintAuxBuffer_raw KB +#define GLSL_paintBuffer "DC" +#define GLSL_paintBuffer_raw DC +#define GLSL_pathBuffer "JB" +#define GLSL_pathBuffer_raw JB +#define GLSL_sourceTexture "VC" +#define GLSL_sourceTexture_raw VC +#define GLSL_stencilVertexMain "UE" +#define GLSL_stencilVertexMain_raw UE +#define GLSL_tessVertexTexture "BC" +#define GLSL_tessVertexTexture_raw BC +#define GLSL_tessellateFragmentMain "WE" +#define GLSL_tessellateFragmentMain_raw WE +#define GLSL_tessellateVertexMain "VE" +#define GLSL_tessellateVertexMain_raw VE diff --git a/third_party/rive_renderer/source/generated/shaders/constants.glsl.hpp b/third_party/rive_renderer/source/generated/shaders/constants.glsl.hpp new file mode 100644 index 0000000..daa7b98 --- /dev/null +++ b/third_party/rive_renderer/source/generated/shaders/constants.glsl.hpp @@ -0,0 +1,120 @@ +#pragma once + +#include "constants.exports.h" + +namespace rive { +namespace gpu { +namespace glsl { +const char constants[] = R"===(#define md float(2048) +#define La 11 +#define T8 float(512) +#define ua float(0.001953125) +#define U8 float(3) +#define xa 0 +#define ya 1 +#define Ma 3u +#define nd (Ma+1u) +#define Na 7 +#define Oa 0x7fu +#define ta 0x80000000u +#define va 0x40000000u +#define J8 0x20000000u +#define ad (ta|va|J8) +#define Pa (1u<<31u) +#define od (1u<<29u) +#define a3 (7u<<26u) +#define pd (5u<<26u) +#define qd (4u<<26u) +#define i7 (2u<<26u) +#define j7 (1u<<26u) +#define k7 (1u<<25u) +#define rd (1u<<24u) +#define T2 (1u<<23u) +#define V8 (1u<<22u) +#define Qa (1u<<21u) +#define l7 (1u<<20u) +#define Ra (1u<<19u) +#define fd 0xffffu +#define sd 0u +#define m7 0 +#define Sa 1 +#define Ta 2 +#define m7 0 +#define Sa 1 +#define Ta 2 +#define N6 0u +#define q8 1u +#define O6 2u +#define td 3u +#define ud 4u +#define Kc 0x100u +#define p8 0x200u +#define Lc 0x400u +#define U2 0 +#define Y5 1 +#define K3 0 +#define Ua 1 +#define f5 2 +#define Va 3 +#define l8 4 +#define m8 5 +#define Wa 6 +#define vd 7 +#define wd 8 +#define Xa 9 +#define Z5 10 +#define Ya 11 +#define W8 12 +#define X8 13 +#define Za 14 +#define g5 15 +#define P0(e) (2+e) +#define ab 2 +#define a6 3 +#define i8 0 +#define B5 1 +#define bb 2 +#define k8 3 +#define xd 4 +#define gd 1023u +#define B8 0u +#define tc 1u +#define uc 2u +#define vc 3u +#define wc 4u +#define xc 5u +#define zc 6u +#define Ac 7u +#define Bc 8u +#define Cc 9u +#define Dc 10u +#define sc 11u +#define Ec 12u +#define Fc 13u +#define Gc 14u +#define Hc 15u +#define n8 float(2048) +#define Y9 float(0.00048828125) +#define o8 float(1<<16) +#define x8 (1u<<16) +#define T4 17u +#define V6 0x1ffffu +#define Y8 0x1ffffu +#define Z8 float(2048) +#define a9 float(0.00048828125) +#define c6 (1u<<16) +#define yd 0x13B5u +#define zd 0 +#define Ad 1 +#define Bd 2 +#define Cd 3 +#define Dd 4 +#define Ed 5 +#define Fd 6 +#define Gd 7 +#define Hd 8 +#define Id 9 +)==="; +} // namespace glsl +} // namespace gpu +} // namespace rive \ No newline at end of file diff --git a/third_party/rive_renderer/source/generated/shaders/constants.minified.glsl b/third_party/rive_renderer/source/generated/shaders/constants.minified.glsl new file mode 100644 index 0000000..ebf6f64 --- /dev/null +++ b/third_party/rive_renderer/source/generated/shaders/constants.minified.glsl @@ -0,0 +1,109 @@ +#define md float(2048) +#define La 11 +#define T8 float(512) +#define ua float(0.001953125) +#define U8 float(3) +#define xa 0 +#define ya 1 +#define Ma 3u +#define nd (Ma+1u) +#define Na 7 +#define Oa 0x7fu +#define ta 0x80000000u +#define va 0x40000000u +#define J8 0x20000000u +#define ad (ta|va|J8) +#define Pa (1u<<31u) +#define od (1u<<29u) +#define a3 (7u<<26u) +#define pd (5u<<26u) +#define qd (4u<<26u) +#define i7 (2u<<26u) +#define j7 (1u<<26u) +#define k7 (1u<<25u) +#define rd (1u<<24u) +#define T2 (1u<<23u) +#define V8 (1u<<22u) +#define Qa (1u<<21u) +#define l7 (1u<<20u) +#define Ra (1u<<19u) +#define fd 0xffffu +#define sd 0u +#define m7 0 +#define Sa 1 +#define Ta 2 +#define m7 0 +#define Sa 1 +#define Ta 2 +#define N6 0u +#define q8 1u +#define O6 2u +#define td 3u +#define ud 4u +#define Kc 0x100u +#define p8 0x200u +#define Lc 0x400u +#define U2 0 +#define Y5 1 +#define K3 0 +#define Ua 1 +#define f5 2 +#define Va 3 +#define l8 4 +#define m8 5 +#define Wa 6 +#define vd 7 +#define wd 8 +#define Xa 9 +#define Z5 10 +#define Ya 11 +#define W8 12 +#define X8 13 +#define Za 14 +#define g5 15 +#define P0(e) (2+e) +#define ab 2 +#define a6 3 +#define i8 0 +#define B5 1 +#define bb 2 +#define k8 3 +#define xd 4 +#define gd 1023u +#define B8 0u +#define tc 1u +#define uc 2u +#define vc 3u +#define wc 4u +#define xc 5u +#define zc 6u +#define Ac 7u +#define Bc 8u +#define Cc 9u +#define Dc 10u +#define sc 11u +#define Ec 12u +#define Fc 13u +#define Gc 14u +#define Hc 15u +#define n8 float(2048) +#define Y9 float(0.00048828125) +#define o8 float(1<<16) +#define x8 (1u<<16) +#define T4 17u +#define V6 0x1ffffu +#define Y8 0x1ffffu +#define Z8 float(2048) +#define a9 float(0.00048828125) +#define c6 (1u<<16) +#define yd 0x13B5u +#define zd 0 +#define Ad 1 +#define Bd 2 +#define Cd 3 +#define Dd 4 +#define Ed 5 +#define Fd 6 +#define Gd 7 +#define Hd 8 +#define Id 9 diff --git a/third_party/rive_renderer/source/generated/shaders/d3d/color_ramp.frag.h b/third_party/rive_renderer/source/generated/shaders/d3d/color_ramp.frag.h new file mode 100644 index 0000000..78f6178 --- /dev/null +++ b/third_party/rive_renderer/source/generated/shaders/d3d/color_ramp.frag.h @@ -0,0 +1,120 @@ +#if 0 +// +// Generated by Microsoft (R) HLSL Shader Compiler 10.1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------- ------ +// TEXCOORD 0 xyzw 0 NONE float xyzw +// SV_Position 0 xyzw 1 POS float +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------- ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_5_0 +dcl_globalFlags refactoringAllowed +dcl_input_ps linear noperspective v0.xyzw +dcl_output o0.xyzw +mov o0.xyzw, v0.xyzw +ret +// Approximately 2 instruction slots used +#endif + +const BYTE g_main[] = +{ + 68, 88, 66, 67, 202, 17, + 242, 193, 235, 99, 30, 245, + 188, 236, 148, 16, 208, 141, + 89, 243, 1, 0, 0, 0, + 12, 2, 0, 0, 5, 0, + 0, 0, 52, 0, 0, 0, + 160, 0, 0, 0, 248, 0, + 0, 0, 44, 1, 0, 0, + 112, 1, 0, 0, 82, 68, + 69, 70, 100, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 60, 0, 0, 0, 0, 5, + 255, 255, 0, 1, 0, 0, + 60, 0, 0, 0, 82, 68, + 49, 49, 60, 0, 0, 0, + 24, 0, 0, 0, 32, 0, + 0, 0, 40, 0, 0, 0, + 36, 0, 0, 0, 12, 0, + 0, 0, 0, 0, 0, 0, + 77, 105, 99, 114, 111, 115, + 111, 102, 116, 32, 40, 82, + 41, 32, 72, 76, 83, 76, + 32, 83, 104, 97, 100, 101, + 114, 32, 67, 111, 109, 112, + 105, 108, 101, 114, 32, 49, + 48, 46, 49, 0, 73, 83, + 71, 78, 80, 0, 0, 0, + 2, 0, 0, 0, 8, 0, + 0, 0, 56, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 3, 0, 0, 0, + 0, 0, 0, 0, 15, 15, + 0, 0, 65, 0, 0, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 3, 0, 0, 0, + 1, 0, 0, 0, 15, 0, + 0, 0, 84, 69, 88, 67, + 79, 79, 82, 68, 0, 83, + 86, 95, 80, 111, 115, 105, + 116, 105, 111, 110, 0, 171, + 171, 171, 79, 83, 71, 78, + 44, 0, 0, 0, 1, 0, + 0, 0, 8, 0, 0, 0, + 32, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 3, 0, 0, 0, 0, 0, + 0, 0, 15, 0, 0, 0, + 83, 86, 95, 84, 97, 114, + 103, 101, 116, 0, 171, 171, + 83, 72, 69, 88, 60, 0, + 0, 0, 80, 0, 0, 0, + 15, 0, 0, 0, 106, 8, + 0, 1, 98, 32, 0, 3, + 242, 16, 16, 0, 0, 0, + 0, 0, 101, 0, 0, 3, + 242, 32, 16, 0, 0, 0, + 0, 0, 54, 0, 0, 5, + 242, 32, 16, 0, 0, 0, + 0, 0, 70, 30, 16, 0, + 0, 0, 0, 0, 62, 0, + 0, 1, 83, 84, 65, 84, + 148, 0, 0, 0, 2, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 2, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0 +}; diff --git a/third_party/rive_renderer/source/generated/shaders/d3d/color_ramp.vert.h b/third_party/rive_renderer/source/generated/shaders/d3d/color_ramp.vert.h new file mode 100644 index 0000000..1d70455 --- /dev/null +++ b/third_party/rive_renderer/source/generated/shaders/d3d/color_ramp.vert.h @@ -0,0 +1,501 @@ +#if 0 +// +// Generated by Microsoft (R) HLSL Shader Compiler 10.1 +// +// +// Buffer Definitions: +// +// cbuffer VB +// { +// +// struct +// { +// +// float sa; // Offset: 0 +// float Fa; // Offset: 4 +// float bd; // Offset: 8 +// float cd; // Offset: 12 +// uint Ga; // Offset: 16 +// uint id; // Offset: 20 +// uint Oc; // Offset: 24 +// uint Pc; // Offset: 28 +// int4 J6; // Offset: 32 +// float2 U4; // Offset: 48 +// float2 Ha; // Offset: 56 +// uint Z2; // Offset: 64 +// uint d5; // Offset: 68 +// float C1; // Offset: 72 +// uint jd; // Offset: 76 +// +// } q; // Offset: 0 Size: 80 +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim HLSL Bind Count +// ------------------------------ ---------- ------- ----------- -------------- ------ +// VB cbuffer NA NA cb0 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------- ------ +// AC 0 xyzw 0 NONE uint xyzw +// SV_VertexID 0 x 1 VERTID uint x +// SV_InstanceID 0 x 2 INSTID uint +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------- ------ +// TEXCOORD 0 xyzw 0 NONE float xyzw +// SV_Position 0 xyzw 1 POS float xyzw +// +vs_5_0 +dcl_globalFlags refactoringAllowed +dcl_constantbuffer CB0[1], immediateIndexed +dcl_input v0.xyzw +dcl_input_sgv v1.x, vertex_id +dcl_output o0.xyzw +dcl_output_siv o1.xyzw, position +dcl_temps 2 +ushr r0.x, v1.x, l(1) +ige r0.y, l(1), r0.x +ieq r0.xz, r0.xxxx, l(0, 0, 3, 0) +movc r1.z, r0.y, v0.z, v0.w +ushr r1.xyw, r1.zzzz, l(16, 8, 0, 24) +and r1.xyzw, r1.xyzw, l(255, 255, 255, 255) +utof r1.xyzw, r1.xyzw +mul o0.xyzw, r1.xyzw, l(0.003922, 0.003922, 0.003922, 0.003922) +ushr r0.w, v0.x, l(16) +and r1.xyzw, v0.xyyy, l(0x0000ffff, 0x1fffffff, 0x80000000, 0x20000000) +movc r0.y, r0.y, r1.x, r0.w +utof r0.y, r0.y +mad r0.w, r0.y, l(0.000015), l(-0.001953) +mul r0.y, r0.y, l(0.000015) +movc r0.w, r1.w, l(0), r0.w +ine r1.x, r1.z, l(0) +and r0.x, r0.x, r1.x +movc r0.x, r0.x, r0.w, r0.y +add r0.y, r0.x, l(0.001953) +movc r0.y, r1.w, l(1.000000), r0.y +utof r0.w, r1.y +and r1.x, v0.y, l(0x40000000) +ine r1.x, r1.x, l(0) +and r0.z, r0.z, r1.x +movc r0.x, r0.z, r0.y, r0.x +mad o1.x, r0.x, l(2.000000), l(-1.000000) +and r0.x, v1.x, l(1) +movc r0.xy, r0.xxxx, l(1.000000,0,0,0), l(0,1.000000,0,0) +lt r0.z, cb0[0].x, l(0.000000) +movc r0.x, r0.z, r0.y, r0.x +add r0.x, r0.x, r0.w +lt r0.y, l(0.000000), cb0[0].x +iadd r0.y, -r0.y, r0.z +itof r0.y, r0.y +mad o1.y, r0.x, cb0[0].x, -r0.y +mov o1.zw, l(0,0,0,1.000000) +ret +// Approximately 37 instruction slots used +#endif + +const BYTE g_main[] = +{ + 68, 88, 66, 67, 20, 224, + 173, 88, 36, 114, 91, 130, + 108, 185, 74, 215, 95, 3, + 88, 249, 1, 0, 0, 0, + 48, 9, 0, 0, 5, 0, + 0, 0, 52, 0, 0, 0, + 200, 2, 0, 0, 64, 3, + 0, 0, 152, 3, 0, 0, + 148, 8, 0, 0, 82, 68, + 69, 70, 140, 2, 0, 0, + 1, 0, 0, 0, 96, 0, + 0, 0, 1, 0, 0, 0, + 60, 0, 0, 0, 0, 5, + 254, 255, 0, 1, 0, 0, + 100, 2, 0, 0, 82, 68, + 49, 49, 60, 0, 0, 0, + 24, 0, 0, 0, 32, 0, + 0, 0, 40, 0, 0, 0, + 36, 0, 0, 0, 12, 0, + 0, 0, 0, 0, 0, 0, + 92, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 1, 0, + 0, 0, 86, 66, 0, 171, + 92, 0, 0, 0, 1, 0, + 0, 0, 120, 0, 0, 0, + 80, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 160, 0, 0, 0, 0, 0, + 0, 0, 80, 0, 0, 0, + 2, 0, 0, 0, 64, 2, + 0, 0, 0, 0, 0, 0, + 255, 255, 255, 255, 0, 0, + 0, 0, 255, 255, 255, 255, + 0, 0, 0, 0, 113, 0, + 60, 117, 110, 110, 97, 109, + 101, 100, 62, 0, 115, 97, + 0, 102, 108, 111, 97, 116, + 0, 171, 171, 171, 0, 0, + 3, 0, 1, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 175, 0, 0, 0, 70, 97, + 0, 98, 100, 0, 99, 100, + 0, 71, 97, 0, 100, 119, + 111, 114, 100, 0, 171, 171, + 0, 0, 19, 0, 1, 0, + 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 232, 0, 0, 0, + 105, 100, 0, 79, 99, 0, + 80, 99, 0, 74, 54, 0, + 105, 110, 116, 52, 0, 171, + 171, 171, 1, 0, 2, 0, + 1, 0, 4, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 32, 1, + 0, 0, 85, 52, 0, 102, + 108, 111, 97, 116, 50, 0, + 171, 171, 1, 0, 3, 0, + 1, 0, 2, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 79, 1, + 0, 0, 72, 97, 0, 90, + 50, 0, 100, 53, 0, 67, + 49, 0, 106, 100, 0, 171, + 172, 0, 0, 0, 184, 0, + 0, 0, 0, 0, 0, 0, + 220, 0, 0, 0, 184, 0, + 0, 0, 4, 0, 0, 0, + 223, 0, 0, 0, 184, 0, + 0, 0, 8, 0, 0, 0, + 226, 0, 0, 0, 184, 0, + 0, 0, 12, 0, 0, 0, + 229, 0, 0, 0, 240, 0, + 0, 0, 16, 0, 0, 0, + 20, 1, 0, 0, 240, 0, + 0, 0, 20, 0, 0, 0, + 23, 1, 0, 0, 240, 0, + 0, 0, 24, 0, 0, 0, + 26, 1, 0, 0, 240, 0, + 0, 0, 28, 0, 0, 0, + 29, 1, 0, 0, 40, 1, + 0, 0, 32, 0, 0, 0, + 76, 1, 0, 0, 88, 1, + 0, 0, 48, 0, 0, 0, + 124, 1, 0, 0, 88, 1, + 0, 0, 56, 0, 0, 0, + 127, 1, 0, 0, 240, 0, + 0, 0, 64, 0, 0, 0, + 130, 1, 0, 0, 240, 0, + 0, 0, 68, 0, 0, 0, + 133, 1, 0, 0, 184, 0, + 0, 0, 72, 0, 0, 0, + 136, 1, 0, 0, 240, 0, + 0, 0, 76, 0, 0, 0, + 5, 0, 0, 0, 1, 0, + 20, 0, 0, 0, 15, 0, + 140, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 162, 0, 0, 0, + 77, 105, 99, 114, 111, 115, + 111, 102, 116, 32, 40, 82, + 41, 32, 72, 76, 83, 76, + 32, 83, 104, 97, 100, 101, + 114, 32, 67, 111, 109, 112, + 105, 108, 101, 114, 32, 49, + 48, 46, 49, 0, 73, 83, + 71, 78, 112, 0, 0, 0, + 3, 0, 0, 0, 8, 0, + 0, 0, 80, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 15, 15, + 0, 0, 83, 0, 0, 0, + 0, 0, 0, 0, 6, 0, + 0, 0, 1, 0, 0, 0, + 1, 0, 0, 0, 1, 1, + 0, 0, 95, 0, 0, 0, + 0, 0, 0, 0, 8, 0, + 0, 0, 1, 0, 0, 0, + 2, 0, 0, 0, 1, 0, + 0, 0, 65, 67, 0, 83, + 86, 95, 86, 101, 114, 116, + 101, 120, 73, 68, 0, 83, + 86, 95, 73, 110, 115, 116, + 97, 110, 99, 101, 73, 68, + 0, 171, 171, 171, 79, 83, + 71, 78, 80, 0, 0, 0, + 2, 0, 0, 0, 8, 0, + 0, 0, 56, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 3, 0, 0, 0, + 0, 0, 0, 0, 15, 0, + 0, 0, 65, 0, 0, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 3, 0, 0, 0, + 1, 0, 0, 0, 15, 0, + 0, 0, 84, 69, 88, 67, + 79, 79, 82, 68, 0, 83, + 86, 95, 80, 111, 115, 105, + 116, 105, 111, 110, 0, 171, + 171, 171, 83, 72, 69, 88, + 244, 4, 0, 0, 80, 0, + 1, 0, 61, 1, 0, 0, + 106, 8, 0, 1, 89, 0, + 0, 4, 70, 142, 32, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 95, 0, 0, 3, + 242, 16, 16, 0, 0, 0, + 0, 0, 96, 0, 0, 4, + 18, 16, 16, 0, 1, 0, + 0, 0, 6, 0, 0, 0, + 101, 0, 0, 3, 242, 32, + 16, 0, 0, 0, 0, 0, + 103, 0, 0, 4, 242, 32, + 16, 0, 1, 0, 0, 0, + 1, 0, 0, 0, 104, 0, + 0, 2, 2, 0, 0, 0, + 85, 0, 0, 7, 18, 0, + 16, 0, 0, 0, 0, 0, + 10, 16, 16, 0, 1, 0, + 0, 0, 1, 64, 0, 0, + 1, 0, 0, 0, 33, 0, + 0, 7, 34, 0, 16, 0, + 0, 0, 0, 0, 1, 64, + 0, 0, 1, 0, 0, 0, + 10, 0, 16, 0, 0, 0, + 0, 0, 32, 0, 0, 10, + 82, 0, 16, 0, 0, 0, + 0, 0, 6, 0, 16, 0, + 0, 0, 0, 0, 2, 64, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3, 0, + 0, 0, 0, 0, 0, 0, + 55, 0, 0, 9, 66, 0, + 16, 0, 1, 0, 0, 0, + 26, 0, 16, 0, 0, 0, + 0, 0, 42, 16, 16, 0, + 0, 0, 0, 0, 58, 16, + 16, 0, 0, 0, 0, 0, + 85, 0, 0, 10, 178, 0, + 16, 0, 1, 0, 0, 0, + 166, 10, 16, 0, 1, 0, + 0, 0, 2, 64, 0, 0, + 16, 0, 0, 0, 8, 0, + 0, 0, 0, 0, 0, 0, + 24, 0, 0, 0, 1, 0, + 0, 10, 242, 0, 16, 0, + 1, 0, 0, 0, 70, 14, + 16, 0, 1, 0, 0, 0, + 2, 64, 0, 0, 255, 0, + 0, 0, 255, 0, 0, 0, + 255, 0, 0, 0, 255, 0, + 0, 0, 86, 0, 0, 5, + 242, 0, 16, 0, 1, 0, + 0, 0, 70, 14, 16, 0, + 1, 0, 0, 0, 56, 0, + 0, 10, 242, 32, 16, 0, + 0, 0, 0, 0, 70, 14, + 16, 0, 1, 0, 0, 0, + 2, 64, 0, 0, 129, 128, + 128, 59, 129, 128, 128, 59, + 129, 128, 128, 59, 129, 128, + 128, 59, 85, 0, 0, 7, + 130, 0, 16, 0, 0, 0, + 0, 0, 10, 16, 16, 0, + 0, 0, 0, 0, 1, 64, + 0, 0, 16, 0, 0, 0, + 1, 0, 0, 10, 242, 0, + 16, 0, 1, 0, 0, 0, + 70, 21, 16, 0, 0, 0, + 0, 0, 2, 64, 0, 0, + 255, 255, 0, 0, 255, 255, + 255, 31, 0, 0, 0, 128, + 0, 0, 0, 32, 55, 0, + 0, 9, 34, 0, 16, 0, + 0, 0, 0, 0, 26, 0, + 16, 0, 0, 0, 0, 0, + 10, 0, 16, 0, 1, 0, + 0, 0, 58, 0, 16, 0, + 0, 0, 0, 0, 86, 0, + 0, 5, 34, 0, 16, 0, + 0, 0, 0, 0, 26, 0, + 16, 0, 0, 0, 0, 0, + 50, 0, 0, 9, 130, 0, + 16, 0, 0, 0, 0, 0, + 26, 0, 16, 0, 0, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 128, 55, 1, 64, + 0, 0, 0, 0, 0, 187, + 56, 0, 0, 7, 34, 0, + 16, 0, 0, 0, 0, 0, + 26, 0, 16, 0, 0, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 128, 55, 55, 0, + 0, 9, 130, 0, 16, 0, + 0, 0, 0, 0, 58, 0, + 16, 0, 1, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 0, 0, 58, 0, 16, 0, + 0, 0, 0, 0, 39, 0, + 0, 7, 18, 0, 16, 0, + 1, 0, 0, 0, 42, 0, + 16, 0, 1, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 7, + 18, 0, 16, 0, 0, 0, + 0, 0, 10, 0, 16, 0, + 0, 0, 0, 0, 10, 0, + 16, 0, 1, 0, 0, 0, + 55, 0, 0, 9, 18, 0, + 16, 0, 0, 0, 0, 0, + 10, 0, 16, 0, 0, 0, + 0, 0, 58, 0, 16, 0, + 0, 0, 0, 0, 26, 0, + 16, 0, 0, 0, 0, 0, + 0, 0, 0, 7, 34, 0, + 16, 0, 0, 0, 0, 0, + 10, 0, 16, 0, 0, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 0, 59, 55, 0, + 0, 9, 34, 0, 16, 0, + 0, 0, 0, 0, 58, 0, + 16, 0, 1, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 128, 63, 26, 0, 16, 0, + 0, 0, 0, 0, 86, 0, + 0, 5, 130, 0, 16, 0, + 0, 0, 0, 0, 26, 0, + 16, 0, 1, 0, 0, 0, + 1, 0, 0, 7, 18, 0, + 16, 0, 1, 0, 0, 0, + 26, 16, 16, 0, 0, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 0, 64, 39, 0, + 0, 7, 18, 0, 16, 0, + 1, 0, 0, 0, 10, 0, + 16, 0, 1, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 7, + 66, 0, 16, 0, 0, 0, + 0, 0, 42, 0, 16, 0, + 0, 0, 0, 0, 10, 0, + 16, 0, 1, 0, 0, 0, + 55, 0, 0, 9, 18, 0, + 16, 0, 0, 0, 0, 0, + 42, 0, 16, 0, 0, 0, + 0, 0, 26, 0, 16, 0, + 0, 0, 0, 0, 10, 0, + 16, 0, 0, 0, 0, 0, + 50, 0, 0, 9, 18, 32, + 16, 0, 1, 0, 0, 0, + 10, 0, 16, 0, 0, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 0, 64, 1, 64, + 0, 0, 0, 0, 128, 191, + 1, 0, 0, 7, 18, 0, + 16, 0, 0, 0, 0, 0, + 10, 16, 16, 0, 1, 0, + 0, 0, 1, 64, 0, 0, + 1, 0, 0, 0, 55, 0, + 0, 15, 50, 0, 16, 0, + 0, 0, 0, 0, 6, 0, + 16, 0, 0, 0, 0, 0, + 2, 64, 0, 0, 0, 0, + 128, 63, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 2, 64, 0, 0, + 0, 0, 0, 0, 0, 0, + 128, 63, 0, 0, 0, 0, + 0, 0, 0, 0, 49, 0, + 0, 8, 66, 0, 16, 0, + 0, 0, 0, 0, 10, 128, + 32, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 0, 0, + 55, 0, 0, 9, 18, 0, + 16, 0, 0, 0, 0, 0, + 42, 0, 16, 0, 0, 0, + 0, 0, 26, 0, 16, 0, + 0, 0, 0, 0, 10, 0, + 16, 0, 0, 0, 0, 0, + 0, 0, 0, 7, 18, 0, + 16, 0, 0, 0, 0, 0, + 10, 0, 16, 0, 0, 0, + 0, 0, 58, 0, 16, 0, + 0, 0, 0, 0, 49, 0, + 0, 8, 34, 0, 16, 0, + 0, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 0, 0, + 10, 128, 32, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 30, 0, 0, 8, 34, 0, + 16, 0, 0, 0, 0, 0, + 26, 0, 16, 128, 65, 0, + 0, 0, 0, 0, 0, 0, + 42, 0, 16, 0, 0, 0, + 0, 0, 43, 0, 0, 5, + 34, 0, 16, 0, 0, 0, + 0, 0, 26, 0, 16, 0, + 0, 0, 0, 0, 50, 0, + 0, 11, 34, 32, 16, 0, + 1, 0, 0, 0, 10, 0, + 16, 0, 0, 0, 0, 0, + 10, 128, 32, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 26, 0, 16, 128, 65, 0, + 0, 0, 0, 0, 0, 0, + 54, 0, 0, 8, 194, 32, + 16, 0, 1, 0, 0, 0, + 2, 64, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 128, 63, 62, 0, 0, 1, + 83, 84, 65, 84, 148, 0, + 0, 0, 37, 0, 0, 0, + 2, 0, 0, 0, 0, 0, + 0, 0, 4, 0, 0, 0, + 9, 0, 0, 0, 5, 0, + 0, 0, 9, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 8, 0, + 0, 0, 4, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0 +}; diff --git a/third_party/rive_renderer/source/generated/shaders/d3d/render_atlas.vert.h b/third_party/rive_renderer/source/generated/shaders/d3d/render_atlas.vert.h new file mode 100644 index 0000000..1747dce --- /dev/null +++ b/third_party/rive_renderer/source/generated/shaders/d3d/render_atlas.vert.h @@ -0,0 +1,2417 @@ +#if 0 +// +// Generated by Microsoft (R) HLSL Shader Compiler 10.1 +// +// +// Buffer Definitions: +// +// cbuffer VB +// { +// +// struct +// { +// +// float sa; // Offset: 0 +// float Fa; // Offset: 4 +// float bd; // Offset: 8 +// float cd; // Offset: 12 +// uint Ga; // Offset: 16 +// uint id; // Offset: 20 +// uint Oc; // Offset: 24 +// uint Pc; // Offset: 28 +// int4 J6; // Offset: 32 +// float2 U4; // Offset: 48 +// float2 Ha; // Offset: 56 +// uint Z2; // Offset: 64 +// uint d5; // Offset: 68 +// float C1; // Offset: 72 +// uint jd; // Offset: 76 +// +// } q; // Offset: 0 Size: 80 +// +// } +// +// cbuffer Mf +// { +// +// uint ze; // Offset: 0 Size: 4 +// uint PENf; // Offset: 4 Size: 4 [unused] +// uint PEOf; // Offset: 8 Size: 4 [unused] +// uint PEPf; // Offset: 12 Size: 4 [unused] +// +// } +// +// Resource bind info for JB +// { +// +// uint4 $Element; // Offset: 0 Size: 16 +// +// } +// +// Resource bind info for QC +// { +// +// uint4 $Element; // Offset: 0 Size: 16 +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim HLSL Bind Count +// ------------------------------ ---------- ------- ----------- -------------- ------ +// JB texture struct r/o t3 1 +// QC texture struct r/o t6 1 +// BC texture uint4 2d t8 1 +// VB cbuffer NA NA cb0 1 +// Mf cbuffer NA NA cb1 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------- ------ +// LB 0 xyzw 0 NONE float xyzw +// MB 0 xyzw 1 NONE float xyz +// SV_VertexID 0 x 2 VERTID uint +// SV_InstanceID 0 x 3 INSTID uint x +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------- ------ +// TEXCOORD 0 xyzw 0 NONE float xyzw +// SV_Position 0 xyzw 1 POS float xyzw +// +vs_5_0 +dcl_globalFlags refactoringAllowed +dcl_constantbuffer CB0[5], immediateIndexed +dcl_constantbuffer CB1[1], immediateIndexed +dcl_resource_structured t3, 16 +dcl_resource_structured t6, 16 +dcl_resource_texture2d (uint,uint,uint,uint) t8 +dcl_input v0.xyzw +dcl_input v1.xyz +dcl_input_sgv v3.x, instance_id +dcl_output o0.xyzw +dcl_output_siv o1.xyzw, position +dcl_temps 14 +iadd r0.x, v3.x, cb1[0].x +ftoi r1.x, v0.x +ishr r0.y, v0.w, l(2) +and r0.z, v0.w, l(3) +iadd r0.w, r0.y, l(-1) +imin r0.w, r0.w, r1.x +imad r0.x, r0.x, r0.y, r0.w +and r2.x, r0.x, l(2047) +ishr r2.y, r0.x, l(11) +mov r2.zw, l(0,0,0,0) +ld_indexable(texture2d)(uint,uint,uint,uint) r2.xyzw, r2.xyzw, t8.xyzw +and r3.xy, r2.wwww, l(0x0000ffff, 0x00800000, 0, 0) +iadd r0.y, r3.x, l(-1) +ld_structured_indexable(structured_buffer, stride=16)(mixed,mixed,mixed,mixed) r4.xyzw, r0.y, l(0), t6.xyzw +bfi r3.xz, l(16, 0, 16, 0), l(2, 0, 2, 0), r4.zzzz, l(0, 0, 2, 0) +ld_structured_indexable(structured_buffer, stride=16)(mixed,mixed,mixed,mixed) r5.xyzw, r3.x, l(0), t3.xyzw +iadd r0.y, r3.x, l(1) +ld_structured_indexable(structured_buffer, stride=16)(mixed,mixed,mixed,mixed) r6.xyzw, r0.y, l(0), t3.xyzw +ftoi r7.x, v1.x +mov r7.yz, v1.yyzy +mov r1.yz, v0.yyzy +movc r1.xyz, r3.yyyy, r7.zxyz, r1.zxyz +ine r0.y, r0.w, r1.y +if_nz r0.y + iadd r0.y, r0.x, r1.y + iadd r0.y, -r0.w, r0.y + and r7.x, r0.y, l(2047) + ishr r7.y, r0.y, l(11) + mov r7.zw, l(0,0,0,0) + ld_indexable(texture2d)(uint,uint,uint,uint) r7.xyzw, r7.xyzw, t8.wxyz + and r0.w, r7.x, l(0x0080ffff) + and r3.x, r2.w, l(0x0080ffff) + ine r0.w, r0.w, r3.x + if_nz r0.w + eq r0.w, r6.z, l(0.000000) + ne r3.x, r4.x, l(0.000000) + or r0.w, r0.w, r3.x + if_nz r0.w + and r8.x, r4.w, l(2047) + ishr r8.y, r4.w, l(11) + mov r8.zw, l(0,0,0,0) + ld_indexable(texture2d)(uint,uint,uint,uint) r7.xyzw, r8.xyzw, t8.wxyz + mov r0.x, r4.w + mov r2.xyz, r7.yzwy + else + mov r7.x, r2.w + endif + else + mov r0.x, r0.y + mov r2.xyz, r7.yzwy + endif + and r0.y, r7.x, l(0xff7fffff) + iadd r2.w, r3.y, r0.y +endif +and r0.y, r2.w, l(0x1c000000) +ieq r0.w, r0.y, l(0x04000000) +ieq r3.x, r0.z, l(0) +and r0.w, r0.w, r3.x +if_nz r0.w + and r3.x, r2.z, l(0x0000ffff) + utof r7.z, r3.x + ushr r3.x, r2.z, l(16) + utof r3.x, r3.x + add r3.y, -r7.z, l(-1.000000) + add r3.w, -r7.z, r3.x + add r3.w, r3.w, l(1.000000) + ftoi r8.xy, r3.ywyy + and r3.y, r2.w, l(0x00800000) + ineg r8.zw, r8.xxxy + movc r3.yw, r3.yyyy, r8.zzzw, r8.xxxy + iadd r3.yw, r0.xxxx, r3.yyyw + and r8.xy, r3.ywyy, l(2047, 2047, 0, 0) + ishr r9.xy, r3.ywyy, l(11, 11, 0, 0) + mov r8.z, r9.x + mov r8.w, l(0) + ld_indexable(texture2d)(uint,uint,uint,uint) r3.yw, r8.xzww, t8.xzyw + mov r9.zw, r8.yyyw + ld_indexable(texture2d)(uint,uint,uint,uint) r8.xy, r9.zyww, t8.zwxy + and r4.z, r8.y, l(0x0080ffff) + and r3.w, r3.w, l(0x0080ffff) + ine r3.w, r3.w, r4.z + if_nz r3.w + and r9.x, r4.w, l(2047) + ishr r9.y, r4.w, l(11) + mov r9.zw, l(0,0,0,0) + ld_indexable(texture2d)(uint,uint,uint,uint) r8.x, r9.xyzw, t8.zwxy + endif + add r3.w, -r3.y, r8.x + lt r4.z, l(3.141593), |r3.w| + lt r4.w, l(0.000000), r3.w + lt r8.y, r3.w, l(0.000000) + iadd r4.w, -r4.w, r8.y + itof r4.w, r4.w + mad r4.w, -r4.w, l(6.283185), r3.w + movc r9.y, r4.z, r4.w, r3.w + add r3.xw, r3.xxxx, l(-2.000000, 0.000000, 0.000000, -3.000000) + mul r4.z, r3.x, |r9.y| + mul r4.z, r4.z, l(0.318310) + round_ne r4.z, r4.z + max r4.z, r4.z, l(1.000000) + min r10.w, r3.w, r4.z + add r7.w, r3.x, -r10.w + ge r3.x, r7.w, r7.z + lt r3.w, l(0.000000), r9.y + lt r4.z, r9.y, l(0.000000) + iadd r3.w, -r3.w, r4.z + itof r3.w, r3.w + mad r3.w, r3.w, l(3.141593), -r9.y + mov r7.y, -r3.w + eq r3.w, r7.w, r7.z + movc r7.x, r3.w, -r1.z, r1.z + add r4.zw, r7.wwww, l(0.000000, 0.000000, 1.000000, 2.000000) + eq r3.w, r4.z, r7.z + add r10.z, -r4.w, r7.z + mov r10.x, r1.z + movc r9.xzw, r3.wwww, l(0,0,0,0), r10.xxzw + movc r7.xyzw, r3.xxxx, r7.xyzw, r9.xyzw + eq r3.x, r7.w, r7.z + div r3.w, r7.z, r7.w + mad r3.w, r7.y, r3.w, r3.y + movc r2.z, r3.x, r8.x, r3.w + mov r3.x, r7.x + mov r7.x, r3.y +else + mov r3.x, r1.z +endif +sincos r8.x, r9.x, r2.z +mov r8.y, -r9.x +ne r3.yw, r6.wwwz, l(0.000000, 0.000000, 0.000000, 0.000000) +dp2 r9.x, r8.xyxx, r5.xzxx +dp2 r9.y, r8.xyxx, r5.ywyy +dp2 r4.z, r9.xyxx, r9.xyxx +sqrt r4.w, r4.z +div r4.w, l(1.000000, 1.000000, 1.000000, 1.000000), r4.w +max r4.w, r4.w, r6.w +movc r3.y, r3.y, r4.w, r6.w +if_nz r3.w + mul r3.w, r5.z, r5.y + mad r3.w, r5.x, r5.w, -r3.w + lt r4.w, l(0.000000), r3.w + lt r3.w, r3.w, l(0.000000) + iadd r3.w, -r4.w, r3.w + itof r3.w, r3.w + mul r3.w, r3.w, r3.x + and r7.zw, r2.wwww, l(0, 0, 0x00100000, 0x00080000) + min r4.w, r3.w, l(0.000000) + movc r3.w, r7.z, r4.w, r3.w + max r4.w, r3.w, l(0.000000) + movc r3.w, r7.w, r4.w, r3.w + ne r4.w, r3.y, l(0.000000) + add r6.w, |r9.y|, |r9.x| + div r4.z, l(1.000000, 1.000000, 1.000000, 1.000000), r4.z + mul r4.z, r4.z, r6.w + mul r4.z, r4.z, l(0.500000) + movc r9.x, r4.w, r3.y, r4.z + lt r4.z, r6.z, r9.x + eq r6.w, r3.y, l(0.000000) + and r4.z, r4.z, r6.w + div r9.y, r6.z, r9.x + mov r10.x, r6.z + mov r10.y, l(1.000000) + movc r6.zw, r4.zzzz, r9.xxxy, r10.xxxy + add r4.z, r9.x, r6.z + mul r8.zw, r4.zzzz, r8.xxxy + mul r10.x, r3.w, r4.z + add r7.w, r9.x, r9.x + div r7.w, l(1.000000, 1.000000, 1.000000, 1.000000), r7.w + mov r10.y, -r10.x + add r9.yz, r6.zzzz, r10.xxyx + mad r9.yz, r7.wwww, r9.yyzy, l(0.000000, 0.500000, 0.500000, 0.000000) + ult r7.w, l(0x08000000), r0.y + if_nz r7.w + and r10.xyzw, r2.wwww, l(0x00400000, 0x00800000, 0x02000000, 0x00200000) + movc r11.xyz, r10.xxzx, l(2,-2,1.000000,0), l(-2,2,0.250000,0) + movc r7.w, r10.y, r11.y, r11.x + iadd r0.x, r0.x, r7.w + and r12.x, r0.x, l(2047) + ishr r12.y, r0.x, l(11) + mov r12.zw, l(0,0,0,0) + ld_indexable(texture2d)(uint,uint,uint,uint) r0.x, r12.xyzw, t8.zxyw + add r0.x, -r2.z, r0.x + lt r7.w, l(3.141593), |r0.x| + add r10.y, -|r0.x|, l(6.283185) + movc r0.x, r7.w, r10.y, |r0.x| + ine r7.w, r10.x, l(0) + ine r10.x, r7.z, l(0) + ieq r7.w, r7.w, r10.x + movc r7.w, r7.w, l(-0.500000), l(0.500000) + mad r7.w, r0.x, r7.w, r2.z + sincos r10.x, r11.x, r7.w + mov r10.y, -r11.x + dp2 r11.x, r10.xyxx, r5.xzxx + dp2 r11.y, r10.xyxx, r5.ywyy + add r7.w, |r11.y|, |r11.x| + dp2 r10.z, r11.xyxx, r11.xyxx + div r10.z, l(1.000000, 1.000000, 1.000000, 1.000000), r10.z + mul r7.w, r7.w, r10.z + mul r0.x, r0.x, l(0.500000) + sincos null, r0.x, r0.x + ieq r11.xy, r0.yyyy, l(0x14000000, 0x10000000, 0, 0) + ge r0.y, r0.x, l(0.250000) + and r0.y, r0.y, r11.y + or r0.y, r0.y, r11.x + max r10.z, r11.z, r0.x + div r10.z, l(1.000000, 1.000000, 1.000000, 1.000000), r10.z + mul r10.z, r6.z, r10.z + mul r11.x, r7.w, l(0.500000) + mad r6.z, r6.z, r0.x, r11.x + movc r0.y, r0.y, r10.z, r6.z + mad r0.y, r7.w, l(0.500000), r0.y + mul r6.z, r9.x, l(0.125000) + mad r6.z, r0.y, r0.x, r6.z + ge r6.z, r6.z, r4.z + div r0.x, l(1.000000, 1.000000, 1.000000, 1.000000), r0.x + mul r0.x, r0.x, r4.z + mul r11.xyzw, r0.xxyy, r10.xyyx + dp2 r12.x, r8.zwzz, r8.zwzz + dp2 r12.y, r11.zwzz, r11.zwzz + mul r0.x, r8.w, r11.w + mad r0.x, r8.z, r11.z, -r0.x + div r0.x, l(1.000000, 1.000000, 1.000000, 1.000000), r0.x + mul r13.xz, r11.zzwz, l(1.000000, 0.000000, -1.000000, 0.000000) + mul r13.yw, r8.wwwz, l(0.000000, -1.000000, 0.000000, 1.000000) + mul r13.xyzw, r0.xxxx, r13.xyzw + dp2 r13.x, r13.xyxx, r12.xyxx + dp2 r13.y, r13.zwzz, r12.xyxx + movc r11.xy, r6.zzzz, r11.xyxx, r13.xyxx + movc r8.zw, r10.wwww, r11.xxxy, r8.zzzw + mul r10.zw, |r3.wwww|, r8.zzzw + dp2 r0.x, r10.zwzz, r10.xyxx + add r0.x, -r0.x, r0.y + div r9.w, r0.x, r7.w + movc r9.yz, r7.zzzz, r9.yywy, r9.wwzw + endif + mul r0.xy, r6.wwww, r9.yzyy + max r1.y, r0.y, l(0.000100) + mad r0.y, -r9.y, r6.w, l(-2.000000) + movc r1.x, r4.w, r0.y, r0.x + mul r0.xy, r3.wwww, r8.zwzz + dp2 r9.x, r0.xyxx, r5.xzxx + dp2 r9.y, r0.xyxx, r5.ywyy + ine r0.x, r0.z, l(0) + mov o0.zw, l(0,0,0,0) +else + ne r0.y, r3.y, l(0.000000) + if_nz r0.y + lt r0.y, r7.y, l(0.000000) + add r10.x, r7.y, r7.x + mov r10.y, -r7.y + movc r4.zw, r0.yyyy, r10.xxxy, r7.xxxy + add r0.y, r2.z, -r4.z + add r0.y, r0.y, l(1.570796) + mul r0.y, r0.y, l(0.159155) + ge r2.z, r0.y, -r0.y + frc r0.y, |r0.y| + movc r0.y, r2.z, r0.y, -r0.y + mad r0.y, r0.y, l(6.283185), l(-1.570796) + max r0.y, r0.y, l(0.000000) + min r0.y, r4.w, r0.y + mul r2.z, r4.w, l(0.500000) + lt r2.z, r2.z, r0.y + add r3.w, -r0.y, r4.w + movc r0.y, r2.z, r3.w, r0.y + sincos r7.x, r10.x, r0.y + mov r7.y, r10.x + mad r6.zw, -r7.xxxy, |r3.xxxx|, l(0.000000, 0.000000, 1.000000, 1.000000) + mul r7.xy, r6.zwzz, l(0.500000, 0.500000, 0.000000, 0.000000) + add r0.y, r4.w, l(-1.570796) + lt r0.y, |r0.y|, l(0.001000) + sincos r10.x, r11.x, r4.w + div r2.z, r10.x, r11.x + add r3.w, -r4.w, l(1.570796) + lt r4.z, l(0.000000), r3.w + lt r3.w, r3.w, l(0.000000) + iadd r3.w, -r4.z, r3.w + itof r3.w, r3.w + max r4.z, |r2.z|, l(0.000001) + div r4.z, r3.w, r4.z + ge r3.w, r4.z, l(0.000000) + mad r10.xy, -r6.zwzz, l(0.500000, 0.500000, 0.000000, 0.000000), l(1.000000, -2.000000, 0.000000, 0.000000) + mad r6.z, -r10.x, r2.z, r7.y + mad r2.z, r7.x, r2.z, r7.y + movc r4.w, r3.w, r6.z, r2.z + movc r10.zw, r0.yyyy, l(0,0,0,0), r4.zzzw + max r0.y, r7.x, l(0.000000) + add r10.x, r0.y, l(0.250000) + mov r7.xw, r1.xxxx + mov r7.yz, l(0,-2.000000,1000000.000000,0) + movc r1.xyzw, r0.wwww, r10.xyzw, r7.xyzw + mul r0.y, r3.y, r3.x + mul r0.yw, r8.xxxy, r0.yyyy + dp2 r9.x, r0.ywyy, r5.xzxx + dp2 r9.y, r0.ywyy, r5.ywyy + mov o0.zw, r1.zzzw + else + mul r0.y, r5.z, r5.y + mad r0.y, r5.x, r5.w, -r0.y + div r0.y, l(1.000000, 1.000000, 1.000000, 1.000000), r0.y + mul r7.xyzw, r5.wyzx, l(1.000000, -1.000000, -1.000000, 1.000000) + mul r7.xyzw, r0.yyyy, r7.xyzw + mul r0.yw, r3.xxxx, r8.xxxy + dp2 r3.x, r7.xyxx, r0.ywyy + dp2 r3.y, r7.zwzz, r0.ywyy + lt r0.yw, l(0.000000, 0.000000, 0.000000, 0.000000), r3.xxxy + lt r1.zw, r3.xxxy, l(0.000000, 0.000000, 0.000000, 0.000000) + iadd r0.yw, -r0.yyyw, r1.zzzw + itof r0.yw, r0.yyyw + mul r9.xy, r0.ywyy, l(0.500000, 0.500000, 0.000000, 0.000000) + mov o0.zw, l(0,0,0,0) + mov r1.y, l(-1.000000) + endif + and r3.xyw, r2.wwww, l(0x00800000, 0x01000000, 0, 0x80000000) + ine r3.xyw, r3.xyxw, l(0, 0, 0, 0) + ine r0.y, r3.y, r3.x + movc r1.x, r0.y, -r1.x, r1.x + ieq r0.y, r0.z, l(2) + movc r2.xy, r0.yyyy, r4.xyxx, r2.xyxx + ine r0.y, r0.z, l(1) + and r0.x, r0.y, r3.w +endif +dp2 r3.x, r2.xyxx, r5.xzxx +dp2 r3.y, r2.xyxx, r5.ywyy +add r0.yz, r9.xxyx, r3.xxyx +add r0.yz, r6.xxyx, r0.yyzy +movc r0.w, cb0[4].w, l(1.000000), l(0) +add r1.zw, -r1.xxxy, l(0.000000, 0.000000, 1.000000, -1.000000) +mad r1.zw, r0.wwww, r1.zzzw, r1.xxxy +movc o0.xy, r0.xxxx, r1.xyxx, r1.zwzz +ld_structured_indexable(structured_buffer, stride=16)(mixed,mixed,mixed,mixed) r1.xyz, r3.z, l(4), t3.xyzx +mad r0.yz, r0.yyzy, r1.xxxx, r1.yyzy +mad r1.x, r0.y, cb0[3].z, l(-1.000000) +lt r0.y, l(0.000000), cb0[3].w +lt r0.w, cb0[3].w, l(0.000000) +iadd r0.y, -r0.y, r0.w +itof r0.y, r0.y +mad r1.y, r0.z, cb0[3].w, -r0.y +mov r1.zw, l(0,0,0,1.000000) +movc o1.xyzw, r0.xxxx, cb0[4].zzzz, r1.xyzw +ret +// Approximately 339 instruction slots used +#endif + +const BYTE g_main[] = +{ + 68, 88, 66, 67, 127, 48, + 214, 0, 182, 194, 196, 84, + 216, 209, 78, 226, 108, 71, + 10, 252, 1, 0, 0, 0, + 56, 46, 0, 0, 5, 0, + 0, 0, 52, 0, 0, 0, + 248, 4, 0, 0, 136, 5, + 0, 0, 224, 5, 0, 0, + 156, 45, 0, 0, 82, 68, + 69, 70, 188, 4, 0, 0, + 4, 0, 0, 0, 236, 0, + 0, 0, 5, 0, 0, 0, + 60, 0, 0, 0, 0, 5, + 254, 255, 0, 1, 0, 0, + 148, 4, 0, 0, 82, 68, + 49, 49, 60, 0, 0, 0, + 24, 0, 0, 0, 32, 0, + 0, 0, 40, 0, 0, 0, + 36, 0, 0, 0, 12, 0, + 0, 0, 0, 0, 0, 0, + 220, 0, 0, 0, 5, 0, + 0, 0, 6, 0, 0, 0, + 1, 0, 0, 0, 16, 0, + 0, 0, 3, 0, 0, 0, + 1, 0, 0, 0, 1, 0, + 0, 0, 223, 0, 0, 0, + 5, 0, 0, 0, 6, 0, + 0, 0, 1, 0, 0, 0, + 16, 0, 0, 0, 6, 0, + 0, 0, 1, 0, 0, 0, + 1, 0, 0, 0, 226, 0, + 0, 0, 2, 0, 0, 0, + 4, 0, 0, 0, 4, 0, + 0, 0, 255, 255, 255, 255, + 8, 0, 0, 0, 1, 0, + 0, 0, 13, 0, 0, 0, + 229, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 1, 0, + 0, 0, 232, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 1, 0, 0, 0, + 1, 0, 0, 0, 74, 66, + 0, 81, 67, 0, 66, 67, + 0, 86, 66, 0, 77, 102, + 0, 171, 229, 0, 0, 0, + 1, 0, 0, 0, 76, 1, + 0, 0, 80, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 232, 0, 0, 0, + 4, 0, 0, 0, 56, 3, + 0, 0, 16, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 220, 0, 0, 0, + 1, 0, 0, 0, 16, 4, + 0, 0, 16, 0, 0, 0, + 0, 0, 0, 0, 3, 0, + 0, 0, 223, 0, 0, 0, + 1, 0, 0, 0, 108, 4, + 0, 0, 16, 0, 0, 0, + 0, 0, 0, 0, 3, 0, + 0, 0, 116, 1, 0, 0, + 0, 0, 0, 0, 80, 0, + 0, 0, 2, 0, 0, 0, + 20, 3, 0, 0, 0, 0, + 0, 0, 255, 255, 255, 255, + 0, 0, 0, 0, 255, 255, + 255, 255, 0, 0, 0, 0, + 113, 0, 60, 117, 110, 110, + 97, 109, 101, 100, 62, 0, + 115, 97, 0, 102, 108, 111, + 97, 116, 0, 171, 171, 171, + 0, 0, 3, 0, 1, 0, + 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 131, 1, 0, 0, + 70, 97, 0, 98, 100, 0, + 99, 100, 0, 71, 97, 0, + 100, 119, 111, 114, 100, 0, + 171, 171, 0, 0, 19, 0, + 1, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 188, 1, + 0, 0, 105, 100, 0, 79, + 99, 0, 80, 99, 0, 74, + 54, 0, 105, 110, 116, 52, + 0, 171, 171, 171, 1, 0, + 2, 0, 1, 0, 4, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 244, 1, 0, 0, 85, 52, + 0, 102, 108, 111, 97, 116, + 50, 0, 171, 171, 1, 0, + 3, 0, 1, 0, 2, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 35, 2, 0, 0, 72, 97, + 0, 90, 50, 0, 100, 53, + 0, 67, 49, 0, 106, 100, + 0, 171, 128, 1, 0, 0, + 140, 1, 0, 0, 0, 0, + 0, 0, 176, 1, 0, 0, + 140, 1, 0, 0, 4, 0, + 0, 0, 179, 1, 0, 0, + 140, 1, 0, 0, 8, 0, + 0, 0, 182, 1, 0, 0, + 140, 1, 0, 0, 12, 0, + 0, 0, 185, 1, 0, 0, + 196, 1, 0, 0, 16, 0, + 0, 0, 232, 1, 0, 0, + 196, 1, 0, 0, 20, 0, + 0, 0, 235, 1, 0, 0, + 196, 1, 0, 0, 24, 0, + 0, 0, 238, 1, 0, 0, + 196, 1, 0, 0, 28, 0, + 0, 0, 241, 1, 0, 0, + 252, 1, 0, 0, 32, 0, + 0, 0, 32, 2, 0, 0, + 44, 2, 0, 0, 48, 0, + 0, 0, 80, 2, 0, 0, + 44, 2, 0, 0, 56, 0, + 0, 0, 83, 2, 0, 0, + 196, 1, 0, 0, 64, 0, + 0, 0, 86, 2, 0, 0, + 196, 1, 0, 0, 68, 0, + 0, 0, 89, 2, 0, 0, + 140, 1, 0, 0, 72, 0, + 0, 0, 92, 2, 0, 0, + 196, 1, 0, 0, 76, 0, + 0, 0, 5, 0, 0, 0, + 1, 0, 20, 0, 0, 0, + 15, 0, 96, 2, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 118, 1, + 0, 0, 216, 3, 0, 0, + 0, 0, 0, 0, 4, 0, + 0, 0, 2, 0, 0, 0, + 220, 3, 0, 0, 0, 0, + 0, 0, 255, 255, 255, 255, + 0, 0, 0, 0, 255, 255, + 255, 255, 0, 0, 0, 0, + 0, 4, 0, 0, 4, 0, + 0, 0, 4, 0, 0, 0, + 0, 0, 0, 0, 220, 3, + 0, 0, 0, 0, 0, 0, + 255, 255, 255, 255, 0, 0, + 0, 0, 255, 255, 255, 255, + 0, 0, 0, 0, 5, 4, + 0, 0, 8, 0, 0, 0, + 4, 0, 0, 0, 0, 0, + 0, 0, 220, 3, 0, 0, + 0, 0, 0, 0, 255, 255, + 255, 255, 0, 0, 0, 0, + 255, 255, 255, 255, 0, 0, + 0, 0, 10, 4, 0, 0, + 12, 0, 0, 0, 4, 0, + 0, 0, 0, 0, 0, 0, + 220, 3, 0, 0, 0, 0, + 0, 0, 255, 255, 255, 255, + 0, 0, 0, 0, 255, 255, + 255, 255, 0, 0, 0, 0, + 122, 101, 0, 171, 0, 0, + 19, 0, 1, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 188, 1, 0, 0, 80, 69, + 78, 102, 0, 80, 69, 79, + 102, 0, 80, 69, 80, 102, + 0, 171, 56, 4, 0, 0, + 0, 0, 0, 0, 16, 0, + 0, 0, 2, 0, 0, 0, + 72, 4, 0, 0, 0, 0, + 0, 0, 255, 255, 255, 255, + 0, 0, 0, 0, 255, 255, + 255, 255, 0, 0, 0, 0, + 36, 69, 108, 101, 109, 101, + 110, 116, 0, 117, 105, 110, + 116, 52, 0, 171, 1, 0, + 19, 0, 1, 0, 4, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 65, 4, 0, 0, 56, 4, + 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 2, 0, + 0, 0, 72, 4, 0, 0, + 0, 0, 0, 0, 255, 255, + 255, 255, 0, 0, 0, 0, + 255, 255, 255, 255, 0, 0, + 0, 0, 77, 105, 99, 114, + 111, 115, 111, 102, 116, 32, + 40, 82, 41, 32, 72, 76, + 83, 76, 32, 83, 104, 97, + 100, 101, 114, 32, 67, 111, + 109, 112, 105, 108, 101, 114, + 32, 49, 48, 46, 49, 0, + 73, 83, 71, 78, 136, 0, + 0, 0, 4, 0, 0, 0, + 8, 0, 0, 0, 104, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3, 0, + 0, 0, 0, 0, 0, 0, + 15, 15, 0, 0, 107, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3, 0, + 0, 0, 1, 0, 0, 0, + 15, 7, 0, 0, 110, 0, + 0, 0, 0, 0, 0, 0, + 6, 0, 0, 0, 1, 0, + 0, 0, 2, 0, 0, 0, + 1, 0, 0, 0, 122, 0, + 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 1, 0, + 0, 0, 3, 0, 0, 0, + 1, 1, 0, 0, 76, 66, + 0, 77, 66, 0, 83, 86, + 95, 86, 101, 114, 116, 101, + 120, 73, 68, 0, 83, 86, + 95, 73, 110, 115, 116, 97, + 110, 99, 101, 73, 68, 0, + 79, 83, 71, 78, 80, 0, + 0, 0, 2, 0, 0, 0, + 8, 0, 0, 0, 56, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3, 0, + 0, 0, 0, 0, 0, 0, + 15, 0, 0, 0, 65, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 3, 0, + 0, 0, 1, 0, 0, 0, + 15, 0, 0, 0, 84, 69, + 88, 67, 79, 79, 82, 68, + 0, 83, 86, 95, 80, 111, + 115, 105, 116, 105, 111, 110, + 0, 171, 171, 171, 83, 72, + 69, 88, 180, 39, 0, 0, + 80, 0, 1, 0, 237, 9, + 0, 0, 106, 8, 0, 1, + 89, 0, 0, 4, 70, 142, + 32, 0, 0, 0, 0, 0, + 5, 0, 0, 0, 89, 0, + 0, 4, 70, 142, 32, 0, + 1, 0, 0, 0, 1, 0, + 0, 0, 162, 0, 0, 4, + 0, 112, 16, 0, 3, 0, + 0, 0, 16, 0, 0, 0, + 162, 0, 0, 4, 0, 112, + 16, 0, 6, 0, 0, 0, + 16, 0, 0, 0, 88, 24, + 0, 4, 0, 112, 16, 0, + 8, 0, 0, 0, 68, 68, + 0, 0, 95, 0, 0, 3, + 242, 16, 16, 0, 0, 0, + 0, 0, 95, 0, 0, 3, + 114, 16, 16, 0, 1, 0, + 0, 0, 96, 0, 0, 4, + 18, 16, 16, 0, 3, 0, + 0, 0, 8, 0, 0, 0, + 101, 0, 0, 3, 242, 32, + 16, 0, 0, 0, 0, 0, + 103, 0, 0, 4, 242, 32, + 16, 0, 1, 0, 0, 0, + 1, 0, 0, 0, 104, 0, + 0, 2, 14, 0, 0, 0, + 30, 0, 0, 8, 18, 0, + 16, 0, 0, 0, 0, 0, + 10, 16, 16, 0, 3, 0, + 0, 0, 10, 128, 32, 0, + 1, 0, 0, 0, 0, 0, + 0, 0, 27, 0, 0, 5, + 18, 0, 16, 0, 1, 0, + 0, 0, 10, 16, 16, 0, + 0, 0, 0, 0, 42, 0, + 0, 7, 34, 0, 16, 0, + 0, 0, 0, 0, 58, 16, + 16, 0, 0, 0, 0, 0, + 1, 64, 0, 0, 2, 0, + 0, 0, 1, 0, 0, 7, + 66, 0, 16, 0, 0, 0, + 0, 0, 58, 16, 16, 0, + 0, 0, 0, 0, 1, 64, + 0, 0, 3, 0, 0, 0, + 30, 0, 0, 7, 130, 0, + 16, 0, 0, 0, 0, 0, + 26, 0, 16, 0, 0, 0, + 0, 0, 1, 64, 0, 0, + 255, 255, 255, 255, 37, 0, + 0, 7, 130, 0, 16, 0, + 0, 0, 0, 0, 58, 0, + 16, 0, 0, 0, 0, 0, + 10, 0, 16, 0, 1, 0, + 0, 0, 35, 0, 0, 9, + 18, 0, 16, 0, 0, 0, + 0, 0, 10, 0, 16, 0, + 0, 0, 0, 0, 26, 0, + 16, 0, 0, 0, 0, 0, + 58, 0, 16, 0, 0, 0, + 0, 0, 1, 0, 0, 7, + 18, 0, 16, 0, 2, 0, + 0, 0, 10, 0, 16, 0, + 0, 0, 0, 0, 1, 64, + 0, 0, 255, 7, 0, 0, + 42, 0, 0, 7, 34, 0, + 16, 0, 2, 0, 0, 0, + 10, 0, 16, 0, 0, 0, + 0, 0, 1, 64, 0, 0, + 11, 0, 0, 0, 54, 0, + 0, 8, 194, 0, 16, 0, + 2, 0, 0, 0, 2, 64, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 45, 0, 0, 137, 194, 0, + 0, 128, 3, 17, 17, 0, + 242, 0, 16, 0, 2, 0, + 0, 0, 70, 14, 16, 0, + 2, 0, 0, 0, 70, 126, + 16, 0, 8, 0, 0, 0, + 1, 0, 0, 10, 50, 0, + 16, 0, 3, 0, 0, 0, + 246, 15, 16, 0, 2, 0, + 0, 0, 2, 64, 0, 0, + 255, 255, 0, 0, 0, 0, + 128, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 30, 0, + 0, 7, 34, 0, 16, 0, + 0, 0, 0, 0, 10, 0, + 16, 0, 3, 0, 0, 0, + 1, 64, 0, 0, 255, 255, + 255, 255, 167, 0, 0, 139, + 2, 131, 0, 128, 131, 153, + 25, 0, 242, 0, 16, 0, + 4, 0, 0, 0, 26, 0, + 16, 0, 0, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 0, 0, 70, 126, 16, 0, + 6, 0, 0, 0, 140, 0, + 0, 20, 82, 0, 16, 0, + 3, 0, 0, 0, 2, 64, + 0, 0, 16, 0, 0, 0, + 0, 0, 0, 0, 16, 0, + 0, 0, 0, 0, 0, 0, + 2, 64, 0, 0, 2, 0, + 0, 0, 0, 0, 0, 0, + 2, 0, 0, 0, 0, 0, + 0, 0, 166, 10, 16, 0, + 4, 0, 0, 0, 2, 64, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 2, 0, + 0, 0, 0, 0, 0, 0, + 167, 0, 0, 139, 2, 131, + 0, 128, 131, 153, 25, 0, + 242, 0, 16, 0, 5, 0, + 0, 0, 10, 0, 16, 0, + 3, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 0, 0, + 70, 126, 16, 0, 3, 0, + 0, 0, 30, 0, 0, 7, + 34, 0, 16, 0, 0, 0, + 0, 0, 10, 0, 16, 0, + 3, 0, 0, 0, 1, 64, + 0, 0, 1, 0, 0, 0, + 167, 0, 0, 139, 2, 131, + 0, 128, 131, 153, 25, 0, + 242, 0, 16, 0, 6, 0, + 0, 0, 26, 0, 16, 0, + 0, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 0, 0, + 70, 126, 16, 0, 3, 0, + 0, 0, 27, 0, 0, 5, + 18, 0, 16, 0, 7, 0, + 0, 0, 10, 16, 16, 0, + 1, 0, 0, 0, 54, 0, + 0, 5, 98, 0, 16, 0, + 7, 0, 0, 0, 86, 22, + 16, 0, 1, 0, 0, 0, + 54, 0, 0, 5, 98, 0, + 16, 0, 1, 0, 0, 0, + 86, 22, 16, 0, 0, 0, + 0, 0, 55, 0, 0, 9, + 114, 0, 16, 0, 1, 0, + 0, 0, 86, 5, 16, 0, + 3, 0, 0, 0, 38, 9, + 16, 0, 7, 0, 0, 0, + 38, 9, 16, 0, 1, 0, + 0, 0, 39, 0, 0, 7, + 34, 0, 16, 0, 0, 0, + 0, 0, 58, 0, 16, 0, + 0, 0, 0, 0, 26, 0, + 16, 0, 1, 0, 0, 0, + 31, 0, 4, 3, 26, 0, + 16, 0, 0, 0, 0, 0, + 30, 0, 0, 7, 34, 0, + 16, 0, 0, 0, 0, 0, + 10, 0, 16, 0, 0, 0, + 0, 0, 26, 0, 16, 0, + 1, 0, 0, 0, 30, 0, + 0, 8, 34, 0, 16, 0, + 0, 0, 0, 0, 58, 0, + 16, 128, 65, 0, 0, 0, + 0, 0, 0, 0, 26, 0, + 16, 0, 0, 0, 0, 0, + 1, 0, 0, 7, 18, 0, + 16, 0, 7, 0, 0, 0, + 26, 0, 16, 0, 0, 0, + 0, 0, 1, 64, 0, 0, + 255, 7, 0, 0, 42, 0, + 0, 7, 34, 0, 16, 0, + 7, 0, 0, 0, 26, 0, + 16, 0, 0, 0, 0, 0, + 1, 64, 0, 0, 11, 0, + 0, 0, 54, 0, 0, 8, + 194, 0, 16, 0, 7, 0, + 0, 0, 2, 64, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 45, 0, + 0, 137, 194, 0, 0, 128, + 3, 17, 17, 0, 242, 0, + 16, 0, 7, 0, 0, 0, + 70, 14, 16, 0, 7, 0, + 0, 0, 54, 121, 16, 0, + 8, 0, 0, 0, 1, 0, + 0, 7, 130, 0, 16, 0, + 0, 0, 0, 0, 10, 0, + 16, 0, 7, 0, 0, 0, + 1, 64, 0, 0, 255, 255, + 128, 0, 1, 0, 0, 7, + 18, 0, 16, 0, 3, 0, + 0, 0, 58, 0, 16, 0, + 2, 0, 0, 0, 1, 64, + 0, 0, 255, 255, 128, 0, + 39, 0, 0, 7, 130, 0, + 16, 0, 0, 0, 0, 0, + 58, 0, 16, 0, 0, 0, + 0, 0, 10, 0, 16, 0, + 3, 0, 0, 0, 31, 0, + 4, 3, 58, 0, 16, 0, + 0, 0, 0, 0, 24, 0, + 0, 7, 130, 0, 16, 0, + 0, 0, 0, 0, 42, 0, + 16, 0, 6, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 0, 0, 57, 0, 0, 7, + 18, 0, 16, 0, 3, 0, + 0, 0, 10, 0, 16, 0, + 4, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 0, 0, + 60, 0, 0, 7, 130, 0, + 16, 0, 0, 0, 0, 0, + 58, 0, 16, 0, 0, 0, + 0, 0, 10, 0, 16, 0, + 3, 0, 0, 0, 31, 0, + 4, 3, 58, 0, 16, 0, + 0, 0, 0, 0, 1, 0, + 0, 7, 18, 0, 16, 0, + 8, 0, 0, 0, 58, 0, + 16, 0, 4, 0, 0, 0, + 1, 64, 0, 0, 255, 7, + 0, 0, 42, 0, 0, 7, + 34, 0, 16, 0, 8, 0, + 0, 0, 58, 0, 16, 0, + 4, 0, 0, 0, 1, 64, + 0, 0, 11, 0, 0, 0, + 54, 0, 0, 8, 194, 0, + 16, 0, 8, 0, 0, 0, + 2, 64, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 45, 0, 0, 137, + 194, 0, 0, 128, 3, 17, + 17, 0, 242, 0, 16, 0, + 7, 0, 0, 0, 70, 14, + 16, 0, 8, 0, 0, 0, + 54, 121, 16, 0, 8, 0, + 0, 0, 54, 0, 0, 5, + 18, 0, 16, 0, 0, 0, + 0, 0, 58, 0, 16, 0, + 4, 0, 0, 0, 54, 0, + 0, 5, 114, 0, 16, 0, + 2, 0, 0, 0, 150, 7, + 16, 0, 7, 0, 0, 0, + 18, 0, 0, 1, 54, 0, + 0, 5, 18, 0, 16, 0, + 7, 0, 0, 0, 58, 0, + 16, 0, 2, 0, 0, 0, + 21, 0, 0, 1, 18, 0, + 0, 1, 54, 0, 0, 5, + 18, 0, 16, 0, 0, 0, + 0, 0, 26, 0, 16, 0, + 0, 0, 0, 0, 54, 0, + 0, 5, 114, 0, 16, 0, + 2, 0, 0, 0, 150, 7, + 16, 0, 7, 0, 0, 0, + 21, 0, 0, 1, 1, 0, + 0, 7, 34, 0, 16, 0, + 0, 0, 0, 0, 10, 0, + 16, 0, 7, 0, 0, 0, + 1, 64, 0, 0, 255, 255, + 127, 255, 30, 0, 0, 7, + 130, 0, 16, 0, 2, 0, + 0, 0, 26, 0, 16, 0, + 3, 0, 0, 0, 26, 0, + 16, 0, 0, 0, 0, 0, + 21, 0, 0, 1, 1, 0, + 0, 7, 34, 0, 16, 0, + 0, 0, 0, 0, 58, 0, + 16, 0, 2, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 0, 28, 32, 0, 0, 7, + 130, 0, 16, 0, 0, 0, + 0, 0, 26, 0, 16, 0, + 0, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 0, 4, + 32, 0, 0, 7, 18, 0, + 16, 0, 3, 0, 0, 0, + 42, 0, 16, 0, 0, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 0, 0, 1, 0, + 0, 7, 130, 0, 16, 0, + 0, 0, 0, 0, 58, 0, + 16, 0, 0, 0, 0, 0, + 10, 0, 16, 0, 3, 0, + 0, 0, 31, 0, 4, 3, + 58, 0, 16, 0, 0, 0, + 0, 0, 1, 0, 0, 7, + 18, 0, 16, 0, 3, 0, + 0, 0, 42, 0, 16, 0, + 2, 0, 0, 0, 1, 64, + 0, 0, 255, 255, 0, 0, + 86, 0, 0, 5, 66, 0, + 16, 0, 7, 0, 0, 0, + 10, 0, 16, 0, 3, 0, + 0, 0, 85, 0, 0, 7, + 18, 0, 16, 0, 3, 0, + 0, 0, 42, 0, 16, 0, + 2, 0, 0, 0, 1, 64, + 0, 0, 16, 0, 0, 0, + 86, 0, 0, 5, 18, 0, + 16, 0, 3, 0, 0, 0, + 10, 0, 16, 0, 3, 0, + 0, 0, 0, 0, 0, 8, + 34, 0, 16, 0, 3, 0, + 0, 0, 42, 0, 16, 128, + 65, 0, 0, 0, 7, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 128, 191, 0, 0, + 0, 8, 130, 0, 16, 0, + 3, 0, 0, 0, 42, 0, + 16, 128, 65, 0, 0, 0, + 7, 0, 0, 0, 10, 0, + 16, 0, 3, 0, 0, 0, + 0, 0, 0, 7, 130, 0, + 16, 0, 3, 0, 0, 0, + 58, 0, 16, 0, 3, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 128, 63, 27, 0, + 0, 5, 50, 0, 16, 0, + 8, 0, 0, 0, 214, 5, + 16, 0, 3, 0, 0, 0, + 1, 0, 0, 7, 34, 0, + 16, 0, 3, 0, 0, 0, + 58, 0, 16, 0, 2, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 128, 0, 40, 0, + 0, 5, 194, 0, 16, 0, + 8, 0, 0, 0, 6, 4, + 16, 0, 8, 0, 0, 0, + 55, 0, 0, 9, 162, 0, + 16, 0, 3, 0, 0, 0, + 86, 5, 16, 0, 3, 0, + 0, 0, 166, 14, 16, 0, + 8, 0, 0, 0, 6, 4, + 16, 0, 8, 0, 0, 0, + 30, 0, 0, 7, 162, 0, + 16, 0, 3, 0, 0, 0, + 6, 0, 16, 0, 0, 0, + 0, 0, 86, 13, 16, 0, + 3, 0, 0, 0, 1, 0, + 0, 10, 50, 0, 16, 0, + 8, 0, 0, 0, 214, 5, + 16, 0, 3, 0, 0, 0, + 2, 64, 0, 0, 255, 7, + 0, 0, 255, 7, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 42, 0, 0, 10, + 50, 0, 16, 0, 9, 0, + 0, 0, 214, 5, 16, 0, + 3, 0, 0, 0, 2, 64, + 0, 0, 11, 0, 0, 0, + 11, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 54, 0, 0, 5, 66, 0, + 16, 0, 8, 0, 0, 0, + 10, 0, 16, 0, 9, 0, + 0, 0, 54, 0, 0, 5, + 130, 0, 16, 0, 8, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 0, 0, 45, 0, + 0, 137, 194, 0, 0, 128, + 3, 17, 17, 0, 162, 0, + 16, 0, 3, 0, 0, 0, + 134, 15, 16, 0, 8, 0, + 0, 0, 134, 125, 16, 0, + 8, 0, 0, 0, 54, 0, + 0, 5, 194, 0, 16, 0, + 9, 0, 0, 0, 86, 13, + 16, 0, 8, 0, 0, 0, + 45, 0, 0, 137, 194, 0, + 0, 128, 3, 17, 17, 0, + 50, 0, 16, 0, 8, 0, + 0, 0, 102, 15, 16, 0, + 9, 0, 0, 0, 230, 116, + 16, 0, 8, 0, 0, 0, + 1, 0, 0, 7, 66, 0, + 16, 0, 4, 0, 0, 0, + 26, 0, 16, 0, 8, 0, + 0, 0, 1, 64, 0, 0, + 255, 255, 128, 0, 1, 0, + 0, 7, 130, 0, 16, 0, + 3, 0, 0, 0, 58, 0, + 16, 0, 3, 0, 0, 0, + 1, 64, 0, 0, 255, 255, + 128, 0, 39, 0, 0, 7, + 130, 0, 16, 0, 3, 0, + 0, 0, 58, 0, 16, 0, + 3, 0, 0, 0, 42, 0, + 16, 0, 4, 0, 0, 0, + 31, 0, 4, 3, 58, 0, + 16, 0, 3, 0, 0, 0, + 1, 0, 0, 7, 18, 0, + 16, 0, 9, 0, 0, 0, + 58, 0, 16, 0, 4, 0, + 0, 0, 1, 64, 0, 0, + 255, 7, 0, 0, 42, 0, + 0, 7, 34, 0, 16, 0, + 9, 0, 0, 0, 58, 0, + 16, 0, 4, 0, 0, 0, + 1, 64, 0, 0, 11, 0, + 0, 0, 54, 0, 0, 8, + 194, 0, 16, 0, 9, 0, + 0, 0, 2, 64, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 45, 0, + 0, 137, 194, 0, 0, 128, + 3, 17, 17, 0, 18, 0, + 16, 0, 8, 0, 0, 0, + 70, 14, 16, 0, 9, 0, + 0, 0, 230, 116, 16, 0, + 8, 0, 0, 0, 21, 0, + 0, 1, 0, 0, 0, 8, + 130, 0, 16, 0, 3, 0, + 0, 0, 26, 0, 16, 128, + 65, 0, 0, 0, 3, 0, + 0, 0, 10, 0, 16, 0, + 8, 0, 0, 0, 49, 0, + 0, 8, 66, 0, 16, 0, + 4, 0, 0, 0, 1, 64, + 0, 0, 219, 15, 73, 64, + 58, 0, 16, 128, 129, 0, + 0, 0, 3, 0, 0, 0, + 49, 0, 0, 7, 130, 0, + 16, 0, 4, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 0, 0, 58, 0, 16, 0, + 3, 0, 0, 0, 49, 0, + 0, 7, 34, 0, 16, 0, + 8, 0, 0, 0, 58, 0, + 16, 0, 3, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 0, 0, 30, 0, 0, 8, + 130, 0, 16, 0, 4, 0, + 0, 0, 58, 0, 16, 128, + 65, 0, 0, 0, 4, 0, + 0, 0, 26, 0, 16, 0, + 8, 0, 0, 0, 43, 0, + 0, 5, 130, 0, 16, 0, + 4, 0, 0, 0, 58, 0, + 16, 0, 4, 0, 0, 0, + 50, 0, 0, 10, 130, 0, + 16, 0, 4, 0, 0, 0, + 58, 0, 16, 128, 65, 0, + 0, 0, 4, 0, 0, 0, + 1, 64, 0, 0, 219, 15, + 201, 64, 58, 0, 16, 0, + 3, 0, 0, 0, 55, 0, + 0, 9, 34, 0, 16, 0, + 9, 0, 0, 0, 42, 0, + 16, 0, 4, 0, 0, 0, + 58, 0, 16, 0, 4, 0, + 0, 0, 58, 0, 16, 0, + 3, 0, 0, 0, 0, 0, + 0, 10, 146, 0, 16, 0, + 3, 0, 0, 0, 6, 0, + 16, 0, 3, 0, 0, 0, + 2, 64, 0, 0, 0, 0, + 0, 192, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 64, 192, 56, 0, 0, 8, + 66, 0, 16, 0, 4, 0, + 0, 0, 10, 0, 16, 0, + 3, 0, 0, 0, 26, 0, + 16, 128, 129, 0, 0, 0, + 9, 0, 0, 0, 56, 0, + 0, 7, 66, 0, 16, 0, + 4, 0, 0, 0, 42, 0, + 16, 0, 4, 0, 0, 0, + 1, 64, 0, 0, 131, 249, + 162, 62, 64, 0, 0, 5, + 66, 0, 16, 0, 4, 0, + 0, 0, 42, 0, 16, 0, + 4, 0, 0, 0, 52, 0, + 0, 7, 66, 0, 16, 0, + 4, 0, 0, 0, 42, 0, + 16, 0, 4, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 128, 63, 51, 0, 0, 7, + 130, 0, 16, 0, 10, 0, + 0, 0, 58, 0, 16, 0, + 3, 0, 0, 0, 42, 0, + 16, 0, 4, 0, 0, 0, + 0, 0, 0, 8, 130, 0, + 16, 0, 7, 0, 0, 0, + 10, 0, 16, 0, 3, 0, + 0, 0, 58, 0, 16, 128, + 65, 0, 0, 0, 10, 0, + 0, 0, 29, 0, 0, 7, + 18, 0, 16, 0, 3, 0, + 0, 0, 58, 0, 16, 0, + 7, 0, 0, 0, 42, 0, + 16, 0, 7, 0, 0, 0, + 49, 0, 0, 7, 130, 0, + 16, 0, 3, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 0, 0, 26, 0, 16, 0, + 9, 0, 0, 0, 49, 0, + 0, 7, 66, 0, 16, 0, + 4, 0, 0, 0, 26, 0, + 16, 0, 9, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 0, 0, 30, 0, 0, 8, + 130, 0, 16, 0, 3, 0, + 0, 0, 58, 0, 16, 128, + 65, 0, 0, 0, 3, 0, + 0, 0, 42, 0, 16, 0, + 4, 0, 0, 0, 43, 0, + 0, 5, 130, 0, 16, 0, + 3, 0, 0, 0, 58, 0, + 16, 0, 3, 0, 0, 0, + 50, 0, 0, 10, 130, 0, + 16, 0, 3, 0, 0, 0, + 58, 0, 16, 0, 3, 0, + 0, 0, 1, 64, 0, 0, + 219, 15, 73, 64, 26, 0, + 16, 128, 65, 0, 0, 0, + 9, 0, 0, 0, 54, 0, + 0, 6, 34, 0, 16, 0, + 7, 0, 0, 0, 58, 0, + 16, 128, 65, 0, 0, 0, + 3, 0, 0, 0, 24, 0, + 0, 7, 130, 0, 16, 0, + 3, 0, 0, 0, 58, 0, + 16, 0, 7, 0, 0, 0, + 42, 0, 16, 0, 7, 0, + 0, 0, 55, 0, 0, 10, + 18, 0, 16, 0, 7, 0, + 0, 0, 58, 0, 16, 0, + 3, 0, 0, 0, 42, 0, + 16, 128, 65, 0, 0, 0, + 1, 0, 0, 0, 42, 0, + 16, 0, 1, 0, 0, 0, + 0, 0, 0, 10, 194, 0, + 16, 0, 4, 0, 0, 0, + 246, 15, 16, 0, 7, 0, + 0, 0, 2, 64, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 128, 63, + 0, 0, 0, 64, 24, 0, + 0, 7, 130, 0, 16, 0, + 3, 0, 0, 0, 42, 0, + 16, 0, 4, 0, 0, 0, + 42, 0, 16, 0, 7, 0, + 0, 0, 0, 0, 0, 8, + 66, 0, 16, 0, 10, 0, + 0, 0, 58, 0, 16, 128, + 65, 0, 0, 0, 4, 0, + 0, 0, 42, 0, 16, 0, + 7, 0, 0, 0, 54, 0, + 0, 5, 18, 0, 16, 0, + 10, 0, 0, 0, 42, 0, + 16, 0, 1, 0, 0, 0, + 55, 0, 0, 12, 210, 0, + 16, 0, 9, 0, 0, 0, + 246, 15, 16, 0, 3, 0, + 0, 0, 2, 64, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 6, 14, + 16, 0, 10, 0, 0, 0, + 55, 0, 0, 9, 242, 0, + 16, 0, 7, 0, 0, 0, + 6, 0, 16, 0, 3, 0, + 0, 0, 70, 14, 16, 0, + 7, 0, 0, 0, 70, 14, + 16, 0, 9, 0, 0, 0, + 24, 0, 0, 7, 18, 0, + 16, 0, 3, 0, 0, 0, + 58, 0, 16, 0, 7, 0, + 0, 0, 42, 0, 16, 0, + 7, 0, 0, 0, 14, 0, + 0, 7, 130, 0, 16, 0, + 3, 0, 0, 0, 42, 0, + 16, 0, 7, 0, 0, 0, + 58, 0, 16, 0, 7, 0, + 0, 0, 50, 0, 0, 9, + 130, 0, 16, 0, 3, 0, + 0, 0, 26, 0, 16, 0, + 7, 0, 0, 0, 58, 0, + 16, 0, 3, 0, 0, 0, + 26, 0, 16, 0, 3, 0, + 0, 0, 55, 0, 0, 9, + 66, 0, 16, 0, 2, 0, + 0, 0, 10, 0, 16, 0, + 3, 0, 0, 0, 10, 0, + 16, 0, 8, 0, 0, 0, + 58, 0, 16, 0, 3, 0, + 0, 0, 54, 0, 0, 5, + 18, 0, 16, 0, 3, 0, + 0, 0, 10, 0, 16, 0, + 7, 0, 0, 0, 54, 0, + 0, 5, 18, 0, 16, 0, + 7, 0, 0, 0, 26, 0, + 16, 0, 3, 0, 0, 0, + 18, 0, 0, 1, 54, 0, + 0, 5, 18, 0, 16, 0, + 3, 0, 0, 0, 42, 0, + 16, 0, 1, 0, 0, 0, + 21, 0, 0, 1, 77, 0, + 0, 7, 18, 0, 16, 0, + 8, 0, 0, 0, 18, 0, + 16, 0, 9, 0, 0, 0, + 42, 0, 16, 0, 2, 0, + 0, 0, 54, 0, 0, 6, + 34, 0, 16, 0, 8, 0, + 0, 0, 10, 0, 16, 128, + 65, 0, 0, 0, 9, 0, + 0, 0, 57, 0, 0, 10, + 162, 0, 16, 0, 3, 0, + 0, 0, 246, 11, 16, 0, + 6, 0, 0, 0, 2, 64, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 15, 0, 0, 7, 18, 0, + 16, 0, 9, 0, 0, 0, + 70, 0, 16, 0, 8, 0, + 0, 0, 134, 0, 16, 0, + 5, 0, 0, 0, 15, 0, + 0, 7, 34, 0, 16, 0, + 9, 0, 0, 0, 70, 0, + 16, 0, 8, 0, 0, 0, + 214, 5, 16, 0, 5, 0, + 0, 0, 15, 0, 0, 7, + 66, 0, 16, 0, 4, 0, + 0, 0, 70, 0, 16, 0, + 9, 0, 0, 0, 70, 0, + 16, 0, 9, 0, 0, 0, + 75, 0, 0, 5, 130, 0, + 16, 0, 4, 0, 0, 0, + 42, 0, 16, 0, 4, 0, + 0, 0, 14, 0, 0, 10, + 130, 0, 16, 0, 4, 0, + 0, 0, 2, 64, 0, 0, + 0, 0, 128, 63, 0, 0, + 128, 63, 0, 0, 128, 63, + 0, 0, 128, 63, 58, 0, + 16, 0, 4, 0, 0, 0, + 52, 0, 0, 7, 130, 0, + 16, 0, 4, 0, 0, 0, + 58, 0, 16, 0, 4, 0, + 0, 0, 58, 0, 16, 0, + 6, 0, 0, 0, 55, 0, + 0, 9, 34, 0, 16, 0, + 3, 0, 0, 0, 26, 0, + 16, 0, 3, 0, 0, 0, + 58, 0, 16, 0, 4, 0, + 0, 0, 58, 0, 16, 0, + 6, 0, 0, 0, 31, 0, + 4, 3, 58, 0, 16, 0, + 3, 0, 0, 0, 56, 0, + 0, 7, 130, 0, 16, 0, + 3, 0, 0, 0, 42, 0, + 16, 0, 5, 0, 0, 0, + 26, 0, 16, 0, 5, 0, + 0, 0, 50, 0, 0, 10, + 130, 0, 16, 0, 3, 0, + 0, 0, 10, 0, 16, 0, + 5, 0, 0, 0, 58, 0, + 16, 0, 5, 0, 0, 0, + 58, 0, 16, 128, 65, 0, + 0, 0, 3, 0, 0, 0, + 49, 0, 0, 7, 130, 0, + 16, 0, 4, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 0, 0, 58, 0, 16, 0, + 3, 0, 0, 0, 49, 0, + 0, 7, 130, 0, 16, 0, + 3, 0, 0, 0, 58, 0, + 16, 0, 3, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 0, 0, 30, 0, 0, 8, + 130, 0, 16, 0, 3, 0, + 0, 0, 58, 0, 16, 128, + 65, 0, 0, 0, 4, 0, + 0, 0, 58, 0, 16, 0, + 3, 0, 0, 0, 43, 0, + 0, 5, 130, 0, 16, 0, + 3, 0, 0, 0, 58, 0, + 16, 0, 3, 0, 0, 0, + 56, 0, 0, 7, 130, 0, + 16, 0, 3, 0, 0, 0, + 58, 0, 16, 0, 3, 0, + 0, 0, 10, 0, 16, 0, + 3, 0, 0, 0, 1, 0, + 0, 10, 194, 0, 16, 0, + 7, 0, 0, 0, 246, 15, + 16, 0, 2, 0, 0, 0, + 2, 64, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 16, 0, 0, 0, + 8, 0, 51, 0, 0, 7, + 130, 0, 16, 0, 4, 0, + 0, 0, 58, 0, 16, 0, + 3, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 0, 0, + 55, 0, 0, 9, 130, 0, + 16, 0, 3, 0, 0, 0, + 42, 0, 16, 0, 7, 0, + 0, 0, 58, 0, 16, 0, + 4, 0, 0, 0, 58, 0, + 16, 0, 3, 0, 0, 0, + 52, 0, 0, 7, 130, 0, + 16, 0, 4, 0, 0, 0, + 58, 0, 16, 0, 3, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 0, 0, 55, 0, + 0, 9, 130, 0, 16, 0, + 3, 0, 0, 0, 58, 0, + 16, 0, 7, 0, 0, 0, + 58, 0, 16, 0, 4, 0, + 0, 0, 58, 0, 16, 0, + 3, 0, 0, 0, 57, 0, + 0, 7, 130, 0, 16, 0, + 4, 0, 0, 0, 26, 0, + 16, 0, 3, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 9, + 130, 0, 16, 0, 6, 0, + 0, 0, 26, 0, 16, 128, + 129, 0, 0, 0, 9, 0, + 0, 0, 10, 0, 16, 128, + 129, 0, 0, 0, 9, 0, + 0, 0, 14, 0, 0, 10, + 66, 0, 16, 0, 4, 0, + 0, 0, 2, 64, 0, 0, + 0, 0, 128, 63, 0, 0, + 128, 63, 0, 0, 128, 63, + 0, 0, 128, 63, 42, 0, + 16, 0, 4, 0, 0, 0, + 56, 0, 0, 7, 66, 0, + 16, 0, 4, 0, 0, 0, + 42, 0, 16, 0, 4, 0, + 0, 0, 58, 0, 16, 0, + 6, 0, 0, 0, 56, 0, + 0, 7, 66, 0, 16, 0, + 4, 0, 0, 0, 42, 0, + 16, 0, 4, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 0, 63, 55, 0, 0, 9, + 18, 0, 16, 0, 9, 0, + 0, 0, 58, 0, 16, 0, + 4, 0, 0, 0, 26, 0, + 16, 0, 3, 0, 0, 0, + 42, 0, 16, 0, 4, 0, + 0, 0, 49, 0, 0, 7, + 66, 0, 16, 0, 4, 0, + 0, 0, 42, 0, 16, 0, + 6, 0, 0, 0, 10, 0, + 16, 0, 9, 0, 0, 0, + 24, 0, 0, 7, 130, 0, + 16, 0, 6, 0, 0, 0, + 26, 0, 16, 0, 3, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 0, 0, 1, 0, + 0, 7, 66, 0, 16, 0, + 4, 0, 0, 0, 42, 0, + 16, 0, 4, 0, 0, 0, + 58, 0, 16, 0, 6, 0, + 0, 0, 14, 0, 0, 7, + 34, 0, 16, 0, 9, 0, + 0, 0, 42, 0, 16, 0, + 6, 0, 0, 0, 10, 0, + 16, 0, 9, 0, 0, 0, + 54, 0, 0, 5, 18, 0, + 16, 0, 10, 0, 0, 0, + 42, 0, 16, 0, 6, 0, + 0, 0, 54, 0, 0, 5, + 34, 0, 16, 0, 10, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 128, 63, 55, 0, + 0, 9, 194, 0, 16, 0, + 6, 0, 0, 0, 166, 10, + 16, 0, 4, 0, 0, 0, + 6, 4, 16, 0, 9, 0, + 0, 0, 6, 4, 16, 0, + 10, 0, 0, 0, 0, 0, + 0, 7, 66, 0, 16, 0, + 4, 0, 0, 0, 10, 0, + 16, 0, 9, 0, 0, 0, + 42, 0, 16, 0, 6, 0, + 0, 0, 56, 0, 0, 7, + 194, 0, 16, 0, 8, 0, + 0, 0, 166, 10, 16, 0, + 4, 0, 0, 0, 6, 4, + 16, 0, 8, 0, 0, 0, + 56, 0, 0, 7, 18, 0, + 16, 0, 10, 0, 0, 0, + 58, 0, 16, 0, 3, 0, + 0, 0, 42, 0, 16, 0, + 4, 0, 0, 0, 0, 0, + 0, 7, 130, 0, 16, 0, + 7, 0, 0, 0, 10, 0, + 16, 0, 9, 0, 0, 0, + 10, 0, 16, 0, 9, 0, + 0, 0, 14, 0, 0, 10, + 130, 0, 16, 0, 7, 0, + 0, 0, 2, 64, 0, 0, + 0, 0, 128, 63, 0, 0, + 128, 63, 0, 0, 128, 63, + 0, 0, 128, 63, 58, 0, + 16, 0, 7, 0, 0, 0, + 54, 0, 0, 6, 34, 0, + 16, 0, 10, 0, 0, 0, + 10, 0, 16, 128, 65, 0, + 0, 0, 10, 0, 0, 0, + 0, 0, 0, 7, 98, 0, + 16, 0, 9, 0, 0, 0, + 166, 10, 16, 0, 6, 0, + 0, 0, 6, 1, 16, 0, + 10, 0, 0, 0, 50, 0, + 0, 12, 98, 0, 16, 0, + 9, 0, 0, 0, 246, 15, + 16, 0, 7, 0, 0, 0, + 86, 6, 16, 0, 9, 0, + 0, 0, 2, 64, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 63, 0, 0, 0, 63, + 0, 0, 0, 0, 79, 0, + 0, 7, 130, 0, 16, 0, + 7, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 0, 8, + 26, 0, 16, 0, 0, 0, + 0, 0, 31, 0, 4, 3, + 58, 0, 16, 0, 7, 0, + 0, 0, 1, 0, 0, 10, + 242, 0, 16, 0, 10, 0, + 0, 0, 246, 15, 16, 0, + 2, 0, 0, 0, 2, 64, + 0, 0, 0, 0, 64, 0, + 0, 0, 128, 0, 0, 0, + 0, 2, 0, 0, 32, 0, + 55, 0, 0, 15, 114, 0, + 16, 0, 11, 0, 0, 0, + 6, 2, 16, 0, 10, 0, + 0, 0, 2, 64, 0, 0, + 2, 0, 0, 0, 254, 255, + 255, 255, 0, 0, 128, 63, + 0, 0, 0, 0, 2, 64, + 0, 0, 254, 255, 255, 255, + 2, 0, 0, 0, 0, 0, + 128, 62, 0, 0, 0, 0, + 55, 0, 0, 9, 130, 0, + 16, 0, 7, 0, 0, 0, + 26, 0, 16, 0, 10, 0, + 0, 0, 26, 0, 16, 0, + 11, 0, 0, 0, 10, 0, + 16, 0, 11, 0, 0, 0, + 30, 0, 0, 7, 18, 0, + 16, 0, 0, 0, 0, 0, + 10, 0, 16, 0, 0, 0, + 0, 0, 58, 0, 16, 0, + 7, 0, 0, 0, 1, 0, + 0, 7, 18, 0, 16, 0, + 12, 0, 0, 0, 10, 0, + 16, 0, 0, 0, 0, 0, + 1, 64, 0, 0, 255, 7, + 0, 0, 42, 0, 0, 7, + 34, 0, 16, 0, 12, 0, + 0, 0, 10, 0, 16, 0, + 0, 0, 0, 0, 1, 64, + 0, 0, 11, 0, 0, 0, + 54, 0, 0, 8, 194, 0, + 16, 0, 12, 0, 0, 0, + 2, 64, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 45, 0, 0, 137, + 194, 0, 0, 128, 3, 17, + 17, 0, 18, 0, 16, 0, + 0, 0, 0, 0, 70, 14, + 16, 0, 12, 0, 0, 0, + 38, 125, 16, 0, 8, 0, + 0, 0, 0, 0, 0, 8, + 18, 0, 16, 0, 0, 0, + 0, 0, 42, 0, 16, 128, + 65, 0, 0, 0, 2, 0, + 0, 0, 10, 0, 16, 0, + 0, 0, 0, 0, 49, 0, + 0, 8, 130, 0, 16, 0, + 7, 0, 0, 0, 1, 64, + 0, 0, 219, 15, 73, 64, + 10, 0, 16, 128, 129, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 8, 34, 0, + 16, 0, 10, 0, 0, 0, + 10, 0, 16, 128, 193, 0, + 0, 0, 0, 0, 0, 0, + 1, 64, 0, 0, 219, 15, + 201, 64, 55, 0, 0, 10, + 18, 0, 16, 0, 0, 0, + 0, 0, 58, 0, 16, 0, + 7, 0, 0, 0, 26, 0, + 16, 0, 10, 0, 0, 0, + 10, 0, 16, 128, 129, 0, + 0, 0, 0, 0, 0, 0, + 39, 0, 0, 7, 130, 0, + 16, 0, 7, 0, 0, 0, + 10, 0, 16, 0, 10, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 0, 0, 39, 0, + 0, 7, 18, 0, 16, 0, + 10, 0, 0, 0, 42, 0, + 16, 0, 7, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 0, 0, 32, 0, 0, 7, + 130, 0, 16, 0, 7, 0, + 0, 0, 58, 0, 16, 0, + 7, 0, 0, 0, 10, 0, + 16, 0, 10, 0, 0, 0, + 55, 0, 0, 9, 130, 0, + 16, 0, 7, 0, 0, 0, + 58, 0, 16, 0, 7, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 0, 191, 1, 64, + 0, 0, 0, 0, 0, 63, + 50, 0, 0, 9, 130, 0, + 16, 0, 7, 0, 0, 0, + 10, 0, 16, 0, 0, 0, + 0, 0, 58, 0, 16, 0, + 7, 0, 0, 0, 42, 0, + 16, 0, 2, 0, 0, 0, + 77, 0, 0, 7, 18, 0, + 16, 0, 10, 0, 0, 0, + 18, 0, 16, 0, 11, 0, + 0, 0, 58, 0, 16, 0, + 7, 0, 0, 0, 54, 0, + 0, 6, 34, 0, 16, 0, + 10, 0, 0, 0, 10, 0, + 16, 128, 65, 0, 0, 0, + 11, 0, 0, 0, 15, 0, + 0, 7, 18, 0, 16, 0, + 11, 0, 0, 0, 70, 0, + 16, 0, 10, 0, 0, 0, + 134, 0, 16, 0, 5, 0, + 0, 0, 15, 0, 0, 7, + 34, 0, 16, 0, 11, 0, + 0, 0, 70, 0, 16, 0, + 10, 0, 0, 0, 214, 5, + 16, 0, 5, 0, 0, 0, + 0, 0, 0, 9, 130, 0, + 16, 0, 7, 0, 0, 0, + 26, 0, 16, 128, 129, 0, + 0, 0, 11, 0, 0, 0, + 10, 0, 16, 128, 129, 0, + 0, 0, 11, 0, 0, 0, + 15, 0, 0, 7, 66, 0, + 16, 0, 10, 0, 0, 0, + 70, 0, 16, 0, 11, 0, + 0, 0, 70, 0, 16, 0, + 11, 0, 0, 0, 14, 0, + 0, 10, 66, 0, 16, 0, + 10, 0, 0, 0, 2, 64, + 0, 0, 0, 0, 128, 63, + 0, 0, 128, 63, 0, 0, + 128, 63, 0, 0, 128, 63, + 42, 0, 16, 0, 10, 0, + 0, 0, 56, 0, 0, 7, + 130, 0, 16, 0, 7, 0, + 0, 0, 58, 0, 16, 0, + 7, 0, 0, 0, 42, 0, + 16, 0, 10, 0, 0, 0, + 56, 0, 0, 7, 18, 0, + 16, 0, 0, 0, 0, 0, + 10, 0, 16, 0, 0, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 0, 63, 77, 0, + 0, 6, 0, 208, 0, 0, + 18, 0, 16, 0, 0, 0, + 0, 0, 10, 0, 16, 0, + 0, 0, 0, 0, 32, 0, + 0, 10, 50, 0, 16, 0, + 11, 0, 0, 0, 86, 5, + 16, 0, 0, 0, 0, 0, + 2, 64, 0, 0, 0, 0, + 0, 20, 0, 0, 0, 16, + 0, 0, 0, 0, 0, 0, + 0, 0, 29, 0, 0, 7, + 34, 0, 16, 0, 0, 0, + 0, 0, 10, 0, 16, 0, + 0, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 128, 62, + 1, 0, 0, 7, 34, 0, + 16, 0, 0, 0, 0, 0, + 26, 0, 16, 0, 0, 0, + 0, 0, 26, 0, 16, 0, + 11, 0, 0, 0, 60, 0, + 0, 7, 34, 0, 16, 0, + 0, 0, 0, 0, 26, 0, + 16, 0, 0, 0, 0, 0, + 10, 0, 16, 0, 11, 0, + 0, 0, 52, 0, 0, 7, + 66, 0, 16, 0, 10, 0, + 0, 0, 42, 0, 16, 0, + 11, 0, 0, 0, 10, 0, + 16, 0, 0, 0, 0, 0, + 14, 0, 0, 10, 66, 0, + 16, 0, 10, 0, 0, 0, + 2, 64, 0, 0, 0, 0, + 128, 63, 0, 0, 128, 63, + 0, 0, 128, 63, 0, 0, + 128, 63, 42, 0, 16, 0, + 10, 0, 0, 0, 56, 0, + 0, 7, 66, 0, 16, 0, + 10, 0, 0, 0, 42, 0, + 16, 0, 6, 0, 0, 0, + 42, 0, 16, 0, 10, 0, + 0, 0, 56, 0, 0, 7, + 18, 0, 16, 0, 11, 0, + 0, 0, 58, 0, 16, 0, + 7, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 0, 63, + 50, 0, 0, 9, 66, 0, + 16, 0, 6, 0, 0, 0, + 42, 0, 16, 0, 6, 0, + 0, 0, 10, 0, 16, 0, + 0, 0, 0, 0, 10, 0, + 16, 0, 11, 0, 0, 0, + 55, 0, 0, 9, 34, 0, + 16, 0, 0, 0, 0, 0, + 26, 0, 16, 0, 0, 0, + 0, 0, 42, 0, 16, 0, + 10, 0, 0, 0, 42, 0, + 16, 0, 6, 0, 0, 0, + 50, 0, 0, 9, 34, 0, + 16, 0, 0, 0, 0, 0, + 58, 0, 16, 0, 7, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 0, 63, 26, 0, + 16, 0, 0, 0, 0, 0, + 56, 0, 0, 7, 66, 0, + 16, 0, 6, 0, 0, 0, + 10, 0, 16, 0, 9, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 0, 62, 50, 0, + 0, 9, 66, 0, 16, 0, + 6, 0, 0, 0, 26, 0, + 16, 0, 0, 0, 0, 0, + 10, 0, 16, 0, 0, 0, + 0, 0, 42, 0, 16, 0, + 6, 0, 0, 0, 29, 0, + 0, 7, 66, 0, 16, 0, + 6, 0, 0, 0, 42, 0, + 16, 0, 6, 0, 0, 0, + 42, 0, 16, 0, 4, 0, + 0, 0, 14, 0, 0, 10, + 18, 0, 16, 0, 0, 0, + 0, 0, 2, 64, 0, 0, + 0, 0, 128, 63, 0, 0, + 128, 63, 0, 0, 128, 63, + 0, 0, 128, 63, 10, 0, + 16, 0, 0, 0, 0, 0, + 56, 0, 0, 7, 18, 0, + 16, 0, 0, 0, 0, 0, + 10, 0, 16, 0, 0, 0, + 0, 0, 42, 0, 16, 0, + 4, 0, 0, 0, 56, 0, + 0, 7, 242, 0, 16, 0, + 11, 0, 0, 0, 6, 5, + 16, 0, 0, 0, 0, 0, + 70, 1, 16, 0, 10, 0, + 0, 0, 15, 0, 0, 7, + 18, 0, 16, 0, 12, 0, + 0, 0, 230, 10, 16, 0, + 8, 0, 0, 0, 230, 10, + 16, 0, 8, 0, 0, 0, + 15, 0, 0, 7, 34, 0, + 16, 0, 12, 0, 0, 0, + 230, 10, 16, 0, 11, 0, + 0, 0, 230, 10, 16, 0, + 11, 0, 0, 0, 56, 0, + 0, 7, 18, 0, 16, 0, + 0, 0, 0, 0, 58, 0, + 16, 0, 8, 0, 0, 0, + 58, 0, 16, 0, 11, 0, + 0, 0, 50, 0, 0, 10, + 18, 0, 16, 0, 0, 0, + 0, 0, 42, 0, 16, 0, + 8, 0, 0, 0, 42, 0, + 16, 0, 11, 0, 0, 0, + 10, 0, 16, 128, 65, 0, + 0, 0, 0, 0, 0, 0, + 14, 0, 0, 10, 18, 0, + 16, 0, 0, 0, 0, 0, + 2, 64, 0, 0, 0, 0, + 128, 63, 0, 0, 128, 63, + 0, 0, 128, 63, 0, 0, + 128, 63, 10, 0, 16, 0, + 0, 0, 0, 0, 56, 0, + 0, 10, 82, 0, 16, 0, + 13, 0, 0, 0, 166, 11, + 16, 0, 11, 0, 0, 0, + 2, 64, 0, 0, 0, 0, + 128, 63, 0, 0, 0, 0, + 0, 0, 128, 191, 0, 0, + 0, 0, 56, 0, 0, 10, + 162, 0, 16, 0, 13, 0, + 0, 0, 246, 11, 16, 0, + 8, 0, 0, 0, 2, 64, + 0, 0, 0, 0, 0, 0, + 0, 0, 128, 191, 0, 0, + 0, 0, 0, 0, 128, 63, + 56, 0, 0, 7, 242, 0, + 16, 0, 13, 0, 0, 0, + 6, 0, 16, 0, 0, 0, + 0, 0, 70, 14, 16, 0, + 13, 0, 0, 0, 15, 0, + 0, 7, 18, 0, 16, 0, + 13, 0, 0, 0, 70, 0, + 16, 0, 13, 0, 0, 0, + 70, 0, 16, 0, 12, 0, + 0, 0, 15, 0, 0, 7, + 34, 0, 16, 0, 13, 0, + 0, 0, 230, 10, 16, 0, + 13, 0, 0, 0, 70, 0, + 16, 0, 12, 0, 0, 0, + 55, 0, 0, 9, 50, 0, + 16, 0, 11, 0, 0, 0, + 166, 10, 16, 0, 6, 0, + 0, 0, 70, 0, 16, 0, + 11, 0, 0, 0, 70, 0, + 16, 0, 13, 0, 0, 0, + 55, 0, 0, 9, 194, 0, + 16, 0, 8, 0, 0, 0, + 246, 15, 16, 0, 10, 0, + 0, 0, 6, 4, 16, 0, + 11, 0, 0, 0, 166, 14, + 16, 0, 8, 0, 0, 0, + 56, 0, 0, 8, 194, 0, + 16, 0, 10, 0, 0, 0, + 246, 15, 16, 128, 129, 0, + 0, 0, 3, 0, 0, 0, + 166, 14, 16, 0, 8, 0, + 0, 0, 15, 0, 0, 7, + 18, 0, 16, 0, 0, 0, + 0, 0, 230, 10, 16, 0, + 10, 0, 0, 0, 70, 0, + 16, 0, 10, 0, 0, 0, + 0, 0, 0, 8, 18, 0, + 16, 0, 0, 0, 0, 0, + 10, 0, 16, 128, 65, 0, + 0, 0, 0, 0, 0, 0, + 26, 0, 16, 0, 0, 0, + 0, 0, 14, 0, 0, 7, + 130, 0, 16, 0, 9, 0, + 0, 0, 10, 0, 16, 0, + 0, 0, 0, 0, 58, 0, + 16, 0, 7, 0, 0, 0, + 55, 0, 0, 9, 98, 0, + 16, 0, 9, 0, 0, 0, + 166, 10, 16, 0, 7, 0, + 0, 0, 86, 7, 16, 0, + 9, 0, 0, 0, 246, 14, + 16, 0, 9, 0, 0, 0, + 21, 0, 0, 1, 56, 0, + 0, 7, 50, 0, 16, 0, + 0, 0, 0, 0, 246, 15, + 16, 0, 6, 0, 0, 0, + 150, 5, 16, 0, 9, 0, + 0, 0, 52, 0, 0, 7, + 34, 0, 16, 0, 1, 0, + 0, 0, 26, 0, 16, 0, + 0, 0, 0, 0, 1, 64, + 0, 0, 23, 183, 209, 56, + 50, 0, 0, 10, 34, 0, + 16, 0, 0, 0, 0, 0, + 26, 0, 16, 128, 65, 0, + 0, 0, 9, 0, 0, 0, + 58, 0, 16, 0, 6, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 0, 192, 55, 0, + 0, 9, 18, 0, 16, 0, + 1, 0, 0, 0, 58, 0, + 16, 0, 4, 0, 0, 0, + 26, 0, 16, 0, 0, 0, + 0, 0, 10, 0, 16, 0, + 0, 0, 0, 0, 56, 0, + 0, 7, 50, 0, 16, 0, + 0, 0, 0, 0, 246, 15, + 16, 0, 3, 0, 0, 0, + 230, 10, 16, 0, 8, 0, + 0, 0, 15, 0, 0, 7, + 18, 0, 16, 0, 9, 0, + 0, 0, 70, 0, 16, 0, + 0, 0, 0, 0, 134, 0, + 16, 0, 5, 0, 0, 0, + 15, 0, 0, 7, 34, 0, + 16, 0, 9, 0, 0, 0, + 70, 0, 16, 0, 0, 0, + 0, 0, 214, 5, 16, 0, + 5, 0, 0, 0, 39, 0, + 0, 7, 18, 0, 16, 0, + 0, 0, 0, 0, 42, 0, + 16, 0, 0, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 0, 0, 54, 0, 0, 8, + 194, 32, 16, 0, 0, 0, + 0, 0, 2, 64, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 18, 0, + 0, 1, 57, 0, 0, 7, + 34, 0, 16, 0, 0, 0, + 0, 0, 26, 0, 16, 0, + 3, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 0, 0, + 31, 0, 4, 3, 26, 0, + 16, 0, 0, 0, 0, 0, + 49, 0, 0, 7, 34, 0, + 16, 0, 0, 0, 0, 0, + 26, 0, 16, 0, 7, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 7, 18, 0, 16, 0, + 10, 0, 0, 0, 26, 0, + 16, 0, 7, 0, 0, 0, + 10, 0, 16, 0, 7, 0, + 0, 0, 54, 0, 0, 6, + 34, 0, 16, 0, 10, 0, + 0, 0, 26, 0, 16, 128, + 65, 0, 0, 0, 7, 0, + 0, 0, 55, 0, 0, 9, + 194, 0, 16, 0, 4, 0, + 0, 0, 86, 5, 16, 0, + 0, 0, 0, 0, 6, 4, + 16, 0, 10, 0, 0, 0, + 6, 4, 16, 0, 7, 0, + 0, 0, 0, 0, 0, 8, + 34, 0, 16, 0, 0, 0, + 0, 0, 42, 0, 16, 0, + 2, 0, 0, 0, 42, 0, + 16, 128, 65, 0, 0, 0, + 4, 0, 0, 0, 0, 0, + 0, 7, 34, 0, 16, 0, + 0, 0, 0, 0, 26, 0, + 16, 0, 0, 0, 0, 0, + 1, 64, 0, 0, 219, 15, + 201, 63, 56, 0, 0, 7, + 34, 0, 16, 0, 0, 0, + 0, 0, 26, 0, 16, 0, + 0, 0, 0, 0, 1, 64, + 0, 0, 131, 249, 34, 62, + 29, 0, 0, 8, 66, 0, + 16, 0, 2, 0, 0, 0, + 26, 0, 16, 0, 0, 0, + 0, 0, 26, 0, 16, 128, + 65, 0, 0, 0, 0, 0, + 0, 0, 26, 0, 0, 6, + 34, 0, 16, 0, 0, 0, + 0, 0, 26, 0, 16, 128, + 129, 0, 0, 0, 0, 0, + 0, 0, 55, 0, 0, 10, + 34, 0, 16, 0, 0, 0, + 0, 0, 42, 0, 16, 0, + 2, 0, 0, 0, 26, 0, + 16, 0, 0, 0, 0, 0, + 26, 0, 16, 128, 65, 0, + 0, 0, 0, 0, 0, 0, + 50, 0, 0, 9, 34, 0, + 16, 0, 0, 0, 0, 0, + 26, 0, 16, 0, 0, 0, + 0, 0, 1, 64, 0, 0, + 219, 15, 201, 64, 1, 64, + 0, 0, 219, 15, 201, 191, + 52, 0, 0, 7, 34, 0, + 16, 0, 0, 0, 0, 0, + 26, 0, 16, 0, 0, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 0, 0, 51, 0, + 0, 7, 34, 0, 16, 0, + 0, 0, 0, 0, 58, 0, + 16, 0, 4, 0, 0, 0, + 26, 0, 16, 0, 0, 0, + 0, 0, 56, 0, 0, 7, + 66, 0, 16, 0, 2, 0, + 0, 0, 58, 0, 16, 0, + 4, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 0, 63, + 49, 0, 0, 7, 66, 0, + 16, 0, 2, 0, 0, 0, + 42, 0, 16, 0, 2, 0, + 0, 0, 26, 0, 16, 0, + 0, 0, 0, 0, 0, 0, + 0, 8, 130, 0, 16, 0, + 3, 0, 0, 0, 26, 0, + 16, 128, 65, 0, 0, 0, + 0, 0, 0, 0, 58, 0, + 16, 0, 4, 0, 0, 0, + 55, 0, 0, 9, 34, 0, + 16, 0, 0, 0, 0, 0, + 42, 0, 16, 0, 2, 0, + 0, 0, 58, 0, 16, 0, + 3, 0, 0, 0, 26, 0, + 16, 0, 0, 0, 0, 0, + 77, 0, 0, 7, 18, 0, + 16, 0, 7, 0, 0, 0, + 18, 0, 16, 0, 10, 0, + 0, 0, 26, 0, 16, 0, + 0, 0, 0, 0, 54, 0, + 0, 5, 34, 0, 16, 0, + 7, 0, 0, 0, 10, 0, + 16, 0, 10, 0, 0, 0, + 50, 0, 0, 14, 194, 0, + 16, 0, 6, 0, 0, 0, + 6, 4, 16, 128, 65, 0, + 0, 0, 7, 0, 0, 0, + 6, 0, 16, 128, 129, 0, + 0, 0, 3, 0, 0, 0, + 2, 64, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 128, 63, 0, 0, + 128, 63, 56, 0, 0, 10, + 50, 0, 16, 0, 7, 0, + 0, 0, 230, 10, 16, 0, + 6, 0, 0, 0, 2, 64, + 0, 0, 0, 0, 0, 63, + 0, 0, 0, 63, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 7, 34, 0, + 16, 0, 0, 0, 0, 0, + 58, 0, 16, 0, 4, 0, + 0, 0, 1, 64, 0, 0, + 219, 15, 201, 191, 49, 0, + 0, 8, 34, 0, 16, 0, + 0, 0, 0, 0, 26, 0, + 16, 128, 129, 0, 0, 0, + 0, 0, 0, 0, 1, 64, + 0, 0, 111, 18, 131, 58, + 77, 0, 0, 7, 18, 0, + 16, 0, 10, 0, 0, 0, + 18, 0, 16, 0, 11, 0, + 0, 0, 58, 0, 16, 0, + 4, 0, 0, 0, 14, 0, + 0, 7, 66, 0, 16, 0, + 2, 0, 0, 0, 10, 0, + 16, 0, 10, 0, 0, 0, + 10, 0, 16, 0, 11, 0, + 0, 0, 0, 0, 0, 8, + 130, 0, 16, 0, 3, 0, + 0, 0, 58, 0, 16, 128, + 65, 0, 0, 0, 4, 0, + 0, 0, 1, 64, 0, 0, + 219, 15, 201, 63, 49, 0, + 0, 7, 66, 0, 16, 0, + 4, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 0, 0, + 58, 0, 16, 0, 3, 0, + 0, 0, 49, 0, 0, 7, + 130, 0, 16, 0, 3, 0, + 0, 0, 58, 0, 16, 0, + 3, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 0, 0, + 30, 0, 0, 8, 130, 0, + 16, 0, 3, 0, 0, 0, + 42, 0, 16, 128, 65, 0, + 0, 0, 4, 0, 0, 0, + 58, 0, 16, 0, 3, 0, + 0, 0, 43, 0, 0, 5, + 130, 0, 16, 0, 3, 0, + 0, 0, 58, 0, 16, 0, + 3, 0, 0, 0, 52, 0, + 0, 8, 66, 0, 16, 0, + 4, 0, 0, 0, 42, 0, + 16, 128, 129, 0, 0, 0, + 2, 0, 0, 0, 1, 64, + 0, 0, 189, 55, 134, 53, + 14, 0, 0, 7, 66, 0, + 16, 0, 4, 0, 0, 0, + 58, 0, 16, 0, 3, 0, + 0, 0, 42, 0, 16, 0, + 4, 0, 0, 0, 29, 0, + 0, 7, 130, 0, 16, 0, + 3, 0, 0, 0, 42, 0, + 16, 0, 4, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 0, 0, 50, 0, 0, 16, + 50, 0, 16, 0, 10, 0, + 0, 0, 230, 10, 16, 128, + 65, 0, 0, 0, 6, 0, + 0, 0, 2, 64, 0, 0, + 0, 0, 0, 63, 0, 0, + 0, 63, 0, 0, 0, 0, + 0, 0, 0, 0, 2, 64, + 0, 0, 0, 0, 128, 63, + 0, 0, 0, 192, 0, 0, + 0, 0, 0, 0, 0, 0, + 50, 0, 0, 10, 66, 0, + 16, 0, 6, 0, 0, 0, + 10, 0, 16, 128, 65, 0, + 0, 0, 10, 0, 0, 0, + 42, 0, 16, 0, 2, 0, + 0, 0, 26, 0, 16, 0, + 7, 0, 0, 0, 50, 0, + 0, 9, 66, 0, 16, 0, + 2, 0, 0, 0, 10, 0, + 16, 0, 7, 0, 0, 0, + 42, 0, 16, 0, 2, 0, + 0, 0, 26, 0, 16, 0, + 7, 0, 0, 0, 55, 0, + 0, 9, 130, 0, 16, 0, + 4, 0, 0, 0, 58, 0, + 16, 0, 3, 0, 0, 0, + 42, 0, 16, 0, 6, 0, + 0, 0, 42, 0, 16, 0, + 2, 0, 0, 0, 55, 0, + 0, 12, 194, 0, 16, 0, + 10, 0, 0, 0, 86, 5, + 16, 0, 0, 0, 0, 0, + 2, 64, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 166, 14, 16, 0, + 4, 0, 0, 0, 52, 0, + 0, 7, 34, 0, 16, 0, + 0, 0, 0, 0, 10, 0, + 16, 0, 7, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 7, + 18, 0, 16, 0, 10, 0, + 0, 0, 26, 0, 16, 0, + 0, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 128, 62, + 54, 0, 0, 5, 146, 0, + 16, 0, 7, 0, 0, 0, + 6, 0, 16, 0, 1, 0, + 0, 0, 54, 0, 0, 8, + 98, 0, 16, 0, 7, 0, + 0, 0, 2, 64, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 192, 0, 36, 116, 73, + 0, 0, 0, 0, 55, 0, + 0, 9, 242, 0, 16, 0, + 1, 0, 0, 0, 246, 15, + 16, 0, 0, 0, 0, 0, + 70, 14, 16, 0, 10, 0, + 0, 0, 70, 14, 16, 0, + 7, 0, 0, 0, 56, 0, + 0, 7, 34, 0, 16, 0, + 0, 0, 0, 0, 26, 0, + 16, 0, 3, 0, 0, 0, + 10, 0, 16, 0, 3, 0, + 0, 0, 56, 0, 0, 7, + 162, 0, 16, 0, 0, 0, + 0, 0, 6, 4, 16, 0, + 8, 0, 0, 0, 86, 5, + 16, 0, 0, 0, 0, 0, + 15, 0, 0, 7, 18, 0, + 16, 0, 9, 0, 0, 0, + 214, 5, 16, 0, 0, 0, + 0, 0, 134, 0, 16, 0, + 5, 0, 0, 0, 15, 0, + 0, 7, 34, 0, 16, 0, + 9, 0, 0, 0, 214, 5, + 16, 0, 0, 0, 0, 0, + 214, 5, 16, 0, 5, 0, + 0, 0, 54, 0, 0, 5, + 194, 32, 16, 0, 0, 0, + 0, 0, 166, 14, 16, 0, + 1, 0, 0, 0, 18, 0, + 0, 1, 56, 0, 0, 7, + 34, 0, 16, 0, 0, 0, + 0, 0, 42, 0, 16, 0, + 5, 0, 0, 0, 26, 0, + 16, 0, 5, 0, 0, 0, + 50, 0, 0, 10, 34, 0, + 16, 0, 0, 0, 0, 0, + 10, 0, 16, 0, 5, 0, + 0, 0, 58, 0, 16, 0, + 5, 0, 0, 0, 26, 0, + 16, 128, 65, 0, 0, 0, + 0, 0, 0, 0, 14, 0, + 0, 10, 34, 0, 16, 0, + 0, 0, 0, 0, 2, 64, + 0, 0, 0, 0, 128, 63, + 0, 0, 128, 63, 0, 0, + 128, 63, 0, 0, 128, 63, + 26, 0, 16, 0, 0, 0, + 0, 0, 56, 0, 0, 10, + 242, 0, 16, 0, 7, 0, + 0, 0, 118, 2, 16, 0, + 5, 0, 0, 0, 2, 64, + 0, 0, 0, 0, 128, 63, + 0, 0, 128, 191, 0, 0, + 128, 191, 0, 0, 128, 63, + 56, 0, 0, 7, 242, 0, + 16, 0, 7, 0, 0, 0, + 86, 5, 16, 0, 0, 0, + 0, 0, 70, 14, 16, 0, + 7, 0, 0, 0, 56, 0, + 0, 7, 162, 0, 16, 0, + 0, 0, 0, 0, 6, 0, + 16, 0, 3, 0, 0, 0, + 6, 4, 16, 0, 8, 0, + 0, 0, 15, 0, 0, 7, + 18, 0, 16, 0, 3, 0, + 0, 0, 70, 0, 16, 0, + 7, 0, 0, 0, 214, 5, + 16, 0, 0, 0, 0, 0, + 15, 0, 0, 7, 34, 0, + 16, 0, 3, 0, 0, 0, + 230, 10, 16, 0, 7, 0, + 0, 0, 214, 5, 16, 0, + 0, 0, 0, 0, 49, 0, + 0, 10, 162, 0, 16, 0, + 0, 0, 0, 0, 2, 64, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 6, 4, 16, 0, 3, 0, + 0, 0, 49, 0, 0, 10, + 194, 0, 16, 0, 1, 0, + 0, 0, 6, 4, 16, 0, + 3, 0, 0, 0, 2, 64, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 30, 0, 0, 8, 162, 0, + 16, 0, 0, 0, 0, 0, + 86, 13, 16, 128, 65, 0, + 0, 0, 0, 0, 0, 0, + 166, 14, 16, 0, 1, 0, + 0, 0, 43, 0, 0, 5, + 162, 0, 16, 0, 0, 0, + 0, 0, 86, 13, 16, 0, + 0, 0, 0, 0, 56, 0, + 0, 10, 50, 0, 16, 0, + 9, 0, 0, 0, 214, 5, + 16, 0, 0, 0, 0, 0, + 2, 64, 0, 0, 0, 0, + 0, 63, 0, 0, 0, 63, + 0, 0, 0, 0, 0, 0, + 0, 0, 54, 0, 0, 8, + 194, 32, 16, 0, 0, 0, + 0, 0, 2, 64, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 54, 0, + 0, 5, 34, 0, 16, 0, + 1, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 128, 191, + 21, 0, 0, 1, 1, 0, + 0, 10, 178, 0, 16, 0, + 3, 0, 0, 0, 246, 15, + 16, 0, 2, 0, 0, 0, + 2, 64, 0, 0, 0, 0, + 128, 0, 0, 0, 0, 1, + 0, 0, 0, 0, 0, 0, + 0, 128, 39, 0, 0, 10, + 178, 0, 16, 0, 3, 0, + 0, 0, 70, 12, 16, 0, + 3, 0, 0, 0, 2, 64, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 39, 0, 0, 7, 34, 0, + 16, 0, 0, 0, 0, 0, + 26, 0, 16, 0, 3, 0, + 0, 0, 10, 0, 16, 0, + 3, 0, 0, 0, 55, 0, + 0, 10, 18, 0, 16, 0, + 1, 0, 0, 0, 26, 0, + 16, 0, 0, 0, 0, 0, + 10, 0, 16, 128, 65, 0, + 0, 0, 1, 0, 0, 0, + 10, 0, 16, 0, 1, 0, + 0, 0, 32, 0, 0, 7, + 34, 0, 16, 0, 0, 0, + 0, 0, 42, 0, 16, 0, + 0, 0, 0, 0, 1, 64, + 0, 0, 2, 0, 0, 0, + 55, 0, 0, 9, 50, 0, + 16, 0, 2, 0, 0, 0, + 86, 5, 16, 0, 0, 0, + 0, 0, 70, 0, 16, 0, + 4, 0, 0, 0, 70, 0, + 16, 0, 2, 0, 0, 0, + 39, 0, 0, 7, 34, 0, + 16, 0, 0, 0, 0, 0, + 42, 0, 16, 0, 0, 0, + 0, 0, 1, 64, 0, 0, + 1, 0, 0, 0, 1, 0, + 0, 7, 18, 0, 16, 0, + 0, 0, 0, 0, 26, 0, + 16, 0, 0, 0, 0, 0, + 58, 0, 16, 0, 3, 0, + 0, 0, 21, 0, 0, 1, + 15, 0, 0, 7, 18, 0, + 16, 0, 3, 0, 0, 0, + 70, 0, 16, 0, 2, 0, + 0, 0, 134, 0, 16, 0, + 5, 0, 0, 0, 15, 0, + 0, 7, 34, 0, 16, 0, + 3, 0, 0, 0, 70, 0, + 16, 0, 2, 0, 0, 0, + 214, 5, 16, 0, 5, 0, + 0, 0, 0, 0, 0, 7, + 98, 0, 16, 0, 0, 0, + 0, 0, 6, 1, 16, 0, + 9, 0, 0, 0, 6, 1, + 16, 0, 3, 0, 0, 0, + 0, 0, 0, 7, 98, 0, + 16, 0, 0, 0, 0, 0, + 6, 1, 16, 0, 6, 0, + 0, 0, 86, 6, 16, 0, + 0, 0, 0, 0, 55, 0, + 0, 10, 130, 0, 16, 0, + 0, 0, 0, 0, 58, 128, + 32, 0, 0, 0, 0, 0, + 4, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 128, 63, + 1, 64, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 11, + 194, 0, 16, 0, 1, 0, + 0, 0, 6, 4, 16, 128, + 65, 0, 0, 0, 1, 0, + 0, 0, 2, 64, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 128, 63, + 0, 0, 128, 191, 50, 0, + 0, 9, 194, 0, 16, 0, + 1, 0, 0, 0, 246, 15, + 16, 0, 0, 0, 0, 0, + 166, 14, 16, 0, 1, 0, + 0, 0, 6, 4, 16, 0, + 1, 0, 0, 0, 55, 0, + 0, 9, 50, 32, 16, 0, + 0, 0, 0, 0, 6, 0, + 16, 0, 0, 0, 0, 0, + 70, 0, 16, 0, 1, 0, + 0, 0, 230, 10, 16, 0, + 1, 0, 0, 0, 167, 0, + 0, 139, 2, 131, 0, 128, + 131, 153, 25, 0, 114, 0, + 16, 0, 1, 0, 0, 0, + 42, 0, 16, 0, 3, 0, + 0, 0, 1, 64, 0, 0, + 4, 0, 0, 0, 70, 114, + 16, 0, 3, 0, 0, 0, + 50, 0, 0, 9, 98, 0, + 16, 0, 0, 0, 0, 0, + 86, 6, 16, 0, 0, 0, + 0, 0, 6, 0, 16, 0, + 1, 0, 0, 0, 86, 6, + 16, 0, 1, 0, 0, 0, + 50, 0, 0, 10, 18, 0, + 16, 0, 1, 0, 0, 0, + 26, 0, 16, 0, 0, 0, + 0, 0, 42, 128, 32, 0, + 0, 0, 0, 0, 3, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 128, 191, 49, 0, + 0, 8, 34, 0, 16, 0, + 0, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 0, 0, + 58, 128, 32, 0, 0, 0, + 0, 0, 3, 0, 0, 0, + 49, 0, 0, 8, 130, 0, + 16, 0, 0, 0, 0, 0, + 58, 128, 32, 0, 0, 0, + 0, 0, 3, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 0, 0, 30, 0, 0, 8, + 34, 0, 16, 0, 0, 0, + 0, 0, 26, 0, 16, 128, + 65, 0, 0, 0, 0, 0, + 0, 0, 58, 0, 16, 0, + 0, 0, 0, 0, 43, 0, + 0, 5, 34, 0, 16, 0, + 0, 0, 0, 0, 26, 0, + 16, 0, 0, 0, 0, 0, + 50, 0, 0, 11, 34, 0, + 16, 0, 1, 0, 0, 0, + 42, 0, 16, 0, 0, 0, + 0, 0, 58, 128, 32, 0, + 0, 0, 0, 0, 3, 0, + 0, 0, 26, 0, 16, 128, + 65, 0, 0, 0, 0, 0, + 0, 0, 54, 0, 0, 8, + 194, 0, 16, 0, 1, 0, + 0, 0, 2, 64, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 128, 63, 55, 0, + 0, 10, 242, 32, 16, 0, + 1, 0, 0, 0, 6, 0, + 16, 0, 0, 0, 0, 0, + 166, 138, 32, 0, 0, 0, + 0, 0, 4, 0, 0, 0, + 70, 14, 16, 0, 1, 0, + 0, 0, 62, 0, 0, 1, + 83, 84, 65, 84, 148, 0, + 0, 0, 83, 1, 0, 0, + 14, 0, 0, 0, 0, 0, + 0, 0, 5, 0, 0, 0, + 163, 0, 0, 0, 39, 0, + 0, 0, 27, 0, 0, 0, + 6, 0, 0, 0, 8, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 11, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 29, 0, 0, 0, 32, 0, + 0, 0, 13, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0 +}; diff --git a/third_party/rive_renderer/source/generated/shaders/d3d/render_atlas_fill.frag.h b/third_party/rive_renderer/source/generated/shaders/d3d/render_atlas_fill.frag.h new file mode 100644 index 0000000..58e0c4c --- /dev/null +++ b/third_party/rive_renderer/source/generated/shaders/d3d/render_atlas_fill.frag.h @@ -0,0 +1,352 @@ +#if 0 +// +// Generated by Microsoft (R) HLSL Shader Compiler 10.1 +// +// +// Resource Bindings: +// +// Name Type Format Dim HLSL Bind Count +// ------------------------------ ---------- ------- ----------- -------------- ------ +// M8 sampler NA NA s10 1 +// JC texture float 1darray t10 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------- ------ +// TEXCOORD 0 xyzw 0 NONE float xyzw +// SV_Position 0 xyzw 1 POS float +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------- ------ +// SV_Target 0 x 0 TARGET float x +// +ps_5_0 +dcl_globalFlags refactoringAllowed +dcl_sampler s10, mode_default +dcl_resource_texture1darray (float,float,float,float) t10 +dcl_input_ps linear noperspective v0.xyzw +dcl_output o0.x +dcl_temps 6 +max r0.x, v0.w, l(0.000000) +ge r0.z, v0.z, l(0.000000) +mov r0.y, l(0) +sample_l_indexable(texture1darray)(float,float,float,float) r0.y, r0.xyxx, t10.yxzw, s10, l(0.000000) +and r0.y, r0.y, r0.z +lt r0.z, |v0.z|, l(1000.000000) +if_nz r0.z + add r0.z, |v0.x|, l(-0.250000) + add r0.w, -v0.y, l(-2.000000) + add r1.x, -r0.x, r0.w + mul r1.y, r1.x, l(0.598413) + mad r2.xyzw, r1.xxxx, l(0.125000, 0.375000, 0.625000, 0.875000), r0.xxxx + mad r0.x, r0.w, v0.z, r0.z + mad r3.xyzw, r2.zxwy, -v0.zzzz, r0.xxxx + mov r4.xz, r3.yywy + mov r4.yw, l(0,0,0,0) + sample_l_indexable(texture1darray)(float,float,float,float) r5.x, r4.xyxx, t10.xyzw, s10, l(0.000000) + sample_l_indexable(texture1darray)(float,float,float,float) r5.y, r4.zwzz, t10.yxzw, s10, l(0.000000) + mov r3.yw, l(0,0,0,0) + sample_l_indexable(texture1darray)(float,float,float,float) r5.z, r3.xyxx, t10.yzxw, s10, l(0.000000) + sample_l_indexable(texture1darray)(float,float,float,float) r5.w, r3.zwzz, t10.yzwx, s10, l(0.000000) + mad r2.xyzw, r2.xyzw, l(5.095931, 5.095931, 5.095931, 5.095931), l(-2.547965, -2.547965, -2.547965, -2.547965) + mul r2.xyzw, r2.xyzw, -r2.xyzw + exp r2.xyzw, r2.xyzw + dp4 r0.x, r5.xyzw, r2.xyzw + mad r0.y, r0.x, r1.y, r0.y +endif +lt r0.x, l(0.000000), v0.x +lt r0.z, v0.x, l(0.000000) +iadd r0.x, -r0.x, r0.z +itof r0.x, r0.x +mul o0.x, r0.x, r0.y +ret +// Approximately 33 instruction slots used +#endif + +const BYTE g_main[] = +{ + 68, 88, 66, 67, 217, 220, + 138, 177, 184, 179, 84, 150, + 127, 197, 117, 110, 61, 197, + 78, 54, 1, 0, 0, 0, + 132, 6, 0, 0, 5, 0, + 0, 0, 52, 0, 0, 0, + 232, 0, 0, 0, 64, 1, + 0, 0, 116, 1, 0, 0, + 232, 5, 0, 0, 82, 68, + 69, 70, 172, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 2, 0, 0, 0, + 60, 0, 0, 0, 0, 5, + 255, 255, 0, 1, 0, 0, + 130, 0, 0, 0, 82, 68, + 49, 49, 60, 0, 0, 0, + 24, 0, 0, 0, 32, 0, + 0, 0, 40, 0, 0, 0, + 36, 0, 0, 0, 12, 0, + 0, 0, 0, 0, 0, 0, + 124, 0, 0, 0, 3, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 10, 0, 0, 0, + 1, 0, 0, 0, 1, 0, + 0, 0, 127, 0, 0, 0, + 2, 0, 0, 0, 5, 0, + 0, 0, 3, 0, 0, 0, + 255, 255, 255, 255, 10, 0, + 0, 0, 1, 0, 0, 0, + 1, 0, 0, 0, 77, 56, + 0, 74, 67, 0, 77, 105, + 99, 114, 111, 115, 111, 102, + 116, 32, 40, 82, 41, 32, + 72, 76, 83, 76, 32, 83, + 104, 97, 100, 101, 114, 32, + 67, 111, 109, 112, 105, 108, + 101, 114, 32, 49, 48, 46, + 49, 0, 171, 171, 73, 83, + 71, 78, 80, 0, 0, 0, + 2, 0, 0, 0, 8, 0, + 0, 0, 56, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 3, 0, 0, 0, + 0, 0, 0, 0, 15, 15, + 0, 0, 65, 0, 0, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 3, 0, 0, 0, + 1, 0, 0, 0, 15, 0, + 0, 0, 84, 69, 88, 67, + 79, 79, 82, 68, 0, 83, + 86, 95, 80, 111, 115, 105, + 116, 105, 111, 110, 0, 171, + 171, 171, 79, 83, 71, 78, + 44, 0, 0, 0, 1, 0, + 0, 0, 8, 0, 0, 0, + 32, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 3, 0, 0, 0, 0, 0, + 0, 0, 1, 14, 0, 0, + 83, 86, 95, 84, 97, 114, + 103, 101, 116, 0, 171, 171, + 83, 72, 69, 88, 108, 4, + 0, 0, 80, 0, 0, 0, + 27, 1, 0, 0, 106, 8, + 0, 1, 90, 0, 0, 3, + 0, 96, 16, 0, 10, 0, + 0, 0, 88, 56, 0, 4, + 0, 112, 16, 0, 10, 0, + 0, 0, 85, 85, 0, 0, + 98, 32, 0, 3, 242, 16, + 16, 0, 0, 0, 0, 0, + 101, 0, 0, 3, 18, 32, + 16, 0, 0, 0, 0, 0, + 104, 0, 0, 2, 6, 0, + 0, 0, 52, 0, 0, 7, + 18, 0, 16, 0, 0, 0, + 0, 0, 58, 16, 16, 0, + 0, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 0, 0, + 29, 0, 0, 7, 66, 0, + 16, 0, 0, 0, 0, 0, + 42, 16, 16, 0, 0, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 0, 0, 54, 0, + 0, 5, 34, 0, 16, 0, + 0, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 0, 0, + 72, 0, 0, 141, 194, 1, + 0, 128, 67, 85, 21, 0, + 34, 0, 16, 0, 0, 0, + 0, 0, 70, 0, 16, 0, + 0, 0, 0, 0, 22, 126, + 16, 0, 10, 0, 0, 0, + 0, 96, 16, 0, 10, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 0, 0, 1, 0, + 0, 7, 34, 0, 16, 0, + 0, 0, 0, 0, 26, 0, + 16, 0, 0, 0, 0, 0, + 42, 0, 16, 0, 0, 0, + 0, 0, 49, 0, 0, 8, + 66, 0, 16, 0, 0, 0, + 0, 0, 42, 16, 16, 128, + 129, 0, 0, 0, 0, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 122, 68, 31, 0, + 4, 3, 42, 0, 16, 0, + 0, 0, 0, 0, 0, 0, + 0, 8, 66, 0, 16, 0, + 0, 0, 0, 0, 10, 16, + 16, 128, 129, 0, 0, 0, + 0, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 128, 190, + 0, 0, 0, 8, 130, 0, + 16, 0, 0, 0, 0, 0, + 26, 16, 16, 128, 65, 0, + 0, 0, 0, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 0, 192, 0, 0, 0, 8, + 18, 0, 16, 0, 1, 0, + 0, 0, 10, 0, 16, 128, + 65, 0, 0, 0, 0, 0, + 0, 0, 58, 0, 16, 0, + 0, 0, 0, 0, 56, 0, + 0, 7, 34, 0, 16, 0, + 1, 0, 0, 0, 10, 0, + 16, 0, 1, 0, 0, 0, + 1, 64, 0, 0, 159, 49, + 25, 63, 50, 0, 0, 12, + 242, 0, 16, 0, 2, 0, + 0, 0, 6, 0, 16, 0, + 1, 0, 0, 0, 2, 64, + 0, 0, 255, 255, 255, 61, + 0, 0, 192, 62, 0, 0, + 32, 63, 255, 255, 95, 63, + 6, 0, 16, 0, 0, 0, + 0, 0, 50, 0, 0, 9, + 18, 0, 16, 0, 0, 0, + 0, 0, 58, 0, 16, 0, + 0, 0, 0, 0, 42, 16, + 16, 0, 0, 0, 0, 0, + 42, 0, 16, 0, 0, 0, + 0, 0, 50, 0, 0, 10, + 242, 0, 16, 0, 3, 0, + 0, 0, 38, 7, 16, 0, + 2, 0, 0, 0, 166, 26, + 16, 128, 65, 0, 0, 0, + 0, 0, 0, 0, 6, 0, + 16, 0, 0, 0, 0, 0, + 54, 0, 0, 5, 82, 0, + 16, 0, 4, 0, 0, 0, + 86, 7, 16, 0, 3, 0, + 0, 0, 54, 0, 0, 8, + 162, 0, 16, 0, 4, 0, + 0, 0, 2, 64, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 72, 0, + 0, 141, 194, 1, 0, 128, + 67, 85, 21, 0, 18, 0, + 16, 0, 5, 0, 0, 0, + 70, 0, 16, 0, 4, 0, + 0, 0, 70, 126, 16, 0, + 10, 0, 0, 0, 0, 96, + 16, 0, 10, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 0, 0, 72, 0, 0, 141, + 194, 1, 0, 128, 67, 85, + 21, 0, 34, 0, 16, 0, + 5, 0, 0, 0, 230, 10, + 16, 0, 4, 0, 0, 0, + 22, 126, 16, 0, 10, 0, + 0, 0, 0, 96, 16, 0, + 10, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 0, 0, + 54, 0, 0, 8, 162, 0, + 16, 0, 3, 0, 0, 0, + 2, 64, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 72, 0, 0, 141, + 194, 1, 0, 128, 67, 85, + 21, 0, 66, 0, 16, 0, + 5, 0, 0, 0, 70, 0, + 16, 0, 3, 0, 0, 0, + 150, 124, 16, 0, 10, 0, + 0, 0, 0, 96, 16, 0, + 10, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 0, 0, + 72, 0, 0, 141, 194, 1, + 0, 128, 67, 85, 21, 0, + 130, 0, 16, 0, 5, 0, + 0, 0, 230, 10, 16, 0, + 3, 0, 0, 0, 150, 115, + 16, 0, 10, 0, 0, 0, + 0, 96, 16, 0, 10, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 0, 0, 50, 0, + 0, 15, 242, 0, 16, 0, + 2, 0, 0, 0, 70, 14, + 16, 0, 2, 0, 0, 0, + 2, 64, 0, 0, 221, 17, + 163, 64, 221, 17, 163, 64, + 221, 17, 163, 64, 221, 17, + 163, 64, 2, 64, 0, 0, + 221, 17, 35, 192, 221, 17, + 35, 192, 221, 17, 35, 192, + 221, 17, 35, 192, 56, 0, + 0, 8, 242, 0, 16, 0, + 2, 0, 0, 0, 70, 14, + 16, 0, 2, 0, 0, 0, + 70, 14, 16, 128, 65, 0, + 0, 0, 2, 0, 0, 0, + 25, 0, 0, 5, 242, 0, + 16, 0, 2, 0, 0, 0, + 70, 14, 16, 0, 2, 0, + 0, 0, 17, 0, 0, 7, + 18, 0, 16, 0, 0, 0, + 0, 0, 70, 14, 16, 0, + 5, 0, 0, 0, 70, 14, + 16, 0, 2, 0, 0, 0, + 50, 0, 0, 9, 34, 0, + 16, 0, 0, 0, 0, 0, + 10, 0, 16, 0, 0, 0, + 0, 0, 26, 0, 16, 0, + 1, 0, 0, 0, 26, 0, + 16, 0, 0, 0, 0, 0, + 21, 0, 0, 1, 49, 0, + 0, 7, 18, 0, 16, 0, + 0, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 0, 0, + 10, 16, 16, 0, 0, 0, + 0, 0, 49, 0, 0, 7, + 66, 0, 16, 0, 0, 0, + 0, 0, 10, 16, 16, 0, + 0, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 0, 0, + 30, 0, 0, 8, 18, 0, + 16, 0, 0, 0, 0, 0, + 10, 0, 16, 128, 65, 0, + 0, 0, 0, 0, 0, 0, + 42, 0, 16, 0, 0, 0, + 0, 0, 43, 0, 0, 5, + 18, 0, 16, 0, 0, 0, + 0, 0, 10, 0, 16, 0, + 0, 0, 0, 0, 56, 0, + 0, 7, 18, 32, 16, 0, + 0, 0, 0, 0, 10, 0, + 16, 0, 0, 0, 0, 0, + 26, 0, 16, 0, 0, 0, + 0, 0, 62, 0, 0, 1, + 83, 84, 65, 84, 148, 0, + 0, 0, 33, 0, 0, 0, + 6, 0, 0, 0, 0, 0, + 0, 0, 2, 0, 0, 0, + 18, 0, 0, 0, 1, 0, + 0, 0, 1, 0, 0, 0, + 1, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 5, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 4, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0 +}; diff --git a/third_party/rive_renderer/source/generated/shaders/d3d/render_atlas_stroke.frag.h b/third_party/rive_renderer/source/generated/shaders/d3d/render_atlas_stroke.frag.h new file mode 100644 index 0000000..f9548df --- /dev/null +++ b/third_party/rive_renderer/source/generated/shaders/d3d/render_atlas_stroke.frag.h @@ -0,0 +1,195 @@ +#if 0 +// +// Generated by Microsoft (R) HLSL Shader Compiler 10.1 +// +// +// Resource Bindings: +// +// Name Type Format Dim HLSL Bind Count +// ------------------------------ ---------- ------- ----------- -------------- ------ +// M8 sampler NA NA s10 1 +// JC texture float 1darray t10 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------- ------ +// TEXCOORD 0 xyzw 0 NONE float xy +// SV_Position 0 xyzw 1 POS float +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------- ------ +// SV_Target 0 x 0 TARGET float x +// +ps_5_0 +dcl_globalFlags refactoringAllowed +dcl_sampler s10, mode_default +dcl_resource_texture1darray (float,float,float,float) t10 +dcl_input_ps linear noperspective v0.xy +dcl_output o0.x +dcl_temps 1 +add r0.x, v0.x, l(3.000000) +mov r0.yw, l(0,0,0,0) +sample_l_indexable(texture1darray)(float,float,float,float) r0.x, r0.xyxx, t10.xyzw, s10, l(0.000000) +add r0.x, -r0.x, l(1.000000) +add r0.z, -v0.y, l(1.000000) +sample_l_indexable(texture1darray)(float,float,float,float) r0.y, r0.zwzz, t10.yxzw, s10, l(0.000000) +add o0.x, -r0.y, r0.x +ret +// Approximately 8 instruction slots used +#endif + +const BYTE g_main[] = +{ + 68, 88, 66, 67, 165, 25, + 130, 128, 89, 132, 241, 41, + 156, 101, 68, 43, 180, 42, + 208, 205, 1, 0, 0, 0, + 104, 3, 0, 0, 5, 0, + 0, 0, 52, 0, 0, 0, + 232, 0, 0, 0, 64, 1, + 0, 0, 116, 1, 0, 0, + 204, 2, 0, 0, 82, 68, + 69, 70, 172, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 2, 0, 0, 0, + 60, 0, 0, 0, 0, 5, + 255, 255, 0, 1, 0, 0, + 130, 0, 0, 0, 82, 68, + 49, 49, 60, 0, 0, 0, + 24, 0, 0, 0, 32, 0, + 0, 0, 40, 0, 0, 0, + 36, 0, 0, 0, 12, 0, + 0, 0, 0, 0, 0, 0, + 124, 0, 0, 0, 3, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 10, 0, 0, 0, + 1, 0, 0, 0, 1, 0, + 0, 0, 127, 0, 0, 0, + 2, 0, 0, 0, 5, 0, + 0, 0, 3, 0, 0, 0, + 255, 255, 255, 255, 10, 0, + 0, 0, 1, 0, 0, 0, + 1, 0, 0, 0, 77, 56, + 0, 74, 67, 0, 77, 105, + 99, 114, 111, 115, 111, 102, + 116, 32, 40, 82, 41, 32, + 72, 76, 83, 76, 32, 83, + 104, 97, 100, 101, 114, 32, + 67, 111, 109, 112, 105, 108, + 101, 114, 32, 49, 48, 46, + 49, 0, 171, 171, 73, 83, + 71, 78, 80, 0, 0, 0, + 2, 0, 0, 0, 8, 0, + 0, 0, 56, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 3, 0, 0, 0, + 0, 0, 0, 0, 15, 3, + 0, 0, 65, 0, 0, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 3, 0, 0, 0, + 1, 0, 0, 0, 15, 0, + 0, 0, 84, 69, 88, 67, + 79, 79, 82, 68, 0, 83, + 86, 95, 80, 111, 115, 105, + 116, 105, 111, 110, 0, 171, + 171, 171, 79, 83, 71, 78, + 44, 0, 0, 0, 1, 0, + 0, 0, 8, 0, 0, 0, + 32, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 3, 0, 0, 0, 0, 0, + 0, 0, 1, 14, 0, 0, + 83, 86, 95, 84, 97, 114, + 103, 101, 116, 0, 171, 171, + 83, 72, 69, 88, 80, 1, + 0, 0, 80, 0, 0, 0, + 84, 0, 0, 0, 106, 8, + 0, 1, 90, 0, 0, 3, + 0, 96, 16, 0, 10, 0, + 0, 0, 88, 56, 0, 4, + 0, 112, 16, 0, 10, 0, + 0, 0, 85, 85, 0, 0, + 98, 32, 0, 3, 50, 16, + 16, 0, 0, 0, 0, 0, + 101, 0, 0, 3, 18, 32, + 16, 0, 0, 0, 0, 0, + 104, 0, 0, 2, 1, 0, + 0, 0, 0, 0, 0, 7, + 18, 0, 16, 0, 0, 0, + 0, 0, 10, 16, 16, 0, + 0, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 64, 64, + 54, 0, 0, 8, 162, 0, + 16, 0, 0, 0, 0, 0, + 2, 64, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 72, 0, 0, 141, + 194, 1, 0, 128, 67, 85, + 21, 0, 18, 0, 16, 0, + 0, 0, 0, 0, 70, 0, + 16, 0, 0, 0, 0, 0, + 70, 126, 16, 0, 10, 0, + 0, 0, 0, 96, 16, 0, + 10, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 8, 18, 0, + 16, 0, 0, 0, 0, 0, + 10, 0, 16, 128, 65, 0, + 0, 0, 0, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 128, 63, 0, 0, 0, 8, + 66, 0, 16, 0, 0, 0, + 0, 0, 26, 16, 16, 128, + 65, 0, 0, 0, 0, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 128, 63, 72, 0, + 0, 141, 194, 1, 0, 128, + 67, 85, 21, 0, 34, 0, + 16, 0, 0, 0, 0, 0, + 230, 10, 16, 0, 0, 0, + 0, 0, 22, 126, 16, 0, + 10, 0, 0, 0, 0, 96, + 16, 0, 10, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 8, + 18, 32, 16, 0, 0, 0, + 0, 0, 26, 0, 16, 128, + 65, 0, 0, 0, 0, 0, + 0, 0, 10, 0, 16, 0, + 0, 0, 0, 0, 62, 0, + 0, 1, 83, 84, 65, 84, + 148, 0, 0, 0, 8, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 2, 0, + 0, 0, 4, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 2, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0 +}; diff --git a/third_party/rive_renderer/source/generated/shaders/d3d/root.sig.h b/third_party/rive_renderer/source/generated/shaders/d3d/root.sig.h new file mode 100644 index 0000000..4f18f5c --- /dev/null +++ b/third_party/rive_renderer/source/generated/shaders/d3d/root.sig.h @@ -0,0 +1,123 @@ +#if 0 +Disassembly failed +#endif + +const BYTE g_ROOT_SIG[] = +{ + 68, 88, 66, 67, 3, 61, + 92, 108, 130, 101, 197, 191, + 222, 129, 206, 39, 2, 17, + 14, 98, 1, 0, 0, 0, + 180, 2, 0, 0, 1, 0, + 0, 0, 36, 0, 0, 0, + 82, 84, 83, 48, 136, 2, + 0, 0, 2, 0, 0, 0, + 9, 0, 0, 0, 24, 0, + 0, 0, 0, 0, 0, 0, + 136, 2, 0, 0, 1, 0, + 0, 0, 2, 0, 0, 0, + 0, 0, 0, 0, 132, 0, + 0, 0, 2, 0, 0, 0, + 0, 0, 0, 0, 144, 0, + 0, 0, 1, 0, 0, 0, + 1, 0, 0, 0, 156, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 168, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 16, 1, + 0, 0, 0, 0, 0, 0, + 5, 0, 0, 0, 120, 1, + 0, 0, 0, 0, 0, 0, + 5, 0, 0, 0, 152, 1, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 2, + 0, 0, 0, 0, 0, 0, + 5, 0, 0, 0, 104, 2, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 2, 0, + 0, 0, 2, 0, 0, 0, + 0, 0, 0, 0, 2, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 4, 0, 0, 0, + 176, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 3, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 255, 255, 255, 255, 0, 0, + 0, 0, 1, 0, 0, 0, + 4, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 255, 255, 255, 255, 0, 0, + 0, 0, 1, 0, 0, 0, + 5, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 255, 255, 255, 255, 0, 0, + 0, 0, 1, 0, 0, 0, + 6, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 255, 255, 255, 255, 4, 0, + 0, 0, 24, 1, 0, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 8, 0, 0, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 255, 255, 255, 255, + 0, 0, 0, 0, 1, 0, + 0, 0, 9, 0, 0, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 255, 255, 255, 255, + 0, 0, 0, 0, 1, 0, + 0, 0, 10, 0, 0, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 255, 255, 255, 255, + 0, 0, 0, 0, 1, 0, + 0, 0, 11, 0, 0, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 255, 255, 255, 255, + 1, 0, 0, 0, 128, 1, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 12, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 255, 255, + 255, 255, 4, 0, 0, 0, + 160, 1, 0, 0, 1, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 3, 0, 0, 0, + 255, 255, 255, 255, 1, 0, + 0, 0, 1, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 0, 0, 2, 0, 0, 0, + 255, 255, 255, 255, 1, 0, + 0, 0, 1, 0, 0, 0, + 2, 0, 0, 0, 0, 0, + 0, 0, 3, 0, 0, 0, + 255, 255, 255, 255, 1, 0, + 0, 0, 1, 0, 0, 0, + 3, 0, 0, 0, 0, 0, + 0, 0, 2, 0, 0, 0, + 255, 255, 255, 255, 4, 0, + 0, 0, 8, 2, 0, 0, + 3, 0, 0, 0, 1, 0, + 0, 0, 8, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 255, 255, 255, 255, + 3, 0, 0, 0, 1, 0, + 0, 0, 9, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 255, 255, 255, 255, + 3, 0, 0, 0, 1, 0, + 0, 0, 10, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 255, 255, 255, 255, + 3, 0, 0, 0, 1, 0, + 0, 0, 11, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 255, 255, 255, 255, + 1, 0, 0, 0, 112, 2, + 0, 0, 3, 0, 0, 0, + 1, 0, 0, 0, 13, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 255, 255, + 255, 255 +}; diff --git a/third_party/rive_renderer/source/generated/shaders/d3d/tessellate.frag.h b/third_party/rive_renderer/source/generated/shaders/d3d/tessellate.frag.h new file mode 100644 index 0000000..b3ad637 --- /dev/null +++ b/third_party/rive_renderer/source/generated/shaders/d3d/tessellate.frag.h @@ -0,0 +1,1418 @@ +#if 0 +// +// Generated by Microsoft (R) HLSL Shader Compiler 10.1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------- ------ +// TEXCOORD 0 xyzw 0 NONE float xyzw +// TEXCOORD 1 xyzw 1 NONE float xyzw +// TEXCOORD 2 xyzw 2 NONE float xyzw +// TEXCOORD 3 xyz 3 NONE float xyz +// TEXCOORD 4 x 4 NONE uint x +// SV_Position 0 xyzw 5 POS float +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------- ------ +// SV_Target 0 xyzw 0 TARGET uint xyzw +// +ps_5_0 +dcl_globalFlags refactoringAllowed +dcl_input_ps linear noperspective v0.xyzw +dcl_input_ps linear noperspective v1.xyzw +dcl_input_ps linear noperspective v2.xyzw +dcl_input_ps linear noperspective v3.xyz +dcl_input_ps constant v4.x +dcl_output o0.xyzw +dcl_temps 10 +ne r0.xy, v0.zwzz, v0.xyxx +or r0.x, r0.y, r0.x +ne r0.yz, v0.zzwz, v1.xxyx +or r0.y, r0.z, r0.y +movc r0.zw, r0.yyyy, v1.xxxy, v1.zzzw +movc r0.xz, r0.xxxx, v0.zzwz, r0.zzwz +add r0.xz, r0.xxzx, -v0.xxyx +ne r1.xy, v1.xyxx, v1.zwzz +or r0.w, r1.y, r1.x +movc r1.xy, r0.yyyy, v0.zwzz, v0.xyxx +movc r0.yw, r0.wwww, v1.xxxy, r1.xxxy +add r0.yw, -r0.yyyw, v1.zzzw +round_ni r1.x, v2.x +max r1.w, r1.x, l(0.000000) +ftou r2.x, v2.z +and r2.y, r2.x, l(1023) +utof r3.x, r2.y +ushr r2.x, r2.x, l(10) +utof r2.y, r2.x +add r1.z, -r2.y, v2.y +ge r2.w, r1.z, r1.w +add r2.z, -r1.z, r1.w +and r4.xyz, v4.xxxx, l(0xe3ffffff, 0x1c000000, 0x02000000, 0) +ult r3.w, l(0x08000000), r4.y +lt r5.xy, r2.zzzz, l(2.500000, 3.500000, 0.000000, 0.000000) +or r4.w, v4.x, l(0x00400000) +movc r4.w, r5.x, r4.w, v4.x +lt r5.x, l(1.500000), r2.z +and r5.x, r5.y, r5.x +or r5.y, r4.w, l(0x00200000) +movc r2.x, r5.x, r5.y, r4.w +ine r4.z, r4.z, l(0) +ieq r4.y, r4.y, l(0x04000000) +or r4.y, r4.y, r4.z +add r4.zw, r2.yyyz, l(0.000000, 0.000000, -2.000000, -1.000000) +movc r5.yz, r4.yyyy, r4.zzwz, r2.yyzy +mov r5.x, v4.x +movc r5.xzw, r3.wwww, r2.xxyz, r5.xxyz +lt r2.x, v3.z, l(0.000000) +movc r2.x, r2.x, l(0x00100000), l(0x00080000) +or r2.z, r2.x, r5.x +mov r1.xy, v1.xyxx +mov r5.xy, v1.zwzz +movc r1.xyzw, r2.wwww, r1.xyzw, r5.xyzw +movc r4.yz, r2.wwww, v0.xxyx, v1.zzwz +movc r0.xz, r2.wwww, r0.xxzx, r0.yywy +mov r3.y, v2.w +mov r3.z, r4.x +mov r2.x, l(1.000000) +mov r2.y, v3.z +movc r3.xyw, r2.wwww, r3.xyxz, r2.xyxz +eq r2.x, r1.w, l(0.000000) +eq r2.y, r1.z, r1.w +or r2.x, r2.y, r2.x +and r2.y, r3.w, l(0x1c000000) +ult r2.z, l(0x08000000), r2.y +or r2.x, r2.z, r2.x +if_nz r2.x + movc r0.yw, r2.wwww, r0.yyyw, v3.xxxy + mul r2.x, r1.z, l(0.500000) + lt r2.x, r1.w, r2.x + movc r3.xy, r2.xxxx, r4.yzyy, v1.zwzz + movc r0.yw, r2.xxxx, r0.xxxz, r0.yyyw + dp2 r2.x, r0.ywyy, r0.ywyy + rsq r2.x, r2.x + mul r0.yw, r0.yyyw, r2.xxxx + max r0.y, r0.y, l(-1.000000) + min r0.y, r0.y, l(1.000000) + add r2.x, -|r0.y|, l(1.000000) + sqrt r2.x, r2.x + mad r2.z, |r0.y|, l(-0.018729), l(0.074261) + mad r2.z, r2.z, |r0.y|, l(-0.212114) + mad r2.z, r2.z, |r0.y|, l(1.570729) + mul r4.x, r2.x, r2.z + mad r4.x, r4.x, l(-2.000000), l(3.141593) + lt r0.y, r0.y, -r0.y + and r0.y, r0.y, r4.x + mad r0.y, r2.z, r2.x, r0.y + ge r0.w, r0.w, l(0.000000) + movc r0.y, r0.w, r0.y, -r0.y +else + movc r2.xz, r2.wwww, v0.zzwz, v1.zzwz + and r0.w, r3.w, l(0x80000000) + if_nz r0.w + mov r3.xy, r2.xzxx + mov r0.y, l(0) + else + eq r0.w, r1.z, r3.x + if_nz r0.w + div r5.x, r1.w, r3.x + mov r5.y, l(0) + mov r0.w, l(0) + else + add r4.xw, -r4.yyyz, r2.xxxz + add r5.zw, -r4.yyyz, v1.zzzw + add r6.xy, r1.xyxx, -r2.xzxx + add r6.zw, -r4.xxxw, r6.xxxy + mad r5.zw, r6.xxxy, l(0.000000, 0.000000, -3.000000, -3.000000), r5.zzzw + add r2.w, r3.x, r3.x + mul r6.xy, r2.wwww, r6.zwzz + mul r2.w, r3.x, r3.x + mul r7.xy, r2.wwww, r4.xwxx + add r2.w, r3.x, l(-1.000000) + min r2.w, r1.w, r2.w + dp2 r7.z, r0.xzxx, r0.xzxx + rsq r7.z, r7.z + mul r0.xz, r0.xxzx, r7.zzzz + add r7.z, r1.w, l(1.000000) + mul r7.z, |r3.y|, r7.z + mov r7.w, l(0) + mov r8.x, l(9) + loop + ilt r8.y, r8.x, l(0) + breakc_nz r8.y + itof r8.y, r8.x + exp r8.y, r8.y + add r8.y, r7.w, r8.y + ge r8.z, r2.w, r8.y + mad r9.xy, r8.yyyy, r5.zwzz, r6.xyxx + mad r9.xy, r8.yyyy, r9.xyxx, r7.xyxx + dp2 r8.w, r9.xyxx, r9.xyxx + rsq r8.w, r8.w + mul r9.xy, r8.wwww, r9.xyxx + dp2 r8.w, r9.xyxx, r0.xzxx + mad r9.x, r8.y, -|r3.y|, r7.z + min r9.x, r9.x, l(3.141593) + sincos null, r9.x, r9.x + ge r8.w, r8.w, r9.x + movc r8.y, r8.w, r8.y, r7.w + movc r7.w, r8.z, r8.y, r7.w + iadd r8.x, r8.x, l(-1) + endloop + div r2.w, r7.w, r3.x + add r6.x, r1.w, -r7.w + max r0.x, r0.x, l(-1.000000) + min r0.x, r0.x, l(1.000000) + add r6.y, -|r0.x|, l(1.000000) + sqrt r6.y, r6.y + mad r7.x, |r0.x|, l(-0.018729), l(0.074261) + mad r7.x, r7.x, |r0.x|, l(-0.212114) + mad r7.x, r7.x, |r0.x|, l(1.570729) + mul r7.y, r6.y, r7.x + mad r7.y, r7.y, l(-2.000000), l(3.141593) + lt r0.x, r0.x, -r0.x + and r0.x, r0.x, r7.y + mad r0.x, r7.x, r6.y, r0.x + ge r0.z, r0.z, l(0.000000) + movc r0.x, r0.z, r0.x, -r0.x + mad r0.w, r6.x, r3.y, r0.x + sincos r7.x, r0.x, r0.w + mov r7.y, -r0.x + dp2 r8.z, r7.xyxx, r5.zwzz + dp2 r0.x, r7.xyxx, r6.zwzz + dp2 r8.x, r7.xyxx, r4.xwxx + mul r0.z, r8.x, r8.z + mad r0.z, r0.x, r0.x, -r0.z + max r0.z, r0.z, l(0.000000) + sqrt r0.z, r0.z + lt r4.x, l(0.000000), r0.x + movc r0.z, r4.x, -r0.z, r0.z + add r8.y, -r0.x, r0.z + mul r0.x, r8.y, r8.z + mul r0.x, r0.x, l(-0.500000) + mad r0.z, r8.y, r8.y, r0.x + mad r0.x, r8.z, r8.x, r0.x + lt r0.x, |r0.z|, |r0.x| + movc r0.xz, r0.xxxx, r8.yyzy, r8.xxyx + ne r4.x, r0.z, l(0.000000) + div r0.x, r0.x, r0.z + and r0.x, r0.x, r4.x + mov_sat r0.x, r0.x + eq r0.z, r6.x, l(0.000000) + movc r5.y, r0.z, l(0), r0.x + max r5.x, r2.w, r5.y + endif + add r0.xz, -r4.yyzy, r2.xxzx + mad r0.xz, r0.xxzx, r5.xxxx, r4.yyzy + add r4.xy, r1.xyxx, -r2.xzxx + mad r2.xz, r4.xxyx, r5.xxxx, r2.xxzx + add r4.xy, -r1.xyxx, v1.zwzz + mad r1.xy, r4.xyxx, r5.xxxx, r1.xyxx + add r4.xy, -r0.xzxx, r2.xzxx + mad r0.xz, r4.xxyx, r5.xxxx, r0.xxzx + add r1.xy, -r2.xzxx, r1.xyxx + mad r1.xy, r1.xyxx, r5.xxxx, r2.xzxx + add r1.xy, -r0.xzxx, r1.xyxx + mad r3.xy, r1.xyxx, r5.xxxx, r0.xzxx + ne r0.x, r5.y, r5.x + dp2 r0.z, r1.xyxx, r1.xyxx + rsq r0.z, r0.z + mul r1.xy, r0.zzzz, r1.xyxx + max r0.z, r1.x, l(-1.000000) + min r0.z, r0.z, l(1.000000) + add r1.x, -|r0.z|, l(1.000000) + sqrt r1.x, r1.x + mad r2.x, |r0.z|, l(-0.018729), l(0.074261) + mad r2.x, r2.x, |r0.z|, l(-0.212114) + mad r2.x, r2.x, |r0.z|, l(1.570729) + mul r2.z, r1.x, r2.x + mad r2.z, r2.z, l(-2.000000), l(3.141593) + lt r0.z, r0.z, -r0.z + and r0.z, r0.z, r2.z + mad r0.z, r2.x, r1.x, r0.z + ge r1.x, r1.y, l(0.000000) + movc r0.z, r1.x, r0.z, -r0.z + movc r0.y, r0.x, r0.z, r0.w + endif +endif +ieq r0.x, r2.y, l(0x04000000) +ftou r0.zw, r1.zzzw +ishl r0.z, r0.z, l(16) +or r0.z, r0.w, r0.z +mul r0.y, r0.y, l(0.159155) +ge r0.w, r0.y, -r0.y +frc r0.y, |r0.y| +movc r0.y, r0.w, r0.y, -r0.y +mul r0.y, r0.y, l(6.283185) +movc r3.z, r0.x, r0.z, r0.y +mov o0.xyzw, r3.xyzw +ret +// Approximately 220 instruction slots used +#endif + +const BYTE g_main[] = +{ + 68, 88, 66, 67, 225, 236, + 243, 192, 161, 17, 15, 154, + 184, 138, 170, 204, 240, 23, + 147, 97, 1, 0, 0, 0, + 40, 27, 0, 0, 5, 0, + 0, 0, 52, 0, 0, 0, + 160, 0, 0, 0, 88, 1, + 0, 0, 140, 1, 0, 0, + 140, 26, 0, 0, 82, 68, + 69, 70, 100, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 60, 0, 0, 0, 0, 5, + 255, 255, 0, 1, 0, 0, + 60, 0, 0, 0, 82, 68, + 49, 49, 60, 0, 0, 0, + 24, 0, 0, 0, 32, 0, + 0, 0, 40, 0, 0, 0, + 36, 0, 0, 0, 12, 0, + 0, 0, 0, 0, 0, 0, + 77, 105, 99, 114, 111, 115, + 111, 102, 116, 32, 40, 82, + 41, 32, 72, 76, 83, 76, + 32, 83, 104, 97, 100, 101, + 114, 32, 67, 111, 109, 112, + 105, 108, 101, 114, 32, 49, + 48, 46, 49, 0, 73, 83, + 71, 78, 176, 0, 0, 0, + 6, 0, 0, 0, 8, 0, + 0, 0, 152, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 3, 0, 0, 0, + 0, 0, 0, 0, 15, 15, + 0, 0, 152, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 0, 0, 3, 0, 0, 0, + 1, 0, 0, 0, 15, 15, + 0, 0, 152, 0, 0, 0, + 2, 0, 0, 0, 0, 0, + 0, 0, 3, 0, 0, 0, + 2, 0, 0, 0, 15, 15, + 0, 0, 152, 0, 0, 0, + 3, 0, 0, 0, 0, 0, + 0, 0, 3, 0, 0, 0, + 3, 0, 0, 0, 7, 7, + 0, 0, 152, 0, 0, 0, + 4, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 4, 0, 0, 0, 1, 1, + 0, 0, 161, 0, 0, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 3, 0, 0, 0, + 5, 0, 0, 0, 15, 0, + 0, 0, 84, 69, 88, 67, + 79, 79, 82, 68, 0, 83, + 86, 95, 80, 111, 115, 105, + 116, 105, 111, 110, 0, 171, + 171, 171, 79, 83, 71, 78, + 44, 0, 0, 0, 1, 0, + 0, 0, 8, 0, 0, 0, + 32, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 0, 0, 15, 0, 0, 0, + 83, 86, 95, 84, 97, 114, + 103, 101, 116, 0, 171, 171, + 83, 72, 69, 88, 248, 24, + 0, 0, 80, 0, 0, 0, + 62, 6, 0, 0, 106, 8, + 0, 1, 98, 32, 0, 3, + 242, 16, 16, 0, 0, 0, + 0, 0, 98, 32, 0, 3, + 242, 16, 16, 0, 1, 0, + 0, 0, 98, 32, 0, 3, + 242, 16, 16, 0, 2, 0, + 0, 0, 98, 32, 0, 3, + 114, 16, 16, 0, 3, 0, + 0, 0, 98, 8, 0, 3, + 18, 16, 16, 0, 4, 0, + 0, 0, 101, 0, 0, 3, + 242, 32, 16, 0, 0, 0, + 0, 0, 104, 0, 0, 2, + 10, 0, 0, 0, 57, 0, + 0, 7, 50, 0, 16, 0, + 0, 0, 0, 0, 230, 26, + 16, 0, 0, 0, 0, 0, + 70, 16, 16, 0, 0, 0, + 0, 0, 60, 0, 0, 7, + 18, 0, 16, 0, 0, 0, + 0, 0, 26, 0, 16, 0, + 0, 0, 0, 0, 10, 0, + 16, 0, 0, 0, 0, 0, + 57, 0, 0, 7, 98, 0, + 16, 0, 0, 0, 0, 0, + 166, 27, 16, 0, 0, 0, + 0, 0, 6, 17, 16, 0, + 1, 0, 0, 0, 60, 0, + 0, 7, 34, 0, 16, 0, + 0, 0, 0, 0, 42, 0, + 16, 0, 0, 0, 0, 0, + 26, 0, 16, 0, 0, 0, + 0, 0, 55, 0, 0, 9, + 194, 0, 16, 0, 0, 0, + 0, 0, 86, 5, 16, 0, + 0, 0, 0, 0, 6, 20, + 16, 0, 1, 0, 0, 0, + 166, 30, 16, 0, 1, 0, + 0, 0, 55, 0, 0, 9, + 82, 0, 16, 0, 0, 0, + 0, 0, 6, 0, 16, 0, + 0, 0, 0, 0, 166, 27, + 16, 0, 0, 0, 0, 0, + 166, 11, 16, 0, 0, 0, + 0, 0, 0, 0, 0, 8, + 82, 0, 16, 0, 0, 0, + 0, 0, 6, 2, 16, 0, + 0, 0, 0, 0, 6, 17, + 16, 128, 65, 0, 0, 0, + 0, 0, 0, 0, 57, 0, + 0, 7, 50, 0, 16, 0, + 1, 0, 0, 0, 70, 16, + 16, 0, 1, 0, 0, 0, + 230, 26, 16, 0, 1, 0, + 0, 0, 60, 0, 0, 7, + 130, 0, 16, 0, 0, 0, + 0, 0, 26, 0, 16, 0, + 1, 0, 0, 0, 10, 0, + 16, 0, 1, 0, 0, 0, + 55, 0, 0, 9, 50, 0, + 16, 0, 1, 0, 0, 0, + 86, 5, 16, 0, 0, 0, + 0, 0, 230, 26, 16, 0, + 0, 0, 0, 0, 70, 16, + 16, 0, 0, 0, 0, 0, + 55, 0, 0, 9, 162, 0, + 16, 0, 0, 0, 0, 0, + 246, 15, 16, 0, 0, 0, + 0, 0, 6, 20, 16, 0, + 1, 0, 0, 0, 6, 4, + 16, 0, 1, 0, 0, 0, + 0, 0, 0, 8, 162, 0, + 16, 0, 0, 0, 0, 0, + 86, 13, 16, 128, 65, 0, + 0, 0, 0, 0, 0, 0, + 166, 30, 16, 0, 1, 0, + 0, 0, 65, 0, 0, 5, + 18, 0, 16, 0, 1, 0, + 0, 0, 10, 16, 16, 0, + 2, 0, 0, 0, 52, 0, + 0, 7, 130, 0, 16, 0, + 1, 0, 0, 0, 10, 0, + 16, 0, 1, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 0, 0, 28, 0, 0, 5, + 18, 0, 16, 0, 2, 0, + 0, 0, 42, 16, 16, 0, + 2, 0, 0, 0, 1, 0, + 0, 7, 34, 0, 16, 0, + 2, 0, 0, 0, 10, 0, + 16, 0, 2, 0, 0, 0, + 1, 64, 0, 0, 255, 3, + 0, 0, 86, 0, 0, 5, + 18, 0, 16, 0, 3, 0, + 0, 0, 26, 0, 16, 0, + 2, 0, 0, 0, 85, 0, + 0, 7, 18, 0, 16, 0, + 2, 0, 0, 0, 10, 0, + 16, 0, 2, 0, 0, 0, + 1, 64, 0, 0, 10, 0, + 0, 0, 86, 0, 0, 5, + 34, 0, 16, 0, 2, 0, + 0, 0, 10, 0, 16, 0, + 2, 0, 0, 0, 0, 0, + 0, 8, 66, 0, 16, 0, + 1, 0, 0, 0, 26, 0, + 16, 128, 65, 0, 0, 0, + 2, 0, 0, 0, 26, 16, + 16, 0, 2, 0, 0, 0, + 29, 0, 0, 7, 130, 0, + 16, 0, 2, 0, 0, 0, + 42, 0, 16, 0, 1, 0, + 0, 0, 58, 0, 16, 0, + 1, 0, 0, 0, 0, 0, + 0, 8, 66, 0, 16, 0, + 2, 0, 0, 0, 42, 0, + 16, 128, 65, 0, 0, 0, + 1, 0, 0, 0, 58, 0, + 16, 0, 1, 0, 0, 0, + 1, 0, 0, 10, 114, 0, + 16, 0, 4, 0, 0, 0, + 6, 16, 16, 0, 4, 0, + 0, 0, 2, 64, 0, 0, + 255, 255, 255, 227, 0, 0, + 0, 28, 0, 0, 0, 2, + 0, 0, 0, 0, 79, 0, + 0, 7, 130, 0, 16, 0, + 3, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 0, 8, + 26, 0, 16, 0, 4, 0, + 0, 0, 49, 0, 0, 10, + 50, 0, 16, 0, 5, 0, + 0, 0, 166, 10, 16, 0, + 2, 0, 0, 0, 2, 64, + 0, 0, 0, 0, 32, 64, + 0, 0, 96, 64, 0, 0, + 0, 0, 0, 0, 0, 0, + 60, 0, 0, 7, 130, 0, + 16, 0, 4, 0, 0, 0, + 10, 16, 16, 0, 4, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 64, 0, 55, 0, + 0, 9, 130, 0, 16, 0, + 4, 0, 0, 0, 10, 0, + 16, 0, 5, 0, 0, 0, + 58, 0, 16, 0, 4, 0, + 0, 0, 10, 16, 16, 0, + 4, 0, 0, 0, 49, 0, + 0, 7, 18, 0, 16, 0, + 5, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 192, 63, + 42, 0, 16, 0, 2, 0, + 0, 0, 1, 0, 0, 7, + 18, 0, 16, 0, 5, 0, + 0, 0, 26, 0, 16, 0, + 5, 0, 0, 0, 10, 0, + 16, 0, 5, 0, 0, 0, + 60, 0, 0, 7, 34, 0, + 16, 0, 5, 0, 0, 0, + 58, 0, 16, 0, 4, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 32, 0, 55, 0, + 0, 9, 18, 0, 16, 0, + 2, 0, 0, 0, 10, 0, + 16, 0, 5, 0, 0, 0, + 26, 0, 16, 0, 5, 0, + 0, 0, 58, 0, 16, 0, + 4, 0, 0, 0, 39, 0, + 0, 7, 66, 0, 16, 0, + 4, 0, 0, 0, 42, 0, + 16, 0, 4, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 0, 0, 32, 0, 0, 7, + 34, 0, 16, 0, 4, 0, + 0, 0, 26, 0, 16, 0, + 4, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 0, 4, + 60, 0, 0, 7, 34, 0, + 16, 0, 4, 0, 0, 0, + 26, 0, 16, 0, 4, 0, + 0, 0, 42, 0, 16, 0, + 4, 0, 0, 0, 0, 0, + 0, 10, 194, 0, 16, 0, + 4, 0, 0, 0, 86, 9, + 16, 0, 2, 0, 0, 0, + 2, 64, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 192, 0, 0, + 128, 191, 55, 0, 0, 9, + 98, 0, 16, 0, 5, 0, + 0, 0, 86, 5, 16, 0, + 4, 0, 0, 0, 166, 11, + 16, 0, 4, 0, 0, 0, + 86, 6, 16, 0, 2, 0, + 0, 0, 54, 0, 0, 5, + 18, 0, 16, 0, 5, 0, + 0, 0, 10, 16, 16, 0, + 4, 0, 0, 0, 55, 0, + 0, 9, 210, 0, 16, 0, + 5, 0, 0, 0, 246, 15, + 16, 0, 3, 0, 0, 0, + 6, 9, 16, 0, 2, 0, + 0, 0, 6, 9, 16, 0, + 5, 0, 0, 0, 49, 0, + 0, 7, 18, 0, 16, 0, + 2, 0, 0, 0, 42, 16, + 16, 0, 3, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 0, 0, 55, 0, 0, 9, + 18, 0, 16, 0, 2, 0, + 0, 0, 10, 0, 16, 0, + 2, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 16, 0, + 1, 64, 0, 0, 0, 0, + 8, 0, 60, 0, 0, 7, + 66, 0, 16, 0, 2, 0, + 0, 0, 10, 0, 16, 0, + 2, 0, 0, 0, 10, 0, + 16, 0, 5, 0, 0, 0, + 54, 0, 0, 5, 50, 0, + 16, 0, 1, 0, 0, 0, + 70, 16, 16, 0, 1, 0, + 0, 0, 54, 0, 0, 5, + 50, 0, 16, 0, 5, 0, + 0, 0, 230, 26, 16, 0, + 1, 0, 0, 0, 55, 0, + 0, 9, 242, 0, 16, 0, + 1, 0, 0, 0, 246, 15, + 16, 0, 2, 0, 0, 0, + 70, 14, 16, 0, 1, 0, + 0, 0, 70, 14, 16, 0, + 5, 0, 0, 0, 55, 0, + 0, 9, 98, 0, 16, 0, + 4, 0, 0, 0, 246, 15, + 16, 0, 2, 0, 0, 0, + 6, 17, 16, 0, 0, 0, + 0, 0, 166, 27, 16, 0, + 1, 0, 0, 0, 55, 0, + 0, 9, 82, 0, 16, 0, + 0, 0, 0, 0, 246, 15, + 16, 0, 2, 0, 0, 0, + 6, 2, 16, 0, 0, 0, + 0, 0, 86, 7, 16, 0, + 0, 0, 0, 0, 54, 0, + 0, 5, 34, 0, 16, 0, + 3, 0, 0, 0, 58, 16, + 16, 0, 2, 0, 0, 0, + 54, 0, 0, 5, 66, 0, + 16, 0, 3, 0, 0, 0, + 10, 0, 16, 0, 4, 0, + 0, 0, 54, 0, 0, 5, + 18, 0, 16, 0, 2, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 128, 63, 54, 0, + 0, 5, 34, 0, 16, 0, + 2, 0, 0, 0, 42, 16, + 16, 0, 3, 0, 0, 0, + 55, 0, 0, 9, 178, 0, + 16, 0, 3, 0, 0, 0, + 246, 15, 16, 0, 2, 0, + 0, 0, 70, 8, 16, 0, + 3, 0, 0, 0, 70, 8, + 16, 0, 2, 0, 0, 0, + 24, 0, 0, 7, 18, 0, + 16, 0, 2, 0, 0, 0, + 58, 0, 16, 0, 1, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 0, 0, 24, 0, + 0, 7, 34, 0, 16, 0, + 2, 0, 0, 0, 42, 0, + 16, 0, 1, 0, 0, 0, + 58, 0, 16, 0, 1, 0, + 0, 0, 60, 0, 0, 7, + 18, 0, 16, 0, 2, 0, + 0, 0, 26, 0, 16, 0, + 2, 0, 0, 0, 10, 0, + 16, 0, 2, 0, 0, 0, + 1, 0, 0, 7, 34, 0, + 16, 0, 2, 0, 0, 0, + 58, 0, 16, 0, 3, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 0, 28, 79, 0, + 0, 7, 66, 0, 16, 0, + 2, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 0, 8, + 26, 0, 16, 0, 2, 0, + 0, 0, 60, 0, 0, 7, + 18, 0, 16, 0, 2, 0, + 0, 0, 42, 0, 16, 0, + 2, 0, 0, 0, 10, 0, + 16, 0, 2, 0, 0, 0, + 31, 0, 4, 3, 10, 0, + 16, 0, 2, 0, 0, 0, + 55, 0, 0, 9, 162, 0, + 16, 0, 0, 0, 0, 0, + 246, 15, 16, 0, 2, 0, + 0, 0, 86, 13, 16, 0, + 0, 0, 0, 0, 6, 20, + 16, 0, 3, 0, 0, 0, + 56, 0, 0, 7, 18, 0, + 16, 0, 2, 0, 0, 0, + 42, 0, 16, 0, 1, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 0, 63, 49, 0, + 0, 7, 18, 0, 16, 0, + 2, 0, 0, 0, 58, 0, + 16, 0, 1, 0, 0, 0, + 10, 0, 16, 0, 2, 0, + 0, 0, 55, 0, 0, 9, + 50, 0, 16, 0, 3, 0, + 0, 0, 6, 0, 16, 0, + 2, 0, 0, 0, 150, 5, + 16, 0, 4, 0, 0, 0, + 230, 26, 16, 0, 1, 0, + 0, 0, 55, 0, 0, 9, + 162, 0, 16, 0, 0, 0, + 0, 0, 6, 0, 16, 0, + 2, 0, 0, 0, 6, 8, + 16, 0, 0, 0, 0, 0, + 86, 13, 16, 0, 0, 0, + 0, 0, 15, 0, 0, 7, + 18, 0, 16, 0, 2, 0, + 0, 0, 214, 5, 16, 0, + 0, 0, 0, 0, 214, 5, + 16, 0, 0, 0, 0, 0, + 68, 0, 0, 5, 18, 0, + 16, 0, 2, 0, 0, 0, + 10, 0, 16, 0, 2, 0, + 0, 0, 56, 0, 0, 7, + 162, 0, 16, 0, 0, 0, + 0, 0, 86, 13, 16, 0, + 0, 0, 0, 0, 6, 0, + 16, 0, 2, 0, 0, 0, + 52, 0, 0, 7, 34, 0, + 16, 0, 0, 0, 0, 0, + 26, 0, 16, 0, 0, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 128, 191, 51, 0, + 0, 7, 34, 0, 16, 0, + 0, 0, 0, 0, 26, 0, + 16, 0, 0, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 128, 63, 0, 0, 0, 8, + 18, 0, 16, 0, 2, 0, + 0, 0, 26, 0, 16, 128, + 193, 0, 0, 0, 0, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 128, 63, 75, 0, + 0, 5, 18, 0, 16, 0, + 2, 0, 0, 0, 10, 0, + 16, 0, 2, 0, 0, 0, + 50, 0, 0, 10, 66, 0, + 16, 0, 2, 0, 0, 0, + 26, 0, 16, 128, 129, 0, + 0, 0, 0, 0, 0, 0, + 1, 64, 0, 0, 48, 110, + 153, 188, 1, 64, 0, 0, + 39, 22, 152, 61, 50, 0, + 0, 10, 66, 0, 16, 0, + 2, 0, 0, 0, 42, 0, + 16, 0, 2, 0, 0, 0, + 26, 0, 16, 128, 129, 0, + 0, 0, 0, 0, 0, 0, + 1, 64, 0, 0, 132, 52, + 89, 190, 50, 0, 0, 10, + 66, 0, 16, 0, 2, 0, + 0, 0, 42, 0, 16, 0, + 2, 0, 0, 0, 26, 0, + 16, 128, 129, 0, 0, 0, + 0, 0, 0, 0, 1, 64, + 0, 0, 164, 13, 201, 63, + 56, 0, 0, 7, 18, 0, + 16, 0, 4, 0, 0, 0, + 10, 0, 16, 0, 2, 0, + 0, 0, 42, 0, 16, 0, + 2, 0, 0, 0, 50, 0, + 0, 9, 18, 0, 16, 0, + 4, 0, 0, 0, 10, 0, + 16, 0, 4, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 0, 192, 1, 64, 0, 0, + 219, 15, 73, 64, 49, 0, + 0, 8, 34, 0, 16, 0, + 0, 0, 0, 0, 26, 0, + 16, 0, 0, 0, 0, 0, + 26, 0, 16, 128, 65, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 7, 34, 0, + 16, 0, 0, 0, 0, 0, + 26, 0, 16, 0, 0, 0, + 0, 0, 10, 0, 16, 0, + 4, 0, 0, 0, 50, 0, + 0, 9, 34, 0, 16, 0, + 0, 0, 0, 0, 42, 0, + 16, 0, 2, 0, 0, 0, + 10, 0, 16, 0, 2, 0, + 0, 0, 26, 0, 16, 0, + 0, 0, 0, 0, 29, 0, + 0, 7, 130, 0, 16, 0, + 0, 0, 0, 0, 58, 0, + 16, 0, 0, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 0, 0, 55, 0, 0, 10, + 34, 0, 16, 0, 0, 0, + 0, 0, 58, 0, 16, 0, + 0, 0, 0, 0, 26, 0, + 16, 0, 0, 0, 0, 0, + 26, 0, 16, 128, 65, 0, + 0, 0, 0, 0, 0, 0, + 18, 0, 0, 1, 55, 0, + 0, 9, 82, 0, 16, 0, + 2, 0, 0, 0, 246, 15, + 16, 0, 2, 0, 0, 0, + 166, 27, 16, 0, 0, 0, + 0, 0, 166, 27, 16, 0, + 1, 0, 0, 0, 1, 0, + 0, 7, 130, 0, 16, 0, + 0, 0, 0, 0, 58, 0, + 16, 0, 3, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 0, 128, 31, 0, 4, 3, + 58, 0, 16, 0, 0, 0, + 0, 0, 54, 0, 0, 5, + 50, 0, 16, 0, 3, 0, + 0, 0, 134, 0, 16, 0, + 2, 0, 0, 0, 54, 0, + 0, 5, 34, 0, 16, 0, + 0, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 0, 0, + 18, 0, 0, 1, 24, 0, + 0, 7, 130, 0, 16, 0, + 0, 0, 0, 0, 42, 0, + 16, 0, 1, 0, 0, 0, + 10, 0, 16, 0, 3, 0, + 0, 0, 31, 0, 4, 3, + 58, 0, 16, 0, 0, 0, + 0, 0, 14, 0, 0, 7, + 18, 0, 16, 0, 5, 0, + 0, 0, 58, 0, 16, 0, + 1, 0, 0, 0, 10, 0, + 16, 0, 3, 0, 0, 0, + 54, 0, 0, 5, 34, 0, + 16, 0, 5, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 0, 0, 54, 0, 0, 5, + 130, 0, 16, 0, 0, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 0, 0, 18, 0, + 0, 1, 0, 0, 0, 8, + 146, 0, 16, 0, 4, 0, + 0, 0, 86, 9, 16, 128, + 65, 0, 0, 0, 4, 0, + 0, 0, 6, 8, 16, 0, + 2, 0, 0, 0, 0, 0, + 0, 8, 194, 0, 16, 0, + 5, 0, 0, 0, 86, 9, + 16, 128, 65, 0, 0, 0, + 4, 0, 0, 0, 166, 30, + 16, 0, 1, 0, 0, 0, + 0, 0, 0, 8, 50, 0, + 16, 0, 6, 0, 0, 0, + 70, 0, 16, 0, 1, 0, + 0, 0, 134, 0, 16, 128, + 65, 0, 0, 0, 2, 0, + 0, 0, 0, 0, 0, 8, + 194, 0, 16, 0, 6, 0, + 0, 0, 6, 12, 16, 128, + 65, 0, 0, 0, 4, 0, + 0, 0, 6, 4, 16, 0, + 6, 0, 0, 0, 50, 0, + 0, 12, 194, 0, 16, 0, + 5, 0, 0, 0, 6, 4, + 16, 0, 6, 0, 0, 0, + 2, 64, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 64, 192, 0, 0, + 64, 192, 166, 14, 16, 0, + 5, 0, 0, 0, 0, 0, + 0, 7, 130, 0, 16, 0, + 2, 0, 0, 0, 10, 0, + 16, 0, 3, 0, 0, 0, + 10, 0, 16, 0, 3, 0, + 0, 0, 56, 0, 0, 7, + 50, 0, 16, 0, 6, 0, + 0, 0, 246, 15, 16, 0, + 2, 0, 0, 0, 230, 10, + 16, 0, 6, 0, 0, 0, + 56, 0, 0, 7, 130, 0, + 16, 0, 2, 0, 0, 0, + 10, 0, 16, 0, 3, 0, + 0, 0, 10, 0, 16, 0, + 3, 0, 0, 0, 56, 0, + 0, 7, 50, 0, 16, 0, + 7, 0, 0, 0, 246, 15, + 16, 0, 2, 0, 0, 0, + 198, 0, 16, 0, 4, 0, + 0, 0, 0, 0, 0, 7, + 130, 0, 16, 0, 2, 0, + 0, 0, 10, 0, 16, 0, + 3, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 128, 191, + 51, 0, 0, 7, 130, 0, + 16, 0, 2, 0, 0, 0, + 58, 0, 16, 0, 1, 0, + 0, 0, 58, 0, 16, 0, + 2, 0, 0, 0, 15, 0, + 0, 7, 66, 0, 16, 0, + 7, 0, 0, 0, 134, 0, + 16, 0, 0, 0, 0, 0, + 134, 0, 16, 0, 0, 0, + 0, 0, 68, 0, 0, 5, + 66, 0, 16, 0, 7, 0, + 0, 0, 42, 0, 16, 0, + 7, 0, 0, 0, 56, 0, + 0, 7, 82, 0, 16, 0, + 0, 0, 0, 0, 6, 2, + 16, 0, 0, 0, 0, 0, + 166, 10, 16, 0, 7, 0, + 0, 0, 0, 0, 0, 7, + 66, 0, 16, 0, 7, 0, + 0, 0, 58, 0, 16, 0, + 1, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 128, 63, + 56, 0, 0, 8, 66, 0, + 16, 0, 7, 0, 0, 0, + 26, 0, 16, 128, 129, 0, + 0, 0, 3, 0, 0, 0, + 42, 0, 16, 0, 7, 0, + 0, 0, 54, 0, 0, 5, + 130, 0, 16, 0, 7, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 0, 0, 54, 0, + 0, 5, 18, 0, 16, 0, + 8, 0, 0, 0, 1, 64, + 0, 0, 9, 0, 0, 0, + 48, 0, 0, 1, 34, 0, + 0, 7, 34, 0, 16, 0, + 8, 0, 0, 0, 10, 0, + 16, 0, 8, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 0, 0, 3, 0, 4, 3, + 26, 0, 16, 0, 8, 0, + 0, 0, 43, 0, 0, 5, + 34, 0, 16, 0, 8, 0, + 0, 0, 10, 0, 16, 0, + 8, 0, 0, 0, 25, 0, + 0, 5, 34, 0, 16, 0, + 8, 0, 0, 0, 26, 0, + 16, 0, 8, 0, 0, 0, + 0, 0, 0, 7, 34, 0, + 16, 0, 8, 0, 0, 0, + 58, 0, 16, 0, 7, 0, + 0, 0, 26, 0, 16, 0, + 8, 0, 0, 0, 29, 0, + 0, 7, 66, 0, 16, 0, + 8, 0, 0, 0, 58, 0, + 16, 0, 2, 0, 0, 0, + 26, 0, 16, 0, 8, 0, + 0, 0, 50, 0, 0, 9, + 50, 0, 16, 0, 9, 0, + 0, 0, 86, 5, 16, 0, + 8, 0, 0, 0, 230, 10, + 16, 0, 5, 0, 0, 0, + 70, 0, 16, 0, 6, 0, + 0, 0, 50, 0, 0, 9, + 50, 0, 16, 0, 9, 0, + 0, 0, 86, 5, 16, 0, + 8, 0, 0, 0, 70, 0, + 16, 0, 9, 0, 0, 0, + 70, 0, 16, 0, 7, 0, + 0, 0, 15, 0, 0, 7, + 130, 0, 16, 0, 8, 0, + 0, 0, 70, 0, 16, 0, + 9, 0, 0, 0, 70, 0, + 16, 0, 9, 0, 0, 0, + 68, 0, 0, 5, 130, 0, + 16, 0, 8, 0, 0, 0, + 58, 0, 16, 0, 8, 0, + 0, 0, 56, 0, 0, 7, + 50, 0, 16, 0, 9, 0, + 0, 0, 246, 15, 16, 0, + 8, 0, 0, 0, 70, 0, + 16, 0, 9, 0, 0, 0, + 15, 0, 0, 7, 130, 0, + 16, 0, 8, 0, 0, 0, + 70, 0, 16, 0, 9, 0, + 0, 0, 134, 0, 16, 0, + 0, 0, 0, 0, 50, 0, + 0, 10, 18, 0, 16, 0, + 9, 0, 0, 0, 26, 0, + 16, 0, 8, 0, 0, 0, + 26, 0, 16, 128, 193, 0, + 0, 0, 3, 0, 0, 0, + 42, 0, 16, 0, 7, 0, + 0, 0, 51, 0, 0, 7, + 18, 0, 16, 0, 9, 0, + 0, 0, 10, 0, 16, 0, + 9, 0, 0, 0, 1, 64, + 0, 0, 219, 15, 73, 64, + 77, 0, 0, 6, 0, 208, + 0, 0, 18, 0, 16, 0, + 9, 0, 0, 0, 10, 0, + 16, 0, 9, 0, 0, 0, + 29, 0, 0, 7, 130, 0, + 16, 0, 8, 0, 0, 0, + 58, 0, 16, 0, 8, 0, + 0, 0, 10, 0, 16, 0, + 9, 0, 0, 0, 55, 0, + 0, 9, 34, 0, 16, 0, + 8, 0, 0, 0, 58, 0, + 16, 0, 8, 0, 0, 0, + 26, 0, 16, 0, 8, 0, + 0, 0, 58, 0, 16, 0, + 7, 0, 0, 0, 55, 0, + 0, 9, 130, 0, 16, 0, + 7, 0, 0, 0, 42, 0, + 16, 0, 8, 0, 0, 0, + 26, 0, 16, 0, 8, 0, + 0, 0, 58, 0, 16, 0, + 7, 0, 0, 0, 30, 0, + 0, 7, 18, 0, 16, 0, + 8, 0, 0, 0, 10, 0, + 16, 0, 8, 0, 0, 0, + 1, 64, 0, 0, 255, 255, + 255, 255, 22, 0, 0, 1, + 14, 0, 0, 7, 130, 0, + 16, 0, 2, 0, 0, 0, + 58, 0, 16, 0, 7, 0, + 0, 0, 10, 0, 16, 0, + 3, 0, 0, 0, 0, 0, + 0, 8, 18, 0, 16, 0, + 6, 0, 0, 0, 58, 0, + 16, 0, 1, 0, 0, 0, + 58, 0, 16, 128, 65, 0, + 0, 0, 7, 0, 0, 0, + 52, 0, 0, 7, 18, 0, + 16, 0, 0, 0, 0, 0, + 10, 0, 16, 0, 0, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 128, 191, 51, 0, + 0, 7, 18, 0, 16, 0, + 0, 0, 0, 0, 10, 0, + 16, 0, 0, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 128, 63, 0, 0, 0, 8, + 34, 0, 16, 0, 6, 0, + 0, 0, 10, 0, 16, 128, + 193, 0, 0, 0, 0, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 128, 63, 75, 0, + 0, 5, 34, 0, 16, 0, + 6, 0, 0, 0, 26, 0, + 16, 0, 6, 0, 0, 0, + 50, 0, 0, 10, 18, 0, + 16, 0, 7, 0, 0, 0, + 10, 0, 16, 128, 129, 0, + 0, 0, 0, 0, 0, 0, + 1, 64, 0, 0, 48, 110, + 153, 188, 1, 64, 0, 0, + 39, 22, 152, 61, 50, 0, + 0, 10, 18, 0, 16, 0, + 7, 0, 0, 0, 10, 0, + 16, 0, 7, 0, 0, 0, + 10, 0, 16, 128, 129, 0, + 0, 0, 0, 0, 0, 0, + 1, 64, 0, 0, 132, 52, + 89, 190, 50, 0, 0, 10, + 18, 0, 16, 0, 7, 0, + 0, 0, 10, 0, 16, 0, + 7, 0, 0, 0, 10, 0, + 16, 128, 129, 0, 0, 0, + 0, 0, 0, 0, 1, 64, + 0, 0, 164, 13, 201, 63, + 56, 0, 0, 7, 34, 0, + 16, 0, 7, 0, 0, 0, + 26, 0, 16, 0, 6, 0, + 0, 0, 10, 0, 16, 0, + 7, 0, 0, 0, 50, 0, + 0, 9, 34, 0, 16, 0, + 7, 0, 0, 0, 26, 0, + 16, 0, 7, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 0, 192, 1, 64, 0, 0, + 219, 15, 73, 64, 49, 0, + 0, 8, 18, 0, 16, 0, + 0, 0, 0, 0, 10, 0, + 16, 0, 0, 0, 0, 0, + 10, 0, 16, 128, 65, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 7, 18, 0, + 16, 0, 0, 0, 0, 0, + 10, 0, 16, 0, 0, 0, + 0, 0, 26, 0, 16, 0, + 7, 0, 0, 0, 50, 0, + 0, 9, 18, 0, 16, 0, + 0, 0, 0, 0, 10, 0, + 16, 0, 7, 0, 0, 0, + 26, 0, 16, 0, 6, 0, + 0, 0, 10, 0, 16, 0, + 0, 0, 0, 0, 29, 0, + 0, 7, 66, 0, 16, 0, + 0, 0, 0, 0, 42, 0, + 16, 0, 0, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 0, 0, 55, 0, 0, 10, + 18, 0, 16, 0, 0, 0, + 0, 0, 42, 0, 16, 0, + 0, 0, 0, 0, 10, 0, + 16, 0, 0, 0, 0, 0, + 10, 0, 16, 128, 65, 0, + 0, 0, 0, 0, 0, 0, + 50, 0, 0, 9, 130, 0, + 16, 0, 0, 0, 0, 0, + 10, 0, 16, 0, 6, 0, + 0, 0, 26, 0, 16, 0, + 3, 0, 0, 0, 10, 0, + 16, 0, 0, 0, 0, 0, + 77, 0, 0, 7, 18, 0, + 16, 0, 7, 0, 0, 0, + 18, 0, 16, 0, 0, 0, + 0, 0, 58, 0, 16, 0, + 0, 0, 0, 0, 54, 0, + 0, 6, 34, 0, 16, 0, + 7, 0, 0, 0, 10, 0, + 16, 128, 65, 0, 0, 0, + 0, 0, 0, 0, 15, 0, + 0, 7, 66, 0, 16, 0, + 8, 0, 0, 0, 70, 0, + 16, 0, 7, 0, 0, 0, + 230, 10, 16, 0, 5, 0, + 0, 0, 15, 0, 0, 7, + 18, 0, 16, 0, 0, 0, + 0, 0, 70, 0, 16, 0, + 7, 0, 0, 0, 230, 10, + 16, 0, 6, 0, 0, 0, + 15, 0, 0, 7, 18, 0, + 16, 0, 8, 0, 0, 0, + 70, 0, 16, 0, 7, 0, + 0, 0, 198, 0, 16, 0, + 4, 0, 0, 0, 56, 0, + 0, 7, 66, 0, 16, 0, + 0, 0, 0, 0, 10, 0, + 16, 0, 8, 0, 0, 0, + 42, 0, 16, 0, 8, 0, + 0, 0, 50, 0, 0, 10, + 66, 0, 16, 0, 0, 0, + 0, 0, 10, 0, 16, 0, + 0, 0, 0, 0, 10, 0, + 16, 0, 0, 0, 0, 0, + 42, 0, 16, 128, 65, 0, + 0, 0, 0, 0, 0, 0, + 52, 0, 0, 7, 66, 0, + 16, 0, 0, 0, 0, 0, + 42, 0, 16, 0, 0, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 0, 0, 75, 0, + 0, 5, 66, 0, 16, 0, + 0, 0, 0, 0, 42, 0, + 16, 0, 0, 0, 0, 0, + 49, 0, 0, 7, 18, 0, + 16, 0, 4, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 0, 0, 10, 0, 16, 0, + 0, 0, 0, 0, 55, 0, + 0, 10, 66, 0, 16, 0, + 0, 0, 0, 0, 10, 0, + 16, 0, 4, 0, 0, 0, + 42, 0, 16, 128, 65, 0, + 0, 0, 0, 0, 0, 0, + 42, 0, 16, 0, 0, 0, + 0, 0, 0, 0, 0, 8, + 34, 0, 16, 0, 8, 0, + 0, 0, 10, 0, 16, 128, + 65, 0, 0, 0, 0, 0, + 0, 0, 42, 0, 16, 0, + 0, 0, 0, 0, 56, 0, + 0, 7, 18, 0, 16, 0, + 0, 0, 0, 0, 26, 0, + 16, 0, 8, 0, 0, 0, + 42, 0, 16, 0, 8, 0, + 0, 0, 56, 0, 0, 7, + 18, 0, 16, 0, 0, 0, + 0, 0, 10, 0, 16, 0, + 0, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 0, 191, + 50, 0, 0, 9, 66, 0, + 16, 0, 0, 0, 0, 0, + 26, 0, 16, 0, 8, 0, + 0, 0, 26, 0, 16, 0, + 8, 0, 0, 0, 10, 0, + 16, 0, 0, 0, 0, 0, + 50, 0, 0, 9, 18, 0, + 16, 0, 0, 0, 0, 0, + 42, 0, 16, 0, 8, 0, + 0, 0, 10, 0, 16, 0, + 8, 0, 0, 0, 10, 0, + 16, 0, 0, 0, 0, 0, + 49, 0, 0, 9, 18, 0, + 16, 0, 0, 0, 0, 0, + 42, 0, 16, 128, 129, 0, + 0, 0, 0, 0, 0, 0, + 10, 0, 16, 128, 129, 0, + 0, 0, 0, 0, 0, 0, + 55, 0, 0, 9, 82, 0, + 16, 0, 0, 0, 0, 0, + 6, 0, 16, 0, 0, 0, + 0, 0, 86, 6, 16, 0, + 8, 0, 0, 0, 6, 1, + 16, 0, 8, 0, 0, 0, + 57, 0, 0, 7, 18, 0, + 16, 0, 4, 0, 0, 0, + 42, 0, 16, 0, 0, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 0, 0, 14, 0, + 0, 7, 18, 0, 16, 0, + 0, 0, 0, 0, 10, 0, + 16, 0, 0, 0, 0, 0, + 42, 0, 16, 0, 0, 0, + 0, 0, 1, 0, 0, 7, + 18, 0, 16, 0, 0, 0, + 0, 0, 10, 0, 16, 0, + 0, 0, 0, 0, 10, 0, + 16, 0, 4, 0, 0, 0, + 54, 32, 0, 5, 18, 0, + 16, 0, 0, 0, 0, 0, + 10, 0, 16, 0, 0, 0, + 0, 0, 24, 0, 0, 7, + 66, 0, 16, 0, 0, 0, + 0, 0, 10, 0, 16, 0, + 6, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 0, 0, + 55, 0, 0, 9, 34, 0, + 16, 0, 5, 0, 0, 0, + 42, 0, 16, 0, 0, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 0, 0, 10, 0, + 16, 0, 0, 0, 0, 0, + 52, 0, 0, 7, 18, 0, + 16, 0, 5, 0, 0, 0, + 58, 0, 16, 0, 2, 0, + 0, 0, 26, 0, 16, 0, + 5, 0, 0, 0, 21, 0, + 0, 1, 0, 0, 0, 8, + 82, 0, 16, 0, 0, 0, + 0, 0, 86, 6, 16, 128, + 65, 0, 0, 0, 4, 0, + 0, 0, 6, 2, 16, 0, + 2, 0, 0, 0, 50, 0, + 0, 9, 82, 0, 16, 0, + 0, 0, 0, 0, 6, 2, + 16, 0, 0, 0, 0, 0, + 6, 0, 16, 0, 5, 0, + 0, 0, 86, 6, 16, 0, + 4, 0, 0, 0, 0, 0, + 0, 8, 50, 0, 16, 0, + 4, 0, 0, 0, 70, 0, + 16, 0, 1, 0, 0, 0, + 134, 0, 16, 128, 65, 0, + 0, 0, 2, 0, 0, 0, + 50, 0, 0, 9, 82, 0, + 16, 0, 2, 0, 0, 0, + 6, 1, 16, 0, 4, 0, + 0, 0, 6, 0, 16, 0, + 5, 0, 0, 0, 6, 2, + 16, 0, 2, 0, 0, 0, + 0, 0, 0, 8, 50, 0, + 16, 0, 4, 0, 0, 0, + 70, 0, 16, 128, 65, 0, + 0, 0, 1, 0, 0, 0, + 230, 26, 16, 0, 1, 0, + 0, 0, 50, 0, 0, 9, + 50, 0, 16, 0, 1, 0, + 0, 0, 70, 0, 16, 0, + 4, 0, 0, 0, 6, 0, + 16, 0, 5, 0, 0, 0, + 70, 0, 16, 0, 1, 0, + 0, 0, 0, 0, 0, 8, + 50, 0, 16, 0, 4, 0, + 0, 0, 134, 0, 16, 128, + 65, 0, 0, 0, 0, 0, + 0, 0, 134, 0, 16, 0, + 2, 0, 0, 0, 50, 0, + 0, 9, 82, 0, 16, 0, + 0, 0, 0, 0, 6, 1, + 16, 0, 4, 0, 0, 0, + 6, 0, 16, 0, 5, 0, + 0, 0, 6, 2, 16, 0, + 0, 0, 0, 0, 0, 0, + 0, 8, 50, 0, 16, 0, + 1, 0, 0, 0, 134, 0, + 16, 128, 65, 0, 0, 0, + 2, 0, 0, 0, 70, 0, + 16, 0, 1, 0, 0, 0, + 50, 0, 0, 9, 50, 0, + 16, 0, 1, 0, 0, 0, + 70, 0, 16, 0, 1, 0, + 0, 0, 6, 0, 16, 0, + 5, 0, 0, 0, 134, 0, + 16, 0, 2, 0, 0, 0, + 0, 0, 0, 8, 50, 0, + 16, 0, 1, 0, 0, 0, + 134, 0, 16, 128, 65, 0, + 0, 0, 0, 0, 0, 0, + 70, 0, 16, 0, 1, 0, + 0, 0, 50, 0, 0, 9, + 50, 0, 16, 0, 3, 0, + 0, 0, 70, 0, 16, 0, + 1, 0, 0, 0, 6, 0, + 16, 0, 5, 0, 0, 0, + 134, 0, 16, 0, 0, 0, + 0, 0, 57, 0, 0, 7, + 18, 0, 16, 0, 0, 0, + 0, 0, 26, 0, 16, 0, + 5, 0, 0, 0, 10, 0, + 16, 0, 5, 0, 0, 0, + 15, 0, 0, 7, 66, 0, + 16, 0, 0, 0, 0, 0, + 70, 0, 16, 0, 1, 0, + 0, 0, 70, 0, 16, 0, + 1, 0, 0, 0, 68, 0, + 0, 5, 66, 0, 16, 0, + 0, 0, 0, 0, 42, 0, + 16, 0, 0, 0, 0, 0, + 56, 0, 0, 7, 50, 0, + 16, 0, 1, 0, 0, 0, + 166, 10, 16, 0, 0, 0, + 0, 0, 70, 0, 16, 0, + 1, 0, 0, 0, 52, 0, + 0, 7, 66, 0, 16, 0, + 0, 0, 0, 0, 10, 0, + 16, 0, 1, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 128, 191, 51, 0, 0, 7, + 66, 0, 16, 0, 0, 0, + 0, 0, 42, 0, 16, 0, + 0, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 128, 63, + 0, 0, 0, 8, 18, 0, + 16, 0, 1, 0, 0, 0, + 42, 0, 16, 128, 193, 0, + 0, 0, 0, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 128, 63, 75, 0, 0, 5, + 18, 0, 16, 0, 1, 0, + 0, 0, 10, 0, 16, 0, + 1, 0, 0, 0, 50, 0, + 0, 10, 18, 0, 16, 0, + 2, 0, 0, 0, 42, 0, + 16, 128, 129, 0, 0, 0, + 0, 0, 0, 0, 1, 64, + 0, 0, 48, 110, 153, 188, + 1, 64, 0, 0, 39, 22, + 152, 61, 50, 0, 0, 10, + 18, 0, 16, 0, 2, 0, + 0, 0, 10, 0, 16, 0, + 2, 0, 0, 0, 42, 0, + 16, 128, 129, 0, 0, 0, + 0, 0, 0, 0, 1, 64, + 0, 0, 132, 52, 89, 190, + 50, 0, 0, 10, 18, 0, + 16, 0, 2, 0, 0, 0, + 10, 0, 16, 0, 2, 0, + 0, 0, 42, 0, 16, 128, + 129, 0, 0, 0, 0, 0, + 0, 0, 1, 64, 0, 0, + 164, 13, 201, 63, 56, 0, + 0, 7, 66, 0, 16, 0, + 2, 0, 0, 0, 10, 0, + 16, 0, 1, 0, 0, 0, + 10, 0, 16, 0, 2, 0, + 0, 0, 50, 0, 0, 9, + 66, 0, 16, 0, 2, 0, + 0, 0, 42, 0, 16, 0, + 2, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 0, 192, + 1, 64, 0, 0, 219, 15, + 73, 64, 49, 0, 0, 8, + 66, 0, 16, 0, 0, 0, + 0, 0, 42, 0, 16, 0, + 0, 0, 0, 0, 42, 0, + 16, 128, 65, 0, 0, 0, + 0, 0, 0, 0, 1, 0, + 0, 7, 66, 0, 16, 0, + 0, 0, 0, 0, 42, 0, + 16, 0, 0, 0, 0, 0, + 42, 0, 16, 0, 2, 0, + 0, 0, 50, 0, 0, 9, + 66, 0, 16, 0, 0, 0, + 0, 0, 10, 0, 16, 0, + 2, 0, 0, 0, 10, 0, + 16, 0, 1, 0, 0, 0, + 42, 0, 16, 0, 0, 0, + 0, 0, 29, 0, 0, 7, + 18, 0, 16, 0, 1, 0, + 0, 0, 26, 0, 16, 0, + 1, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 0, 0, + 55, 0, 0, 10, 66, 0, + 16, 0, 0, 0, 0, 0, + 10, 0, 16, 0, 1, 0, + 0, 0, 42, 0, 16, 0, + 0, 0, 0, 0, 42, 0, + 16, 128, 65, 0, 0, 0, + 0, 0, 0, 0, 55, 0, + 0, 9, 34, 0, 16, 0, + 0, 0, 0, 0, 10, 0, + 16, 0, 0, 0, 0, 0, + 42, 0, 16, 0, 0, 0, + 0, 0, 58, 0, 16, 0, + 0, 0, 0, 0, 21, 0, + 0, 1, 21, 0, 0, 1, + 32, 0, 0, 7, 18, 0, + 16, 0, 0, 0, 0, 0, + 26, 0, 16, 0, 2, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 0, 4, 28, 0, + 0, 5, 194, 0, 16, 0, + 0, 0, 0, 0, 166, 14, + 16, 0, 1, 0, 0, 0, + 41, 0, 0, 7, 66, 0, + 16, 0, 0, 0, 0, 0, + 42, 0, 16, 0, 0, 0, + 0, 0, 1, 64, 0, 0, + 16, 0, 0, 0, 60, 0, + 0, 7, 66, 0, 16, 0, + 0, 0, 0, 0, 58, 0, + 16, 0, 0, 0, 0, 0, + 42, 0, 16, 0, 0, 0, + 0, 0, 56, 0, 0, 7, + 34, 0, 16, 0, 0, 0, + 0, 0, 26, 0, 16, 0, + 0, 0, 0, 0, 1, 64, + 0, 0, 131, 249, 34, 62, + 29, 0, 0, 8, 130, 0, + 16, 0, 0, 0, 0, 0, + 26, 0, 16, 0, 0, 0, + 0, 0, 26, 0, 16, 128, + 65, 0, 0, 0, 0, 0, + 0, 0, 26, 0, 0, 6, + 34, 0, 16, 0, 0, 0, + 0, 0, 26, 0, 16, 128, + 129, 0, 0, 0, 0, 0, + 0, 0, 55, 0, 0, 10, + 34, 0, 16, 0, 0, 0, + 0, 0, 58, 0, 16, 0, + 0, 0, 0, 0, 26, 0, + 16, 0, 0, 0, 0, 0, + 26, 0, 16, 128, 65, 0, + 0, 0, 0, 0, 0, 0, + 56, 0, 0, 7, 34, 0, + 16, 0, 0, 0, 0, 0, + 26, 0, 16, 0, 0, 0, + 0, 0, 1, 64, 0, 0, + 219, 15, 201, 64, 55, 0, + 0, 9, 66, 0, 16, 0, + 3, 0, 0, 0, 10, 0, + 16, 0, 0, 0, 0, 0, + 42, 0, 16, 0, 0, 0, + 0, 0, 26, 0, 16, 0, + 0, 0, 0, 0, 54, 0, + 0, 5, 242, 32, 16, 0, + 0, 0, 0, 0, 70, 14, + 16, 0, 3, 0, 0, 0, + 62, 0, 0, 1, 83, 84, + 65, 84, 148, 0, 0, 0, + 220, 0, 0, 0, 10, 0, + 0, 0, 0, 0, 0, 0, + 6, 0, 0, 0, 130, 0, + 0, 0, 6, 0, 0, 0, + 22, 0, 0, 0, 4, 0, + 0, 0, 4, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 15, 0, + 0, 0, 28, 0, 0, 0, + 7, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0 +}; diff --git a/third_party/rive_renderer/source/generated/shaders/d3d/tessellate.vert.h b/third_party/rive_renderer/source/generated/shaders/d3d/tessellate.vert.h new file mode 100644 index 0000000..0bc8d08 --- /dev/null +++ b/third_party/rive_renderer/source/generated/shaders/d3d/tessellate.vert.h @@ -0,0 +1,2369 @@ +#if 0 +// +// Generated by Microsoft (R) HLSL Shader Compiler 10.1 +// +// +// Buffer Definitions: +// +// cbuffer VB +// { +// +// struct +// { +// +// float sa; // Offset: 0 +// float Fa; // Offset: 4 +// float bd; // Offset: 8 +// float cd; // Offset: 12 +// uint Ga; // Offset: 16 +// uint id; // Offset: 20 +// uint Oc; // Offset: 24 +// uint Pc; // Offset: 28 +// int4 J6; // Offset: 32 +// float2 U4; // Offset: 48 +// float2 Ha; // Offset: 56 +// uint Z2; // Offset: 64 +// uint d5; // Offset: 68 +// float C1; // Offset: 72 +// uint jd; // Offset: 76 +// +// } q; // Offset: 0 Size: 80 +// +// } +// +// Resource bind info for JB +// { +// +// uint4 $Element; // Offset: 0 Size: 16 +// +// } +// +// Resource bind info for QC +// { +// +// uint4 $Element; // Offset: 0 Size: 16 +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim HLSL Bind Count +// ------------------------------ ---------- ------- ----------- -------------- ------ +// M8 sampler NA NA s10 1 +// JB texture struct r/o t3 1 +// QC texture struct r/o t6 1 +// JC texture float 1darray t10 1 +// VB cbuffer NA NA cb0 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------- ------ +// RC 0 xyzw 0 NONE float xyzw +// SC 0 xyzw 1 NONE float xyzw +// GC 0 xyzw 2 NONE float xyzw +// RB 0 xyzw 3 NONE uint xyzw +// SV_VertexID 0 x 4 VERTID uint x +// SV_InstanceID 0 x 5 INSTID uint +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------- ------ +// TEXCOORD 0 xyzw 0 NONE float xyzw +// TEXCOORD 1 xyzw 1 NONE float xyzw +// TEXCOORD 2 xyzw 2 NONE float xyzw +// TEXCOORD 3 xyz 3 NONE float xyz +// TEXCOORD 4 x 4 NONE uint x +// SV_Position 0 xyzw 5 POS float xyzw +// +vs_5_0 +dcl_globalFlags refactoringAllowed +dcl_constantbuffer CB0[1], immediateIndexed +dcl_sampler s10, mode_default +dcl_resource_structured t3, 16 +dcl_resource_structured t6, 16 +dcl_resource_texture1darray (float,float,float,float) t10 +dcl_input v0.xyzw +dcl_input v1.xyzw +dcl_input v2.xyzw +dcl_input v3.xyzw +dcl_input_sgv v4.x, vertex_id +dcl_output o0.xyzw +dcl_output o1.xyzw +dcl_output o2.xyzw +dcl_output o3.xyz +dcl_output o4.x +dcl_output_siv o5.xyzw, position +dcl_temps 10 +ult r0.x, v4.x, l(4) +movc r0.y, r0.x, v2.z, v2.w +movc r0.x, r0.x, v3.x, v3.y +ibfe r0.z, l(16), l(0), r0.x +ishr r0.x, r0.x, l(16) +itof r0.xz, r0.xxzx +and r1.xy, v4.xxxx, l(1, 2, 0, 0) +movc r0.w, r1.x, r0.x, r0.z +add r1.x, r0.y, l(1.000000) +movc r1.x, r1.y, r0.y, r1.x +add r1.y, -r0.z, r0.x +mul r1.y, r1.y, cb0[0].y +lt r1.y, r1.y, l(0.000000) +mad r0.y, r0.y, l(2.000000), l(1.000000) +add r0.y, -r1.x, r0.y +movc r0.y, r1.y, r0.y, r1.x +ubfe r1.x, l(10), l(10), v3.z +ushr r1.y, v3.z, l(20) +and r2.xyzw, v3.zwww, l(1023, 0x0000ffff, 0x20000000, 0x1e000000) +iadd r1.z, r2.y, l(-1) +ld_structured_indexable(structured_buffer, stride=16)(mixed,mixed,mixed,mixed) r1.z, r1.z, l(8), t6.xxxx +movc r1.z, v3.w, r1.z, l(0) +ishl r1.w, r1.z, l(2) +bfi r2.y, l(30), l(2), r1.z, l(1) +ld_structured_indexable(structured_buffer, stride=16)(mixed,mixed,mixed,mixed) r3.xy, r2.y, l(8), t3.xyxx +movc r3.xy, r1.zzzz, r3.xyxx, l(0,0,0,0) +ne r1.z, r3.y, l(0.000000) +eq r2.y, r3.x, l(0.000000) +and r1.z, r1.z, r2.y +if_nz r1.z + add r4.xyzw, -v0.xyzw, v1.zwxy + dp2 r1.z, r4.xyxx, r4.xyxx + sqrt r2.y, r1.z + ne r3.x, r2.y, l(0.000000) + if_nz r3.x + mul r3.xz, r4.yyxy, l(-1.000000, 0.000000, 1.000000, 0.000000) + div r3.xz, r3.xxzx, r2.yyyy + add r5.xy, -v0.xyxx, v1.xyxx + dp2 r2.y, r3.xzxx, r5.xyxx + add r5.xy, -v0.xyxx, v0.zwzz + dp2 r3.x, r3.xzxx, r5.xyxx + add r2.y, -r2.y, r3.x + mul r3.z, r2.y, l(3.000000) + add r2.y, -r2.y, -r3.x + mov r3.w, l(0.500000) + mov r5.x, l(0) + loop + ige r5.y, r5.x, l(3) + breakc_nz r5.y + mul r5.y, r3.w, r3.z + mad r5.y, r5.y, r3.w, -r3.x + mad r5.z, r3.z, r3.w, r2.y + add r5.w, r5.z, r5.z + lt r5.z, r5.z, l(0.000000) + movc r5.y, r5.z, -r5.y, r5.y + lt r5.z, l(0.000000), r5.y + lt r6.x, r5.y, |r5.w| + div r5.y, r5.y, |r5.w| + movc r5.y, r6.x, r5.y, l(1.000000) + and r3.w, r5.y, r5.z + iadd r5.x, r5.x, l(1) + endloop + mul r2.y, r2.y, l(3.000000) + mad r2.y, r3.w, r3.z, r2.y + mul r3.x, r3.x, l(3.000000) + mad r2.y, r3.w, r2.y, r3.x + mul r2.y, r2.y, r3.w + mov r2.y, |r2.y| + else + mov r3.w, l(0.500000) + mov r2.y, l(0) + endif + mul r3.x, r3.y, l(0.333333) + add r5.xyzw, -v0.xyxy, v0.zwzw + add r6.xy, r4.zwzz, -r5.zwzz + mad r7.xyzw, r4.zwzw, l(-3.000000, -3.000000, -3.000000, -3.000000), r4.xyxy + add r8.xyzw, r6.xyxy, r6.xyxy + mad r4.zw, r7.zzzw, r3.wwww, r8.xxxy + mad r4.zw, r4.zzzw, r3.wwww, r5.xxxy + mul r4.zw, r4.zzzw, l(0.000000, 0.000000, 3.000000, 3.000000) + dp2 r3.z, r4.zwzz, r4.zwzz + sqrt r3.z, r3.z + ne r6.z, r3.z, l(0.000000) + if_nz r6.z + div r3.z, l(1.000000, 1.000000, 1.000000, 1.000000), r3.z + mul r4.zw, r3.zzzz, r4.zzzw + dp2 r3.z, r7.zwzz, r4.zwzz + add r6.z, r3.z, r3.z + dp2 r6.x, r6.xyxx, r4.zwzz + mul r6.x, r6.x, l(4.000000) + mad r6.x, r6.z, r3.w, r6.x + mul r6.x, r3.w, r6.x + dp2 r4.z, r5.zwzz, r4.zwzz + mul r4.z, r4.z, l(6.000000) + mad r4.z, r6.x, l(3.000000), r4.z + add r4.w, -r3.w, l(1.000000) + min r4.w, r3.w, r4.w + mul r6.x, r4.w, r4.w + mad r6.x, r6.x, r6.z, r4.z + mul r4.w, r4.w, r6.x + mul r4.w, r4.w, l(0.999900) + min r4.w, r3.x, r4.w + eq r3.z, r3.z, l(0.000000) + if_nz r3.z + div r3.z, r4.w, r4.z + else + div r6.x, l(1.000000, 1.000000, 1.000000, 1.000000), r6.z + mul r4.z, r4.z, r6.x + mul r4.w, -r4.w, r6.x + mul r4.z, r4.z, l(-0.333333) + mul r6.x, r4.w, l(0.500000) + mul r6.y, r4.z, r4.z + mul r6.y, r4.z, r6.y + mad r6.y, r6.x, r6.x, -r6.y + lt r6.z, r6.y, l(0.000000) + sqrt r6.w, r4.z + mul r9.x, r6.w, r6.w + mul r9.x, r6.w, r9.x + div r9.x, r6.x, r9.x + add r9.y, -|r9.x|, l(1.000000) + sqrt r9.y, r9.y + mad r9.z, |r9.x|, l(-0.018729), l(0.074261) + mad r9.z, r9.z, |r9.x|, l(-0.212114) + mad r9.z, r9.z, |r9.x|, l(1.570729) + mul r9.w, r9.y, r9.z + mad r9.w, r9.w, l(-2.000000), l(3.141593) + lt r9.x, r9.x, -r9.x + and r9.x, r9.x, r9.w + mad r9.x, r9.z, r9.y, r9.x + mul r6.w, r6.w, l(-2.000000) + mad r9.x, r9.x, l(0.333333), l(-2.094395) + sincos null, r9.x, r9.x + mul r6.w, r6.w, r9.x + sqrt r6.y, r6.y + add r6.x, r6.y, |r6.x| + log r6.x, r6.x + mul r6.x, r6.x, l(0.333333) + exp r6.x, r6.x + lt r4.w, r4.w, l(0.000000) + movc r4.w, r4.w, -r6.x, r6.x + ne r6.x, r4.w, l(0.000000) + div r4.z, r4.z, r4.w + add r4.z, r4.z, r4.w + and r4.z, r4.z, r6.x + movc r3.z, r6.z, r6.w, r4.z + endif + mov r6.zw, |r3.zzzz| + mov r6.xy, -r6.wwww + add r6.xyzw, r3.wwww, r6.xyzw + mad r7.xyzw, r7.xyzw, r6.xyzw, r8.xyzw + mad r5.xyzw, r7.xyzw, r6.xyzw, r5.xyzw + ne r3.zw, v0.zzzw, v0.xxxy + or r3.z, r3.w, r3.z + ne r4.zw, v0.zzzw, v1.xxxy + or r3.w, r4.w, r4.z + movc r4.zw, r3.wwww, v1.xxxy, v1.zzzw + movc r4.zw, r3.zzzz, v0.zzzw, r4.zzzw + add r4.zw, r4.zzzw, -v0.xxxy + ne r6.xz, v1.xxyx, v1.zzwz + or r3.z, r6.z, r6.x + movc r6.xz, r3.wwww, v0.zzwz, v0.xxyx + movc r3.zw, r3.zzzz, v1.xxxy, r6.xxxz + add r3.zw, -r3.zzzw, v1.zzzw + lt r6.x, r6.y, l(0.001000) + movc r4.zw, r6.xxxx, r4.zzzw, r5.xxxy + lt r5.x, l(0.999000), r6.w + movc r3.zw, r5.xxxx, r3.zzzw, r5.zzzw + dp2 r5.x, r4.zwzz, r3.zwzz + dp2 r4.z, r4.zwzz, r4.zwzz + dp2 r3.z, r3.zwzz, r3.zwzz + mul r3.z, r3.z, r4.z + eq r3.w, r3.z, l(0.000000) + rsq r3.z, r3.z + mul r3.z, r3.z, r5.x + max r3.z, r3.z, l(-1.000000) + min r3.z, r3.z, l(1.000000) + movc r3.z, r3.w, l(1.000000), r3.z + add r3.w, -|r3.z|, l(1.000000) + sqrt r3.w, r3.w + mad r4.z, |r3.z|, l(-0.018729), l(0.074261) + mad r4.z, r4.z, |r3.z|, l(-0.212114) + mad r4.z, r4.z, |r3.z|, l(1.570729) + mul r4.w, r3.w, r4.z + mad r4.w, r4.w, l(-2.000000), l(3.141593) + lt r3.z, r3.z, -r3.z + and r3.z, r3.z, r4.w + mad r3.z, r4.z, r3.w, r3.z + else + mov r3.z, l(0) + endif + mad r3.z, -r3.z, l(0.318310), l(1.000000) + mul r3.x, r3.x, r3.x + div r1.z, r1.z, r3.x + add r1.z, r1.z, l(-1.000000) + mul r1.z, r1.z, l(0.500000) + min r1.z, r1.z, r3.z + min r1.z, r1.z, l(0.990000) + mul r5.x, r1.z, l(0.500000) + mov r5.y, l(1.000000) + sample_l_indexable(texture1darray)(float,float,float,float) r1.z, r5.xyxx, t10.yzxw, s10, l(0.000000) + mad r1.z, r1.z, l(-2.000000), l(1.000000) + mul r1.z, r3.y, r1.z + lt r3.x, l(0.000000), r1.z + lt r3.y, r1.z, r2.y + div r1.z, r1.z, r2.y + movc r1.z, r3.y, r1.z, l(1.000000) + and r1.z, r1.z, r3.x + mad r3.xyzw, r4.xyxy, l(0.333333, 0.333333, 0.666667, 0.666667), v0.xyxy + add r3.xy, r3.xyxx, -v0.zwzz + mad r4.xy, r1.zzzz, r3.xyxx, v0.zwzz + add r3.xy, r3.zwzz, -v1.xyxx + mad r3.xy, r1.zzzz, r3.xyxx, v1.xyxx +else + mov r4.xy, v0.zwzz + mov r3.xy, v1.xyxx +endif +ld_structured_indexable(structured_buffer, stride=16)(mixed,mixed,mixed,mixed) r5.xyzw, r1.w, l(0), t3.xyzw +mad r1.zw, r4.xxxy, l(0.000000, 0.000000, -2.000000, -2.000000), r3.xxxy +add r1.zw, r1.zzzw, v0.xxxy +dp2 r6.x, r1.zwzz, r5.xzxx +dp2 r6.y, r1.zwzz, r5.ywyy +mad r1.zw, r3.xxxy, l(0.000000, 0.000000, -2.000000, -2.000000), v1.zzzw +add r1.zw, r4.xxxy, r1.zzzw +dp2 r7.x, r1.zwzz, r5.xzxx +dp2 r7.y, r1.zwzz, r5.ywyy +dp2 r1.z, r6.xyxx, r6.xyxx +dp2 r1.w, r7.xyxx, r7.xyxx +max r1.z, r1.w, r1.z +sqrt r1.z, r1.z +mul r1.z, r1.z, l(3.000000) +sqrt r1.z, r1.z +round_pi r1.z, r1.z +max r1.z, r1.z, l(1.000000) +ftou r1.z, r1.z +umin r1.z, r2.x, r1.z +movc r1.z, r2.z, r1.z, r2.x +iadd r1.w, r1.x, r1.z +iadd r1.w, r1.y, r1.w +iadd r1.w, r1.w, l(-1) +ne r2.xy, r4.xyxx, v0.xyxx +or r2.x, r2.y, r2.x +ne r2.yz, r3.xxyx, r4.xxyx +or r2.y, r2.z, r2.y +movc r5.xy, r2.yyyy, r3.xyxx, v1.zwzz +movc r2.xz, r2.xxxx, r4.xxyx, r5.xxyx +add r2.xz, r2.xxzx, -v0.xxyx +ne r5.xy, r3.xyxx, v1.zwzz +or r5.x, r5.y, r5.x +movc r5.yz, r2.yyyy, r4.xxyx, v0.xxyx +movc r5.xy, r5.xxxx, r3.xyxx, r5.yzyy +add r5.xy, -r5.xyxx, v1.zwzz +dp2 r2.y, r2.xzxx, r5.xyxx +dp2 r5.z, r2.xzxx, r2.xzxx +dp2 r5.w, r5.xyxx, r5.xyxx +mul r5.z, r5.w, r5.z +eq r6.x, r5.z, l(0.000000) +rsq r5.z, r5.z +mul r2.yz, r2.yyzy, r5.zzxz +max r2.y, r2.y, l(-1.000000) +min r2.y, r2.y, l(1.000000) +movc r2.y, r6.x, l(1.000000), r2.y +add r5.z, -|r2.y|, l(1.000000) +sqrt r5.z, r5.z +mad r6.x, |r2.y|, l(-0.018729), l(0.074261) +mad r6.x, r6.x, |r2.y|, l(-0.212114) +mad r6.x, r6.x, |r2.y|, l(1.570729) +mul r6.y, r5.z, r6.x +mad r6.y, r6.y, l(-2.000000), l(3.141593) +lt r2.y, r2.y, -r2.y +and r2.y, r2.y, r6.y +mad r2.y, r6.x, r5.z, r2.y +utof r1.x, r1.x +div r1.x, r2.y, r1.x +add r6.xy, r3.xyxx, -v0.xyxx +add r6.zw, -r4.yyyx, v1.wwwz +mul r2.y, r6.w, r6.y +mad r2.y, r6.x, r6.z, -r2.y +eq r5.z, r2.y, l(0.000000) +mad r2.x, r2.x, r5.y, -r2.z +movc r2.x, r5.z, r2.x, r2.y +lt r2.x, r2.x, l(0.000000) +movc o2.w, r2.x, -r1.x, r1.x +utof r1.x, r1.w +add r1.w, -r0.w, r0.x +add o2.x, -|r1.w|, r1.x +imad r1.z, r1.y, l(1024), r1.z +utof o2.z, r1.z +dp2 r1.z, r5.xyxx, v2.xyxx +dp2 r1.w, v2.xyxx, v2.xyxx +mul r1.w, r1.w, r5.w +eq r2.x, r1.w, l(0.000000) +rsq r1.w, r1.w +mul r1.z, r1.w, r1.z +max r1.z, r1.z, l(-1.000000) +min r1.z, r1.z, l(1.000000) +movc r1.z, r2.x, l(1.000000), r1.z +add r1.w, -|r1.z|, l(1.000000) +sqrt r1.w, r1.w +mad r2.x, |r1.z|, l(-0.018729), l(0.074261) +mad r2.x, r2.x, |r1.z|, l(-0.212114) +mad r2.x, r2.x, |r1.z|, l(1.570729) +mul r2.y, r1.w, r2.x +mad r2.y, r2.y, l(-2.000000), l(3.141593) +lt r1.z, r1.z, -r1.z +and r1.z, r1.z, r2.y +mad r1.z, r2.x, r1.w, r1.z +utof r1.y, r1.y +ieq r1.w, r2.w, l(0x0a000000) +add r2.x, r1.y, l(-2.000000) +movc r1.y, r1.w, r2.x, r1.y +div r1.y, r1.z, r1.y +mul r1.z, r5.y, v2.x +mad r1.z, r5.x, v2.y, -r1.z +lt r1.z, r1.z, l(0.000000) +movc o3.z, r1.z, -r1.y, r1.y +lt r0.x, r0.x, r0.z +or r0.z, v3.w, l(0x00800000) +movc o4.x, r0.x, r0.z, v3.w +mad o5.x, r0.w, l(0.000977), l(-1.000000) +lt r0.x, l(0.000000), cb0[0].y +lt r0.z, cb0[0].y, l(0.000000) +iadd r0.x, -r0.x, r0.z +itof r0.x, r0.x +mad o5.y, r0.y, cb0[0].y, -r0.x +mov r4.zw, v0.xxxy +mov o0.xyzw, r4.zwxy +mov r3.zw, v1.zzzw +mov o1.xyzw, r3.xyzw +mov o2.y, r1.x +mov o5.zw, l(0,0,0,1.000000) +mov o3.xy, v2.xyxx +ret +// Approximately 332 instruction slots used +#endif + +const BYTE g_main[] = +{ + 68, 88, 66, 67, 11, 244, + 197, 21, 189, 32, 150, 132, + 173, 16, 80, 177, 133, 110, + 217, 193, 1, 0, 0, 0, + 52, 45, 0, 0, 5, 0, + 0, 0, 52, 0, 0, 0, + 8, 4, 0, 0, 208, 4, + 0, 0, 136, 5, 0, 0, + 152, 44, 0, 0, 82, 68, + 69, 70, 204, 3, 0, 0, + 3, 0, 0, 0, 236, 0, + 0, 0, 5, 0, 0, 0, + 60, 0, 0, 0, 0, 5, + 254, 255, 0, 1, 0, 0, + 164, 3, 0, 0, 82, 68, + 49, 49, 60, 0, 0, 0, + 24, 0, 0, 0, 32, 0, + 0, 0, 40, 0, 0, 0, + 36, 0, 0, 0, 12, 0, + 0, 0, 0, 0, 0, 0, + 220, 0, 0, 0, 3, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 10, 0, 0, 0, + 1, 0, 0, 0, 1, 0, + 0, 0, 223, 0, 0, 0, + 5, 0, 0, 0, 6, 0, + 0, 0, 1, 0, 0, 0, + 16, 0, 0, 0, 3, 0, + 0, 0, 1, 0, 0, 0, + 1, 0, 0, 0, 226, 0, + 0, 0, 5, 0, 0, 0, + 6, 0, 0, 0, 1, 0, + 0, 0, 16, 0, 0, 0, + 6, 0, 0, 0, 1, 0, + 0, 0, 1, 0, 0, 0, + 229, 0, 0, 0, 2, 0, + 0, 0, 5, 0, 0, 0, + 3, 0, 0, 0, 255, 255, + 255, 255, 10, 0, 0, 0, + 1, 0, 0, 0, 1, 0, + 0, 0, 232, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 1, 0, 0, 0, 77, 56, + 0, 74, 66, 0, 81, 67, + 0, 74, 67, 0, 86, 66, + 0, 171, 232, 0, 0, 0, + 1, 0, 0, 0, 52, 1, + 0, 0, 80, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 223, 0, 0, 0, + 1, 0, 0, 0, 32, 3, + 0, 0, 16, 0, 0, 0, + 0, 0, 0, 0, 3, 0, + 0, 0, 226, 0, 0, 0, + 1, 0, 0, 0, 124, 3, + 0, 0, 16, 0, 0, 0, + 0, 0, 0, 0, 3, 0, + 0, 0, 92, 1, 0, 0, + 0, 0, 0, 0, 80, 0, + 0, 0, 2, 0, 0, 0, + 252, 2, 0, 0, 0, 0, + 0, 0, 255, 255, 255, 255, + 0, 0, 0, 0, 255, 255, + 255, 255, 0, 0, 0, 0, + 113, 0, 60, 117, 110, 110, + 97, 109, 101, 100, 62, 0, + 115, 97, 0, 102, 108, 111, + 97, 116, 0, 171, 171, 171, + 0, 0, 3, 0, 1, 0, + 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 107, 1, 0, 0, + 70, 97, 0, 98, 100, 0, + 99, 100, 0, 71, 97, 0, + 100, 119, 111, 114, 100, 0, + 171, 171, 0, 0, 19, 0, + 1, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 164, 1, + 0, 0, 105, 100, 0, 79, + 99, 0, 80, 99, 0, 74, + 54, 0, 105, 110, 116, 52, + 0, 171, 171, 171, 1, 0, + 2, 0, 1, 0, 4, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 220, 1, 0, 0, 85, 52, + 0, 102, 108, 111, 97, 116, + 50, 0, 171, 171, 1, 0, + 3, 0, 1, 0, 2, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 11, 2, 0, 0, 72, 97, + 0, 90, 50, 0, 100, 53, + 0, 67, 49, 0, 106, 100, + 0, 171, 104, 1, 0, 0, + 116, 1, 0, 0, 0, 0, + 0, 0, 152, 1, 0, 0, + 116, 1, 0, 0, 4, 0, + 0, 0, 155, 1, 0, 0, + 116, 1, 0, 0, 8, 0, + 0, 0, 158, 1, 0, 0, + 116, 1, 0, 0, 12, 0, + 0, 0, 161, 1, 0, 0, + 172, 1, 0, 0, 16, 0, + 0, 0, 208, 1, 0, 0, + 172, 1, 0, 0, 20, 0, + 0, 0, 211, 1, 0, 0, + 172, 1, 0, 0, 24, 0, + 0, 0, 214, 1, 0, 0, + 172, 1, 0, 0, 28, 0, + 0, 0, 217, 1, 0, 0, + 228, 1, 0, 0, 32, 0, + 0, 0, 8, 2, 0, 0, + 20, 2, 0, 0, 48, 0, + 0, 0, 56, 2, 0, 0, + 20, 2, 0, 0, 56, 0, + 0, 0, 59, 2, 0, 0, + 172, 1, 0, 0, 64, 0, + 0, 0, 62, 2, 0, 0, + 172, 1, 0, 0, 68, 0, + 0, 0, 65, 2, 0, 0, + 116, 1, 0, 0, 72, 0, + 0, 0, 68, 2, 0, 0, + 172, 1, 0, 0, 76, 0, + 0, 0, 5, 0, 0, 0, + 1, 0, 20, 0, 0, 0, + 15, 0, 72, 2, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 94, 1, + 0, 0, 72, 3, 0, 0, + 0, 0, 0, 0, 16, 0, + 0, 0, 2, 0, 0, 0, + 88, 3, 0, 0, 0, 0, + 0, 0, 255, 255, 255, 255, + 0, 0, 0, 0, 255, 255, + 255, 255, 0, 0, 0, 0, + 36, 69, 108, 101, 109, 101, + 110, 116, 0, 117, 105, 110, + 116, 52, 0, 171, 1, 0, + 19, 0, 1, 0, 4, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 81, 3, 0, 0, 72, 3, + 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 2, 0, + 0, 0, 88, 3, 0, 0, + 0, 0, 0, 0, 255, 255, + 255, 255, 0, 0, 0, 0, + 255, 255, 255, 255, 0, 0, + 0, 0, 77, 105, 99, 114, + 111, 115, 111, 102, 116, 32, + 40, 82, 41, 32, 72, 76, + 83, 76, 32, 83, 104, 97, + 100, 101, 114, 32, 67, 111, + 109, 112, 105, 108, 101, 114, + 32, 49, 48, 46, 49, 0, + 73, 83, 71, 78, 192, 0, + 0, 0, 6, 0, 0, 0, + 8, 0, 0, 0, 152, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3, 0, + 0, 0, 0, 0, 0, 0, + 15, 15, 0, 0, 155, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3, 0, + 0, 0, 1, 0, 0, 0, + 15, 15, 0, 0, 158, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3, 0, + 0, 0, 2, 0, 0, 0, + 15, 15, 0, 0, 161, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 3, 0, 0, 0, + 15, 15, 0, 0, 164, 0, + 0, 0, 0, 0, 0, 0, + 6, 0, 0, 0, 1, 0, + 0, 0, 4, 0, 0, 0, + 1, 1, 0, 0, 176, 0, + 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 1, 0, + 0, 0, 5, 0, 0, 0, + 1, 0, 0, 0, 82, 67, + 0, 83, 67, 0, 71, 67, + 0, 82, 66, 0, 83, 86, + 95, 86, 101, 114, 116, 101, + 120, 73, 68, 0, 83, 86, + 95, 73, 110, 115, 116, 97, + 110, 99, 101, 73, 68, 0, + 171, 171, 79, 83, 71, 78, + 176, 0, 0, 0, 6, 0, + 0, 0, 8, 0, 0, 0, + 152, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 3, 0, 0, 0, 0, 0, + 0, 0, 15, 0, 0, 0, + 152, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 3, 0, 0, 0, 1, 0, + 0, 0, 15, 0, 0, 0, + 152, 0, 0, 0, 2, 0, + 0, 0, 0, 0, 0, 0, + 3, 0, 0, 0, 2, 0, + 0, 0, 15, 0, 0, 0, + 152, 0, 0, 0, 3, 0, + 0, 0, 0, 0, 0, 0, + 3, 0, 0, 0, 3, 0, + 0, 0, 7, 8, 0, 0, + 152, 0, 0, 0, 4, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 4, 0, + 0, 0, 1, 14, 0, 0, + 161, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 3, 0, 0, 0, 5, 0, + 0, 0, 15, 0, 0, 0, + 84, 69, 88, 67, 79, 79, + 82, 68, 0, 83, 86, 95, + 80, 111, 115, 105, 116, 105, + 111, 110, 0, 171, 171, 171, + 83, 72, 69, 88, 8, 39, + 0, 0, 80, 0, 1, 0, + 194, 9, 0, 0, 106, 8, + 0, 1, 89, 0, 0, 4, + 70, 142, 32, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 90, 0, 0, 3, 0, 96, + 16, 0, 10, 0, 0, 0, + 162, 0, 0, 4, 0, 112, + 16, 0, 3, 0, 0, 0, + 16, 0, 0, 0, 162, 0, + 0, 4, 0, 112, 16, 0, + 6, 0, 0, 0, 16, 0, + 0, 0, 88, 56, 0, 4, + 0, 112, 16, 0, 10, 0, + 0, 0, 85, 85, 0, 0, + 95, 0, 0, 3, 242, 16, + 16, 0, 0, 0, 0, 0, + 95, 0, 0, 3, 242, 16, + 16, 0, 1, 0, 0, 0, + 95, 0, 0, 3, 242, 16, + 16, 0, 2, 0, 0, 0, + 95, 0, 0, 3, 242, 16, + 16, 0, 3, 0, 0, 0, + 96, 0, 0, 4, 18, 16, + 16, 0, 4, 0, 0, 0, + 6, 0, 0, 0, 101, 0, + 0, 3, 242, 32, 16, 0, + 0, 0, 0, 0, 101, 0, + 0, 3, 242, 32, 16, 0, + 1, 0, 0, 0, 101, 0, + 0, 3, 242, 32, 16, 0, + 2, 0, 0, 0, 101, 0, + 0, 3, 114, 32, 16, 0, + 3, 0, 0, 0, 101, 0, + 0, 3, 18, 32, 16, 0, + 4, 0, 0, 0, 103, 0, + 0, 4, 242, 32, 16, 0, + 5, 0, 0, 0, 1, 0, + 0, 0, 104, 0, 0, 2, + 10, 0, 0, 0, 79, 0, + 0, 7, 18, 0, 16, 0, + 0, 0, 0, 0, 10, 16, + 16, 0, 4, 0, 0, 0, + 1, 64, 0, 0, 4, 0, + 0, 0, 55, 0, 0, 9, + 34, 0, 16, 0, 0, 0, + 0, 0, 10, 0, 16, 0, + 0, 0, 0, 0, 42, 16, + 16, 0, 2, 0, 0, 0, + 58, 16, 16, 0, 2, 0, + 0, 0, 55, 0, 0, 9, + 18, 0, 16, 0, 0, 0, + 0, 0, 10, 0, 16, 0, + 0, 0, 0, 0, 10, 16, + 16, 0, 3, 0, 0, 0, + 26, 16, 16, 0, 3, 0, + 0, 0, 139, 0, 0, 9, + 66, 0, 16, 0, 0, 0, + 0, 0, 1, 64, 0, 0, + 16, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 0, 0, + 10, 0, 16, 0, 0, 0, + 0, 0, 42, 0, 0, 7, + 18, 0, 16, 0, 0, 0, + 0, 0, 10, 0, 16, 0, + 0, 0, 0, 0, 1, 64, + 0, 0, 16, 0, 0, 0, + 43, 0, 0, 5, 82, 0, + 16, 0, 0, 0, 0, 0, + 6, 2, 16, 0, 0, 0, + 0, 0, 1, 0, 0, 10, + 50, 0, 16, 0, 1, 0, + 0, 0, 6, 16, 16, 0, + 4, 0, 0, 0, 2, 64, + 0, 0, 1, 0, 0, 0, + 2, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 55, 0, 0, 9, 130, 0, + 16, 0, 0, 0, 0, 0, + 10, 0, 16, 0, 1, 0, + 0, 0, 10, 0, 16, 0, + 0, 0, 0, 0, 42, 0, + 16, 0, 0, 0, 0, 0, + 0, 0, 0, 7, 18, 0, + 16, 0, 1, 0, 0, 0, + 26, 0, 16, 0, 0, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 128, 63, 55, 0, + 0, 9, 18, 0, 16, 0, + 1, 0, 0, 0, 26, 0, + 16, 0, 1, 0, 0, 0, + 26, 0, 16, 0, 0, 0, + 0, 0, 10, 0, 16, 0, + 1, 0, 0, 0, 0, 0, + 0, 8, 34, 0, 16, 0, + 1, 0, 0, 0, 42, 0, + 16, 128, 65, 0, 0, 0, + 0, 0, 0, 0, 10, 0, + 16, 0, 0, 0, 0, 0, + 56, 0, 0, 8, 34, 0, + 16, 0, 1, 0, 0, 0, + 26, 0, 16, 0, 1, 0, + 0, 0, 26, 128, 32, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 49, 0, 0, 7, + 34, 0, 16, 0, 1, 0, + 0, 0, 26, 0, 16, 0, + 1, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 0, 0, + 50, 0, 0, 9, 34, 0, + 16, 0, 0, 0, 0, 0, + 26, 0, 16, 0, 0, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 0, 64, 1, 64, + 0, 0, 0, 0, 128, 63, + 0, 0, 0, 8, 34, 0, + 16, 0, 0, 0, 0, 0, + 10, 0, 16, 128, 65, 0, + 0, 0, 1, 0, 0, 0, + 26, 0, 16, 0, 0, 0, + 0, 0, 55, 0, 0, 9, + 34, 0, 16, 0, 0, 0, + 0, 0, 26, 0, 16, 0, + 1, 0, 0, 0, 26, 0, + 16, 0, 0, 0, 0, 0, + 10, 0, 16, 0, 1, 0, + 0, 0, 138, 0, 0, 9, + 18, 0, 16, 0, 1, 0, + 0, 0, 1, 64, 0, 0, + 10, 0, 0, 0, 1, 64, + 0, 0, 10, 0, 0, 0, + 42, 16, 16, 0, 3, 0, + 0, 0, 85, 0, 0, 7, + 34, 0, 16, 0, 1, 0, + 0, 0, 42, 16, 16, 0, + 3, 0, 0, 0, 1, 64, + 0, 0, 20, 0, 0, 0, + 1, 0, 0, 10, 242, 0, + 16, 0, 2, 0, 0, 0, + 230, 31, 16, 0, 3, 0, + 0, 0, 2, 64, 0, 0, + 255, 3, 0, 0, 255, 255, + 0, 0, 0, 0, 0, 32, + 0, 0, 0, 30, 30, 0, + 0, 7, 66, 0, 16, 0, + 1, 0, 0, 0, 26, 0, + 16, 0, 2, 0, 0, 0, + 1, 64, 0, 0, 255, 255, + 255, 255, 167, 0, 0, 139, + 2, 131, 0, 128, 131, 153, + 25, 0, 66, 0, 16, 0, + 1, 0, 0, 0, 42, 0, + 16, 0, 1, 0, 0, 0, + 1, 64, 0, 0, 8, 0, + 0, 0, 6, 112, 16, 0, + 6, 0, 0, 0, 55, 0, + 0, 9, 66, 0, 16, 0, + 1, 0, 0, 0, 58, 16, + 16, 0, 3, 0, 0, 0, + 42, 0, 16, 0, 1, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 0, 0, 41, 0, + 0, 7, 130, 0, 16, 0, + 1, 0, 0, 0, 42, 0, + 16, 0, 1, 0, 0, 0, + 1, 64, 0, 0, 2, 0, + 0, 0, 140, 0, 0, 11, + 34, 0, 16, 0, 2, 0, + 0, 0, 1, 64, 0, 0, + 30, 0, 0, 0, 1, 64, + 0, 0, 2, 0, 0, 0, + 42, 0, 16, 0, 1, 0, + 0, 0, 1, 64, 0, 0, + 1, 0, 0, 0, 167, 0, + 0, 139, 2, 131, 0, 128, + 131, 153, 25, 0, 50, 0, + 16, 0, 3, 0, 0, 0, + 26, 0, 16, 0, 2, 0, + 0, 0, 1, 64, 0, 0, + 8, 0, 0, 0, 70, 112, + 16, 0, 3, 0, 0, 0, + 55, 0, 0, 12, 50, 0, + 16, 0, 3, 0, 0, 0, + 166, 10, 16, 0, 1, 0, + 0, 0, 70, 0, 16, 0, + 3, 0, 0, 0, 2, 64, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 57, 0, 0, 7, 66, 0, + 16, 0, 1, 0, 0, 0, + 26, 0, 16, 0, 3, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 0, 0, 24, 0, + 0, 7, 34, 0, 16, 0, + 2, 0, 0, 0, 10, 0, + 16, 0, 3, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 7, + 66, 0, 16, 0, 1, 0, + 0, 0, 42, 0, 16, 0, + 1, 0, 0, 0, 26, 0, + 16, 0, 2, 0, 0, 0, + 31, 0, 4, 3, 42, 0, + 16, 0, 1, 0, 0, 0, + 0, 0, 0, 8, 242, 0, + 16, 0, 4, 0, 0, 0, + 70, 30, 16, 128, 65, 0, + 0, 0, 0, 0, 0, 0, + 230, 20, 16, 0, 1, 0, + 0, 0, 15, 0, 0, 7, + 66, 0, 16, 0, 1, 0, + 0, 0, 70, 0, 16, 0, + 4, 0, 0, 0, 70, 0, + 16, 0, 4, 0, 0, 0, + 75, 0, 0, 5, 34, 0, + 16, 0, 2, 0, 0, 0, + 42, 0, 16, 0, 1, 0, + 0, 0, 57, 0, 0, 7, + 18, 0, 16, 0, 3, 0, + 0, 0, 26, 0, 16, 0, + 2, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 0, 0, + 31, 0, 4, 3, 10, 0, + 16, 0, 3, 0, 0, 0, + 56, 0, 0, 10, 82, 0, + 16, 0, 3, 0, 0, 0, + 86, 4, 16, 0, 4, 0, + 0, 0, 2, 64, 0, 0, + 0, 0, 128, 191, 0, 0, + 0, 0, 0, 0, 128, 63, + 0, 0, 0, 0, 14, 0, + 0, 7, 82, 0, 16, 0, + 3, 0, 0, 0, 6, 2, + 16, 0, 3, 0, 0, 0, + 86, 5, 16, 0, 2, 0, + 0, 0, 0, 0, 0, 8, + 50, 0, 16, 0, 5, 0, + 0, 0, 70, 16, 16, 128, + 65, 0, 0, 0, 0, 0, + 0, 0, 70, 16, 16, 0, + 1, 0, 0, 0, 15, 0, + 0, 7, 34, 0, 16, 0, + 2, 0, 0, 0, 134, 0, + 16, 0, 3, 0, 0, 0, + 70, 0, 16, 0, 5, 0, + 0, 0, 0, 0, 0, 8, + 50, 0, 16, 0, 5, 0, + 0, 0, 70, 16, 16, 128, + 65, 0, 0, 0, 0, 0, + 0, 0, 230, 26, 16, 0, + 0, 0, 0, 0, 15, 0, + 0, 7, 18, 0, 16, 0, + 3, 0, 0, 0, 134, 0, + 16, 0, 3, 0, 0, 0, + 70, 0, 16, 0, 5, 0, + 0, 0, 0, 0, 0, 8, + 34, 0, 16, 0, 2, 0, + 0, 0, 26, 0, 16, 128, + 65, 0, 0, 0, 2, 0, + 0, 0, 10, 0, 16, 0, + 3, 0, 0, 0, 56, 0, + 0, 7, 66, 0, 16, 0, + 3, 0, 0, 0, 26, 0, + 16, 0, 2, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 64, 64, 0, 0, 0, 9, + 34, 0, 16, 0, 2, 0, + 0, 0, 26, 0, 16, 128, + 65, 0, 0, 0, 2, 0, + 0, 0, 10, 0, 16, 128, + 65, 0, 0, 0, 3, 0, + 0, 0, 54, 0, 0, 5, + 130, 0, 16, 0, 3, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 0, 63, 54, 0, + 0, 5, 18, 0, 16, 0, + 5, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 0, 0, + 48, 0, 0, 1, 33, 0, + 0, 7, 34, 0, 16, 0, + 5, 0, 0, 0, 10, 0, + 16, 0, 5, 0, 0, 0, + 1, 64, 0, 0, 3, 0, + 0, 0, 3, 0, 4, 3, + 26, 0, 16, 0, 5, 0, + 0, 0, 56, 0, 0, 7, + 34, 0, 16, 0, 5, 0, + 0, 0, 58, 0, 16, 0, + 3, 0, 0, 0, 42, 0, + 16, 0, 3, 0, 0, 0, + 50, 0, 0, 10, 34, 0, + 16, 0, 5, 0, 0, 0, + 26, 0, 16, 0, 5, 0, + 0, 0, 58, 0, 16, 0, + 3, 0, 0, 0, 10, 0, + 16, 128, 65, 0, 0, 0, + 3, 0, 0, 0, 50, 0, + 0, 9, 66, 0, 16, 0, + 5, 0, 0, 0, 42, 0, + 16, 0, 3, 0, 0, 0, + 58, 0, 16, 0, 3, 0, + 0, 0, 26, 0, 16, 0, + 2, 0, 0, 0, 0, 0, + 0, 7, 130, 0, 16, 0, + 5, 0, 0, 0, 42, 0, + 16, 0, 5, 0, 0, 0, + 42, 0, 16, 0, 5, 0, + 0, 0, 49, 0, 0, 7, + 66, 0, 16, 0, 5, 0, + 0, 0, 42, 0, 16, 0, + 5, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 0, 0, + 55, 0, 0, 10, 34, 0, + 16, 0, 5, 0, 0, 0, + 42, 0, 16, 0, 5, 0, + 0, 0, 26, 0, 16, 128, + 65, 0, 0, 0, 5, 0, + 0, 0, 26, 0, 16, 0, + 5, 0, 0, 0, 49, 0, + 0, 7, 66, 0, 16, 0, + 5, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 0, 0, + 26, 0, 16, 0, 5, 0, + 0, 0, 49, 0, 0, 8, + 18, 0, 16, 0, 6, 0, + 0, 0, 26, 0, 16, 0, + 5, 0, 0, 0, 58, 0, + 16, 128, 129, 0, 0, 0, + 5, 0, 0, 0, 14, 0, + 0, 8, 34, 0, 16, 0, + 5, 0, 0, 0, 26, 0, + 16, 0, 5, 0, 0, 0, + 58, 0, 16, 128, 129, 0, + 0, 0, 5, 0, 0, 0, + 55, 0, 0, 9, 34, 0, + 16, 0, 5, 0, 0, 0, + 10, 0, 16, 0, 6, 0, + 0, 0, 26, 0, 16, 0, + 5, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 128, 63, + 1, 0, 0, 7, 130, 0, + 16, 0, 3, 0, 0, 0, + 26, 0, 16, 0, 5, 0, + 0, 0, 42, 0, 16, 0, + 5, 0, 0, 0, 30, 0, + 0, 7, 18, 0, 16, 0, + 5, 0, 0, 0, 10, 0, + 16, 0, 5, 0, 0, 0, + 1, 64, 0, 0, 1, 0, + 0, 0, 22, 0, 0, 1, + 56, 0, 0, 7, 34, 0, + 16, 0, 2, 0, 0, 0, + 26, 0, 16, 0, 2, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 64, 64, 50, 0, + 0, 9, 34, 0, 16, 0, + 2, 0, 0, 0, 58, 0, + 16, 0, 3, 0, 0, 0, + 42, 0, 16, 0, 3, 0, + 0, 0, 26, 0, 16, 0, + 2, 0, 0, 0, 56, 0, + 0, 7, 18, 0, 16, 0, + 3, 0, 0, 0, 10, 0, + 16, 0, 3, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 64, 64, 50, 0, 0, 9, + 34, 0, 16, 0, 2, 0, + 0, 0, 58, 0, 16, 0, + 3, 0, 0, 0, 26, 0, + 16, 0, 2, 0, 0, 0, + 10, 0, 16, 0, 3, 0, + 0, 0, 56, 0, 0, 7, + 34, 0, 16, 0, 2, 0, + 0, 0, 26, 0, 16, 0, + 2, 0, 0, 0, 58, 0, + 16, 0, 3, 0, 0, 0, + 54, 0, 0, 6, 34, 0, + 16, 0, 2, 0, 0, 0, + 26, 0, 16, 128, 129, 0, + 0, 0, 2, 0, 0, 0, + 18, 0, 0, 1, 54, 0, + 0, 5, 130, 0, 16, 0, + 3, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 0, 63, + 54, 0, 0, 5, 34, 0, + 16, 0, 2, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 0, 0, 21, 0, 0, 1, + 56, 0, 0, 7, 18, 0, + 16, 0, 3, 0, 0, 0, + 26, 0, 16, 0, 3, 0, + 0, 0, 1, 64, 0, 0, + 171, 170, 170, 62, 0, 0, + 0, 8, 242, 0, 16, 0, + 5, 0, 0, 0, 70, 20, + 16, 128, 65, 0, 0, 0, + 0, 0, 0, 0, 230, 30, + 16, 0, 0, 0, 0, 0, + 0, 0, 0, 8, 50, 0, + 16, 0, 6, 0, 0, 0, + 230, 10, 16, 0, 4, 0, + 0, 0, 230, 10, 16, 128, + 65, 0, 0, 0, 5, 0, + 0, 0, 50, 0, 0, 12, + 242, 0, 16, 0, 7, 0, + 0, 0, 230, 14, 16, 0, + 4, 0, 0, 0, 2, 64, + 0, 0, 0, 0, 64, 192, + 0, 0, 64, 192, 0, 0, + 64, 192, 0, 0, 64, 192, + 70, 4, 16, 0, 4, 0, + 0, 0, 0, 0, 0, 7, + 242, 0, 16, 0, 8, 0, + 0, 0, 70, 4, 16, 0, + 6, 0, 0, 0, 70, 4, + 16, 0, 6, 0, 0, 0, + 50, 0, 0, 9, 194, 0, + 16, 0, 4, 0, 0, 0, + 166, 14, 16, 0, 7, 0, + 0, 0, 246, 15, 16, 0, + 3, 0, 0, 0, 6, 4, + 16, 0, 8, 0, 0, 0, + 50, 0, 0, 9, 194, 0, + 16, 0, 4, 0, 0, 0, + 166, 14, 16, 0, 4, 0, + 0, 0, 246, 15, 16, 0, + 3, 0, 0, 0, 6, 4, + 16, 0, 5, 0, 0, 0, + 56, 0, 0, 10, 194, 0, + 16, 0, 4, 0, 0, 0, + 166, 14, 16, 0, 4, 0, + 0, 0, 2, 64, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 64, 64, + 0, 0, 64, 64, 15, 0, + 0, 7, 66, 0, 16, 0, + 3, 0, 0, 0, 230, 10, + 16, 0, 4, 0, 0, 0, + 230, 10, 16, 0, 4, 0, + 0, 0, 75, 0, 0, 5, + 66, 0, 16, 0, 3, 0, + 0, 0, 42, 0, 16, 0, + 3, 0, 0, 0, 57, 0, + 0, 7, 66, 0, 16, 0, + 6, 0, 0, 0, 42, 0, + 16, 0, 3, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 0, 0, 31, 0, 4, 3, + 42, 0, 16, 0, 6, 0, + 0, 0, 14, 0, 0, 10, + 66, 0, 16, 0, 3, 0, + 0, 0, 2, 64, 0, 0, + 0, 0, 128, 63, 0, 0, + 128, 63, 0, 0, 128, 63, + 0, 0, 128, 63, 42, 0, + 16, 0, 3, 0, 0, 0, + 56, 0, 0, 7, 194, 0, + 16, 0, 4, 0, 0, 0, + 166, 10, 16, 0, 3, 0, + 0, 0, 166, 14, 16, 0, + 4, 0, 0, 0, 15, 0, + 0, 7, 66, 0, 16, 0, + 3, 0, 0, 0, 230, 10, + 16, 0, 7, 0, 0, 0, + 230, 10, 16, 0, 4, 0, + 0, 0, 0, 0, 0, 7, + 66, 0, 16, 0, 6, 0, + 0, 0, 42, 0, 16, 0, + 3, 0, 0, 0, 42, 0, + 16, 0, 3, 0, 0, 0, + 15, 0, 0, 7, 18, 0, + 16, 0, 6, 0, 0, 0, + 70, 0, 16, 0, 6, 0, + 0, 0, 230, 10, 16, 0, + 4, 0, 0, 0, 56, 0, + 0, 7, 18, 0, 16, 0, + 6, 0, 0, 0, 10, 0, + 16, 0, 6, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 128, 64, 50, 0, 0, 9, + 18, 0, 16, 0, 6, 0, + 0, 0, 42, 0, 16, 0, + 6, 0, 0, 0, 58, 0, + 16, 0, 3, 0, 0, 0, + 10, 0, 16, 0, 6, 0, + 0, 0, 56, 0, 0, 7, + 18, 0, 16, 0, 6, 0, + 0, 0, 58, 0, 16, 0, + 3, 0, 0, 0, 10, 0, + 16, 0, 6, 0, 0, 0, + 15, 0, 0, 7, 66, 0, + 16, 0, 4, 0, 0, 0, + 230, 10, 16, 0, 5, 0, + 0, 0, 230, 10, 16, 0, + 4, 0, 0, 0, 56, 0, + 0, 7, 66, 0, 16, 0, + 4, 0, 0, 0, 42, 0, + 16, 0, 4, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 192, 64, 50, 0, 0, 9, + 66, 0, 16, 0, 4, 0, + 0, 0, 10, 0, 16, 0, + 6, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 64, 64, + 42, 0, 16, 0, 4, 0, + 0, 0, 0, 0, 0, 8, + 130, 0, 16, 0, 4, 0, + 0, 0, 58, 0, 16, 128, + 65, 0, 0, 0, 3, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 128, 63, 51, 0, + 0, 7, 130, 0, 16, 0, + 4, 0, 0, 0, 58, 0, + 16, 0, 3, 0, 0, 0, + 58, 0, 16, 0, 4, 0, + 0, 0, 56, 0, 0, 7, + 18, 0, 16, 0, 6, 0, + 0, 0, 58, 0, 16, 0, + 4, 0, 0, 0, 58, 0, + 16, 0, 4, 0, 0, 0, + 50, 0, 0, 9, 18, 0, + 16, 0, 6, 0, 0, 0, + 10, 0, 16, 0, 6, 0, + 0, 0, 42, 0, 16, 0, + 6, 0, 0, 0, 42, 0, + 16, 0, 4, 0, 0, 0, + 56, 0, 0, 7, 130, 0, + 16, 0, 4, 0, 0, 0, + 58, 0, 16, 0, 4, 0, + 0, 0, 10, 0, 16, 0, + 6, 0, 0, 0, 56, 0, + 0, 7, 130, 0, 16, 0, + 4, 0, 0, 0, 58, 0, + 16, 0, 4, 0, 0, 0, + 1, 64, 0, 0, 114, 249, + 127, 63, 51, 0, 0, 7, + 130, 0, 16, 0, 4, 0, + 0, 0, 10, 0, 16, 0, + 3, 0, 0, 0, 58, 0, + 16, 0, 4, 0, 0, 0, + 24, 0, 0, 7, 66, 0, + 16, 0, 3, 0, 0, 0, + 42, 0, 16, 0, 3, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 0, 0, 31, 0, + 4, 3, 42, 0, 16, 0, + 3, 0, 0, 0, 14, 0, + 0, 7, 66, 0, 16, 0, + 3, 0, 0, 0, 58, 0, + 16, 0, 4, 0, 0, 0, + 42, 0, 16, 0, 4, 0, + 0, 0, 18, 0, 0, 1, + 14, 0, 0, 10, 18, 0, + 16, 0, 6, 0, 0, 0, + 2, 64, 0, 0, 0, 0, + 128, 63, 0, 0, 128, 63, + 0, 0, 128, 63, 0, 0, + 128, 63, 42, 0, 16, 0, + 6, 0, 0, 0, 56, 0, + 0, 7, 66, 0, 16, 0, + 4, 0, 0, 0, 42, 0, + 16, 0, 4, 0, 0, 0, + 10, 0, 16, 0, 6, 0, + 0, 0, 56, 0, 0, 8, + 130, 0, 16, 0, 4, 0, + 0, 0, 58, 0, 16, 128, + 65, 0, 0, 0, 4, 0, + 0, 0, 10, 0, 16, 0, + 6, 0, 0, 0, 56, 0, + 0, 7, 66, 0, 16, 0, + 4, 0, 0, 0, 42, 0, + 16, 0, 4, 0, 0, 0, + 1, 64, 0, 0, 171, 170, + 170, 190, 56, 0, 0, 7, + 18, 0, 16, 0, 6, 0, + 0, 0, 58, 0, 16, 0, + 4, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 0, 63, + 56, 0, 0, 7, 34, 0, + 16, 0, 6, 0, 0, 0, + 42, 0, 16, 0, 4, 0, + 0, 0, 42, 0, 16, 0, + 4, 0, 0, 0, 56, 0, + 0, 7, 34, 0, 16, 0, + 6, 0, 0, 0, 42, 0, + 16, 0, 4, 0, 0, 0, + 26, 0, 16, 0, 6, 0, + 0, 0, 50, 0, 0, 10, + 34, 0, 16, 0, 6, 0, + 0, 0, 10, 0, 16, 0, + 6, 0, 0, 0, 10, 0, + 16, 0, 6, 0, 0, 0, + 26, 0, 16, 128, 65, 0, + 0, 0, 6, 0, 0, 0, + 49, 0, 0, 7, 66, 0, + 16, 0, 6, 0, 0, 0, + 26, 0, 16, 0, 6, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 0, 0, 75, 0, + 0, 5, 130, 0, 16, 0, + 6, 0, 0, 0, 42, 0, + 16, 0, 4, 0, 0, 0, + 56, 0, 0, 7, 18, 0, + 16, 0, 9, 0, 0, 0, + 58, 0, 16, 0, 6, 0, + 0, 0, 58, 0, 16, 0, + 6, 0, 0, 0, 56, 0, + 0, 7, 18, 0, 16, 0, + 9, 0, 0, 0, 58, 0, + 16, 0, 6, 0, 0, 0, + 10, 0, 16, 0, 9, 0, + 0, 0, 14, 0, 0, 7, + 18, 0, 16, 0, 9, 0, + 0, 0, 10, 0, 16, 0, + 6, 0, 0, 0, 10, 0, + 16, 0, 9, 0, 0, 0, + 0, 0, 0, 8, 34, 0, + 16, 0, 9, 0, 0, 0, + 10, 0, 16, 128, 193, 0, + 0, 0, 9, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 128, 63, 75, 0, 0, 5, + 34, 0, 16, 0, 9, 0, + 0, 0, 26, 0, 16, 0, + 9, 0, 0, 0, 50, 0, + 0, 10, 66, 0, 16, 0, + 9, 0, 0, 0, 10, 0, + 16, 128, 129, 0, 0, 0, + 9, 0, 0, 0, 1, 64, + 0, 0, 48, 110, 153, 188, + 1, 64, 0, 0, 39, 22, + 152, 61, 50, 0, 0, 10, + 66, 0, 16, 0, 9, 0, + 0, 0, 42, 0, 16, 0, + 9, 0, 0, 0, 10, 0, + 16, 128, 129, 0, 0, 0, + 9, 0, 0, 0, 1, 64, + 0, 0, 132, 52, 89, 190, + 50, 0, 0, 10, 66, 0, + 16, 0, 9, 0, 0, 0, + 42, 0, 16, 0, 9, 0, + 0, 0, 10, 0, 16, 128, + 129, 0, 0, 0, 9, 0, + 0, 0, 1, 64, 0, 0, + 164, 13, 201, 63, 56, 0, + 0, 7, 130, 0, 16, 0, + 9, 0, 0, 0, 26, 0, + 16, 0, 9, 0, 0, 0, + 42, 0, 16, 0, 9, 0, + 0, 0, 50, 0, 0, 9, + 130, 0, 16, 0, 9, 0, + 0, 0, 58, 0, 16, 0, + 9, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 0, 192, + 1, 64, 0, 0, 219, 15, + 73, 64, 49, 0, 0, 8, + 18, 0, 16, 0, 9, 0, + 0, 0, 10, 0, 16, 0, + 9, 0, 0, 0, 10, 0, + 16, 128, 65, 0, 0, 0, + 9, 0, 0, 0, 1, 0, + 0, 7, 18, 0, 16, 0, + 9, 0, 0, 0, 10, 0, + 16, 0, 9, 0, 0, 0, + 58, 0, 16, 0, 9, 0, + 0, 0, 50, 0, 0, 9, + 18, 0, 16, 0, 9, 0, + 0, 0, 42, 0, 16, 0, + 9, 0, 0, 0, 26, 0, + 16, 0, 9, 0, 0, 0, + 10, 0, 16, 0, 9, 0, + 0, 0, 56, 0, 0, 7, + 130, 0, 16, 0, 6, 0, + 0, 0, 58, 0, 16, 0, + 6, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 0, 192, + 50, 0, 0, 9, 18, 0, + 16, 0, 9, 0, 0, 0, + 10, 0, 16, 0, 9, 0, + 0, 0, 1, 64, 0, 0, + 171, 170, 170, 62, 1, 64, + 0, 0, 146, 10, 6, 192, + 77, 0, 0, 6, 0, 208, + 0, 0, 18, 0, 16, 0, + 9, 0, 0, 0, 10, 0, + 16, 0, 9, 0, 0, 0, + 56, 0, 0, 7, 130, 0, + 16, 0, 6, 0, 0, 0, + 58, 0, 16, 0, 6, 0, + 0, 0, 10, 0, 16, 0, + 9, 0, 0, 0, 75, 0, + 0, 5, 34, 0, 16, 0, + 6, 0, 0, 0, 26, 0, + 16, 0, 6, 0, 0, 0, + 0, 0, 0, 8, 18, 0, + 16, 0, 6, 0, 0, 0, + 26, 0, 16, 0, 6, 0, + 0, 0, 10, 0, 16, 128, + 129, 0, 0, 0, 6, 0, + 0, 0, 47, 0, 0, 5, + 18, 0, 16, 0, 6, 0, + 0, 0, 10, 0, 16, 0, + 6, 0, 0, 0, 56, 0, + 0, 7, 18, 0, 16, 0, + 6, 0, 0, 0, 10, 0, + 16, 0, 6, 0, 0, 0, + 1, 64, 0, 0, 171, 170, + 170, 62, 25, 0, 0, 5, + 18, 0, 16, 0, 6, 0, + 0, 0, 10, 0, 16, 0, + 6, 0, 0, 0, 49, 0, + 0, 7, 130, 0, 16, 0, + 4, 0, 0, 0, 58, 0, + 16, 0, 4, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 0, 0, 55, 0, 0, 10, + 130, 0, 16, 0, 4, 0, + 0, 0, 58, 0, 16, 0, + 4, 0, 0, 0, 10, 0, + 16, 128, 65, 0, 0, 0, + 6, 0, 0, 0, 10, 0, + 16, 0, 6, 0, 0, 0, + 57, 0, 0, 7, 18, 0, + 16, 0, 6, 0, 0, 0, + 58, 0, 16, 0, 4, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 0, 0, 14, 0, + 0, 7, 66, 0, 16, 0, + 4, 0, 0, 0, 42, 0, + 16, 0, 4, 0, 0, 0, + 58, 0, 16, 0, 4, 0, + 0, 0, 0, 0, 0, 7, + 66, 0, 16, 0, 4, 0, + 0, 0, 42, 0, 16, 0, + 4, 0, 0, 0, 58, 0, + 16, 0, 4, 0, 0, 0, + 1, 0, 0, 7, 66, 0, + 16, 0, 4, 0, 0, 0, + 42, 0, 16, 0, 4, 0, + 0, 0, 10, 0, 16, 0, + 6, 0, 0, 0, 55, 0, + 0, 9, 66, 0, 16, 0, + 3, 0, 0, 0, 42, 0, + 16, 0, 6, 0, 0, 0, + 58, 0, 16, 0, 6, 0, + 0, 0, 42, 0, 16, 0, + 4, 0, 0, 0, 21, 0, + 0, 1, 54, 0, 0, 6, + 194, 0, 16, 0, 6, 0, + 0, 0, 166, 10, 16, 128, + 129, 0, 0, 0, 3, 0, + 0, 0, 54, 0, 0, 6, + 50, 0, 16, 0, 6, 0, + 0, 0, 246, 15, 16, 128, + 65, 0, 0, 0, 6, 0, + 0, 0, 0, 0, 0, 7, + 242, 0, 16, 0, 6, 0, + 0, 0, 246, 15, 16, 0, + 3, 0, 0, 0, 70, 14, + 16, 0, 6, 0, 0, 0, + 50, 0, 0, 9, 242, 0, + 16, 0, 7, 0, 0, 0, + 70, 14, 16, 0, 7, 0, + 0, 0, 70, 14, 16, 0, + 6, 0, 0, 0, 70, 14, + 16, 0, 8, 0, 0, 0, + 50, 0, 0, 9, 242, 0, + 16, 0, 5, 0, 0, 0, + 70, 14, 16, 0, 7, 0, + 0, 0, 70, 14, 16, 0, + 6, 0, 0, 0, 70, 14, + 16, 0, 5, 0, 0, 0, + 57, 0, 0, 7, 194, 0, + 16, 0, 3, 0, 0, 0, + 166, 30, 16, 0, 0, 0, + 0, 0, 6, 20, 16, 0, + 0, 0, 0, 0, 60, 0, + 0, 7, 66, 0, 16, 0, + 3, 0, 0, 0, 58, 0, + 16, 0, 3, 0, 0, 0, + 42, 0, 16, 0, 3, 0, + 0, 0, 57, 0, 0, 7, + 194, 0, 16, 0, 4, 0, + 0, 0, 166, 30, 16, 0, + 0, 0, 0, 0, 6, 20, + 16, 0, 1, 0, 0, 0, + 60, 0, 0, 7, 130, 0, + 16, 0, 3, 0, 0, 0, + 58, 0, 16, 0, 4, 0, + 0, 0, 42, 0, 16, 0, + 4, 0, 0, 0, 55, 0, + 0, 9, 194, 0, 16, 0, + 4, 0, 0, 0, 246, 15, + 16, 0, 3, 0, 0, 0, + 6, 20, 16, 0, 1, 0, + 0, 0, 166, 30, 16, 0, + 1, 0, 0, 0, 55, 0, + 0, 9, 194, 0, 16, 0, + 4, 0, 0, 0, 166, 10, + 16, 0, 3, 0, 0, 0, + 166, 30, 16, 0, 0, 0, + 0, 0, 166, 14, 16, 0, + 4, 0, 0, 0, 0, 0, + 0, 8, 194, 0, 16, 0, + 4, 0, 0, 0, 166, 14, + 16, 0, 4, 0, 0, 0, + 6, 20, 16, 128, 65, 0, + 0, 0, 0, 0, 0, 0, + 57, 0, 0, 7, 82, 0, + 16, 0, 6, 0, 0, 0, + 6, 17, 16, 0, 1, 0, + 0, 0, 166, 27, 16, 0, + 1, 0, 0, 0, 60, 0, + 0, 7, 66, 0, 16, 0, + 3, 0, 0, 0, 42, 0, + 16, 0, 6, 0, 0, 0, + 10, 0, 16, 0, 6, 0, + 0, 0, 55, 0, 0, 9, + 82, 0, 16, 0, 6, 0, + 0, 0, 246, 15, 16, 0, + 3, 0, 0, 0, 166, 27, + 16, 0, 0, 0, 0, 0, + 6, 17, 16, 0, 0, 0, + 0, 0, 55, 0, 0, 9, + 194, 0, 16, 0, 3, 0, + 0, 0, 166, 10, 16, 0, + 3, 0, 0, 0, 6, 20, + 16, 0, 1, 0, 0, 0, + 6, 8, 16, 0, 6, 0, + 0, 0, 0, 0, 0, 8, + 194, 0, 16, 0, 3, 0, + 0, 0, 166, 14, 16, 128, + 65, 0, 0, 0, 3, 0, + 0, 0, 166, 30, 16, 0, + 1, 0, 0, 0, 49, 0, + 0, 7, 18, 0, 16, 0, + 6, 0, 0, 0, 26, 0, + 16, 0, 6, 0, 0, 0, + 1, 64, 0, 0, 111, 18, + 131, 58, 55, 0, 0, 9, + 194, 0, 16, 0, 4, 0, + 0, 0, 6, 0, 16, 0, + 6, 0, 0, 0, 166, 14, + 16, 0, 4, 0, 0, 0, + 6, 4, 16, 0, 5, 0, + 0, 0, 49, 0, 0, 7, + 18, 0, 16, 0, 5, 0, + 0, 0, 1, 64, 0, 0, + 119, 190, 127, 63, 58, 0, + 16, 0, 6, 0, 0, 0, + 55, 0, 0, 9, 194, 0, + 16, 0, 3, 0, 0, 0, + 6, 0, 16, 0, 5, 0, + 0, 0, 166, 14, 16, 0, + 3, 0, 0, 0, 166, 14, + 16, 0, 5, 0, 0, 0, + 15, 0, 0, 7, 18, 0, + 16, 0, 5, 0, 0, 0, + 230, 10, 16, 0, 4, 0, + 0, 0, 230, 10, 16, 0, + 3, 0, 0, 0, 15, 0, + 0, 7, 66, 0, 16, 0, + 4, 0, 0, 0, 230, 10, + 16, 0, 4, 0, 0, 0, + 230, 10, 16, 0, 4, 0, + 0, 0, 15, 0, 0, 7, + 66, 0, 16, 0, 3, 0, + 0, 0, 230, 10, 16, 0, + 3, 0, 0, 0, 230, 10, + 16, 0, 3, 0, 0, 0, + 56, 0, 0, 7, 66, 0, + 16, 0, 3, 0, 0, 0, + 42, 0, 16, 0, 3, 0, + 0, 0, 42, 0, 16, 0, + 4, 0, 0, 0, 24, 0, + 0, 7, 130, 0, 16, 0, + 3, 0, 0, 0, 42, 0, + 16, 0, 3, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 0, 0, 68, 0, 0, 5, + 66, 0, 16, 0, 3, 0, + 0, 0, 42, 0, 16, 0, + 3, 0, 0, 0, 56, 0, + 0, 7, 66, 0, 16, 0, + 3, 0, 0, 0, 42, 0, + 16, 0, 3, 0, 0, 0, + 10, 0, 16, 0, 5, 0, + 0, 0, 52, 0, 0, 7, + 66, 0, 16, 0, 3, 0, + 0, 0, 42, 0, 16, 0, + 3, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 128, 191, + 51, 0, 0, 7, 66, 0, + 16, 0, 3, 0, 0, 0, + 42, 0, 16, 0, 3, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 128, 63, 55, 0, + 0, 9, 66, 0, 16, 0, + 3, 0, 0, 0, 58, 0, + 16, 0, 3, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 128, 63, 42, 0, 16, 0, + 3, 0, 0, 0, 0, 0, + 0, 8, 130, 0, 16, 0, + 3, 0, 0, 0, 42, 0, + 16, 128, 193, 0, 0, 0, + 3, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 128, 63, + 75, 0, 0, 5, 130, 0, + 16, 0, 3, 0, 0, 0, + 58, 0, 16, 0, 3, 0, + 0, 0, 50, 0, 0, 10, + 66, 0, 16, 0, 4, 0, + 0, 0, 42, 0, 16, 128, + 129, 0, 0, 0, 3, 0, + 0, 0, 1, 64, 0, 0, + 48, 110, 153, 188, 1, 64, + 0, 0, 39, 22, 152, 61, + 50, 0, 0, 10, 66, 0, + 16, 0, 4, 0, 0, 0, + 42, 0, 16, 0, 4, 0, + 0, 0, 42, 0, 16, 128, + 129, 0, 0, 0, 3, 0, + 0, 0, 1, 64, 0, 0, + 132, 52, 89, 190, 50, 0, + 0, 10, 66, 0, 16, 0, + 4, 0, 0, 0, 42, 0, + 16, 0, 4, 0, 0, 0, + 42, 0, 16, 128, 129, 0, + 0, 0, 3, 0, 0, 0, + 1, 64, 0, 0, 164, 13, + 201, 63, 56, 0, 0, 7, + 130, 0, 16, 0, 4, 0, + 0, 0, 58, 0, 16, 0, + 3, 0, 0, 0, 42, 0, + 16, 0, 4, 0, 0, 0, + 50, 0, 0, 9, 130, 0, + 16, 0, 4, 0, 0, 0, + 58, 0, 16, 0, 4, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 0, 192, 1, 64, + 0, 0, 219, 15, 73, 64, + 49, 0, 0, 8, 66, 0, + 16, 0, 3, 0, 0, 0, + 42, 0, 16, 0, 3, 0, + 0, 0, 42, 0, 16, 128, + 65, 0, 0, 0, 3, 0, + 0, 0, 1, 0, 0, 7, + 66, 0, 16, 0, 3, 0, + 0, 0, 42, 0, 16, 0, + 3, 0, 0, 0, 58, 0, + 16, 0, 4, 0, 0, 0, + 50, 0, 0, 9, 66, 0, + 16, 0, 3, 0, 0, 0, + 42, 0, 16, 0, 4, 0, + 0, 0, 58, 0, 16, 0, + 3, 0, 0, 0, 42, 0, + 16, 0, 3, 0, 0, 0, + 18, 0, 0, 1, 54, 0, + 0, 5, 66, 0, 16, 0, + 3, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 0, 0, + 21, 0, 0, 1, 50, 0, + 0, 10, 66, 0, 16, 0, + 3, 0, 0, 0, 42, 0, + 16, 128, 65, 0, 0, 0, + 3, 0, 0, 0, 1, 64, + 0, 0, 131, 249, 162, 62, + 1, 64, 0, 0, 0, 0, + 128, 63, 56, 0, 0, 7, + 18, 0, 16, 0, 3, 0, + 0, 0, 10, 0, 16, 0, + 3, 0, 0, 0, 10, 0, + 16, 0, 3, 0, 0, 0, + 14, 0, 0, 7, 66, 0, + 16, 0, 1, 0, 0, 0, + 42, 0, 16, 0, 1, 0, + 0, 0, 10, 0, 16, 0, + 3, 0, 0, 0, 0, 0, + 0, 7, 66, 0, 16, 0, + 1, 0, 0, 0, 42, 0, + 16, 0, 1, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 128, 191, 56, 0, 0, 7, + 66, 0, 16, 0, 1, 0, + 0, 0, 42, 0, 16, 0, + 1, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 0, 63, + 51, 0, 0, 7, 66, 0, + 16, 0, 1, 0, 0, 0, + 42, 0, 16, 0, 1, 0, + 0, 0, 42, 0, 16, 0, + 3, 0, 0, 0, 51, 0, + 0, 7, 66, 0, 16, 0, + 1, 0, 0, 0, 42, 0, + 16, 0, 1, 0, 0, 0, + 1, 64, 0, 0, 164, 112, + 125, 63, 56, 0, 0, 7, + 18, 0, 16, 0, 5, 0, + 0, 0, 42, 0, 16, 0, + 1, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 0, 63, + 54, 0, 0, 5, 34, 0, + 16, 0, 5, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 128, 63, 72, 0, 0, 141, + 194, 1, 0, 128, 67, 85, + 21, 0, 66, 0, 16, 0, + 1, 0, 0, 0, 70, 0, + 16, 0, 5, 0, 0, 0, + 150, 124, 16, 0, 10, 0, + 0, 0, 0, 96, 16, 0, + 10, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 0, 0, + 50, 0, 0, 9, 66, 0, + 16, 0, 1, 0, 0, 0, + 42, 0, 16, 0, 1, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 0, 192, 1, 64, + 0, 0, 0, 0, 128, 63, + 56, 0, 0, 7, 66, 0, + 16, 0, 1, 0, 0, 0, + 26, 0, 16, 0, 3, 0, + 0, 0, 42, 0, 16, 0, + 1, 0, 0, 0, 49, 0, + 0, 7, 18, 0, 16, 0, + 3, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 0, 0, + 42, 0, 16, 0, 1, 0, + 0, 0, 49, 0, 0, 7, + 34, 0, 16, 0, 3, 0, + 0, 0, 42, 0, 16, 0, + 1, 0, 0, 0, 26, 0, + 16, 0, 2, 0, 0, 0, + 14, 0, 0, 7, 66, 0, + 16, 0, 1, 0, 0, 0, + 42, 0, 16, 0, 1, 0, + 0, 0, 26, 0, 16, 0, + 2, 0, 0, 0, 55, 0, + 0, 9, 66, 0, 16, 0, + 1, 0, 0, 0, 26, 0, + 16, 0, 3, 0, 0, 0, + 42, 0, 16, 0, 1, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 128, 63, 1, 0, + 0, 7, 66, 0, 16, 0, + 1, 0, 0, 0, 42, 0, + 16, 0, 1, 0, 0, 0, + 10, 0, 16, 0, 3, 0, + 0, 0, 50, 0, 0, 12, + 242, 0, 16, 0, 3, 0, + 0, 0, 70, 4, 16, 0, + 4, 0, 0, 0, 2, 64, + 0, 0, 171, 170, 170, 62, + 171, 170, 170, 62, 171, 170, + 42, 63, 171, 170, 42, 63, + 70, 20, 16, 0, 0, 0, + 0, 0, 0, 0, 0, 8, + 50, 0, 16, 0, 3, 0, + 0, 0, 70, 0, 16, 0, + 3, 0, 0, 0, 230, 26, + 16, 128, 65, 0, 0, 0, + 0, 0, 0, 0, 50, 0, + 0, 9, 50, 0, 16, 0, + 4, 0, 0, 0, 166, 10, + 16, 0, 1, 0, 0, 0, + 70, 0, 16, 0, 3, 0, + 0, 0, 230, 26, 16, 0, + 0, 0, 0, 0, 0, 0, + 0, 8, 50, 0, 16, 0, + 3, 0, 0, 0, 230, 10, + 16, 0, 3, 0, 0, 0, + 70, 16, 16, 128, 65, 0, + 0, 0, 1, 0, 0, 0, + 50, 0, 0, 9, 50, 0, + 16, 0, 3, 0, 0, 0, + 166, 10, 16, 0, 1, 0, + 0, 0, 70, 0, 16, 0, + 3, 0, 0, 0, 70, 16, + 16, 0, 1, 0, 0, 0, + 18, 0, 0, 1, 54, 0, + 0, 5, 50, 0, 16, 0, + 4, 0, 0, 0, 230, 26, + 16, 0, 0, 0, 0, 0, + 54, 0, 0, 5, 50, 0, + 16, 0, 3, 0, 0, 0, + 70, 16, 16, 0, 1, 0, + 0, 0, 21, 0, 0, 1, + 167, 0, 0, 139, 2, 131, + 0, 128, 131, 153, 25, 0, + 242, 0, 16, 0, 5, 0, + 0, 0, 58, 0, 16, 0, + 1, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 0, 0, + 70, 126, 16, 0, 3, 0, + 0, 0, 50, 0, 0, 12, + 194, 0, 16, 0, 1, 0, + 0, 0, 6, 4, 16, 0, + 4, 0, 0, 0, 2, 64, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 192, 0, 0, 0, 192, + 6, 4, 16, 0, 3, 0, + 0, 0, 0, 0, 0, 7, + 194, 0, 16, 0, 1, 0, + 0, 0, 166, 14, 16, 0, + 1, 0, 0, 0, 6, 20, + 16, 0, 0, 0, 0, 0, + 15, 0, 0, 7, 18, 0, + 16, 0, 6, 0, 0, 0, + 230, 10, 16, 0, 1, 0, + 0, 0, 134, 0, 16, 0, + 5, 0, 0, 0, 15, 0, + 0, 7, 34, 0, 16, 0, + 6, 0, 0, 0, 230, 10, + 16, 0, 1, 0, 0, 0, + 214, 5, 16, 0, 5, 0, + 0, 0, 50, 0, 0, 12, + 194, 0, 16, 0, 1, 0, + 0, 0, 6, 4, 16, 0, + 3, 0, 0, 0, 2, 64, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 192, 0, 0, 0, 192, + 166, 30, 16, 0, 1, 0, + 0, 0, 0, 0, 0, 7, + 194, 0, 16, 0, 1, 0, + 0, 0, 6, 4, 16, 0, + 4, 0, 0, 0, 166, 14, + 16, 0, 1, 0, 0, 0, + 15, 0, 0, 7, 18, 0, + 16, 0, 7, 0, 0, 0, + 230, 10, 16, 0, 1, 0, + 0, 0, 134, 0, 16, 0, + 5, 0, 0, 0, 15, 0, + 0, 7, 34, 0, 16, 0, + 7, 0, 0, 0, 230, 10, + 16, 0, 1, 0, 0, 0, + 214, 5, 16, 0, 5, 0, + 0, 0, 15, 0, 0, 7, + 66, 0, 16, 0, 1, 0, + 0, 0, 70, 0, 16, 0, + 6, 0, 0, 0, 70, 0, + 16, 0, 6, 0, 0, 0, + 15, 0, 0, 7, 130, 0, + 16, 0, 1, 0, 0, 0, + 70, 0, 16, 0, 7, 0, + 0, 0, 70, 0, 16, 0, + 7, 0, 0, 0, 52, 0, + 0, 7, 66, 0, 16, 0, + 1, 0, 0, 0, 58, 0, + 16, 0, 1, 0, 0, 0, + 42, 0, 16, 0, 1, 0, + 0, 0, 75, 0, 0, 5, + 66, 0, 16, 0, 1, 0, + 0, 0, 42, 0, 16, 0, + 1, 0, 0, 0, 56, 0, + 0, 7, 66, 0, 16, 0, + 1, 0, 0, 0, 42, 0, + 16, 0, 1, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 64, 64, 75, 0, 0, 5, + 66, 0, 16, 0, 1, 0, + 0, 0, 42, 0, 16, 0, + 1, 0, 0, 0, 66, 0, + 0, 5, 66, 0, 16, 0, + 1, 0, 0, 0, 42, 0, + 16, 0, 1, 0, 0, 0, + 52, 0, 0, 7, 66, 0, + 16, 0, 1, 0, 0, 0, + 42, 0, 16, 0, 1, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 128, 63, 28, 0, + 0, 5, 66, 0, 16, 0, + 1, 0, 0, 0, 42, 0, + 16, 0, 1, 0, 0, 0, + 84, 0, 0, 7, 66, 0, + 16, 0, 1, 0, 0, 0, + 10, 0, 16, 0, 2, 0, + 0, 0, 42, 0, 16, 0, + 1, 0, 0, 0, 55, 0, + 0, 9, 66, 0, 16, 0, + 1, 0, 0, 0, 42, 0, + 16, 0, 2, 0, 0, 0, + 42, 0, 16, 0, 1, 0, + 0, 0, 10, 0, 16, 0, + 2, 0, 0, 0, 30, 0, + 0, 7, 130, 0, 16, 0, + 1, 0, 0, 0, 10, 0, + 16, 0, 1, 0, 0, 0, + 42, 0, 16, 0, 1, 0, + 0, 0, 30, 0, 0, 7, + 130, 0, 16, 0, 1, 0, + 0, 0, 26, 0, 16, 0, + 1, 0, 0, 0, 58, 0, + 16, 0, 1, 0, 0, 0, + 30, 0, 0, 7, 130, 0, + 16, 0, 1, 0, 0, 0, + 58, 0, 16, 0, 1, 0, + 0, 0, 1, 64, 0, 0, + 255, 255, 255, 255, 57, 0, + 0, 7, 50, 0, 16, 0, + 2, 0, 0, 0, 70, 0, + 16, 0, 4, 0, 0, 0, + 70, 16, 16, 0, 0, 0, + 0, 0, 60, 0, 0, 7, + 18, 0, 16, 0, 2, 0, + 0, 0, 26, 0, 16, 0, + 2, 0, 0, 0, 10, 0, + 16, 0, 2, 0, 0, 0, + 57, 0, 0, 7, 98, 0, + 16, 0, 2, 0, 0, 0, + 6, 1, 16, 0, 3, 0, + 0, 0, 6, 1, 16, 0, + 4, 0, 0, 0, 60, 0, + 0, 7, 34, 0, 16, 0, + 2, 0, 0, 0, 42, 0, + 16, 0, 2, 0, 0, 0, + 26, 0, 16, 0, 2, 0, + 0, 0, 55, 0, 0, 9, + 50, 0, 16, 0, 5, 0, + 0, 0, 86, 5, 16, 0, + 2, 0, 0, 0, 70, 0, + 16, 0, 3, 0, 0, 0, + 230, 26, 16, 0, 1, 0, + 0, 0, 55, 0, 0, 9, + 82, 0, 16, 0, 2, 0, + 0, 0, 6, 0, 16, 0, + 2, 0, 0, 0, 6, 1, + 16, 0, 4, 0, 0, 0, + 6, 1, 16, 0, 5, 0, + 0, 0, 0, 0, 0, 8, + 82, 0, 16, 0, 2, 0, + 0, 0, 6, 2, 16, 0, + 2, 0, 0, 0, 6, 17, + 16, 128, 65, 0, 0, 0, + 0, 0, 0, 0, 57, 0, + 0, 7, 50, 0, 16, 0, + 5, 0, 0, 0, 70, 0, + 16, 0, 3, 0, 0, 0, + 230, 26, 16, 0, 1, 0, + 0, 0, 60, 0, 0, 7, + 18, 0, 16, 0, 5, 0, + 0, 0, 26, 0, 16, 0, + 5, 0, 0, 0, 10, 0, + 16, 0, 5, 0, 0, 0, + 55, 0, 0, 9, 98, 0, + 16, 0, 5, 0, 0, 0, + 86, 5, 16, 0, 2, 0, + 0, 0, 6, 1, 16, 0, + 4, 0, 0, 0, 6, 17, + 16, 0, 0, 0, 0, 0, + 55, 0, 0, 9, 50, 0, + 16, 0, 5, 0, 0, 0, + 6, 0, 16, 0, 5, 0, + 0, 0, 70, 0, 16, 0, + 3, 0, 0, 0, 150, 5, + 16, 0, 5, 0, 0, 0, + 0, 0, 0, 8, 50, 0, + 16, 0, 5, 0, 0, 0, + 70, 0, 16, 128, 65, 0, + 0, 0, 5, 0, 0, 0, + 230, 26, 16, 0, 1, 0, + 0, 0, 15, 0, 0, 7, + 34, 0, 16, 0, 2, 0, + 0, 0, 134, 0, 16, 0, + 2, 0, 0, 0, 70, 0, + 16, 0, 5, 0, 0, 0, + 15, 0, 0, 7, 66, 0, + 16, 0, 5, 0, 0, 0, + 134, 0, 16, 0, 2, 0, + 0, 0, 134, 0, 16, 0, + 2, 0, 0, 0, 15, 0, + 0, 7, 130, 0, 16, 0, + 5, 0, 0, 0, 70, 0, + 16, 0, 5, 0, 0, 0, + 70, 0, 16, 0, 5, 0, + 0, 0, 56, 0, 0, 7, + 66, 0, 16, 0, 5, 0, + 0, 0, 58, 0, 16, 0, + 5, 0, 0, 0, 42, 0, + 16, 0, 5, 0, 0, 0, + 24, 0, 0, 7, 18, 0, + 16, 0, 6, 0, 0, 0, + 42, 0, 16, 0, 5, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 0, 0, 68, 0, + 0, 5, 66, 0, 16, 0, + 5, 0, 0, 0, 42, 0, + 16, 0, 5, 0, 0, 0, + 56, 0, 0, 7, 98, 0, + 16, 0, 2, 0, 0, 0, + 86, 6, 16, 0, 2, 0, + 0, 0, 166, 8, 16, 0, + 5, 0, 0, 0, 52, 0, + 0, 7, 34, 0, 16, 0, + 2, 0, 0, 0, 26, 0, + 16, 0, 2, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 128, 191, 51, 0, 0, 7, + 34, 0, 16, 0, 2, 0, + 0, 0, 26, 0, 16, 0, + 2, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 128, 63, + 55, 0, 0, 9, 34, 0, + 16, 0, 2, 0, 0, 0, + 10, 0, 16, 0, 6, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 128, 63, 26, 0, + 16, 0, 2, 0, 0, 0, + 0, 0, 0, 8, 66, 0, + 16, 0, 5, 0, 0, 0, + 26, 0, 16, 128, 193, 0, + 0, 0, 2, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 128, 63, 75, 0, 0, 5, + 66, 0, 16, 0, 5, 0, + 0, 0, 42, 0, 16, 0, + 5, 0, 0, 0, 50, 0, + 0, 10, 18, 0, 16, 0, + 6, 0, 0, 0, 26, 0, + 16, 128, 129, 0, 0, 0, + 2, 0, 0, 0, 1, 64, + 0, 0, 48, 110, 153, 188, + 1, 64, 0, 0, 39, 22, + 152, 61, 50, 0, 0, 10, + 18, 0, 16, 0, 6, 0, + 0, 0, 10, 0, 16, 0, + 6, 0, 0, 0, 26, 0, + 16, 128, 129, 0, 0, 0, + 2, 0, 0, 0, 1, 64, + 0, 0, 132, 52, 89, 190, + 50, 0, 0, 10, 18, 0, + 16, 0, 6, 0, 0, 0, + 10, 0, 16, 0, 6, 0, + 0, 0, 26, 0, 16, 128, + 129, 0, 0, 0, 2, 0, + 0, 0, 1, 64, 0, 0, + 164, 13, 201, 63, 56, 0, + 0, 7, 34, 0, 16, 0, + 6, 0, 0, 0, 42, 0, + 16, 0, 5, 0, 0, 0, + 10, 0, 16, 0, 6, 0, + 0, 0, 50, 0, 0, 9, + 34, 0, 16, 0, 6, 0, + 0, 0, 26, 0, 16, 0, + 6, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 0, 192, + 1, 64, 0, 0, 219, 15, + 73, 64, 49, 0, 0, 8, + 34, 0, 16, 0, 2, 0, + 0, 0, 26, 0, 16, 0, + 2, 0, 0, 0, 26, 0, + 16, 128, 65, 0, 0, 0, + 2, 0, 0, 0, 1, 0, + 0, 7, 34, 0, 16, 0, + 2, 0, 0, 0, 26, 0, + 16, 0, 2, 0, 0, 0, + 26, 0, 16, 0, 6, 0, + 0, 0, 50, 0, 0, 9, + 34, 0, 16, 0, 2, 0, + 0, 0, 10, 0, 16, 0, + 6, 0, 0, 0, 42, 0, + 16, 0, 5, 0, 0, 0, + 26, 0, 16, 0, 2, 0, + 0, 0, 86, 0, 0, 5, + 18, 0, 16, 0, 1, 0, + 0, 0, 10, 0, 16, 0, + 1, 0, 0, 0, 14, 0, + 0, 7, 18, 0, 16, 0, + 1, 0, 0, 0, 26, 0, + 16, 0, 2, 0, 0, 0, + 10, 0, 16, 0, 1, 0, + 0, 0, 0, 0, 0, 8, + 50, 0, 16, 0, 6, 0, + 0, 0, 70, 0, 16, 0, + 3, 0, 0, 0, 70, 16, + 16, 128, 65, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 8, 194, 0, 16, 0, + 6, 0, 0, 0, 86, 1, + 16, 128, 65, 0, 0, 0, + 4, 0, 0, 0, 246, 27, + 16, 0, 1, 0, 0, 0, + 56, 0, 0, 7, 34, 0, + 16, 0, 2, 0, 0, 0, + 58, 0, 16, 0, 6, 0, + 0, 0, 26, 0, 16, 0, + 6, 0, 0, 0, 50, 0, + 0, 10, 34, 0, 16, 0, + 2, 0, 0, 0, 10, 0, + 16, 0, 6, 0, 0, 0, + 42, 0, 16, 0, 6, 0, + 0, 0, 26, 0, 16, 128, + 65, 0, 0, 0, 2, 0, + 0, 0, 24, 0, 0, 7, + 66, 0, 16, 0, 5, 0, + 0, 0, 26, 0, 16, 0, + 2, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 0, 0, + 50, 0, 0, 10, 18, 0, + 16, 0, 2, 0, 0, 0, + 10, 0, 16, 0, 2, 0, + 0, 0, 26, 0, 16, 0, + 5, 0, 0, 0, 42, 0, + 16, 128, 65, 0, 0, 0, + 2, 0, 0, 0, 55, 0, + 0, 9, 18, 0, 16, 0, + 2, 0, 0, 0, 42, 0, + 16, 0, 5, 0, 0, 0, + 10, 0, 16, 0, 2, 0, + 0, 0, 26, 0, 16, 0, + 2, 0, 0, 0, 49, 0, + 0, 7, 18, 0, 16, 0, + 2, 0, 0, 0, 10, 0, + 16, 0, 2, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 0, 0, 55, 0, 0, 10, + 130, 32, 16, 0, 2, 0, + 0, 0, 10, 0, 16, 0, + 2, 0, 0, 0, 10, 0, + 16, 128, 65, 0, 0, 0, + 1, 0, 0, 0, 10, 0, + 16, 0, 1, 0, 0, 0, + 86, 0, 0, 5, 18, 0, + 16, 0, 1, 0, 0, 0, + 58, 0, 16, 0, 1, 0, + 0, 0, 0, 0, 0, 8, + 130, 0, 16, 0, 1, 0, + 0, 0, 58, 0, 16, 128, + 65, 0, 0, 0, 0, 0, + 0, 0, 10, 0, 16, 0, + 0, 0, 0, 0, 0, 0, + 0, 8, 18, 32, 16, 0, + 2, 0, 0, 0, 58, 0, + 16, 128, 193, 0, 0, 0, + 1, 0, 0, 0, 10, 0, + 16, 0, 1, 0, 0, 0, + 35, 0, 0, 9, 66, 0, + 16, 0, 1, 0, 0, 0, + 26, 0, 16, 0, 1, 0, + 0, 0, 1, 64, 0, 0, + 0, 4, 0, 0, 42, 0, + 16, 0, 1, 0, 0, 0, + 86, 0, 0, 5, 66, 32, + 16, 0, 2, 0, 0, 0, + 42, 0, 16, 0, 1, 0, + 0, 0, 15, 0, 0, 7, + 66, 0, 16, 0, 1, 0, + 0, 0, 70, 0, 16, 0, + 5, 0, 0, 0, 70, 16, + 16, 0, 2, 0, 0, 0, + 15, 0, 0, 7, 130, 0, + 16, 0, 1, 0, 0, 0, + 70, 16, 16, 0, 2, 0, + 0, 0, 70, 16, 16, 0, + 2, 0, 0, 0, 56, 0, + 0, 7, 130, 0, 16, 0, + 1, 0, 0, 0, 58, 0, + 16, 0, 1, 0, 0, 0, + 58, 0, 16, 0, 5, 0, + 0, 0, 24, 0, 0, 7, + 18, 0, 16, 0, 2, 0, + 0, 0, 58, 0, 16, 0, + 1, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 0, 0, + 68, 0, 0, 5, 130, 0, + 16, 0, 1, 0, 0, 0, + 58, 0, 16, 0, 1, 0, + 0, 0, 56, 0, 0, 7, + 66, 0, 16, 0, 1, 0, + 0, 0, 58, 0, 16, 0, + 1, 0, 0, 0, 42, 0, + 16, 0, 1, 0, 0, 0, + 52, 0, 0, 7, 66, 0, + 16, 0, 1, 0, 0, 0, + 42, 0, 16, 0, 1, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 128, 191, 51, 0, + 0, 7, 66, 0, 16, 0, + 1, 0, 0, 0, 42, 0, + 16, 0, 1, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 128, 63, 55, 0, 0, 9, + 66, 0, 16, 0, 1, 0, + 0, 0, 10, 0, 16, 0, + 2, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 128, 63, + 42, 0, 16, 0, 1, 0, + 0, 0, 0, 0, 0, 8, + 130, 0, 16, 0, 1, 0, + 0, 0, 42, 0, 16, 128, + 193, 0, 0, 0, 1, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 128, 63, 75, 0, + 0, 5, 130, 0, 16, 0, + 1, 0, 0, 0, 58, 0, + 16, 0, 1, 0, 0, 0, + 50, 0, 0, 10, 18, 0, + 16, 0, 2, 0, 0, 0, + 42, 0, 16, 128, 129, 0, + 0, 0, 1, 0, 0, 0, + 1, 64, 0, 0, 48, 110, + 153, 188, 1, 64, 0, 0, + 39, 22, 152, 61, 50, 0, + 0, 10, 18, 0, 16, 0, + 2, 0, 0, 0, 10, 0, + 16, 0, 2, 0, 0, 0, + 42, 0, 16, 128, 129, 0, + 0, 0, 1, 0, 0, 0, + 1, 64, 0, 0, 132, 52, + 89, 190, 50, 0, 0, 10, + 18, 0, 16, 0, 2, 0, + 0, 0, 10, 0, 16, 0, + 2, 0, 0, 0, 42, 0, + 16, 128, 129, 0, 0, 0, + 1, 0, 0, 0, 1, 64, + 0, 0, 164, 13, 201, 63, + 56, 0, 0, 7, 34, 0, + 16, 0, 2, 0, 0, 0, + 58, 0, 16, 0, 1, 0, + 0, 0, 10, 0, 16, 0, + 2, 0, 0, 0, 50, 0, + 0, 9, 34, 0, 16, 0, + 2, 0, 0, 0, 26, 0, + 16, 0, 2, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 0, 192, 1, 64, 0, 0, + 219, 15, 73, 64, 49, 0, + 0, 8, 66, 0, 16, 0, + 1, 0, 0, 0, 42, 0, + 16, 0, 1, 0, 0, 0, + 42, 0, 16, 128, 65, 0, + 0, 0, 1, 0, 0, 0, + 1, 0, 0, 7, 66, 0, + 16, 0, 1, 0, 0, 0, + 42, 0, 16, 0, 1, 0, + 0, 0, 26, 0, 16, 0, + 2, 0, 0, 0, 50, 0, + 0, 9, 66, 0, 16, 0, + 1, 0, 0, 0, 10, 0, + 16, 0, 2, 0, 0, 0, + 58, 0, 16, 0, 1, 0, + 0, 0, 42, 0, 16, 0, + 1, 0, 0, 0, 86, 0, + 0, 5, 34, 0, 16, 0, + 1, 0, 0, 0, 26, 0, + 16, 0, 1, 0, 0, 0, + 32, 0, 0, 7, 130, 0, + 16, 0, 1, 0, 0, 0, + 58, 0, 16, 0, 2, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 0, 10, 0, 0, + 0, 7, 18, 0, 16, 0, + 2, 0, 0, 0, 26, 0, + 16, 0, 1, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 0, 192, 55, 0, 0, 9, + 34, 0, 16, 0, 1, 0, + 0, 0, 58, 0, 16, 0, + 1, 0, 0, 0, 10, 0, + 16, 0, 2, 0, 0, 0, + 26, 0, 16, 0, 1, 0, + 0, 0, 14, 0, 0, 7, + 34, 0, 16, 0, 1, 0, + 0, 0, 42, 0, 16, 0, + 1, 0, 0, 0, 26, 0, + 16, 0, 1, 0, 0, 0, + 56, 0, 0, 7, 66, 0, + 16, 0, 1, 0, 0, 0, + 26, 0, 16, 0, 5, 0, + 0, 0, 10, 16, 16, 0, + 2, 0, 0, 0, 50, 0, + 0, 10, 66, 0, 16, 0, + 1, 0, 0, 0, 10, 0, + 16, 0, 5, 0, 0, 0, + 26, 16, 16, 0, 2, 0, + 0, 0, 42, 0, 16, 128, + 65, 0, 0, 0, 1, 0, + 0, 0, 49, 0, 0, 7, + 66, 0, 16, 0, 1, 0, + 0, 0, 42, 0, 16, 0, + 1, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 0, 0, + 55, 0, 0, 10, 66, 32, + 16, 0, 3, 0, 0, 0, + 42, 0, 16, 0, 1, 0, + 0, 0, 26, 0, 16, 128, + 65, 0, 0, 0, 1, 0, + 0, 0, 26, 0, 16, 0, + 1, 0, 0, 0, 49, 0, + 0, 7, 18, 0, 16, 0, + 0, 0, 0, 0, 10, 0, + 16, 0, 0, 0, 0, 0, + 42, 0, 16, 0, 0, 0, + 0, 0, 60, 0, 0, 7, + 66, 0, 16, 0, 0, 0, + 0, 0, 58, 16, 16, 0, + 3, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 128, 0, + 55, 0, 0, 9, 18, 32, + 16, 0, 4, 0, 0, 0, + 10, 0, 16, 0, 0, 0, + 0, 0, 42, 0, 16, 0, + 0, 0, 0, 0, 58, 16, + 16, 0, 3, 0, 0, 0, + 50, 0, 0, 9, 18, 32, + 16, 0, 5, 0, 0, 0, + 58, 0, 16, 0, 0, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 128, 58, 1, 64, + 0, 0, 0, 0, 128, 191, + 49, 0, 0, 8, 18, 0, + 16, 0, 0, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 0, 0, 26, 128, 32, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 49, 0, 0, 8, + 66, 0, 16, 0, 0, 0, + 0, 0, 26, 128, 32, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 0, 0, 30, 0, + 0, 8, 18, 0, 16, 0, + 0, 0, 0, 0, 10, 0, + 16, 128, 65, 0, 0, 0, + 0, 0, 0, 0, 42, 0, + 16, 0, 0, 0, 0, 0, + 43, 0, 0, 5, 18, 0, + 16, 0, 0, 0, 0, 0, + 10, 0, 16, 0, 0, 0, + 0, 0, 50, 0, 0, 11, + 34, 32, 16, 0, 5, 0, + 0, 0, 26, 0, 16, 0, + 0, 0, 0, 0, 26, 128, + 32, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 10, 0, + 16, 128, 65, 0, 0, 0, + 0, 0, 0, 0, 54, 0, + 0, 5, 194, 0, 16, 0, + 4, 0, 0, 0, 6, 20, + 16, 0, 0, 0, 0, 0, + 54, 0, 0, 5, 242, 32, + 16, 0, 0, 0, 0, 0, + 230, 4, 16, 0, 4, 0, + 0, 0, 54, 0, 0, 5, + 194, 0, 16, 0, 3, 0, + 0, 0, 166, 30, 16, 0, + 1, 0, 0, 0, 54, 0, + 0, 5, 242, 32, 16, 0, + 1, 0, 0, 0, 70, 14, + 16, 0, 3, 0, 0, 0, + 54, 0, 0, 5, 34, 32, + 16, 0, 2, 0, 0, 0, + 10, 0, 16, 0, 1, 0, + 0, 0, 54, 0, 0, 8, + 194, 32, 16, 0, 5, 0, + 0, 0, 2, 64, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 128, 63, 54, 0, + 0, 5, 50, 32, 16, 0, + 3, 0, 0, 0, 70, 16, + 16, 0, 2, 0, 0, 0, + 62, 0, 0, 1, 83, 84, + 65, 84, 148, 0, 0, 0, + 76, 1, 0, 0, 10, 0, + 0, 0, 0, 0, 0, 0, + 11, 0, 0, 0, 223, 0, + 0, 0, 11, 0, 0, 0, + 20, 0, 0, 0, 5, 0, + 0, 0, 5, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 4, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 16, 0, + 0, 0, 31, 0, 0, 0, + 8, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0 +}; diff --git a/third_party/rive_renderer/source/generated/shaders/draw_clockwise_image_mesh.exports.h b/third_party/rive_renderer/source/generated/shaders/draw_clockwise_image_mesh.exports.h new file mode 100644 index 0000000..7d86e26 --- /dev/null +++ b/third_party/rive_renderer/source/generated/shaders/draw_clockwise_image_mesh.exports.h @@ -0,0 +1,208 @@ +#pragma once + +#define GLSL_ATLAS_BLIT "CB" +#define GLSL_ATLAS_BLIT_raw CB +#define GLSL_ATLAS_FEATHERED_FILL "QE" +#define GLSL_ATLAS_FEATHERED_FILL_raw QE +#define GLSL_ATLAS_FEATHERED_STROKE "SE" +#define GLSL_ATLAS_FEATHERED_STROKE_raw SE +#define GLSL_BASE_INSTANCE_UNIFORM_NAME "ED" +#define GLSL_BASE_INSTANCE_UNIFORM_NAME_raw ED +#define GLSL_BORROWED_COVERAGE_PREPASS "OC" +#define GLSL_BORROWED_COVERAGE_PREPASS_raw OC +#define GLSL_CLEAR_CLIP "OE" +#define GLSL_CLEAR_CLIP_raw OE +#define GLSL_CLEAR_COLOR "RD" +#define GLSL_CLEAR_COLOR_raw RD +#define GLSL_CLEAR_COVERAGE "NE" +#define GLSL_CLEAR_COVERAGE_raw NE +#define GLSL_CLOCKWISE_FILL "AD" +#define GLSL_CLOCKWISE_FILL_raw AD +#define GLSL_COALESCED_PLS_RESOLVE_AND_TRANSFER "LC" +#define GLSL_COALESCED_PLS_RESOLVE_AND_TRANSFER_raw LC +#define GLSL_COLOR_PLANE_IDX_OVERRIDE "LD" +#define GLSL_COLOR_PLANE_IDX_OVERRIDE_raw LD +#define GLSL_DISABLE_SHADER_STORAGE_BUFFERS "FE" +#define GLSL_DISABLE_SHADER_STORAGE_BUFFERS_raw FE +#define GLSL_DRAW_IMAGE "UC" +#define GLSL_DRAW_IMAGE_raw UC +#define GLSL_DRAW_IMAGE_MESH "UD" +#define GLSL_DRAW_IMAGE_MESH_raw UD +#define GLSL_DRAW_IMAGE_RECT "TC" +#define GLSL_DRAW_IMAGE_RECT_raw TC +#define GLSL_DRAW_INTERIOR_TRIANGLES "GB" +#define GLSL_DRAW_INTERIOR_TRIANGLES_raw GB +#define GLSL_DRAW_PATH "KC" +#define GLSL_DRAW_PATH_raw KC +#define GLSL_DRAW_RENDER_TARGET_UPDATE_BOUNDS "VD" +#define GLSL_DRAW_RENDER_TARGET_UPDATE_BOUNDS_raw VD +#define GLSL_ENABLE_ADVANCED_BLEND "FB" +#define GLSL_ENABLE_ADVANCED_BLEND_raw FB +#define GLSL_ENABLE_CLIPPING "T" +#define GLSL_ENABLE_CLIPPING_raw T +#define GLSL_ENABLE_CLIP_RECT "BB" +#define GLSL_ENABLE_CLIP_RECT_raw BB +#define GLSL_ENABLE_EVEN_ODD "IC" +#define GLSL_ENABLE_EVEN_ODD_raw IC +#define GLSL_ENABLE_FEATHER "EB" +#define GLSL_ENABLE_FEATHER_raw EB +#define GLSL_ENABLE_HSL_BLEND_MODES "XB" +#define GLSL_ENABLE_HSL_BLEND_MODES_raw XB +#define GLSL_ENABLE_INSTANCE_INDEX "OD" +#define GLSL_ENABLE_INSTANCE_INDEX_raw OD +#define GLSL_ENABLE_KHR_BLEND "KD" +#define GLSL_ENABLE_KHR_BLEND_raw KD +#define GLSL_ENABLE_MIN_16_PRECISION "PD" +#define GLSL_ENABLE_MIN_16_PRECISION_raw PD +#define GLSL_ENABLE_NESTED_CLIPPING "CD" +#define GLSL_ENABLE_NESTED_CLIPPING_raw CD +#define GLSL_ENABLE_RASTERIZER_ORDERED_VIEWS "QD" +#define GLSL_ENABLE_RASTERIZER_ORDERED_VIEWS_raw QD +#define GLSL_ENABLE_TYPED_UAV_LOAD_STORE "FC" +#define GLSL_ENABLE_TYPED_UAV_LOAD_STORE_raw FC +#define GLSL_FIXED_FUNCTION_COLOR_OUTPUT "QB" +#define GLSL_FIXED_FUNCTION_COLOR_OUTPUT_raw QB +#define GLSL_FRAGMENT "HB" +#define GLSL_FRAGMENT_raw HB +#define GLSL_FRAMEBUFFER_BOTTOM_UP "DE" +#define GLSL_FRAMEBUFFER_BOTTOM_UP_raw DE +#define GLSL_FlushUniforms "VB" +#define GLSL_FlushUniforms_raw VB +#define GLSL_GLSL_VERSION "WB" +#define GLSL_GLSL_VERSION_raw WB +#define GLSL_INITIALIZE_PLS "WD" +#define GLSL_INITIALIZE_PLS_raw WD +#define GLSL_ImageDrawUniforms "EC" +#define GLSL_ImageDrawUniforms_raw EC +#define GLSL_LOAD_COLOR "TD" +#define GLSL_LOAD_COLOR_raw TD +#define GLSL_OPTIONALLY_FLAT "OB" +#define GLSL_OPTIONALLY_FLAT_raw OB +#define GLSL_PLS_BLEND_SRC_OVER "ZB" +#define GLSL_PLS_BLEND_SRC_OVER_raw ZB +#define GLSL_PLS_IMPL_ANGLE "_EXPORTED_PLS_IMPL_ANGLE" +#define GLSL_PLS_IMPL_ANGLE_raw _EXPORTED_PLS_IMPL_ANGLE +#define GLSL_PLS_IMPL_DEVICE_BUFFER "LE" +#define GLSL_PLS_IMPL_DEVICE_BUFFER_raw LE +#define GLSL_PLS_IMPL_DEVICE_BUFFER_RASTER_ORDERED "ME" +#define GLSL_PLS_IMPL_DEVICE_BUFFER_RASTER_ORDERED_raw ME +#define GLSL_PLS_IMPL_EXT_NATIVE "GE" +#define GLSL_PLS_IMPL_EXT_NATIVE_raw GE +#define GLSL_PLS_IMPL_FRAMEBUFFER_FETCH "HE" +#define GLSL_PLS_IMPL_FRAMEBUFFER_FETCH_raw HE +#define GLSL_PLS_IMPL_NONE "KE" +#define GLSL_PLS_IMPL_NONE_raw KE +#define GLSL_PLS_IMPL_STORAGE_TEXTURE "IE" +#define GLSL_PLS_IMPL_STORAGE_TEXTURE_raw IE +#define GLSL_PLS_IMPL_SUBPASS_LOAD "JE" +#define GLSL_PLS_IMPL_SUBPASS_LOAD_raw JE +#define GLSL_POST_INVERT_Y "EE" +#define GLSL_POST_INVERT_Y_raw EE +#define GLSL_RENDER_MODE_MSAA "DB" +#define GLSL_RENDER_MODE_MSAA_raw DB +#define GLSL_RESOLVE_PLS "HC" +#define GLSL_RESOLVE_PLS_raw HC +#define GLSL_STORE_COLOR "FD" +#define GLSL_STORE_COLOR_raw FD +#define GLSL_STORE_COLOR_CLEAR "XD" +#define GLSL_STORE_COLOR_CLEAR_raw XD +#define GLSL_SWIZZLE_COLOR_BGRA_TO_RGBA "YD" +#define GLSL_SWIZZLE_COLOR_BGRA_TO_RGBA_raw YD +#define GLSL_TARGET_VULKAN "CC" +#define GLSL_TARGET_VULKAN_raw CC +#define GLSL_TESS_TEXTURE_FLOATING_POINT "CE" +#define GLSL_TESS_TEXTURE_FLOATING_POINT_raw CE +#define GLSL_USE_TEXEL_FETCH_WITH_FRAG_COORD "NC" +#define GLSL_USE_TEXEL_FETCH_WITH_FRAG_COORD_raw NC +#define GLSL_USING_PLS_STORAGE_TEXTURES "DD" +#define GLSL_USING_PLS_STORAGE_TEXTURES_raw DD +#define GLSL_VERTEX "AB" +#define GLSL_VERTEX_raw AB +#define GLSL_VULKAN_VENDOR_ID "BD" +#define GLSL_VULKAN_VENDOR_ID_raw BD +#define GLSL_a_args "RB" +#define GLSL_a_args_raw RB +#define GLSL_a_color0 "YC" +#define GLSL_a_color0_raw YC +#define GLSL_a_color1 "ZC" +#define GLSL_a_color1_raw ZC +#define GLSL_a_contourIDWithFlags "JD" +#define GLSL_a_contourIDWithFlags_raw JD +#define GLSL_a_imageRectVertex "YB" +#define GLSL_a_imageRectVertex_raw YB +#define GLSL_a_joinTan_and_ys "GC" +#define GLSL_a_joinTan_and_ys_raw GC +#define GLSL_a_mirroredVertexData "MB" +#define GLSL_a_mirroredVertexData_raw MB +#define GLSL_a_p0p1_ "RC" +#define GLSL_a_p0p1__raw RC +#define GLSL_a_p2p3_ "SC" +#define GLSL_a_p2p3__raw SC +#define GLSL_a_patchVertexData "LB" +#define GLSL_a_patchVertexData_raw LB +#define GLSL_a_position "SB" +#define GLSL_a_position_raw SB +#define GLSL_a_reflectionX0X1 "HD" +#define GLSL_a_reflectionX0X1_raw HD +#define GLSL_a_segmentCounts "ID" +#define GLSL_a_segmentCounts_raw ID +#define GLSL_a_span "AC" +#define GLSL_a_span_raw AC +#define GLSL_a_spanX "WC" +#define GLSL_a_spanX_raw WC +#define GLSL_a_texCoord "TB" +#define GLSL_a_texCoord_raw TB +#define GLSL_a_triangleVertex "IB" +#define GLSL_a_triangleVertex_raw IB +#define GLSL_a_x0x1 "GD" +#define GLSL_a_x0x1_raw GD +#define GLSL_a_yWithFlags "XC" +#define GLSL_a_yWithFlags_raw XC +#define GLSL_atlasFillFragmentMain "RE" +#define GLSL_atlasFillFragmentMain_raw RE +#define GLSL_atlasStrokeFragmentMain "TE" +#define GLSL_atlasStrokeFragmentMain_raw TE +#define GLSL_atlasTexture "ND" +#define GLSL_atlasTexture_raw ND +#define GLSL_atlasVertexMain "PE" +#define GLSL_atlasVertexMain_raw PE +#define GLSL_blitFragmentMain "MD" +#define GLSL_blitFragmentMain_raw MD +#define GLSL_blitVertexMain "ZD" +#define GLSL_blitVertexMain_raw ZD +#define GLSL_clearColor "SD" +#define GLSL_clearColor_raw SD +#define GLSL_colorRampFragmentMain "BE" +#define GLSL_colorRampFragmentMain_raw BE +#define GLSL_colorRampVertexMain "AE" +#define GLSL_colorRampVertexMain_raw AE +#define GLSL_contourBuffer "QC" +#define GLSL_contourBuffer_raw QC +#define GLSL_drawFragmentMain "NB" +#define GLSL_drawFragmentMain_raw NB +#define GLSL_drawVertexMain "PB" +#define GLSL_drawVertexMain_raw PB +#define GLSL_dstColorTexture "PC" +#define GLSL_dstColorTexture_raw PC +#define GLSL_featherTexture "JC" +#define GLSL_featherTexture_raw JC +#define GLSL_gradTexture "MC" +#define GLSL_gradTexture_raw MC +#define GLSL_imageTexture "UB" +#define GLSL_imageTexture_raw UB +#define GLSL_paintAuxBuffer "KB" +#define GLSL_paintAuxBuffer_raw KB +#define GLSL_paintBuffer "DC" +#define GLSL_paintBuffer_raw DC +#define GLSL_pathBuffer "JB" +#define GLSL_pathBuffer_raw JB +#define GLSL_sourceTexture "VC" +#define GLSL_sourceTexture_raw VC +#define GLSL_stencilVertexMain "UE" +#define GLSL_stencilVertexMain_raw UE +#define GLSL_tessVertexTexture "BC" +#define GLSL_tessVertexTexture_raw BC +#define GLSL_tessellateFragmentMain "WE" +#define GLSL_tessellateFragmentMain_raw WE +#define GLSL_tessellateVertexMain "VE" +#define GLSL_tessellateVertexMain_raw VE diff --git a/third_party/rive_renderer/source/generated/shaders/draw_clockwise_image_mesh.glsl.hpp b/third_party/rive_renderer/source/generated/shaders/draw_clockwise_image_mesh.glsl.hpp new file mode 100644 index 0000000..20b7ac2 --- /dev/null +++ b/third_party/rive_renderer/source/generated/shaders/draw_clockwise_image_mesh.glsl.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include "draw_clockwise_image_mesh.exports.h" + +namespace rive { +namespace gpu { +namespace glsl { +const char draw_clockwise_image_mesh[] = R"===(#ifdef AB +U0(a2)i0(0,c,SB);V0 U0(v2)i0(1,c,TB);V0 +#endif +o1 n0 H(0,c,q0);p1 +#ifdef AB +P2 Q2 N4(PB,a2,c2,v2,w2,n){l0(n,c2,SB,c);l0(n,w2,TB,c);L(q0,c);c J=C0(D1(m0.H6),SB)+m0.S0;q0=TB;f Q=F2(J);P(q0);h1(Q);} +#endif +#ifdef HB +R2 C2(Y5,W8,UB);S2 p4 G3(X8,B3)q4 w3 x3 e2(i,NB){N(q0,c);i n7=o4(UB,B3,q0);n7=E1(Y3(n7),n7.w*m0.H2);f2(n7);} +#endif +)==="; +} // namespace glsl +} // namespace gpu +} // namespace rive \ No newline at end of file diff --git a/third_party/rive_renderer/source/generated/shaders/draw_clockwise_image_mesh.minified.glsl b/third_party/rive_renderer/source/generated/shaders/draw_clockwise_image_mesh.minified.glsl new file mode 100644 index 0000000..6d4172b --- /dev/null +++ b/third_party/rive_renderer/source/generated/shaders/draw_clockwise_image_mesh.minified.glsl @@ -0,0 +1,10 @@ +#ifdef VERTEX +U0(a2)i0(0,c,SB);V0 U0(v2)i0(1,c,TB);V0 +#endif +o1 n0 H(0,c,q0);p1 +#ifdef VERTEX +P2 Q2 N4(PB,a2,c2,v2,w2,n){l0(n,c2,SB,c);l0(n,w2,TB,c);L(q0,c);c J=C0(D1(m0.H6),SB)+m0.S0;q0=TB;f Q=F2(J);P(q0);h1(Q);} +#endif +#ifdef FRAGMENT +R2 C2(Y5,W8,UB);S2 p4 G3(X8,B3)q4 w3 x3 e2(i,NB){N(q0,c);i n7=o4(UB,B3,q0);n7=E1(Y3(n7),n7.w*m0.H2);f2(n7);} +#endif diff --git a/third_party/rive_renderer/source/generated/shaders/draw_clockwise_path.exports.h b/third_party/rive_renderer/source/generated/shaders/draw_clockwise_path.exports.h new file mode 100644 index 0000000..7d86e26 --- /dev/null +++ b/third_party/rive_renderer/source/generated/shaders/draw_clockwise_path.exports.h @@ -0,0 +1,208 @@ +#pragma once + +#define GLSL_ATLAS_BLIT "CB" +#define GLSL_ATLAS_BLIT_raw CB +#define GLSL_ATLAS_FEATHERED_FILL "QE" +#define GLSL_ATLAS_FEATHERED_FILL_raw QE +#define GLSL_ATLAS_FEATHERED_STROKE "SE" +#define GLSL_ATLAS_FEATHERED_STROKE_raw SE +#define GLSL_BASE_INSTANCE_UNIFORM_NAME "ED" +#define GLSL_BASE_INSTANCE_UNIFORM_NAME_raw ED +#define GLSL_BORROWED_COVERAGE_PREPASS "OC" +#define GLSL_BORROWED_COVERAGE_PREPASS_raw OC +#define GLSL_CLEAR_CLIP "OE" +#define GLSL_CLEAR_CLIP_raw OE +#define GLSL_CLEAR_COLOR "RD" +#define GLSL_CLEAR_COLOR_raw RD +#define GLSL_CLEAR_COVERAGE "NE" +#define GLSL_CLEAR_COVERAGE_raw NE +#define GLSL_CLOCKWISE_FILL "AD" +#define GLSL_CLOCKWISE_FILL_raw AD +#define GLSL_COALESCED_PLS_RESOLVE_AND_TRANSFER "LC" +#define GLSL_COALESCED_PLS_RESOLVE_AND_TRANSFER_raw LC +#define GLSL_COLOR_PLANE_IDX_OVERRIDE "LD" +#define GLSL_COLOR_PLANE_IDX_OVERRIDE_raw LD +#define GLSL_DISABLE_SHADER_STORAGE_BUFFERS "FE" +#define GLSL_DISABLE_SHADER_STORAGE_BUFFERS_raw FE +#define GLSL_DRAW_IMAGE "UC" +#define GLSL_DRAW_IMAGE_raw UC +#define GLSL_DRAW_IMAGE_MESH "UD" +#define GLSL_DRAW_IMAGE_MESH_raw UD +#define GLSL_DRAW_IMAGE_RECT "TC" +#define GLSL_DRAW_IMAGE_RECT_raw TC +#define GLSL_DRAW_INTERIOR_TRIANGLES "GB" +#define GLSL_DRAW_INTERIOR_TRIANGLES_raw GB +#define GLSL_DRAW_PATH "KC" +#define GLSL_DRAW_PATH_raw KC +#define GLSL_DRAW_RENDER_TARGET_UPDATE_BOUNDS "VD" +#define GLSL_DRAW_RENDER_TARGET_UPDATE_BOUNDS_raw VD +#define GLSL_ENABLE_ADVANCED_BLEND "FB" +#define GLSL_ENABLE_ADVANCED_BLEND_raw FB +#define GLSL_ENABLE_CLIPPING "T" +#define GLSL_ENABLE_CLIPPING_raw T +#define GLSL_ENABLE_CLIP_RECT "BB" +#define GLSL_ENABLE_CLIP_RECT_raw BB +#define GLSL_ENABLE_EVEN_ODD "IC" +#define GLSL_ENABLE_EVEN_ODD_raw IC +#define GLSL_ENABLE_FEATHER "EB" +#define GLSL_ENABLE_FEATHER_raw EB +#define GLSL_ENABLE_HSL_BLEND_MODES "XB" +#define GLSL_ENABLE_HSL_BLEND_MODES_raw XB +#define GLSL_ENABLE_INSTANCE_INDEX "OD" +#define GLSL_ENABLE_INSTANCE_INDEX_raw OD +#define GLSL_ENABLE_KHR_BLEND "KD" +#define GLSL_ENABLE_KHR_BLEND_raw KD +#define GLSL_ENABLE_MIN_16_PRECISION "PD" +#define GLSL_ENABLE_MIN_16_PRECISION_raw PD +#define GLSL_ENABLE_NESTED_CLIPPING "CD" +#define GLSL_ENABLE_NESTED_CLIPPING_raw CD +#define GLSL_ENABLE_RASTERIZER_ORDERED_VIEWS "QD" +#define GLSL_ENABLE_RASTERIZER_ORDERED_VIEWS_raw QD +#define GLSL_ENABLE_TYPED_UAV_LOAD_STORE "FC" +#define GLSL_ENABLE_TYPED_UAV_LOAD_STORE_raw FC +#define GLSL_FIXED_FUNCTION_COLOR_OUTPUT "QB" +#define GLSL_FIXED_FUNCTION_COLOR_OUTPUT_raw QB +#define GLSL_FRAGMENT "HB" +#define GLSL_FRAGMENT_raw HB +#define GLSL_FRAMEBUFFER_BOTTOM_UP "DE" +#define GLSL_FRAMEBUFFER_BOTTOM_UP_raw DE +#define GLSL_FlushUniforms "VB" +#define GLSL_FlushUniforms_raw VB +#define GLSL_GLSL_VERSION "WB" +#define GLSL_GLSL_VERSION_raw WB +#define GLSL_INITIALIZE_PLS "WD" +#define GLSL_INITIALIZE_PLS_raw WD +#define GLSL_ImageDrawUniforms "EC" +#define GLSL_ImageDrawUniforms_raw EC +#define GLSL_LOAD_COLOR "TD" +#define GLSL_LOAD_COLOR_raw TD +#define GLSL_OPTIONALLY_FLAT "OB" +#define GLSL_OPTIONALLY_FLAT_raw OB +#define GLSL_PLS_BLEND_SRC_OVER "ZB" +#define GLSL_PLS_BLEND_SRC_OVER_raw ZB +#define GLSL_PLS_IMPL_ANGLE "_EXPORTED_PLS_IMPL_ANGLE" +#define GLSL_PLS_IMPL_ANGLE_raw _EXPORTED_PLS_IMPL_ANGLE +#define GLSL_PLS_IMPL_DEVICE_BUFFER "LE" +#define GLSL_PLS_IMPL_DEVICE_BUFFER_raw LE +#define GLSL_PLS_IMPL_DEVICE_BUFFER_RASTER_ORDERED "ME" +#define GLSL_PLS_IMPL_DEVICE_BUFFER_RASTER_ORDERED_raw ME +#define GLSL_PLS_IMPL_EXT_NATIVE "GE" +#define GLSL_PLS_IMPL_EXT_NATIVE_raw GE +#define GLSL_PLS_IMPL_FRAMEBUFFER_FETCH "HE" +#define GLSL_PLS_IMPL_FRAMEBUFFER_FETCH_raw HE +#define GLSL_PLS_IMPL_NONE "KE" +#define GLSL_PLS_IMPL_NONE_raw KE +#define GLSL_PLS_IMPL_STORAGE_TEXTURE "IE" +#define GLSL_PLS_IMPL_STORAGE_TEXTURE_raw IE +#define GLSL_PLS_IMPL_SUBPASS_LOAD "JE" +#define GLSL_PLS_IMPL_SUBPASS_LOAD_raw JE +#define GLSL_POST_INVERT_Y "EE" +#define GLSL_POST_INVERT_Y_raw EE +#define GLSL_RENDER_MODE_MSAA "DB" +#define GLSL_RENDER_MODE_MSAA_raw DB +#define GLSL_RESOLVE_PLS "HC" +#define GLSL_RESOLVE_PLS_raw HC +#define GLSL_STORE_COLOR "FD" +#define GLSL_STORE_COLOR_raw FD +#define GLSL_STORE_COLOR_CLEAR "XD" +#define GLSL_STORE_COLOR_CLEAR_raw XD +#define GLSL_SWIZZLE_COLOR_BGRA_TO_RGBA "YD" +#define GLSL_SWIZZLE_COLOR_BGRA_TO_RGBA_raw YD +#define GLSL_TARGET_VULKAN "CC" +#define GLSL_TARGET_VULKAN_raw CC +#define GLSL_TESS_TEXTURE_FLOATING_POINT "CE" +#define GLSL_TESS_TEXTURE_FLOATING_POINT_raw CE +#define GLSL_USE_TEXEL_FETCH_WITH_FRAG_COORD "NC" +#define GLSL_USE_TEXEL_FETCH_WITH_FRAG_COORD_raw NC +#define GLSL_USING_PLS_STORAGE_TEXTURES "DD" +#define GLSL_USING_PLS_STORAGE_TEXTURES_raw DD +#define GLSL_VERTEX "AB" +#define GLSL_VERTEX_raw AB +#define GLSL_VULKAN_VENDOR_ID "BD" +#define GLSL_VULKAN_VENDOR_ID_raw BD +#define GLSL_a_args "RB" +#define GLSL_a_args_raw RB +#define GLSL_a_color0 "YC" +#define GLSL_a_color0_raw YC +#define GLSL_a_color1 "ZC" +#define GLSL_a_color1_raw ZC +#define GLSL_a_contourIDWithFlags "JD" +#define GLSL_a_contourIDWithFlags_raw JD +#define GLSL_a_imageRectVertex "YB" +#define GLSL_a_imageRectVertex_raw YB +#define GLSL_a_joinTan_and_ys "GC" +#define GLSL_a_joinTan_and_ys_raw GC +#define GLSL_a_mirroredVertexData "MB" +#define GLSL_a_mirroredVertexData_raw MB +#define GLSL_a_p0p1_ "RC" +#define GLSL_a_p0p1__raw RC +#define GLSL_a_p2p3_ "SC" +#define GLSL_a_p2p3__raw SC +#define GLSL_a_patchVertexData "LB" +#define GLSL_a_patchVertexData_raw LB +#define GLSL_a_position "SB" +#define GLSL_a_position_raw SB +#define GLSL_a_reflectionX0X1 "HD" +#define GLSL_a_reflectionX0X1_raw HD +#define GLSL_a_segmentCounts "ID" +#define GLSL_a_segmentCounts_raw ID +#define GLSL_a_span "AC" +#define GLSL_a_span_raw AC +#define GLSL_a_spanX "WC" +#define GLSL_a_spanX_raw WC +#define GLSL_a_texCoord "TB" +#define GLSL_a_texCoord_raw TB +#define GLSL_a_triangleVertex "IB" +#define GLSL_a_triangleVertex_raw IB +#define GLSL_a_x0x1 "GD" +#define GLSL_a_x0x1_raw GD +#define GLSL_a_yWithFlags "XC" +#define GLSL_a_yWithFlags_raw XC +#define GLSL_atlasFillFragmentMain "RE" +#define GLSL_atlasFillFragmentMain_raw RE +#define GLSL_atlasStrokeFragmentMain "TE" +#define GLSL_atlasStrokeFragmentMain_raw TE +#define GLSL_atlasTexture "ND" +#define GLSL_atlasTexture_raw ND +#define GLSL_atlasVertexMain "PE" +#define GLSL_atlasVertexMain_raw PE +#define GLSL_blitFragmentMain "MD" +#define GLSL_blitFragmentMain_raw MD +#define GLSL_blitVertexMain "ZD" +#define GLSL_blitVertexMain_raw ZD +#define GLSL_clearColor "SD" +#define GLSL_clearColor_raw SD +#define GLSL_colorRampFragmentMain "BE" +#define GLSL_colorRampFragmentMain_raw BE +#define GLSL_colorRampVertexMain "AE" +#define GLSL_colorRampVertexMain_raw AE +#define GLSL_contourBuffer "QC" +#define GLSL_contourBuffer_raw QC +#define GLSL_drawFragmentMain "NB" +#define GLSL_drawFragmentMain_raw NB +#define GLSL_drawVertexMain "PB" +#define GLSL_drawVertexMain_raw PB +#define GLSL_dstColorTexture "PC" +#define GLSL_dstColorTexture_raw PC +#define GLSL_featherTexture "JC" +#define GLSL_featherTexture_raw JC +#define GLSL_gradTexture "MC" +#define GLSL_gradTexture_raw MC +#define GLSL_imageTexture "UB" +#define GLSL_imageTexture_raw UB +#define GLSL_paintAuxBuffer "KB" +#define GLSL_paintAuxBuffer_raw KB +#define GLSL_paintBuffer "DC" +#define GLSL_paintBuffer_raw DC +#define GLSL_pathBuffer "JB" +#define GLSL_pathBuffer_raw JB +#define GLSL_sourceTexture "VC" +#define GLSL_sourceTexture_raw VC +#define GLSL_stencilVertexMain "UE" +#define GLSL_stencilVertexMain_raw UE +#define GLSL_tessVertexTexture "BC" +#define GLSL_tessVertexTexture_raw BC +#define GLSL_tessellateFragmentMain "WE" +#define GLSL_tessellateFragmentMain_raw WE +#define GLSL_tessellateVertexMain "VE" +#define GLSL_tessellateVertexMain_raw VE diff --git a/third_party/rive_renderer/source/generated/shaders/draw_clockwise_path.glsl.hpp b/third_party/rive_renderer/source/generated/shaders/draw_clockwise_path.glsl.hpp new file mode 100644 index 0000000..60353aa --- /dev/null +++ b/third_party/rive_renderer/source/generated/shaders/draw_clockwise_path.glsl.hpp @@ -0,0 +1,121 @@ +#pragma once + +#include "draw_clockwise_path.exports.h" + +namespace rive { +namespace gpu { +namespace glsl { +const char draw_clockwise_path[] = R"===(#ifdef KC +#ifdef AB +U0(f0)i0(0,f,LB);i0(1,f,MB);V0 +#endif +o1 L2 H(0,a0,j0);n0 H(1,f,D);n0 H(2,c,Q0);L2 H(3,N0,V2);H(4,c,c3);p1 +#ifdef AB +q1(PB,f0,B,n,K){l0(n,B,LB,f);l0(n,B,MB,f);L(j0,a0);L(D,f);L(V2,N0);L(c3,c);f Q;uint R;c J;if(E6(LB,MB,K,R,J,D Y1)){M L3=w0(JB,R*4u+3u);j0=R;V2=L3.xy;c3=J+uintBitsToFloat(L3.zw);Q=F2(J);}else{Q=f(q.C1,q.C1,q.C1,q.C1);}P(j0);P(D);P(V2);P(c3);h1(Q);} +#endif +#endif +#ifdef GB +#ifdef AB +U0(f0)i0(0,a4,IB);V0 +#endif +o1 L2 H(0,a0,j0); +#ifdef CB +n0 H(1,c,Q0); +#else +OB H(1,g,i1);L2 H(2,N0,V2);H(3,c,c3); +#endif +p1 +#ifdef AB +q1(PB,f0,B,n,K){l0(n,B,IB,Z); +#ifdef CB +L(Q0,c); +#else +#endif +L(j0,a0); +#ifdef CB +L(Q0,c); +#else +L(i1,g);L(V2,N0);L(c3,c); +#endif +uint R;c J; +#ifdef CB +J=a8(IB,R,Q0 Y1); +#else +J=c8(IB,R,i1 Y1);M L3=w0(JB,R*4u+3u);V2=L3.xy;c3=J+uintBitsToFloat(L3.zw); +#endif +j0=Q1(R);f Q=F2(J);P(j0); +#ifdef CB +P(Q0); +#else +P(i1);P(V2);P(c3); +#endif +h1(Q);} +#endif +#endif +#ifdef HB +w3 g4(l8,W9,DC);h4(m8,X9,KB);Jd(vd,Kf,h5);x3 +#ifdef OC +d void Kd(g o7,uint N1){uint cb=uint(abs(o7)*Z8+.5);uint db=q.Z2|(c6-cb);uint W2=c9(h5,N1,db);if(W2>=q.Z2){uint Ld=W2-max(W2,db);eb(h5,N1,Ld-cb);}} +#endif +d void Md(i4(float)d3,g r0,uint N1){if(min(d3,r0)>=1.){return;}g m;uint Nd=uint(abs(r0)*Z8+.5);uint W2=c9(h5,N1,q.Z2|Nd);if(W2=1.&&(d9=(q.Z2|c6))){return;}g m=.0;uint e9=uint(abs(M3)*Z8+.5);if(d9.0){uint Qd=eb(h5,N1,e9);g g2=N8(int((Qd&Y8)-c6))*a9;g e3=g2+M3;g2=clamp(g2,.0,1.);e3=clamp(e3,.0,1.);g hb=1.-g2*d3;if(hb<=.0)discard;m+=(1.-m*d3)*(e3-g2)/hb;}d3*=m;}e2(i,NB){N(j0,a0); +#ifdef Lf +N(D,f); +#elif defined(CB) +N(Q0,c); +#else +N(i1,g); +#endif +#ifndef CB +N(V2,N0);N(c3,c); +#endif +i I2;uint R=j0;N0 F0=k4(DC,R);uint J1=F0.x&0xfu;if(J1<=q8){I2=unpackUnorm4x8(F0.y);}else{S D0=D1(w0(KB,R*4u));f S0=w0(KB,R*4u+1u);c G2=C0(D0,y0)+S0.xy;if(J1!=ud){float t=J1==O6?G2.x:length(G2);t=clamp(t,.0,1.);float x=t*S0.z+S0.w;float y=uintBitsToFloat(F0.y);I2=T1(MC,r8,c(x,y),.0);}else{float H2=uintBitsToFloat(F0.y);float d6=S0.z;I2=T1(UB,B3,G2,d6);I2=E1(Y3(I2),I2.w*H2);}}if(I2.w==.0){discard;} +#ifdef CB +I2.w*=W6(Q0,q.U4 x1); +#else +uint N1=V2.x;uint Rd=V2.y;N0 i5=N0(floor(c3));N1+=(i5.y>>5)*(Rd<<5)+(i5.x>>5)*(32<<5);N1+=((i5.x&0x1f)>>2)*(32<<2)+((i5.y&0x1f)>>2)*(4<<2);N1+=(i5.y&0x3)*4+(i5.x&0x3); +#ifdef OC +if(OC){ +#ifdef GB +g o7=-i1; +#else +g r0; +#ifdef EB +if(EB&&S6(D)){r0=S4(D x1);}else +#endif +{r0=D.x;}g o7=max(-r0,.0); +#endif +Kd(o7,N1);discard;} +#endif +#ifndef GB +if(U6(D)){g r0; +#ifdef EB +if(EB&&w8(D)){r0=R6(D x1);}else +#endif +{r0=min(D.x,D.y);}r0=clamp(r0,.0,1.);Md(I2.w,r0,N1);}else +#endif +{ +#ifdef GB +g r0=i1; +#else +g r0; +#ifdef EB +if(EB&&S6(D)){r0=S4(D x1);}else +#endif +{r0=D.x;}r0=clamp(r0,.0,1.); +#endif +Od(I2.w,r0,N1);} +#endif +f2(I2);} +#endif +)==="; +} // namespace glsl +} // namespace gpu +} // namespace rive \ No newline at end of file diff --git a/third_party/rive_renderer/source/generated/shaders/draw_clockwise_path.minified.glsl b/third_party/rive_renderer/source/generated/shaders/draw_clockwise_path.minified.glsl new file mode 100644 index 0000000..6383edd --- /dev/null +++ b/third_party/rive_renderer/source/generated/shaders/draw_clockwise_path.minified.glsl @@ -0,0 +1,110 @@ +#ifdef DRAW_PATH +#ifdef VERTEX +U0(f0)i0(0,f,LB);i0(1,f,MB);V0 +#endif +o1 L2 H(0,a0,j0);n0 H(1,f,D);n0 H(2,c,Q0);L2 H(3,N0,V2);H(4,c,c3);p1 +#ifdef VERTEX +q1(PB,f0,B,n,K){l0(n,B,LB,f);l0(n,B,MB,f);L(j0,a0);L(D,f);L(V2,N0);L(c3,c);f Q;uint R;c J;if(E6(LB,MB,K,R,J,D Y1)){M L3=w0(JB,R*4u+3u);j0=R;V2=L3.xy;c3=J+uintBitsToFloat(L3.zw);Q=F2(J);}else{Q=f(q.C1,q.C1,q.C1,q.C1);}P(j0);P(D);P(V2);P(c3);h1(Q);} +#endif +#endif +#ifdef DRAW_INTERIOR_TRIANGLES +#ifdef VERTEX +U0(f0)i0(0,a4,IB);V0 +#endif +o1 L2 H(0,a0,j0); +#ifdef ATLAS_BLIT +n0 H(1,c,Q0); +#else +OPTIONALLY_FLAT H(1,g,i1);L2 H(2,N0,V2);H(3,c,c3); +#endif +p1 +#ifdef VERTEX +q1(PB,f0,B,n,K){l0(n,B,IB,Z); +#ifdef ATLAS_BLIT +L(Q0,c); +#else +#endif +L(j0,a0); +#ifdef ATLAS_BLIT +L(Q0,c); +#else +L(i1,g);L(V2,N0);L(c3,c); +#endif +uint R;c J; +#ifdef ATLAS_BLIT +J=a8(IB,R,Q0 Y1); +#else +J=c8(IB,R,i1 Y1);M L3=w0(JB,R*4u+3u);V2=L3.xy;c3=J+uintBitsToFloat(L3.zw); +#endif +j0=Q1(R);f Q=F2(J);P(j0); +#ifdef ATLAS_BLIT +P(Q0); +#else +P(i1);P(V2);P(c3); +#endif +h1(Q);} +#endif +#endif +#ifdef FRAGMENT +w3 g4(l8,W9,DC);h4(m8,X9,KB);Jd(vd,Kf,h5);x3 +#ifdef BORROWED_COVERAGE_PREPASS +d void Kd(g o7,uint N1){uint cb=uint(abs(o7)*Z8+.5);uint db=q.Z2|(c6-cb);uint W2=c9(h5,N1,db);if(W2>=q.Z2){uint Ld=W2-max(W2,db);eb(h5,N1,Ld-cb);}} +#endif +d void Md(i4(float)d3,g r0,uint N1){if(min(d3,r0)>=1.){return;}g m;uint Nd=uint(abs(r0)*Z8+.5);uint W2=c9(h5,N1,q.Z2|Nd);if(W2=1.&&(d9=(q.Z2|c6))){return;}g m=.0;uint e9=uint(abs(M3)*Z8+.5);if(d9.0){uint Qd=eb(h5,N1,e9);g g2=N8(int((Qd&Y8)-c6))*a9;g e3=g2+M3;g2=clamp(g2,.0,1.);e3=clamp(e3,.0,1.);g hb=1.-g2*d3;if(hb<=.0)discard;m+=(1.-m*d3)*(e3-g2)/hb;}d3*=m;}e2(i,NB){N(j0,a0); +#ifdef Lf +N(D,f); +#elif defined(ATLAS_BLIT) +N(Q0,c); +#else +N(i1,g); +#endif +#ifndef ATLAS_BLIT +N(V2,N0);N(c3,c); +#endif +i I2;uint R=j0;N0 F0=k4(DC,R);uint J1=F0.x&0xfu;if(J1<=q8){I2=unpackUnorm4x8(F0.y);}else{S D0=D1(w0(KB,R*4u));f S0=w0(KB,R*4u+1u);c G2=C0(D0,y0)+S0.xy;if(J1!=ud){float t=J1==O6?G2.x:length(G2);t=clamp(t,.0,1.);float x=t*S0.z+S0.w;float y=uintBitsToFloat(F0.y);I2=T1(MC,r8,c(x,y),.0);}else{float H2=uintBitsToFloat(F0.y);float d6=S0.z;I2=T1(UB,B3,G2,d6);I2=E1(Y3(I2),I2.w*H2);}}if(I2.w==.0){discard;} +#ifdef ATLAS_BLIT +I2.w*=W6(Q0,q.U4 x1); +#else +uint N1=V2.x;uint Rd=V2.y;N0 i5=N0(floor(c3));N1+=(i5.y>>5)*(Rd<<5)+(i5.x>>5)*(32<<5);N1+=((i5.x&0x1f)>>2)*(32<<2)+((i5.y&0x1f)>>2)*(4<<2);N1+=(i5.y&0x3)*4+(i5.x&0x3); +#ifdef BORROWED_COVERAGE_PREPASS +if(BORROWED_COVERAGE_PREPASS){ +#ifdef DRAW_INTERIOR_TRIANGLES +g o7=-i1; +#else +g r0; +#ifdef ENABLE_FEATHER +if(ENABLE_FEATHER&&S6(D)){r0=S4(D x1);}else +#endif +{r0=D.x;}g o7=max(-r0,.0); +#endif +Kd(o7,N1);discard;} +#endif +#ifndef DRAW_INTERIOR_TRIANGLES +if(U6(D)){g r0; +#ifdef ENABLE_FEATHER +if(ENABLE_FEATHER&&w8(D)){r0=R6(D x1);}else +#endif +{r0=min(D.x,D.y);}r0=clamp(r0,.0,1.);Md(I2.w,r0,N1);}else +#endif +{ +#ifdef DRAW_INTERIOR_TRIANGLES +g r0=i1; +#else +g r0; +#ifdef ENABLE_FEATHER +if(ENABLE_FEATHER&&S6(D)){r0=S4(D x1);}else +#endif +{r0=D.x;}r0=clamp(r0,.0,1.); +#endif +Od(I2.w,r0,N1);} +#endif +f2(I2);} +#endif diff --git a/third_party/rive_renderer/source/generated/shaders/draw_combinations.metal b/third_party/rive_renderer/source/generated/shaders/draw_combinations.metal new file mode 100644 index 0000000..5561996 --- /dev/null +++ b/third_party/rive_renderer/source/generated/shaders/draw_combinations.metal @@ -0,0 +1,188 @@ +#define VERTEX +#define ENABLE_CLIPPING 1 +#define ENABLE_CLIP_RECT 1 +#define ENABLE_ADVANCED_BLEND 1 +#define ENABLE_FEATHER 1 +namespace p111100000 +{ +#include "draw_path.minified.glsl" +} +#undef ENABLE_CLIPPING +#undef ENABLE_CLIP_RECT +#undef ENABLE_ADVANCED_BLEND +#undef ENABLE_FEATHER +#undef VERTEX + +#define FRAGMENT +#define ENABLE_CLIPPING 1 +#define ENABLE_NESTED_CLIPPING 1 +#define ENABLE_ADVANCED_BLEND 1 +#define ENABLE_EVEN_ODD 1 +#define ENABLE_HSL_BLEND_MODES 1 +#define ENABLE_CLIP_RECT 1 +#define ENABLE_FEATHER 1 +namespace p111111100 +{ +#include "draw_path.minified.glsl" +} +#undef ENABLE_CLIPPING +#undef ENABLE_NESTED_CLIPPING +#undef ENABLE_ADVANCED_BLEND +#undef ENABLE_EVEN_ODD +#undef ENABLE_HSL_BLEND_MODES +#undef ENABLE_CLIP_RECT +#undef ENABLE_FEATHER +#undef FRAGMENT + +#define FRAGMENT +#define ENABLE_CLIPPING 1 +#define ENABLE_NESTED_CLIPPING 1 +#define ENABLE_ADVANCED_BLEND 1 +#define ENABLE_EVEN_ODD 1 +#define ENABLE_HSL_BLEND_MODES 1 +#define ENABLE_CLIP_RECT 1 +#define ENABLE_FEATHER 1 +#define CLOCKWISE_FILL 1 +namespace c111111100 +{ +#include "draw_path.minified.glsl" +} +#undef ENABLE_CLIPPING +#undef ENABLE_NESTED_CLIPPING +#undef ENABLE_ADVANCED_BLEND +#undef ENABLE_EVEN_ODD +#undef ENABLE_HSL_BLEND_MODES +#undef ENABLE_CLIP_RECT +#undef ENABLE_FEATHER +#undef FRAGMENT +#undef CLOCKWISE_FILL + +#define VERTEX +#define DRAW_INTERIOR_TRIANGLES 1 +#define ENABLE_CLIPPING 1 +#define ENABLE_ADVANCED_BLEND 1 +#define ENABLE_CLIP_RECT 1 +#define ENABLE_FEATHER 1 +namespace p111100010 +{ +#include "draw_path.minified.glsl" +} +#undef DRAW_INTERIOR_TRIANGLES +#undef ENABLE_CLIPPING +#undef ENABLE_ADVANCED_BLEND +#undef ENABLE_CLIP_RECT +#undef ENABLE_FEATHER +#undef VERTEX + +#define FRAGMENT +#define DRAW_INTERIOR_TRIANGLES 1 +#define ENABLE_CLIPPING 1 +#define ENABLE_NESTED_CLIPPING 1 +#define ENABLE_ADVANCED_BLEND 1 +#define ENABLE_EVEN_ODD 1 +#define ENABLE_HSL_BLEND_MODES 1 +#define ENABLE_CLIP_RECT 1 +#define ENABLE_FEATHER 1 +namespace p111111110 +{ +#include "draw_path.minified.glsl" +} +#undef DRAW_INTERIOR_TRIANGLES +#undef ENABLE_CLIPPING +#undef ENABLE_NESTED_CLIPPING +#undef ENABLE_ADVANCED_BLEND +#undef ENABLE_EVEN_ODD +#undef ENABLE_HSL_BLEND_MODES +#undef ENABLE_CLIP_RECT +#undef ENABLE_FEATHER +#undef FRAGMENT + +#define FRAGMENT +#define DRAW_INTERIOR_TRIANGLES 1 +#define ENABLE_CLIPPING 1 +#define ENABLE_NESTED_CLIPPING 1 +#define ENABLE_ADVANCED_BLEND 1 +#define ENABLE_EVEN_ODD 1 +#define ENABLE_HSL_BLEND_MODES 1 +#define ENABLE_CLIP_RECT 1 +#define ENABLE_FEATHER 1 +#define CLOCKWISE_FILL 1 +namespace c111111110 +{ +#include "draw_path.minified.glsl" +} +#undef DRAW_INTERIOR_TRIANGLES +#undef ENABLE_CLIPPING +#undef ENABLE_NESTED_CLIPPING +#undef ENABLE_ADVANCED_BLEND +#undef ENABLE_EVEN_ODD +#undef ENABLE_HSL_BLEND_MODES +#undef ENABLE_CLIP_RECT +#undef ENABLE_FEATHER +#undef FRAGMENT +#undef CLOCKWISE_FILL + +#define VERTEX +#define ENABLE_ADVANCED_BLEND 1 +#define ENABLE_CLIP_RECT 1 +#define DRAW_INTERIOR_TRIANGLES 1 +#define ENABLE_CLIPPING 1 +#define ATLAS_BLIT 1 +namespace p111000011 +{ +#include "draw_path.minified.glsl" +} +#undef ENABLE_ADVANCED_BLEND +#undef ENABLE_CLIP_RECT +#undef DRAW_INTERIOR_TRIANGLES +#undef ENABLE_CLIPPING +#undef ATLAS_BLIT +#undef VERTEX + +#define FRAGMENT +#define ENABLE_ADVANCED_BLEND 1 +#define ENABLE_HSL_BLEND_MODES 1 +#define DRAW_INTERIOR_TRIANGLES 1 +#define ENABLE_CLIP_RECT 1 +#define ENABLE_CLIPPING 1 +#define ATLAS_BLIT 1 +namespace p111000111 +{ +#include "draw_path.minified.glsl" +} +#undef ENABLE_ADVANCED_BLEND +#undef ENABLE_HSL_BLEND_MODES +#undef DRAW_INTERIOR_TRIANGLES +#undef ENABLE_CLIP_RECT +#undef ENABLE_CLIPPING +#undef ATLAS_BLIT +#undef FRAGMENT + +#define VERTEX +#define ENABLE_CLIPPING 1 +#define ENABLE_CLIP_RECT 1 +#define ENABLE_ADVANCED_BLEND 1 +namespace m111000000 +{ +#include "draw_image_mesh.minified.glsl" +} +#undef ENABLE_CLIPPING +#undef ENABLE_CLIP_RECT +#undef ENABLE_ADVANCED_BLEND +#undef VERTEX + +#define FRAGMENT +#define ENABLE_CLIPPING 1 +#define ENABLE_CLIP_RECT 1 +#define ENABLE_HSL_BLEND_MODES 1 +#define ENABLE_ADVANCED_BLEND 1 +namespace m111000100 +{ +#include "draw_image_mesh.minified.glsl" +} +#undef ENABLE_CLIPPING +#undef ENABLE_CLIP_RECT +#undef ENABLE_HSL_BLEND_MODES +#undef ENABLE_ADVANCED_BLEND +#undef FRAGMENT + diff --git a/third_party/rive_renderer/source/generated/shaders/draw_image_mesh.exports.h b/third_party/rive_renderer/source/generated/shaders/draw_image_mesh.exports.h new file mode 100644 index 0000000..7d86e26 --- /dev/null +++ b/third_party/rive_renderer/source/generated/shaders/draw_image_mesh.exports.h @@ -0,0 +1,208 @@ +#pragma once + +#define GLSL_ATLAS_BLIT "CB" +#define GLSL_ATLAS_BLIT_raw CB +#define GLSL_ATLAS_FEATHERED_FILL "QE" +#define GLSL_ATLAS_FEATHERED_FILL_raw QE +#define GLSL_ATLAS_FEATHERED_STROKE "SE" +#define GLSL_ATLAS_FEATHERED_STROKE_raw SE +#define GLSL_BASE_INSTANCE_UNIFORM_NAME "ED" +#define GLSL_BASE_INSTANCE_UNIFORM_NAME_raw ED +#define GLSL_BORROWED_COVERAGE_PREPASS "OC" +#define GLSL_BORROWED_COVERAGE_PREPASS_raw OC +#define GLSL_CLEAR_CLIP "OE" +#define GLSL_CLEAR_CLIP_raw OE +#define GLSL_CLEAR_COLOR "RD" +#define GLSL_CLEAR_COLOR_raw RD +#define GLSL_CLEAR_COVERAGE "NE" +#define GLSL_CLEAR_COVERAGE_raw NE +#define GLSL_CLOCKWISE_FILL "AD" +#define GLSL_CLOCKWISE_FILL_raw AD +#define GLSL_COALESCED_PLS_RESOLVE_AND_TRANSFER "LC" +#define GLSL_COALESCED_PLS_RESOLVE_AND_TRANSFER_raw LC +#define GLSL_COLOR_PLANE_IDX_OVERRIDE "LD" +#define GLSL_COLOR_PLANE_IDX_OVERRIDE_raw LD +#define GLSL_DISABLE_SHADER_STORAGE_BUFFERS "FE" +#define GLSL_DISABLE_SHADER_STORAGE_BUFFERS_raw FE +#define GLSL_DRAW_IMAGE "UC" +#define GLSL_DRAW_IMAGE_raw UC +#define GLSL_DRAW_IMAGE_MESH "UD" +#define GLSL_DRAW_IMAGE_MESH_raw UD +#define GLSL_DRAW_IMAGE_RECT "TC" +#define GLSL_DRAW_IMAGE_RECT_raw TC +#define GLSL_DRAW_INTERIOR_TRIANGLES "GB" +#define GLSL_DRAW_INTERIOR_TRIANGLES_raw GB +#define GLSL_DRAW_PATH "KC" +#define GLSL_DRAW_PATH_raw KC +#define GLSL_DRAW_RENDER_TARGET_UPDATE_BOUNDS "VD" +#define GLSL_DRAW_RENDER_TARGET_UPDATE_BOUNDS_raw VD +#define GLSL_ENABLE_ADVANCED_BLEND "FB" +#define GLSL_ENABLE_ADVANCED_BLEND_raw FB +#define GLSL_ENABLE_CLIPPING "T" +#define GLSL_ENABLE_CLIPPING_raw T +#define GLSL_ENABLE_CLIP_RECT "BB" +#define GLSL_ENABLE_CLIP_RECT_raw BB +#define GLSL_ENABLE_EVEN_ODD "IC" +#define GLSL_ENABLE_EVEN_ODD_raw IC +#define GLSL_ENABLE_FEATHER "EB" +#define GLSL_ENABLE_FEATHER_raw EB +#define GLSL_ENABLE_HSL_BLEND_MODES "XB" +#define GLSL_ENABLE_HSL_BLEND_MODES_raw XB +#define GLSL_ENABLE_INSTANCE_INDEX "OD" +#define GLSL_ENABLE_INSTANCE_INDEX_raw OD +#define GLSL_ENABLE_KHR_BLEND "KD" +#define GLSL_ENABLE_KHR_BLEND_raw KD +#define GLSL_ENABLE_MIN_16_PRECISION "PD" +#define GLSL_ENABLE_MIN_16_PRECISION_raw PD +#define GLSL_ENABLE_NESTED_CLIPPING "CD" +#define GLSL_ENABLE_NESTED_CLIPPING_raw CD +#define GLSL_ENABLE_RASTERIZER_ORDERED_VIEWS "QD" +#define GLSL_ENABLE_RASTERIZER_ORDERED_VIEWS_raw QD +#define GLSL_ENABLE_TYPED_UAV_LOAD_STORE "FC" +#define GLSL_ENABLE_TYPED_UAV_LOAD_STORE_raw FC +#define GLSL_FIXED_FUNCTION_COLOR_OUTPUT "QB" +#define GLSL_FIXED_FUNCTION_COLOR_OUTPUT_raw QB +#define GLSL_FRAGMENT "HB" +#define GLSL_FRAGMENT_raw HB +#define GLSL_FRAMEBUFFER_BOTTOM_UP "DE" +#define GLSL_FRAMEBUFFER_BOTTOM_UP_raw DE +#define GLSL_FlushUniforms "VB" +#define GLSL_FlushUniforms_raw VB +#define GLSL_GLSL_VERSION "WB" +#define GLSL_GLSL_VERSION_raw WB +#define GLSL_INITIALIZE_PLS "WD" +#define GLSL_INITIALIZE_PLS_raw WD +#define GLSL_ImageDrawUniforms "EC" +#define GLSL_ImageDrawUniforms_raw EC +#define GLSL_LOAD_COLOR "TD" +#define GLSL_LOAD_COLOR_raw TD +#define GLSL_OPTIONALLY_FLAT "OB" +#define GLSL_OPTIONALLY_FLAT_raw OB +#define GLSL_PLS_BLEND_SRC_OVER "ZB" +#define GLSL_PLS_BLEND_SRC_OVER_raw ZB +#define GLSL_PLS_IMPL_ANGLE "_EXPORTED_PLS_IMPL_ANGLE" +#define GLSL_PLS_IMPL_ANGLE_raw _EXPORTED_PLS_IMPL_ANGLE +#define GLSL_PLS_IMPL_DEVICE_BUFFER "LE" +#define GLSL_PLS_IMPL_DEVICE_BUFFER_raw LE +#define GLSL_PLS_IMPL_DEVICE_BUFFER_RASTER_ORDERED "ME" +#define GLSL_PLS_IMPL_DEVICE_BUFFER_RASTER_ORDERED_raw ME +#define GLSL_PLS_IMPL_EXT_NATIVE "GE" +#define GLSL_PLS_IMPL_EXT_NATIVE_raw GE +#define GLSL_PLS_IMPL_FRAMEBUFFER_FETCH "HE" +#define GLSL_PLS_IMPL_FRAMEBUFFER_FETCH_raw HE +#define GLSL_PLS_IMPL_NONE "KE" +#define GLSL_PLS_IMPL_NONE_raw KE +#define GLSL_PLS_IMPL_STORAGE_TEXTURE "IE" +#define GLSL_PLS_IMPL_STORAGE_TEXTURE_raw IE +#define GLSL_PLS_IMPL_SUBPASS_LOAD "JE" +#define GLSL_PLS_IMPL_SUBPASS_LOAD_raw JE +#define GLSL_POST_INVERT_Y "EE" +#define GLSL_POST_INVERT_Y_raw EE +#define GLSL_RENDER_MODE_MSAA "DB" +#define GLSL_RENDER_MODE_MSAA_raw DB +#define GLSL_RESOLVE_PLS "HC" +#define GLSL_RESOLVE_PLS_raw HC +#define GLSL_STORE_COLOR "FD" +#define GLSL_STORE_COLOR_raw FD +#define GLSL_STORE_COLOR_CLEAR "XD" +#define GLSL_STORE_COLOR_CLEAR_raw XD +#define GLSL_SWIZZLE_COLOR_BGRA_TO_RGBA "YD" +#define GLSL_SWIZZLE_COLOR_BGRA_TO_RGBA_raw YD +#define GLSL_TARGET_VULKAN "CC" +#define GLSL_TARGET_VULKAN_raw CC +#define GLSL_TESS_TEXTURE_FLOATING_POINT "CE" +#define GLSL_TESS_TEXTURE_FLOATING_POINT_raw CE +#define GLSL_USE_TEXEL_FETCH_WITH_FRAG_COORD "NC" +#define GLSL_USE_TEXEL_FETCH_WITH_FRAG_COORD_raw NC +#define GLSL_USING_PLS_STORAGE_TEXTURES "DD" +#define GLSL_USING_PLS_STORAGE_TEXTURES_raw DD +#define GLSL_VERTEX "AB" +#define GLSL_VERTEX_raw AB +#define GLSL_VULKAN_VENDOR_ID "BD" +#define GLSL_VULKAN_VENDOR_ID_raw BD +#define GLSL_a_args "RB" +#define GLSL_a_args_raw RB +#define GLSL_a_color0 "YC" +#define GLSL_a_color0_raw YC +#define GLSL_a_color1 "ZC" +#define GLSL_a_color1_raw ZC +#define GLSL_a_contourIDWithFlags "JD" +#define GLSL_a_contourIDWithFlags_raw JD +#define GLSL_a_imageRectVertex "YB" +#define GLSL_a_imageRectVertex_raw YB +#define GLSL_a_joinTan_and_ys "GC" +#define GLSL_a_joinTan_and_ys_raw GC +#define GLSL_a_mirroredVertexData "MB" +#define GLSL_a_mirroredVertexData_raw MB +#define GLSL_a_p0p1_ "RC" +#define GLSL_a_p0p1__raw RC +#define GLSL_a_p2p3_ "SC" +#define GLSL_a_p2p3__raw SC +#define GLSL_a_patchVertexData "LB" +#define GLSL_a_patchVertexData_raw LB +#define GLSL_a_position "SB" +#define GLSL_a_position_raw SB +#define GLSL_a_reflectionX0X1 "HD" +#define GLSL_a_reflectionX0X1_raw HD +#define GLSL_a_segmentCounts "ID" +#define GLSL_a_segmentCounts_raw ID +#define GLSL_a_span "AC" +#define GLSL_a_span_raw AC +#define GLSL_a_spanX "WC" +#define GLSL_a_spanX_raw WC +#define GLSL_a_texCoord "TB" +#define GLSL_a_texCoord_raw TB +#define GLSL_a_triangleVertex "IB" +#define GLSL_a_triangleVertex_raw IB +#define GLSL_a_x0x1 "GD" +#define GLSL_a_x0x1_raw GD +#define GLSL_a_yWithFlags "XC" +#define GLSL_a_yWithFlags_raw XC +#define GLSL_atlasFillFragmentMain "RE" +#define GLSL_atlasFillFragmentMain_raw RE +#define GLSL_atlasStrokeFragmentMain "TE" +#define GLSL_atlasStrokeFragmentMain_raw TE +#define GLSL_atlasTexture "ND" +#define GLSL_atlasTexture_raw ND +#define GLSL_atlasVertexMain "PE" +#define GLSL_atlasVertexMain_raw PE +#define GLSL_blitFragmentMain "MD" +#define GLSL_blitFragmentMain_raw MD +#define GLSL_blitVertexMain "ZD" +#define GLSL_blitVertexMain_raw ZD +#define GLSL_clearColor "SD" +#define GLSL_clearColor_raw SD +#define GLSL_colorRampFragmentMain "BE" +#define GLSL_colorRampFragmentMain_raw BE +#define GLSL_colorRampVertexMain "AE" +#define GLSL_colorRampVertexMain_raw AE +#define GLSL_contourBuffer "QC" +#define GLSL_contourBuffer_raw QC +#define GLSL_drawFragmentMain "NB" +#define GLSL_drawFragmentMain_raw NB +#define GLSL_drawVertexMain "PB" +#define GLSL_drawVertexMain_raw PB +#define GLSL_dstColorTexture "PC" +#define GLSL_dstColorTexture_raw PC +#define GLSL_featherTexture "JC" +#define GLSL_featherTexture_raw JC +#define GLSL_gradTexture "MC" +#define GLSL_gradTexture_raw MC +#define GLSL_imageTexture "UB" +#define GLSL_imageTexture_raw UB +#define GLSL_paintAuxBuffer "KB" +#define GLSL_paintAuxBuffer_raw KB +#define GLSL_paintBuffer "DC" +#define GLSL_paintBuffer_raw DC +#define GLSL_pathBuffer "JB" +#define GLSL_pathBuffer_raw JB +#define GLSL_sourceTexture "VC" +#define GLSL_sourceTexture_raw VC +#define GLSL_stencilVertexMain "UE" +#define GLSL_stencilVertexMain_raw UE +#define GLSL_tessVertexTexture "BC" +#define GLSL_tessVertexTexture_raw BC +#define GLSL_tessellateFragmentMain "WE" +#define GLSL_tessellateFragmentMain_raw WE +#define GLSL_tessellateVertexMain "VE" +#define GLSL_tessellateVertexMain_raw VE diff --git a/third_party/rive_renderer/source/generated/shaders/draw_image_mesh.glsl.hpp b/third_party/rive_renderer/source/generated/shaders/draw_image_mesh.glsl.hpp new file mode 100644 index 0000000..f3f961b --- /dev/null +++ b/third_party/rive_renderer/source/generated/shaders/draw_image_mesh.glsl.hpp @@ -0,0 +1,93 @@ +#pragma once + +#include "draw_image_mesh.exports.h" + +namespace rive { +namespace gpu { +namespace glsl { +const char draw_image_mesh[] = R"===(#ifdef AB +U0(a2)i0(0,c,SB);V0 U0(v2)i0(1,c,TB);V0 +#endif +o1 n0 H(0,c,q0); +#ifdef T +OB H(1,g,j5); +#endif +#ifdef BB +n0 H(2,f,R0); +#endif +p1 +#ifdef AB +P2 Q2 N4(PB,a2,c2,v2,w2,n){l0(n,c2,SB,c);l0(n,w2,TB,c);L(q0,c); +#ifdef T +L(j5,g); +#endif +#ifdef BB +L(R0,f); +#endif +c J=C0(D1(m0.H6),SB)+m0.S0;q0=TB; +#ifdef T +if(T){j5=g7(m0.Z0,q.d5);} +#endif +#ifdef BB +if(BB){ +#ifndef DB +R0=I6(D1(m0.R1),m0.Z1,J); +#else +Ka(D1(m0.R1),m0.Z1,J); +#endif +} +#endif +f Q=F2(J); +#ifdef DB +Q.z=S8(m0.X5); +#endif +P(q0); +#ifdef T +P(j5); +#endif +#ifdef BB +P(R0); +#endif +h1(Q);} +#endif +#ifdef HB +R2 C2(Y5,W8,UB); +#ifdef DB +#ifdef FB +C2(U2,Za,PC); +#endif +#endif +S2 p4 G3(X8,B3)q4 w3 x3 +#ifndef DB +x2 M0(i8,H0);Y0(B5,r1);M0(bb,N3);Y0(k8,x4);y2 R4(NB){N(q0,c); +#ifdef T +N(j5,g); +#endif +#ifdef BB +N(R0,f); +#endif +i j=o4(UB,B3,q0);g E=1.; +#ifdef BB +if(BB){g l4=A8(I5(R0));E=clamp(l4,v1(.0),E);} +#endif +h2; +#ifdef T +if(T&&j5!=.0){G I1=unpackHalf2x16(j1(r1));g k5=I1.y;g Sd=k5==j5?I1.x:v1(.0);E=min(E,Sd);} +#endif +i w1=I0(H0); +#ifdef FB +if(FB&&m0.z3!=B8){j.xyz=M4(Y3(j),w1,Q1(m0.z3))*j.w;} +#endif +j*=m0.H2*E;j+=w1*(1.-j.w);T0(H0,j);i2(r1);i2(x4);j2;M2;} +#else +e2(i,NB){N(q0,c);i j=o4(UB,B3,q0)*m0.H2; +#ifdef FB +if(FB){i w1=d1(PC,c0(floor(y0.xy)));j.xyz=M4(Y3(j),w1,m0.z3);j.xyz*=j.w;} +#endif +f2(j);} +#endif +#endif +)==="; +} // namespace glsl +} // namespace gpu +} // namespace rive \ No newline at end of file diff --git a/third_party/rive_renderer/source/generated/shaders/draw_image_mesh.minified.glsl b/third_party/rive_renderer/source/generated/shaders/draw_image_mesh.minified.glsl new file mode 100644 index 0000000..f6712c2 --- /dev/null +++ b/third_party/rive_renderer/source/generated/shaders/draw_image_mesh.minified.glsl @@ -0,0 +1,82 @@ +#ifdef VERTEX +U0(a2)i0(0,c,SB);V0 U0(v2)i0(1,c,TB);V0 +#endif +o1 n0 H(0,c,q0); +#ifdef ENABLE_CLIPPING +OPTIONALLY_FLAT H(1,g,j5); +#endif +#ifdef ENABLE_CLIP_RECT +n0 H(2,f,R0); +#endif +p1 +#ifdef VERTEX +P2 Q2 N4(PB,a2,c2,v2,w2,n){l0(n,c2,SB,c);l0(n,w2,TB,c);L(q0,c); +#ifdef ENABLE_CLIPPING +L(j5,g); +#endif +#ifdef ENABLE_CLIP_RECT +L(R0,f); +#endif +c J=C0(D1(m0.H6),SB)+m0.S0;q0=TB; +#ifdef ENABLE_CLIPPING +if(ENABLE_CLIPPING){j5=g7(m0.Z0,q.d5);} +#endif +#ifdef ENABLE_CLIP_RECT +if(ENABLE_CLIP_RECT){ +#ifndef RENDER_MODE_MSAA +R0=I6(D1(m0.R1),m0.Z1,J); +#else +Ka(D1(m0.R1),m0.Z1,J); +#endif +} +#endif +f Q=F2(J); +#ifdef RENDER_MODE_MSAA +Q.z=S8(m0.X5); +#endif +P(q0); +#ifdef ENABLE_CLIPPING +P(j5); +#endif +#ifdef ENABLE_CLIP_RECT +P(R0); +#endif +h1(Q);} +#endif +#ifdef FRAGMENT +R2 C2(Y5,W8,UB); +#ifdef RENDER_MODE_MSAA +#ifdef ENABLE_ADVANCED_BLEND +C2(U2,Za,PC); +#endif +#endif +S2 p4 G3(X8,B3)q4 w3 x3 +#ifndef RENDER_MODE_MSAA +x2 M0(i8,H0);Y0(B5,r1);M0(bb,N3);Y0(k8,x4);y2 R4(NB){N(q0,c); +#ifdef ENABLE_CLIPPING +N(j5,g); +#endif +#ifdef ENABLE_CLIP_RECT +N(R0,f); +#endif +i j=o4(UB,B3,q0);g E=1.; +#ifdef ENABLE_CLIP_RECT +if(ENABLE_CLIP_RECT){g l4=A8(I5(R0));E=clamp(l4,v1(.0),E);} +#endif +h2; +#ifdef ENABLE_CLIPPING +if(ENABLE_CLIPPING&&j5!=.0){G I1=unpackHalf2x16(j1(r1));g k5=I1.y;g Sd=k5==j5?I1.x:v1(.0);E=min(E,Sd);} +#endif +i w1=I0(H0); +#ifdef ENABLE_ADVANCED_BLEND +if(ENABLE_ADVANCED_BLEND&&m0.z3!=B8){j.xyz=M4(Y3(j),w1,Q1(m0.z3))*j.w;} +#endif +j*=m0.H2*E;j+=w1*(1.-j.w);T0(H0,j);i2(r1);i2(x4);j2;M2;} +#else +e2(i,NB){N(q0,c);i j=o4(UB,B3,q0)*m0.H2; +#ifdef ENABLE_ADVANCED_BLEND +if(ENABLE_ADVANCED_BLEND){i w1=d1(PC,c0(floor(y0.xy)));j.xyz=M4(Y3(j),w1,m0.z3);j.xyz*=j.w;} +#endif +f2(j);} +#endif +#endif diff --git a/third_party/rive_renderer/source/generated/shaders/draw_path.exports.h b/third_party/rive_renderer/source/generated/shaders/draw_path.exports.h new file mode 100644 index 0000000..7d86e26 --- /dev/null +++ b/third_party/rive_renderer/source/generated/shaders/draw_path.exports.h @@ -0,0 +1,208 @@ +#pragma once + +#define GLSL_ATLAS_BLIT "CB" +#define GLSL_ATLAS_BLIT_raw CB +#define GLSL_ATLAS_FEATHERED_FILL "QE" +#define GLSL_ATLAS_FEATHERED_FILL_raw QE +#define GLSL_ATLAS_FEATHERED_STROKE "SE" +#define GLSL_ATLAS_FEATHERED_STROKE_raw SE +#define GLSL_BASE_INSTANCE_UNIFORM_NAME "ED" +#define GLSL_BASE_INSTANCE_UNIFORM_NAME_raw ED +#define GLSL_BORROWED_COVERAGE_PREPASS "OC" +#define GLSL_BORROWED_COVERAGE_PREPASS_raw OC +#define GLSL_CLEAR_CLIP "OE" +#define GLSL_CLEAR_CLIP_raw OE +#define GLSL_CLEAR_COLOR "RD" +#define GLSL_CLEAR_COLOR_raw RD +#define GLSL_CLEAR_COVERAGE "NE" +#define GLSL_CLEAR_COVERAGE_raw NE +#define GLSL_CLOCKWISE_FILL "AD" +#define GLSL_CLOCKWISE_FILL_raw AD +#define GLSL_COALESCED_PLS_RESOLVE_AND_TRANSFER "LC" +#define GLSL_COALESCED_PLS_RESOLVE_AND_TRANSFER_raw LC +#define GLSL_COLOR_PLANE_IDX_OVERRIDE "LD" +#define GLSL_COLOR_PLANE_IDX_OVERRIDE_raw LD +#define GLSL_DISABLE_SHADER_STORAGE_BUFFERS "FE" +#define GLSL_DISABLE_SHADER_STORAGE_BUFFERS_raw FE +#define GLSL_DRAW_IMAGE "UC" +#define GLSL_DRAW_IMAGE_raw UC +#define GLSL_DRAW_IMAGE_MESH "UD" +#define GLSL_DRAW_IMAGE_MESH_raw UD +#define GLSL_DRAW_IMAGE_RECT "TC" +#define GLSL_DRAW_IMAGE_RECT_raw TC +#define GLSL_DRAW_INTERIOR_TRIANGLES "GB" +#define GLSL_DRAW_INTERIOR_TRIANGLES_raw GB +#define GLSL_DRAW_PATH "KC" +#define GLSL_DRAW_PATH_raw KC +#define GLSL_DRAW_RENDER_TARGET_UPDATE_BOUNDS "VD" +#define GLSL_DRAW_RENDER_TARGET_UPDATE_BOUNDS_raw VD +#define GLSL_ENABLE_ADVANCED_BLEND "FB" +#define GLSL_ENABLE_ADVANCED_BLEND_raw FB +#define GLSL_ENABLE_CLIPPING "T" +#define GLSL_ENABLE_CLIPPING_raw T +#define GLSL_ENABLE_CLIP_RECT "BB" +#define GLSL_ENABLE_CLIP_RECT_raw BB +#define GLSL_ENABLE_EVEN_ODD "IC" +#define GLSL_ENABLE_EVEN_ODD_raw IC +#define GLSL_ENABLE_FEATHER "EB" +#define GLSL_ENABLE_FEATHER_raw EB +#define GLSL_ENABLE_HSL_BLEND_MODES "XB" +#define GLSL_ENABLE_HSL_BLEND_MODES_raw XB +#define GLSL_ENABLE_INSTANCE_INDEX "OD" +#define GLSL_ENABLE_INSTANCE_INDEX_raw OD +#define GLSL_ENABLE_KHR_BLEND "KD" +#define GLSL_ENABLE_KHR_BLEND_raw KD +#define GLSL_ENABLE_MIN_16_PRECISION "PD" +#define GLSL_ENABLE_MIN_16_PRECISION_raw PD +#define GLSL_ENABLE_NESTED_CLIPPING "CD" +#define GLSL_ENABLE_NESTED_CLIPPING_raw CD +#define GLSL_ENABLE_RASTERIZER_ORDERED_VIEWS "QD" +#define GLSL_ENABLE_RASTERIZER_ORDERED_VIEWS_raw QD +#define GLSL_ENABLE_TYPED_UAV_LOAD_STORE "FC" +#define GLSL_ENABLE_TYPED_UAV_LOAD_STORE_raw FC +#define GLSL_FIXED_FUNCTION_COLOR_OUTPUT "QB" +#define GLSL_FIXED_FUNCTION_COLOR_OUTPUT_raw QB +#define GLSL_FRAGMENT "HB" +#define GLSL_FRAGMENT_raw HB +#define GLSL_FRAMEBUFFER_BOTTOM_UP "DE" +#define GLSL_FRAMEBUFFER_BOTTOM_UP_raw DE +#define GLSL_FlushUniforms "VB" +#define GLSL_FlushUniforms_raw VB +#define GLSL_GLSL_VERSION "WB" +#define GLSL_GLSL_VERSION_raw WB +#define GLSL_INITIALIZE_PLS "WD" +#define GLSL_INITIALIZE_PLS_raw WD +#define GLSL_ImageDrawUniforms "EC" +#define GLSL_ImageDrawUniforms_raw EC +#define GLSL_LOAD_COLOR "TD" +#define GLSL_LOAD_COLOR_raw TD +#define GLSL_OPTIONALLY_FLAT "OB" +#define GLSL_OPTIONALLY_FLAT_raw OB +#define GLSL_PLS_BLEND_SRC_OVER "ZB" +#define GLSL_PLS_BLEND_SRC_OVER_raw ZB +#define GLSL_PLS_IMPL_ANGLE "_EXPORTED_PLS_IMPL_ANGLE" +#define GLSL_PLS_IMPL_ANGLE_raw _EXPORTED_PLS_IMPL_ANGLE +#define GLSL_PLS_IMPL_DEVICE_BUFFER "LE" +#define GLSL_PLS_IMPL_DEVICE_BUFFER_raw LE +#define GLSL_PLS_IMPL_DEVICE_BUFFER_RASTER_ORDERED "ME" +#define GLSL_PLS_IMPL_DEVICE_BUFFER_RASTER_ORDERED_raw ME +#define GLSL_PLS_IMPL_EXT_NATIVE "GE" +#define GLSL_PLS_IMPL_EXT_NATIVE_raw GE +#define GLSL_PLS_IMPL_FRAMEBUFFER_FETCH "HE" +#define GLSL_PLS_IMPL_FRAMEBUFFER_FETCH_raw HE +#define GLSL_PLS_IMPL_NONE "KE" +#define GLSL_PLS_IMPL_NONE_raw KE +#define GLSL_PLS_IMPL_STORAGE_TEXTURE "IE" +#define GLSL_PLS_IMPL_STORAGE_TEXTURE_raw IE +#define GLSL_PLS_IMPL_SUBPASS_LOAD "JE" +#define GLSL_PLS_IMPL_SUBPASS_LOAD_raw JE +#define GLSL_POST_INVERT_Y "EE" +#define GLSL_POST_INVERT_Y_raw EE +#define GLSL_RENDER_MODE_MSAA "DB" +#define GLSL_RENDER_MODE_MSAA_raw DB +#define GLSL_RESOLVE_PLS "HC" +#define GLSL_RESOLVE_PLS_raw HC +#define GLSL_STORE_COLOR "FD" +#define GLSL_STORE_COLOR_raw FD +#define GLSL_STORE_COLOR_CLEAR "XD" +#define GLSL_STORE_COLOR_CLEAR_raw XD +#define GLSL_SWIZZLE_COLOR_BGRA_TO_RGBA "YD" +#define GLSL_SWIZZLE_COLOR_BGRA_TO_RGBA_raw YD +#define GLSL_TARGET_VULKAN "CC" +#define GLSL_TARGET_VULKAN_raw CC +#define GLSL_TESS_TEXTURE_FLOATING_POINT "CE" +#define GLSL_TESS_TEXTURE_FLOATING_POINT_raw CE +#define GLSL_USE_TEXEL_FETCH_WITH_FRAG_COORD "NC" +#define GLSL_USE_TEXEL_FETCH_WITH_FRAG_COORD_raw NC +#define GLSL_USING_PLS_STORAGE_TEXTURES "DD" +#define GLSL_USING_PLS_STORAGE_TEXTURES_raw DD +#define GLSL_VERTEX "AB" +#define GLSL_VERTEX_raw AB +#define GLSL_VULKAN_VENDOR_ID "BD" +#define GLSL_VULKAN_VENDOR_ID_raw BD +#define GLSL_a_args "RB" +#define GLSL_a_args_raw RB +#define GLSL_a_color0 "YC" +#define GLSL_a_color0_raw YC +#define GLSL_a_color1 "ZC" +#define GLSL_a_color1_raw ZC +#define GLSL_a_contourIDWithFlags "JD" +#define GLSL_a_contourIDWithFlags_raw JD +#define GLSL_a_imageRectVertex "YB" +#define GLSL_a_imageRectVertex_raw YB +#define GLSL_a_joinTan_and_ys "GC" +#define GLSL_a_joinTan_and_ys_raw GC +#define GLSL_a_mirroredVertexData "MB" +#define GLSL_a_mirroredVertexData_raw MB +#define GLSL_a_p0p1_ "RC" +#define GLSL_a_p0p1__raw RC +#define GLSL_a_p2p3_ "SC" +#define GLSL_a_p2p3__raw SC +#define GLSL_a_patchVertexData "LB" +#define GLSL_a_patchVertexData_raw LB +#define GLSL_a_position "SB" +#define GLSL_a_position_raw SB +#define GLSL_a_reflectionX0X1 "HD" +#define GLSL_a_reflectionX0X1_raw HD +#define GLSL_a_segmentCounts "ID" +#define GLSL_a_segmentCounts_raw ID +#define GLSL_a_span "AC" +#define GLSL_a_span_raw AC +#define GLSL_a_spanX "WC" +#define GLSL_a_spanX_raw WC +#define GLSL_a_texCoord "TB" +#define GLSL_a_texCoord_raw TB +#define GLSL_a_triangleVertex "IB" +#define GLSL_a_triangleVertex_raw IB +#define GLSL_a_x0x1 "GD" +#define GLSL_a_x0x1_raw GD +#define GLSL_a_yWithFlags "XC" +#define GLSL_a_yWithFlags_raw XC +#define GLSL_atlasFillFragmentMain "RE" +#define GLSL_atlasFillFragmentMain_raw RE +#define GLSL_atlasStrokeFragmentMain "TE" +#define GLSL_atlasStrokeFragmentMain_raw TE +#define GLSL_atlasTexture "ND" +#define GLSL_atlasTexture_raw ND +#define GLSL_atlasVertexMain "PE" +#define GLSL_atlasVertexMain_raw PE +#define GLSL_blitFragmentMain "MD" +#define GLSL_blitFragmentMain_raw MD +#define GLSL_blitVertexMain "ZD" +#define GLSL_blitVertexMain_raw ZD +#define GLSL_clearColor "SD" +#define GLSL_clearColor_raw SD +#define GLSL_colorRampFragmentMain "BE" +#define GLSL_colorRampFragmentMain_raw BE +#define GLSL_colorRampVertexMain "AE" +#define GLSL_colorRampVertexMain_raw AE +#define GLSL_contourBuffer "QC" +#define GLSL_contourBuffer_raw QC +#define GLSL_drawFragmentMain "NB" +#define GLSL_drawFragmentMain_raw NB +#define GLSL_drawVertexMain "PB" +#define GLSL_drawVertexMain_raw PB +#define GLSL_dstColorTexture "PC" +#define GLSL_dstColorTexture_raw PC +#define GLSL_featherTexture "JC" +#define GLSL_featherTexture_raw JC +#define GLSL_gradTexture "MC" +#define GLSL_gradTexture_raw MC +#define GLSL_imageTexture "UB" +#define GLSL_imageTexture_raw UB +#define GLSL_paintAuxBuffer "KB" +#define GLSL_paintAuxBuffer_raw KB +#define GLSL_paintBuffer "DC" +#define GLSL_paintBuffer_raw DC +#define GLSL_pathBuffer "JB" +#define GLSL_pathBuffer_raw JB +#define GLSL_sourceTexture "VC" +#define GLSL_sourceTexture_raw VC +#define GLSL_stencilVertexMain "UE" +#define GLSL_stencilVertexMain_raw UE +#define GLSL_tessVertexTexture "BC" +#define GLSL_tessVertexTexture_raw BC +#define GLSL_tessellateFragmentMain "WE" +#define GLSL_tessellateFragmentMain_raw WE +#define GLSL_tessellateVertexMain "VE" +#define GLSL_tessellateVertexMain_raw VE diff --git a/third_party/rive_renderer/source/generated/shaders/draw_path.glsl.hpp b/third_party/rive_renderer/source/generated/shaders/draw_path.glsl.hpp new file mode 100644 index 0000000..023aec0 --- /dev/null +++ b/third_party/rive_renderer/source/generated/shaders/draw_path.glsl.hpp @@ -0,0 +1,294 @@ +#pragma once + +#include "draw_path.exports.h" + +namespace rive { +namespace gpu { +namespace glsl { +const char draw_path[] = R"===(#ifdef FB +#define o6 !FB +#else +#define o6 true +#endif +#ifdef AB +U0(f0) +#ifdef GB +i0(0,a4,IB); +#else +i0(0,f,LB);i0(1,f,MB); +#endif +V0 +#endif +o1 n0 H(0,f,H1); +#ifdef CB +n0 H(1,c,Q0); +#elif!defined(DB) +#ifdef GB +OB H(1,g,i1); +#elif defined(EB) +n0 H(2,f,D); +#else +n0 H(2,G,D); +#endif +OB H(3,g,j0); +#endif +#ifdef T +OB H(4,G,i3); +#endif +#ifdef BB +n0 H(5,f,R0); +#endif +#ifdef FB +OB H(6,g,U3); +#endif +p1 +#ifdef AB +q1(PB,f0,B,n,K){ +#ifdef GB +l0(n,B,IB,Z); +#else +l0(n,B,LB,f);l0(n,B,MB,f); +#endif +L(H1,f); +#ifdef CB +L(Q0,c); +#elif!defined(DB) +#ifdef GB +L(i1,g); +#elif defined(EB) +L(D,f); +#else +L(D,G); +#endif +L(j0,g); +#endif +#ifdef T +L(i3,G); +#endif +#ifdef BB +L(R0,f); +#endif +#ifdef FB +L(U3,g); +#endif +bool Eb=false;uint R;c J; +#ifdef DB +a0 z7; +#endif +#ifdef CB +J=a8(IB,R, +#ifdef DB +z7, +#endif +Q0 Y1); +#elif defined(GB) +J=c8(IB,R +#ifdef DB +,z7 +#else +,i1 +#endif +Y1); +#else +f O;Eb=!E6(LB,MB,K,R,J +#ifndef DB +,O +#else +,z7 +#endif +Y1); +#ifndef DB +#ifdef EB +D=O; +#else +D.xy=F6(O.xy); +#endif +#endif +#endif +N0 F0=k4(DC,R); +#if!defined(CB)&&!defined(DB) +j0=g7(R,q.d5);if((F0.x&p8)!=0u)j0=-j0; +#endif +uint J1=F0.x&0xfu; +#ifdef T +if(T){uint te=(J1==N6?F0.y:F0.x)>>16;g Z0=g7(te,q.d5);if(J1==N6)Z0=-Z0;i3.x=Z0;} +#endif +#ifdef FB +if(FB){U3=float((F0.x>>4)&0xfu);} +#endif +c p6=J; +#ifdef DE +p6.y=float(q.id)-p6.y; +#endif +#ifdef BB +if(BB){S R1=D1(w0(KB,R*4u+2u));f Z1=w0(KB,R*4u+3u); +#ifndef DB +R0=I6(R1,Z1.xy,p6); +#else +Ka(R1,Z1.xy,p6); +#endif +} +#endif +if(J1==q8){i j=unpackUnorm4x8(F0.y);if(o6)j.xyz*=j.w;H1=f(j);} +#ifdef T +else if(T&&J1==N6){g A7=g7(F0.x>>16,q.d5);i3.y=A7;} +#endif +else{S ue=D1(w0(KB,R*4u));f B7=w0(KB,R*4u+1u);c G2=C0(ue,p6)+B7.xy;if(J1==O6||J1==td){H1.w=-uintBitsToFloat(F0.y);float ve=B7.z;if(ve>.9){H1.z=2.;}else{H1.z=B7.w;}if(J1==O6){H1.y=.0;H1.x=G2.x;}else{H1.z=-H1.z;H1.xy=G2.xy;}}else{float H2=uintBitsToFloat(F0.y);float d6=B7.z;H1=f(G2.x,G2.y,H2,-2.-d6);}}f Q;if(!Eb){Q=F2(J); +#ifdef EE +Q.y=-Q.y; +#endif +#ifdef DB +Q.z=S8(z7); +#endif +}else{Q=f(q.C1,q.C1,q.C1,q.C1);}P(H1); +#ifdef CB +P(Q0); +#elif!defined(DB) +#ifdef GB +P(i1); +#elif defined(EB) +P(D); +#else +P(D); +#endif +P(j0); +#endif +#ifdef T +P(i3); +#endif +#ifdef BB +P(R0); +#endif +#ifdef FB +P(U3); +#endif +h1(Q);} +#endif +#ifdef HB +w3 x3 d i Fb(f J2,float E C5){i j;if(J2.w>=.0){j=I5(J2);if(o6)j*=E;else j.w*=E;}else if(J2.w>-1.){float t=J2.z>.0?J2.x:length(J2.xy);t=clamp(t,.0,1.);float Gb=abs(J2.z);float x=Gb>1.?(1.-1./T8)*t+(.5/T8):(1./T8)*t+Gb;float we=-J2.w;j=T1(MC,r8,c(x,we),.0);j.w*=E;if(o6)j.xyz*=j.w;}else{g d6=-J2.w-2.;j=C7(UB,B3,J2.xy,d6);g H2=J2.z*E;if(o6)j*=H2;else j=E1(Y3(j),j.w*H2);}return j;} +#ifndef DB +x2 M0(i8,H0);Y0(B5,r1);M0(bb,N3);Y0(k8,x4);y2 z2(NB){N(H1,f); +#ifdef CB +N(Q0,c); +#elif!defined(DB) +#ifdef GB +N(i1,g); +#elif defined(EB) +N(D,f); +#else +N(D,G); +#endif +N(j0,g); +#endif +#ifdef T +N(i3,G); +#endif +#ifdef BB +N(R0,f); +#endif +#ifdef FB +N(U3,g); +#endif +#if!defined(GB)||defined(CB) +h2; +#endif +g E; +#ifdef CB +E=W6(Q0,q.U4 x1); +#else +G L3=unpackHalf2x16(j1(x4));g Hb=L3.y;g F1=Hb==j0?L3.x:v1(.0); +#ifdef GB +F1+=i1;i2(x4); +#else +if(U6(D)){g r0; +#ifdef EB +if(EB&&w8(D)){r0=R6(D x1);}else +#endif +{r0=min(D.x,D.y);}F1=max(r0,F1);}else{g r0; +#if defined(EB) +if(EB&&S6(D)){r0=S4(D x1);}else +#endif +{r0=D.x;}F1+=r0;}l1(x4,packHalf2x16(Z3(F1,j0))); +#endif +#ifdef AD +if(AD){ +#ifdef BD +if(BD==yd){if(F1<.0)E=.0;else if(F1<=1.)E=F1;else E=1.;}else +#endif +{E=clamp(F1,v1(.0),v1(1.));}}else +#endif +{E=abs(F1); +#ifdef IC +if(IC&&j0<.0){E=1.-v1(abs(fract(E*.5)*2.+-1.));} +#endif +E=min(E,v1(1.));} +#endif +#ifdef T +if(T&&i3.x<.0){g Z0=-i3.x; +#ifdef CD +if(CD){g A7=i3.y;if(A7!=.0){G I1=unpackHalf2x16(j1(r1));g k5=I1.y;g D7;if(k5!=Z0){D7=k5==A7?I1.x:.0; +#ifndef GB +T0(N3,E1(D7,.0,.0,.0)); +#endif +}else{D7=I0(N3).x; +#ifndef GB +E2(N3); +#endif +}E=min(E,D7);}} +#endif +l1(r1,packHalf2x16(Z3(E,Z0)));E2(H0);}else +#endif +{ +#ifdef T +if(T){g Z0=i3.x;if(Z0!=.0){G I1=unpackHalf2x16(j1(r1));g k5=I1.y;E=(k5==Z0)?min(I1.x,E):v1(.0);}} +#endif +#ifdef BB +if(BB){g l4=A8(I5(R0));E=clamp(l4,v1(.0),E);} +#endif +i j=Fb(H1,E Y2);i w1; +#ifdef CB +w1=I0(H0); +#else +if(Hb!=j0){w1=I0(H0); +#ifndef GB +T0(N3,w1); +#endif +}else{w1=I0(N3); +#ifndef GB +E2(N3); +#endif +} +#endif +#ifdef FB +if(FB){if(U3!=f7(B8)){j.xyz=M4(j.xyz,w1,O8(U3));}j.xyz*=j.w;} +#endif +j+=w1*(1.-j.w);T0(H0,j);i2(r1);} +#if!defined(GB)||defined(CB) +j2; +#endif +M2;} +#else +e2(i,NB){N(H1,f); +#ifdef CB +N(Q0,c); +#endif +#ifdef FB +N(U3,g); +#endif +g E= +#ifdef CB +W6(Q0,q.U4 x1); +#else +1.; +#endif +i j=Fb(H1,E Y2); +#ifdef FB +if(FB){i w1=d1(PC,c0(floor(y0.xy)));j.xyz=M4(j.xyz,w1,O8(U3));j.xyz*=j.w;} +#endif +f2(j);} +#endif +#endif +)==="; +} // namespace glsl +} // namespace gpu +} // namespace rive \ No newline at end of file diff --git a/third_party/rive_renderer/source/generated/shaders/draw_path.minified.glsl b/third_party/rive_renderer/source/generated/shaders/draw_path.minified.glsl new file mode 100644 index 0000000..c9bd340 --- /dev/null +++ b/third_party/rive_renderer/source/generated/shaders/draw_path.minified.glsl @@ -0,0 +1,283 @@ +#ifdef ENABLE_ADVANCED_BLEND +#define o6 !ENABLE_ADVANCED_BLEND +#else +#define o6 true +#endif +#ifdef VERTEX +U0(f0) +#ifdef DRAW_INTERIOR_TRIANGLES +i0(0,a4,IB); +#else +i0(0,f,LB);i0(1,f,MB); +#endif +V0 +#endif +o1 n0 H(0,f,H1); +#ifdef ATLAS_BLIT +n0 H(1,c,Q0); +#elif!defined(RENDER_MODE_MSAA) +#ifdef DRAW_INTERIOR_TRIANGLES +OPTIONALLY_FLAT H(1,g,i1); +#elif defined(ENABLE_FEATHER) +n0 H(2,f,D); +#else +n0 H(2,G,D); +#endif +OPTIONALLY_FLAT H(3,g,j0); +#endif +#ifdef ENABLE_CLIPPING +OPTIONALLY_FLAT H(4,G,i3); +#endif +#ifdef ENABLE_CLIP_RECT +n0 H(5,f,R0); +#endif +#ifdef ENABLE_ADVANCED_BLEND +OPTIONALLY_FLAT H(6,g,U3); +#endif +p1 +#ifdef VERTEX +q1(PB,f0,B,n,K){ +#ifdef DRAW_INTERIOR_TRIANGLES +l0(n,B,IB,Z); +#else +l0(n,B,LB,f);l0(n,B,MB,f); +#endif +L(H1,f); +#ifdef ATLAS_BLIT +L(Q0,c); +#elif!defined(RENDER_MODE_MSAA) +#ifdef DRAW_INTERIOR_TRIANGLES +L(i1,g); +#elif defined(ENABLE_FEATHER) +L(D,f); +#else +L(D,G); +#endif +L(j0,g); +#endif +#ifdef ENABLE_CLIPPING +L(i3,G); +#endif +#ifdef ENABLE_CLIP_RECT +L(R0,f); +#endif +#ifdef ENABLE_ADVANCED_BLEND +L(U3,g); +#endif +bool Eb=false;uint R;c J; +#ifdef RENDER_MODE_MSAA +a0 z7; +#endif +#ifdef ATLAS_BLIT +J=a8(IB,R, +#ifdef RENDER_MODE_MSAA +z7, +#endif +Q0 Y1); +#elif defined(DRAW_INTERIOR_TRIANGLES) +J=c8(IB,R +#ifdef RENDER_MODE_MSAA +,z7 +#else +,i1 +#endif +Y1); +#else +f O;Eb=!E6(LB,MB,K,R,J +#ifndef RENDER_MODE_MSAA +,O +#else +,z7 +#endif +Y1); +#ifndef RENDER_MODE_MSAA +#ifdef ENABLE_FEATHER +D=O; +#else +D.xy=F6(O.xy); +#endif +#endif +#endif +N0 F0=k4(DC,R); +#if!defined(ATLAS_BLIT)&&!defined(RENDER_MODE_MSAA) +j0=g7(R,q.d5);if((F0.x&p8)!=0u)j0=-j0; +#endif +uint J1=F0.x&0xfu; +#ifdef ENABLE_CLIPPING +if(ENABLE_CLIPPING){uint te=(J1==N6?F0.y:F0.x)>>16;g Z0=g7(te,q.d5);if(J1==N6)Z0=-Z0;i3.x=Z0;} +#endif +#ifdef ENABLE_ADVANCED_BLEND +if(ENABLE_ADVANCED_BLEND){U3=float((F0.x>>4)&0xfu);} +#endif +c p6=J; +#ifdef FRAMEBUFFER_BOTTOM_UP +p6.y=float(q.id)-p6.y; +#endif +#ifdef ENABLE_CLIP_RECT +if(ENABLE_CLIP_RECT){S R1=D1(w0(KB,R*4u+2u));f Z1=w0(KB,R*4u+3u); +#ifndef RENDER_MODE_MSAA +R0=I6(R1,Z1.xy,p6); +#else +Ka(R1,Z1.xy,p6); +#endif +} +#endif +if(J1==q8){i j=unpackUnorm4x8(F0.y);if(o6)j.xyz*=j.w;H1=f(j);} +#ifdef ENABLE_CLIPPING +else if(ENABLE_CLIPPING&&J1==N6){g A7=g7(F0.x>>16,q.d5);i3.y=A7;} +#endif +else{S ue=D1(w0(KB,R*4u));f B7=w0(KB,R*4u+1u);c G2=C0(ue,p6)+B7.xy;if(J1==O6||J1==td){H1.w=-uintBitsToFloat(F0.y);float ve=B7.z;if(ve>.9){H1.z=2.;}else{H1.z=B7.w;}if(J1==O6){H1.y=.0;H1.x=G2.x;}else{H1.z=-H1.z;H1.xy=G2.xy;}}else{float H2=uintBitsToFloat(F0.y);float d6=B7.z;H1=f(G2.x,G2.y,H2,-2.-d6);}}f Q;if(!Eb){Q=F2(J); +#ifdef POST_INVERT_Y +Q.y=-Q.y; +#endif +#ifdef RENDER_MODE_MSAA +Q.z=S8(z7); +#endif +}else{Q=f(q.C1,q.C1,q.C1,q.C1);}P(H1); +#ifdef ATLAS_BLIT +P(Q0); +#elif!defined(RENDER_MODE_MSAA) +#ifdef DRAW_INTERIOR_TRIANGLES +P(i1); +#elif defined(ENABLE_FEATHER) +P(D); +#else +P(D); +#endif +P(j0); +#endif +#ifdef ENABLE_CLIPPING +P(i3); +#endif +#ifdef ENABLE_CLIP_RECT +P(R0); +#endif +#ifdef ENABLE_ADVANCED_BLEND +P(U3); +#endif +h1(Q);} +#endif +#ifdef FRAGMENT +w3 x3 d i Fb(f J2,float E C5){i j;if(J2.w>=.0){j=I5(J2);if(o6)j*=E;else j.w*=E;}else if(J2.w>-1.){float t=J2.z>.0?J2.x:length(J2.xy);t=clamp(t,.0,1.);float Gb=abs(J2.z);float x=Gb>1.?(1.-1./T8)*t+(.5/T8):(1./T8)*t+Gb;float we=-J2.w;j=T1(MC,r8,c(x,we),.0);j.w*=E;if(o6)j.xyz*=j.w;}else{g d6=-J2.w-2.;j=C7(UB,B3,J2.xy,d6);g H2=J2.z*E;if(o6)j*=H2;else j=E1(Y3(j),j.w*H2);}return j;} +#ifndef RENDER_MODE_MSAA +x2 M0(i8,H0);Y0(B5,r1);M0(bb,N3);Y0(k8,x4);y2 z2(NB){N(H1,f); +#ifdef ATLAS_BLIT +N(Q0,c); +#elif!defined(RENDER_MODE_MSAA) +#ifdef DRAW_INTERIOR_TRIANGLES +N(i1,g); +#elif defined(ENABLE_FEATHER) +N(D,f); +#else +N(D,G); +#endif +N(j0,g); +#endif +#ifdef ENABLE_CLIPPING +N(i3,G); +#endif +#ifdef ENABLE_CLIP_RECT +N(R0,f); +#endif +#ifdef ENABLE_ADVANCED_BLEND +N(U3,g); +#endif +#if!defined(DRAW_INTERIOR_TRIANGLES)||defined(ATLAS_BLIT) +h2; +#endif +g E; +#ifdef ATLAS_BLIT +E=W6(Q0,q.U4 x1); +#else +G L3=unpackHalf2x16(j1(x4));g Hb=L3.y;g F1=Hb==j0?L3.x:v1(.0); +#ifdef DRAW_INTERIOR_TRIANGLES +F1+=i1;i2(x4); +#else +if(U6(D)){g r0; +#ifdef ENABLE_FEATHER +if(ENABLE_FEATHER&&w8(D)){r0=R6(D x1);}else +#endif +{r0=min(D.x,D.y);}F1=max(r0,F1);}else{g r0; +#if defined(ENABLE_FEATHER) +if(ENABLE_FEATHER&&S6(D)){r0=S4(D x1);}else +#endif +{r0=D.x;}F1+=r0;}l1(x4,packHalf2x16(Z3(F1,j0))); +#endif +#ifdef CLOCKWISE_FILL +if(CLOCKWISE_FILL){ +#ifdef VULKAN_VENDOR_ID +if(VULKAN_VENDOR_ID==yd){if(F1<.0)E=.0;else if(F1<=1.)E=F1;else E=1.;}else +#endif +{E=clamp(F1,v1(.0),v1(1.));}}else +#endif +{E=abs(F1); +#ifdef ENABLE_EVEN_ODD +if(ENABLE_EVEN_ODD&&j0<.0){E=1.-v1(abs(fract(E*.5)*2.+-1.));} +#endif +E=min(E,v1(1.));} +#endif +#ifdef ENABLE_CLIPPING +if(ENABLE_CLIPPING&&i3.x<.0){g Z0=-i3.x; +#ifdef ENABLE_NESTED_CLIPPING +if(ENABLE_NESTED_CLIPPING){g A7=i3.y;if(A7!=.0){G I1=unpackHalf2x16(j1(r1));g k5=I1.y;g D7;if(k5!=Z0){D7=k5==A7?I1.x:.0; +#ifndef DRAW_INTERIOR_TRIANGLES +T0(N3,E1(D7,.0,.0,.0)); +#endif +}else{D7=I0(N3).x; +#ifndef DRAW_INTERIOR_TRIANGLES +E2(N3); +#endif +}E=min(E,D7);}} +#endif +l1(r1,packHalf2x16(Z3(E,Z0)));E2(H0);}else +#endif +{ +#ifdef ENABLE_CLIPPING +if(ENABLE_CLIPPING){g Z0=i3.x;if(Z0!=.0){G I1=unpackHalf2x16(j1(r1));g k5=I1.y;E=(k5==Z0)?min(I1.x,E):v1(.0);}} +#endif +#ifdef ENABLE_CLIP_RECT +if(ENABLE_CLIP_RECT){g l4=A8(I5(R0));E=clamp(l4,v1(.0),E);} +#endif +i j=Fb(H1,E Y2);i w1; +#ifdef ATLAS_BLIT +w1=I0(H0); +#else +if(Hb!=j0){w1=I0(H0); +#ifndef DRAW_INTERIOR_TRIANGLES +T0(N3,w1); +#endif +}else{w1=I0(N3); +#ifndef DRAW_INTERIOR_TRIANGLES +E2(N3); +#endif +} +#endif +#ifdef ENABLE_ADVANCED_BLEND +if(ENABLE_ADVANCED_BLEND){if(U3!=f7(B8)){j.xyz=M4(j.xyz,w1,O8(U3));}j.xyz*=j.w;} +#endif +j+=w1*(1.-j.w);T0(H0,j);i2(r1);} +#if!defined(DRAW_INTERIOR_TRIANGLES)||defined(ATLAS_BLIT) +j2; +#endif +M2;} +#else +e2(i,NB){N(H1,f); +#ifdef ATLAS_BLIT +N(Q0,c); +#endif +#ifdef ENABLE_ADVANCED_BLEND +N(U3,g); +#endif +g E= +#ifdef ATLAS_BLIT +W6(Q0,q.U4 x1); +#else +1.; +#endif +i j=Fb(H1,E Y2); +#ifdef ENABLE_ADVANCED_BLEND +if(ENABLE_ADVANCED_BLEND){i w1=d1(PC,c0(floor(y0.xy)));j.xyz=M4(j.xyz,w1,O8(U3));j.xyz*=j.w;} +#endif +f2(j);} +#endif +#endif diff --git a/third_party/rive_renderer/source/generated/shaders/draw_path_common.exports.h b/third_party/rive_renderer/source/generated/shaders/draw_path_common.exports.h new file mode 100644 index 0000000..7d86e26 --- /dev/null +++ b/third_party/rive_renderer/source/generated/shaders/draw_path_common.exports.h @@ -0,0 +1,208 @@ +#pragma once + +#define GLSL_ATLAS_BLIT "CB" +#define GLSL_ATLAS_BLIT_raw CB +#define GLSL_ATLAS_FEATHERED_FILL "QE" +#define GLSL_ATLAS_FEATHERED_FILL_raw QE +#define GLSL_ATLAS_FEATHERED_STROKE "SE" +#define GLSL_ATLAS_FEATHERED_STROKE_raw SE +#define GLSL_BASE_INSTANCE_UNIFORM_NAME "ED" +#define GLSL_BASE_INSTANCE_UNIFORM_NAME_raw ED +#define GLSL_BORROWED_COVERAGE_PREPASS "OC" +#define GLSL_BORROWED_COVERAGE_PREPASS_raw OC +#define GLSL_CLEAR_CLIP "OE" +#define GLSL_CLEAR_CLIP_raw OE +#define GLSL_CLEAR_COLOR "RD" +#define GLSL_CLEAR_COLOR_raw RD +#define GLSL_CLEAR_COVERAGE "NE" +#define GLSL_CLEAR_COVERAGE_raw NE +#define GLSL_CLOCKWISE_FILL "AD" +#define GLSL_CLOCKWISE_FILL_raw AD +#define GLSL_COALESCED_PLS_RESOLVE_AND_TRANSFER "LC" +#define GLSL_COALESCED_PLS_RESOLVE_AND_TRANSFER_raw LC +#define GLSL_COLOR_PLANE_IDX_OVERRIDE "LD" +#define GLSL_COLOR_PLANE_IDX_OVERRIDE_raw LD +#define GLSL_DISABLE_SHADER_STORAGE_BUFFERS "FE" +#define GLSL_DISABLE_SHADER_STORAGE_BUFFERS_raw FE +#define GLSL_DRAW_IMAGE "UC" +#define GLSL_DRAW_IMAGE_raw UC +#define GLSL_DRAW_IMAGE_MESH "UD" +#define GLSL_DRAW_IMAGE_MESH_raw UD +#define GLSL_DRAW_IMAGE_RECT "TC" +#define GLSL_DRAW_IMAGE_RECT_raw TC +#define GLSL_DRAW_INTERIOR_TRIANGLES "GB" +#define GLSL_DRAW_INTERIOR_TRIANGLES_raw GB +#define GLSL_DRAW_PATH "KC" +#define GLSL_DRAW_PATH_raw KC +#define GLSL_DRAW_RENDER_TARGET_UPDATE_BOUNDS "VD" +#define GLSL_DRAW_RENDER_TARGET_UPDATE_BOUNDS_raw VD +#define GLSL_ENABLE_ADVANCED_BLEND "FB" +#define GLSL_ENABLE_ADVANCED_BLEND_raw FB +#define GLSL_ENABLE_CLIPPING "T" +#define GLSL_ENABLE_CLIPPING_raw T +#define GLSL_ENABLE_CLIP_RECT "BB" +#define GLSL_ENABLE_CLIP_RECT_raw BB +#define GLSL_ENABLE_EVEN_ODD "IC" +#define GLSL_ENABLE_EVEN_ODD_raw IC +#define GLSL_ENABLE_FEATHER "EB" +#define GLSL_ENABLE_FEATHER_raw EB +#define GLSL_ENABLE_HSL_BLEND_MODES "XB" +#define GLSL_ENABLE_HSL_BLEND_MODES_raw XB +#define GLSL_ENABLE_INSTANCE_INDEX "OD" +#define GLSL_ENABLE_INSTANCE_INDEX_raw OD +#define GLSL_ENABLE_KHR_BLEND "KD" +#define GLSL_ENABLE_KHR_BLEND_raw KD +#define GLSL_ENABLE_MIN_16_PRECISION "PD" +#define GLSL_ENABLE_MIN_16_PRECISION_raw PD +#define GLSL_ENABLE_NESTED_CLIPPING "CD" +#define GLSL_ENABLE_NESTED_CLIPPING_raw CD +#define GLSL_ENABLE_RASTERIZER_ORDERED_VIEWS "QD" +#define GLSL_ENABLE_RASTERIZER_ORDERED_VIEWS_raw QD +#define GLSL_ENABLE_TYPED_UAV_LOAD_STORE "FC" +#define GLSL_ENABLE_TYPED_UAV_LOAD_STORE_raw FC +#define GLSL_FIXED_FUNCTION_COLOR_OUTPUT "QB" +#define GLSL_FIXED_FUNCTION_COLOR_OUTPUT_raw QB +#define GLSL_FRAGMENT "HB" +#define GLSL_FRAGMENT_raw HB +#define GLSL_FRAMEBUFFER_BOTTOM_UP "DE" +#define GLSL_FRAMEBUFFER_BOTTOM_UP_raw DE +#define GLSL_FlushUniforms "VB" +#define GLSL_FlushUniforms_raw VB +#define GLSL_GLSL_VERSION "WB" +#define GLSL_GLSL_VERSION_raw WB +#define GLSL_INITIALIZE_PLS "WD" +#define GLSL_INITIALIZE_PLS_raw WD +#define GLSL_ImageDrawUniforms "EC" +#define GLSL_ImageDrawUniforms_raw EC +#define GLSL_LOAD_COLOR "TD" +#define GLSL_LOAD_COLOR_raw TD +#define GLSL_OPTIONALLY_FLAT "OB" +#define GLSL_OPTIONALLY_FLAT_raw OB +#define GLSL_PLS_BLEND_SRC_OVER "ZB" +#define GLSL_PLS_BLEND_SRC_OVER_raw ZB +#define GLSL_PLS_IMPL_ANGLE "_EXPORTED_PLS_IMPL_ANGLE" +#define GLSL_PLS_IMPL_ANGLE_raw _EXPORTED_PLS_IMPL_ANGLE +#define GLSL_PLS_IMPL_DEVICE_BUFFER "LE" +#define GLSL_PLS_IMPL_DEVICE_BUFFER_raw LE +#define GLSL_PLS_IMPL_DEVICE_BUFFER_RASTER_ORDERED "ME" +#define GLSL_PLS_IMPL_DEVICE_BUFFER_RASTER_ORDERED_raw ME +#define GLSL_PLS_IMPL_EXT_NATIVE "GE" +#define GLSL_PLS_IMPL_EXT_NATIVE_raw GE +#define GLSL_PLS_IMPL_FRAMEBUFFER_FETCH "HE" +#define GLSL_PLS_IMPL_FRAMEBUFFER_FETCH_raw HE +#define GLSL_PLS_IMPL_NONE "KE" +#define GLSL_PLS_IMPL_NONE_raw KE +#define GLSL_PLS_IMPL_STORAGE_TEXTURE "IE" +#define GLSL_PLS_IMPL_STORAGE_TEXTURE_raw IE +#define GLSL_PLS_IMPL_SUBPASS_LOAD "JE" +#define GLSL_PLS_IMPL_SUBPASS_LOAD_raw JE +#define GLSL_POST_INVERT_Y "EE" +#define GLSL_POST_INVERT_Y_raw EE +#define GLSL_RENDER_MODE_MSAA "DB" +#define GLSL_RENDER_MODE_MSAA_raw DB +#define GLSL_RESOLVE_PLS "HC" +#define GLSL_RESOLVE_PLS_raw HC +#define GLSL_STORE_COLOR "FD" +#define GLSL_STORE_COLOR_raw FD +#define GLSL_STORE_COLOR_CLEAR "XD" +#define GLSL_STORE_COLOR_CLEAR_raw XD +#define GLSL_SWIZZLE_COLOR_BGRA_TO_RGBA "YD" +#define GLSL_SWIZZLE_COLOR_BGRA_TO_RGBA_raw YD +#define GLSL_TARGET_VULKAN "CC" +#define GLSL_TARGET_VULKAN_raw CC +#define GLSL_TESS_TEXTURE_FLOATING_POINT "CE" +#define GLSL_TESS_TEXTURE_FLOATING_POINT_raw CE +#define GLSL_USE_TEXEL_FETCH_WITH_FRAG_COORD "NC" +#define GLSL_USE_TEXEL_FETCH_WITH_FRAG_COORD_raw NC +#define GLSL_USING_PLS_STORAGE_TEXTURES "DD" +#define GLSL_USING_PLS_STORAGE_TEXTURES_raw DD +#define GLSL_VERTEX "AB" +#define GLSL_VERTEX_raw AB +#define GLSL_VULKAN_VENDOR_ID "BD" +#define GLSL_VULKAN_VENDOR_ID_raw BD +#define GLSL_a_args "RB" +#define GLSL_a_args_raw RB +#define GLSL_a_color0 "YC" +#define GLSL_a_color0_raw YC +#define GLSL_a_color1 "ZC" +#define GLSL_a_color1_raw ZC +#define GLSL_a_contourIDWithFlags "JD" +#define GLSL_a_contourIDWithFlags_raw JD +#define GLSL_a_imageRectVertex "YB" +#define GLSL_a_imageRectVertex_raw YB +#define GLSL_a_joinTan_and_ys "GC" +#define GLSL_a_joinTan_and_ys_raw GC +#define GLSL_a_mirroredVertexData "MB" +#define GLSL_a_mirroredVertexData_raw MB +#define GLSL_a_p0p1_ "RC" +#define GLSL_a_p0p1__raw RC +#define GLSL_a_p2p3_ "SC" +#define GLSL_a_p2p3__raw SC +#define GLSL_a_patchVertexData "LB" +#define GLSL_a_patchVertexData_raw LB +#define GLSL_a_position "SB" +#define GLSL_a_position_raw SB +#define GLSL_a_reflectionX0X1 "HD" +#define GLSL_a_reflectionX0X1_raw HD +#define GLSL_a_segmentCounts "ID" +#define GLSL_a_segmentCounts_raw ID +#define GLSL_a_span "AC" +#define GLSL_a_span_raw AC +#define GLSL_a_spanX "WC" +#define GLSL_a_spanX_raw WC +#define GLSL_a_texCoord "TB" +#define GLSL_a_texCoord_raw TB +#define GLSL_a_triangleVertex "IB" +#define GLSL_a_triangleVertex_raw IB +#define GLSL_a_x0x1 "GD" +#define GLSL_a_x0x1_raw GD +#define GLSL_a_yWithFlags "XC" +#define GLSL_a_yWithFlags_raw XC +#define GLSL_atlasFillFragmentMain "RE" +#define GLSL_atlasFillFragmentMain_raw RE +#define GLSL_atlasStrokeFragmentMain "TE" +#define GLSL_atlasStrokeFragmentMain_raw TE +#define GLSL_atlasTexture "ND" +#define GLSL_atlasTexture_raw ND +#define GLSL_atlasVertexMain "PE" +#define GLSL_atlasVertexMain_raw PE +#define GLSL_blitFragmentMain "MD" +#define GLSL_blitFragmentMain_raw MD +#define GLSL_blitVertexMain "ZD" +#define GLSL_blitVertexMain_raw ZD +#define GLSL_clearColor "SD" +#define GLSL_clearColor_raw SD +#define GLSL_colorRampFragmentMain "BE" +#define GLSL_colorRampFragmentMain_raw BE +#define GLSL_colorRampVertexMain "AE" +#define GLSL_colorRampVertexMain_raw AE +#define GLSL_contourBuffer "QC" +#define GLSL_contourBuffer_raw QC +#define GLSL_drawFragmentMain "NB" +#define GLSL_drawFragmentMain_raw NB +#define GLSL_drawVertexMain "PB" +#define GLSL_drawVertexMain_raw PB +#define GLSL_dstColorTexture "PC" +#define GLSL_dstColorTexture_raw PC +#define GLSL_featherTexture "JC" +#define GLSL_featherTexture_raw JC +#define GLSL_gradTexture "MC" +#define GLSL_gradTexture_raw MC +#define GLSL_imageTexture "UB" +#define GLSL_imageTexture_raw UB +#define GLSL_paintAuxBuffer "KB" +#define GLSL_paintAuxBuffer_raw KB +#define GLSL_paintBuffer "DC" +#define GLSL_paintBuffer_raw DC +#define GLSL_pathBuffer "JB" +#define GLSL_pathBuffer_raw JB +#define GLSL_sourceTexture "VC" +#define GLSL_sourceTexture_raw VC +#define GLSL_stencilVertexMain "UE" +#define GLSL_stencilVertexMain_raw UE +#define GLSL_tessVertexTexture "BC" +#define GLSL_tessVertexTexture_raw BC +#define GLSL_tessellateFragmentMain "WE" +#define GLSL_tessellateFragmentMain_raw WE +#define GLSL_tessellateVertexMain "VE" +#define GLSL_tessellateVertexMain_raw VE diff --git a/third_party/rive_renderer/source/generated/shaders/draw_path_common.glsl.hpp b/third_party/rive_renderer/source/generated/shaders/draw_path_common.glsl.hpp new file mode 100644 index 0000000..8dc0a17 --- /dev/null +++ b/third_party/rive_renderer/source/generated/shaders/draw_path_common.glsl.hpp @@ -0,0 +1,128 @@ +#pragma once + +#include "draw_path_common.exports.h" + +namespace rive { +namespace gpu { +namespace glsl { +const char draw_path_common[] = R"===(#define e6 -2. +#define ib -1.5 +#define jb .25 +#define p7 1e3 +#define kb (p7*p7) +#ifdef AB +P2 wa(U2,wd,BC); +#ifdef EB +l5(U2,Z5,JC); +#endif +Q2 E3 O3(Va,Td,JB);g4(l8,W9,DC);h4(m8,X9,KB);O3(Wa,Ud,QC);F3 +#endif +#if defined(EB)||defined(CB) +P3(Z5,M8) +#endif +#ifdef HB +R2 C2(U2,Xa,MC); +#if defined(EB)||defined(CB) +l5(U2,Z5,JC); +#endif +#ifdef CB +y4(Y5,Ya,ND); +#endif +C2(Y5,W8,UB); +#if defined(DB)&&defined(FB) +C2(U2,Za,PC); +#endif +S2 P3(Xa,r8) +#ifdef CB +P3(Ya,Vd) +#endif +p4 G3(X8,B3)q4 +#endif +#ifdef HB +d bool U6(f O){return O.y>=.0;}d bool U6(G O){return O.y>=.0;} +#endif +#if defined(HB)&&defined(EB) +d bool w8(f O){return O.x=.0?m5.y-(1.-m5.x)*g9:m5.y+m5.x*g9;}f O;O.x=max(m5.x,.0)+jb;O.y=-m5.y+e6;O.z=f3;O.w=z4;return O;} +#endif +#ifdef EB +d g S4(f O n5){g f3=O.z;g z4=max(O.w,.0);g o5=f3>=.0?J3(z4):.0;if(abs(f3)>La);}d float ob(S D0,c ae){c M1=C0(D0,ae);return(abs(M1.x)+abs(M1.y))*(1./dot(M1,M1));}d bool E6(f f6,f j9,int K,k1(uint)D2,k1(c)be +#ifndef DB +,k1(f)n1 +#else +,k1(a0)g6 +#endif +q5){int r7=int(f6.x);float m1=f6.y;float k9=f6.z;int pb=floatBitsToInt(f6.w)>>2;int h6=floatBitsToInt(f6.w)&3;int l9=min(r7,pb-1);int Q3=K*pb+l9;H3 B4=d1(BC,A4(Q3));uint Y=v4(B4.w);M m9=w0(QC,Aa(Y));c qb=uintBitsToFloat(m9.xy);D2=m9.z&0xffffu;uint rb=m9.w;S D0=D1(uintBitsToFloat(w0(JB,D2*4u)));M R3=w0(JB,D2*4u+1u);c S0=uintBitsToFloat(R3.xy);float k2=uintBitsToFloat(R3.z);float l2=uintBitsToFloat(R3.w);uint sb=Y&T2;if(sb!=0u){r7=int(j9.x);m1=j9.y;k9=j9.z;}if(r7!=l9){int tb=Q3+r7-l9;H3 ub=d1(BC,A4(tb));if((v4(ub.w)&(T2|0xffffu))!=(Y&(T2|0xffffu))){bool ce=k2==.0||qb.x!=.0;if(ce){Q3=int(rb);B4=d1(BC,A4(Q3));}}else{Q3=tb;B4=ub;}Y=(v4(B4.w)&~T2)|sb;}float O0; +#ifdef EB +float i6;float e1;if((Y&a3)==j7&&h6==m7){uint vb=v4(B4.z);float g3=float(vb&0xffffu);float O1=float(vb>>16);c0 v7=c0(-g3-1.,O1-g3+1.);if((Y&T2)!=0u)v7=-v7;H3 wb=d1(BC,A4(Q3+v7.x));H3 n9=d1(BC,A4(Q3+v7.y));if((v4(n9.w)&(T2|0xffffu))!=(v4(wb.w)&(T2|0xffffu))){n9=d1(BC,A4(int(rb)));}i6=Y4(wb.z);float xb=Y4(n9.z);e1=xb-i6;if(abs(e1)>O2)e1-=e7*sign(e1);float o9=O1+1.-float(Ma);float yb=clamp(round(abs(e1)/O2*o9),1.,o9-1.);float j6=o9-yb;if(g3<=j6){e1=-(O2*sign(e1)-e1);O1=j6;if(g3==j6)m1=-m1;}else if(g3==j6+1.){g3=.0;O1=.0;m1=.0;}else{g3-=j6+2.;O1=yb;}if(g3==O1){O0=xb;}else{O0=i6+e1*(g3/O1);}}else +#endif +{O0=Y4(B4.z);}c B2=c(sin(O0),-cos(O0));c zb=Y4(B4.xy);c w7=c(0,0);if(l2!=.0){l2=max(l2,(U8/3.)/length(C0(D0,B2)));}if(k2!=.0){m1*=sign(determinant(D0));if((Y&l7)!=0u)m1=min(m1,.0);if((Y&Ra)!=0u)m1=max(m1,.0);float S3=l2!=.0?l2:ob(D0,B2)*q3;g Ab=1.;if(S3>k2&&l2==.0){Ab=d4(k2)/d4(S3);k2=S3;}c C4=B2*(k2+S3); +#ifndef DB +float x=m1*(k2+S3);n1.xy=(1./(S3*2.))*(c(x,-x)+k2)+.5;n1.zw=J5(.0); +#endif +uint p9=Y&a3;if(p9>i7){int k6=2;if((Y&V8)==0u)k6=-k6;if((Y&T2)!=0u)k6=-k6;c0 de=A4(Q3+k6);H3 ee=d1(BC,de);float fe=Y4(ee.z);float l6=abs(fe-O0);if(l6>O2)l6=e7-l6;bool x7=(Y&V8)!=0u;bool ge=(Y&l7)!=0u;float Bb=l6*(x7==ge?-.5:.5)+O0;c y7=c(sin(Bb),-cos(Bb));float q9=ob(D0,y7);float m6=cos(l6*.5);float r9;if((p9==pd)||(p9==qd&&m6>=.25)){float he=(Y&k7)!=0u?1.:.25;r9=k2*(1./max(m6,he));}else{r9=k2*m6+q9*.5;}float v9=r9+q9*q3;if((Y&Qa)!=0u){float Cb=k2+S3;float ie=S3*.125;if(Cb<=v9*m6+ie){float je=Cb*(1./m6);C4=y7*je;}else{c w9=y7*v9;c ke=c(dot(C4,C4),dot(w9,w9));C4=C0(ke,inverse(S(C4,w9)));}}c le=abs(m1)*C4;float Db=(v9-dot(le,y7))/(q9*(q3*2.)); +#ifndef DB +if((Y&l7)!=0u)n1.y=Db;else n1.x=Db; +#endif +} +#ifndef DB +n1.xy*=Ab;n1.y=max(n1.y,1e-4);if(l2!=.0){n1.x=e6-n1.x;} +#endif +w7=C0(D0,m1*C4);if(h6!=m7)return false;}else{ +#ifndef DB +n1=f(k9,-1.,.0,.0); +#ifdef EB +if(l2!=.0){n1.y=e6;n1.z=kb;n1.w=k9;if((Y&a3)==j7&&h6==m7){if(e1<.0){i6+=e1;e1=-e1;}float h3=O0-i6;h3=mod(h3+S5,e7)-S5;h3=clamp(h3,.0,e1);if(h3>e1*.5){h3=e1-h3;}c q7=c(sin(h3),cos(h3)); +#if 0 +float y1=1.+.33*log2(S5/(O2-min(e1,O2-O2/16.)));f me=lb(e1,q7,.5*(y1/3.));float ne=S4(me x1);float oe=Z4(ne);float pe=(.5-oe)*(U8*2.);float qe=y1/max(pe,y1);m1*=qe; +#endif +n1=lb(e1,q7,m1);}w7=C0(D0,(m1*l2)*B2);}else +#endif +{w7=sign(C0(m1*B2,inverse(D0)))*q3;}if(bool(Y&T2)!=bool(Y&rd)){n1.x=-n1.x;} +#endif +if(h6==Ta)zb=qb;if((Y&Pa)!=0u&&h6!=Sa){return false;}}be=C0(D0,zb)+w7+S0; +#ifdef DB +M T3=w0(JB,D2*4u+2u);g6=Q1(T3.x); +#else +n1.xy=mix(n1.xy,c(1.,-1.),ed(q.jd!=0u)); +#endif +return true;} +#endif +#if defined(AB)&&defined(GB) +d c c8(Z r5,k1(uint)D2 +#ifdef DB +,k1(a0)g6 +#else +,k1(g)re +#endif +q5){D2=floatBitsToUint(r5.z)&0xffffu; +#ifdef DB +M T3=w0(JB,D2*4u+2u);g6=Q1(T3.x); +#else +re=N8(floatBitsToInt(r5.z)>>16); +#endif +c v5=r5.xy;S D0=D1(uintBitsToFloat(w0(JB,D2*4u)));M R3=w0(JB,D2*4u+1u);c S0=uintBitsToFloat(R3.xy);v5=C0(D0,v5)+S0;return v5;} +#endif +#if defined(AB)&&defined(CB) +d c a8(Z r5,k1(uint)D2, +#ifdef DB +k1(a0)g6, +#endif +k1(c)se q5){D2=floatBitsToUint(r5.z)&0xffffu;M T3=w0(JB,D2*4u+2u); +#ifdef DB +g6=Q1(T3.x); +#endif +c v5=r5.xy;Z n6=uintBitsToFloat(T3.yzw);se=v5*n6.x+n6.yz;return v5;} +#endif +)==="; +} // namespace glsl +} // namespace gpu +} // namespace rive \ No newline at end of file diff --git a/third_party/rive_renderer/source/generated/shaders/draw_path_common.minified.glsl b/third_party/rive_renderer/source/generated/shaders/draw_path_common.minified.glsl new file mode 100644 index 0000000..80bc076 --- /dev/null +++ b/third_party/rive_renderer/source/generated/shaders/draw_path_common.minified.glsl @@ -0,0 +1,117 @@ +#define e6 -2. +#define ib -1.5 +#define jb .25 +#define p7 1e3 +#define kb (p7*p7) +#ifdef VERTEX +P2 wa(U2,wd,BC); +#ifdef ENABLE_FEATHER +l5(U2,Z5,JC); +#endif +Q2 E3 O3(Va,Td,JB);g4(l8,W9,DC);h4(m8,X9,KB);O3(Wa,Ud,QC);F3 +#endif +#if defined(ENABLE_FEATHER)||defined(ATLAS_BLIT) +P3(Z5,M8) +#endif +#ifdef FRAGMENT +R2 C2(U2,Xa,MC); +#if defined(ENABLE_FEATHER)||defined(ATLAS_BLIT) +l5(U2,Z5,JC); +#endif +#ifdef ATLAS_BLIT +y4(Y5,Ya,ND); +#endif +C2(Y5,W8,UB); +#if defined(RENDER_MODE_MSAA)&&defined(ENABLE_ADVANCED_BLEND) +C2(U2,Za,PC); +#endif +S2 P3(Xa,r8) +#ifdef ATLAS_BLIT +P3(Ya,Vd) +#endif +p4 G3(X8,B3)q4 +#endif +#ifdef FRAGMENT +d bool U6(f O){return O.y>=.0;}d bool U6(G O){return O.y>=.0;} +#endif +#if defined(FRAGMENT)&&defined(ENABLE_FEATHER) +d bool w8(f O){return O.x=.0?m5.y-(1.-m5.x)*g9:m5.y+m5.x*g9;}f O;O.x=max(m5.x,.0)+jb;O.y=-m5.y+e6;O.z=f3;O.w=z4;return O;} +#endif +#ifdef ENABLE_FEATHER +d g S4(f O n5){g f3=O.z;g z4=max(O.w,.0);g o5=f3>=.0?J3(z4):.0;if(abs(f3)>La);}d float ob(S D0,c ae){c M1=C0(D0,ae);return(abs(M1.x)+abs(M1.y))*(1./dot(M1,M1));}d bool E6(f f6,f j9,int K,k1(uint)D2,k1(c)be +#ifndef RENDER_MODE_MSAA +,k1(f)n1 +#else +,k1(a0)g6 +#endif +q5){int r7=int(f6.x);float m1=f6.y;float k9=f6.z;int pb=floatBitsToInt(f6.w)>>2;int h6=floatBitsToInt(f6.w)&3;int l9=min(r7,pb-1);int Q3=K*pb+l9;H3 B4=d1(BC,A4(Q3));uint Y=v4(B4.w);M m9=w0(QC,Aa(Y));c qb=uintBitsToFloat(m9.xy);D2=m9.z&0xffffu;uint rb=m9.w;S D0=D1(uintBitsToFloat(w0(JB,D2*4u)));M R3=w0(JB,D2*4u+1u);c S0=uintBitsToFloat(R3.xy);float k2=uintBitsToFloat(R3.z);float l2=uintBitsToFloat(R3.w);uint sb=Y&T2;if(sb!=0u){r7=int(j9.x);m1=j9.y;k9=j9.z;}if(r7!=l9){int tb=Q3+r7-l9;H3 ub=d1(BC,A4(tb));if((v4(ub.w)&(T2|0xffffu))!=(Y&(T2|0xffffu))){bool ce=k2==.0||qb.x!=.0;if(ce){Q3=int(rb);B4=d1(BC,A4(Q3));}}else{Q3=tb;B4=ub;}Y=(v4(B4.w)&~T2)|sb;}float O0; +#ifdef ENABLE_FEATHER +float i6;float e1;if((Y&a3)==j7&&h6==m7){uint vb=v4(B4.z);float g3=float(vb&0xffffu);float O1=float(vb>>16);c0 v7=c0(-g3-1.,O1-g3+1.);if((Y&T2)!=0u)v7=-v7;H3 wb=d1(BC,A4(Q3+v7.x));H3 n9=d1(BC,A4(Q3+v7.y));if((v4(n9.w)&(T2|0xffffu))!=(v4(wb.w)&(T2|0xffffu))){n9=d1(BC,A4(int(rb)));}i6=Y4(wb.z);float xb=Y4(n9.z);e1=xb-i6;if(abs(e1)>O2)e1-=e7*sign(e1);float o9=O1+1.-float(Ma);float yb=clamp(round(abs(e1)/O2*o9),1.,o9-1.);float j6=o9-yb;if(g3<=j6){e1=-(O2*sign(e1)-e1);O1=j6;if(g3==j6)m1=-m1;}else if(g3==j6+1.){g3=.0;O1=.0;m1=.0;}else{g3-=j6+2.;O1=yb;}if(g3==O1){O0=xb;}else{O0=i6+e1*(g3/O1);}}else +#endif +{O0=Y4(B4.z);}c B2=c(sin(O0),-cos(O0));c zb=Y4(B4.xy);c w7=c(0,0);if(l2!=.0){l2=max(l2,(U8/3.)/length(C0(D0,B2)));}if(k2!=.0){m1*=sign(determinant(D0));if((Y&l7)!=0u)m1=min(m1,.0);if((Y&Ra)!=0u)m1=max(m1,.0);float S3=l2!=.0?l2:ob(D0,B2)*q3;g Ab=1.;if(S3>k2&&l2==.0){Ab=d4(k2)/d4(S3);k2=S3;}c C4=B2*(k2+S3); +#ifndef RENDER_MODE_MSAA +float x=m1*(k2+S3);n1.xy=(1./(S3*2.))*(c(x,-x)+k2)+.5;n1.zw=J5(.0); +#endif +uint p9=Y&a3;if(p9>i7){int k6=2;if((Y&V8)==0u)k6=-k6;if((Y&T2)!=0u)k6=-k6;c0 de=A4(Q3+k6);H3 ee=d1(BC,de);float fe=Y4(ee.z);float l6=abs(fe-O0);if(l6>O2)l6=e7-l6;bool x7=(Y&V8)!=0u;bool ge=(Y&l7)!=0u;float Bb=l6*(x7==ge?-.5:.5)+O0;c y7=c(sin(Bb),-cos(Bb));float q9=ob(D0,y7);float m6=cos(l6*.5);float r9;if((p9==pd)||(p9==qd&&m6>=.25)){float he=(Y&k7)!=0u?1.:.25;r9=k2*(1./max(m6,he));}else{r9=k2*m6+q9*.5;}float v9=r9+q9*q3;if((Y&Qa)!=0u){float Cb=k2+S3;float ie=S3*.125;if(Cb<=v9*m6+ie){float je=Cb*(1./m6);C4=y7*je;}else{c w9=y7*v9;c ke=c(dot(C4,C4),dot(w9,w9));C4=C0(ke,inverse(S(C4,w9)));}}c le=abs(m1)*C4;float Db=(v9-dot(le,y7))/(q9*(q3*2.)); +#ifndef RENDER_MODE_MSAA +if((Y&l7)!=0u)n1.y=Db;else n1.x=Db; +#endif +} +#ifndef RENDER_MODE_MSAA +n1.xy*=Ab;n1.y=max(n1.y,1e-4);if(l2!=.0){n1.x=e6-n1.x;} +#endif +w7=C0(D0,m1*C4);if(h6!=m7)return false;}else{ +#ifndef RENDER_MODE_MSAA +n1=f(k9,-1.,.0,.0); +#ifdef ENABLE_FEATHER +if(l2!=.0){n1.y=e6;n1.z=kb;n1.w=k9;if((Y&a3)==j7&&h6==m7){if(e1<.0){i6+=e1;e1=-e1;}float h3=O0-i6;h3=mod(h3+S5,e7)-S5;h3=clamp(h3,.0,e1);if(h3>e1*.5){h3=e1-h3;}c q7=c(sin(h3),cos(h3)); +#if 0 +float y1=1.+.33*log2(S5/(O2-min(e1,O2-O2/16.)));f me=lb(e1,q7,.5*(y1/3.));float ne=S4(me x1);float oe=Z4(ne);float pe=(.5-oe)*(U8*2.);float qe=y1/max(pe,y1);m1*=qe; +#endif +n1=lb(e1,q7,m1);}w7=C0(D0,(m1*l2)*B2);}else +#endif +{w7=sign(C0(m1*B2,inverse(D0)))*q3;}if(bool(Y&T2)!=bool(Y&rd)){n1.x=-n1.x;} +#endif +if(h6==Ta)zb=qb;if((Y&Pa)!=0u&&h6!=Sa){return false;}}be=C0(D0,zb)+w7+S0; +#ifdef RENDER_MODE_MSAA +M T3=w0(JB,D2*4u+2u);g6=Q1(T3.x); +#else +n1.xy=mix(n1.xy,c(1.,-1.),ed(q.jd!=0u)); +#endif +return true;} +#endif +#if defined(VERTEX)&&defined(DRAW_INTERIOR_TRIANGLES) +d c c8(Z r5,k1(uint)D2 +#ifdef RENDER_MODE_MSAA +,k1(a0)g6 +#else +,k1(g)re +#endif +q5){D2=floatBitsToUint(r5.z)&0xffffu; +#ifdef RENDER_MODE_MSAA +M T3=w0(JB,D2*4u+2u);g6=Q1(T3.x); +#else +re=N8(floatBitsToInt(r5.z)>>16); +#endif +c v5=r5.xy;S D0=D1(uintBitsToFloat(w0(JB,D2*4u)));M R3=w0(JB,D2*4u+1u);c S0=uintBitsToFloat(R3.xy);v5=C0(D0,v5)+S0;return v5;} +#endif +#if defined(VERTEX)&&defined(ATLAS_BLIT) +d c a8(Z r5,k1(uint)D2, +#ifdef RENDER_MODE_MSAA +k1(a0)g6, +#endif +k1(c)se q5){D2=floatBitsToUint(r5.z)&0xffffu;M T3=w0(JB,D2*4u+2u); +#ifdef RENDER_MODE_MSAA +g6=Q1(T3.x); +#endif +c v5=r5.xy;Z n6=uintBitsToFloat(T3.yzw);se=v5*n6.x+n6.yz;return v5;} +#endif diff --git a/third_party/rive_renderer/source/generated/shaders/glsl.exports.h b/third_party/rive_renderer/source/generated/shaders/glsl.exports.h new file mode 100644 index 0000000..7d86e26 --- /dev/null +++ b/third_party/rive_renderer/source/generated/shaders/glsl.exports.h @@ -0,0 +1,208 @@ +#pragma once + +#define GLSL_ATLAS_BLIT "CB" +#define GLSL_ATLAS_BLIT_raw CB +#define GLSL_ATLAS_FEATHERED_FILL "QE" +#define GLSL_ATLAS_FEATHERED_FILL_raw QE +#define GLSL_ATLAS_FEATHERED_STROKE "SE" +#define GLSL_ATLAS_FEATHERED_STROKE_raw SE +#define GLSL_BASE_INSTANCE_UNIFORM_NAME "ED" +#define GLSL_BASE_INSTANCE_UNIFORM_NAME_raw ED +#define GLSL_BORROWED_COVERAGE_PREPASS "OC" +#define GLSL_BORROWED_COVERAGE_PREPASS_raw OC +#define GLSL_CLEAR_CLIP "OE" +#define GLSL_CLEAR_CLIP_raw OE +#define GLSL_CLEAR_COLOR "RD" +#define GLSL_CLEAR_COLOR_raw RD +#define GLSL_CLEAR_COVERAGE "NE" +#define GLSL_CLEAR_COVERAGE_raw NE +#define GLSL_CLOCKWISE_FILL "AD" +#define GLSL_CLOCKWISE_FILL_raw AD +#define GLSL_COALESCED_PLS_RESOLVE_AND_TRANSFER "LC" +#define GLSL_COALESCED_PLS_RESOLVE_AND_TRANSFER_raw LC +#define GLSL_COLOR_PLANE_IDX_OVERRIDE "LD" +#define GLSL_COLOR_PLANE_IDX_OVERRIDE_raw LD +#define GLSL_DISABLE_SHADER_STORAGE_BUFFERS "FE" +#define GLSL_DISABLE_SHADER_STORAGE_BUFFERS_raw FE +#define GLSL_DRAW_IMAGE "UC" +#define GLSL_DRAW_IMAGE_raw UC +#define GLSL_DRAW_IMAGE_MESH "UD" +#define GLSL_DRAW_IMAGE_MESH_raw UD +#define GLSL_DRAW_IMAGE_RECT "TC" +#define GLSL_DRAW_IMAGE_RECT_raw TC +#define GLSL_DRAW_INTERIOR_TRIANGLES "GB" +#define GLSL_DRAW_INTERIOR_TRIANGLES_raw GB +#define GLSL_DRAW_PATH "KC" +#define GLSL_DRAW_PATH_raw KC +#define GLSL_DRAW_RENDER_TARGET_UPDATE_BOUNDS "VD" +#define GLSL_DRAW_RENDER_TARGET_UPDATE_BOUNDS_raw VD +#define GLSL_ENABLE_ADVANCED_BLEND "FB" +#define GLSL_ENABLE_ADVANCED_BLEND_raw FB +#define GLSL_ENABLE_CLIPPING "T" +#define GLSL_ENABLE_CLIPPING_raw T +#define GLSL_ENABLE_CLIP_RECT "BB" +#define GLSL_ENABLE_CLIP_RECT_raw BB +#define GLSL_ENABLE_EVEN_ODD "IC" +#define GLSL_ENABLE_EVEN_ODD_raw IC +#define GLSL_ENABLE_FEATHER "EB" +#define GLSL_ENABLE_FEATHER_raw EB +#define GLSL_ENABLE_HSL_BLEND_MODES "XB" +#define GLSL_ENABLE_HSL_BLEND_MODES_raw XB +#define GLSL_ENABLE_INSTANCE_INDEX "OD" +#define GLSL_ENABLE_INSTANCE_INDEX_raw OD +#define GLSL_ENABLE_KHR_BLEND "KD" +#define GLSL_ENABLE_KHR_BLEND_raw KD +#define GLSL_ENABLE_MIN_16_PRECISION "PD" +#define GLSL_ENABLE_MIN_16_PRECISION_raw PD +#define GLSL_ENABLE_NESTED_CLIPPING "CD" +#define GLSL_ENABLE_NESTED_CLIPPING_raw CD +#define GLSL_ENABLE_RASTERIZER_ORDERED_VIEWS "QD" +#define GLSL_ENABLE_RASTERIZER_ORDERED_VIEWS_raw QD +#define GLSL_ENABLE_TYPED_UAV_LOAD_STORE "FC" +#define GLSL_ENABLE_TYPED_UAV_LOAD_STORE_raw FC +#define GLSL_FIXED_FUNCTION_COLOR_OUTPUT "QB" +#define GLSL_FIXED_FUNCTION_COLOR_OUTPUT_raw QB +#define GLSL_FRAGMENT "HB" +#define GLSL_FRAGMENT_raw HB +#define GLSL_FRAMEBUFFER_BOTTOM_UP "DE" +#define GLSL_FRAMEBUFFER_BOTTOM_UP_raw DE +#define GLSL_FlushUniforms "VB" +#define GLSL_FlushUniforms_raw VB +#define GLSL_GLSL_VERSION "WB" +#define GLSL_GLSL_VERSION_raw WB +#define GLSL_INITIALIZE_PLS "WD" +#define GLSL_INITIALIZE_PLS_raw WD +#define GLSL_ImageDrawUniforms "EC" +#define GLSL_ImageDrawUniforms_raw EC +#define GLSL_LOAD_COLOR "TD" +#define GLSL_LOAD_COLOR_raw TD +#define GLSL_OPTIONALLY_FLAT "OB" +#define GLSL_OPTIONALLY_FLAT_raw OB +#define GLSL_PLS_BLEND_SRC_OVER "ZB" +#define GLSL_PLS_BLEND_SRC_OVER_raw ZB +#define GLSL_PLS_IMPL_ANGLE "_EXPORTED_PLS_IMPL_ANGLE" +#define GLSL_PLS_IMPL_ANGLE_raw _EXPORTED_PLS_IMPL_ANGLE +#define GLSL_PLS_IMPL_DEVICE_BUFFER "LE" +#define GLSL_PLS_IMPL_DEVICE_BUFFER_raw LE +#define GLSL_PLS_IMPL_DEVICE_BUFFER_RASTER_ORDERED "ME" +#define GLSL_PLS_IMPL_DEVICE_BUFFER_RASTER_ORDERED_raw ME +#define GLSL_PLS_IMPL_EXT_NATIVE "GE" +#define GLSL_PLS_IMPL_EXT_NATIVE_raw GE +#define GLSL_PLS_IMPL_FRAMEBUFFER_FETCH "HE" +#define GLSL_PLS_IMPL_FRAMEBUFFER_FETCH_raw HE +#define GLSL_PLS_IMPL_NONE "KE" +#define GLSL_PLS_IMPL_NONE_raw KE +#define GLSL_PLS_IMPL_STORAGE_TEXTURE "IE" +#define GLSL_PLS_IMPL_STORAGE_TEXTURE_raw IE +#define GLSL_PLS_IMPL_SUBPASS_LOAD "JE" +#define GLSL_PLS_IMPL_SUBPASS_LOAD_raw JE +#define GLSL_POST_INVERT_Y "EE" +#define GLSL_POST_INVERT_Y_raw EE +#define GLSL_RENDER_MODE_MSAA "DB" +#define GLSL_RENDER_MODE_MSAA_raw DB +#define GLSL_RESOLVE_PLS "HC" +#define GLSL_RESOLVE_PLS_raw HC +#define GLSL_STORE_COLOR "FD" +#define GLSL_STORE_COLOR_raw FD +#define GLSL_STORE_COLOR_CLEAR "XD" +#define GLSL_STORE_COLOR_CLEAR_raw XD +#define GLSL_SWIZZLE_COLOR_BGRA_TO_RGBA "YD" +#define GLSL_SWIZZLE_COLOR_BGRA_TO_RGBA_raw YD +#define GLSL_TARGET_VULKAN "CC" +#define GLSL_TARGET_VULKAN_raw CC +#define GLSL_TESS_TEXTURE_FLOATING_POINT "CE" +#define GLSL_TESS_TEXTURE_FLOATING_POINT_raw CE +#define GLSL_USE_TEXEL_FETCH_WITH_FRAG_COORD "NC" +#define GLSL_USE_TEXEL_FETCH_WITH_FRAG_COORD_raw NC +#define GLSL_USING_PLS_STORAGE_TEXTURES "DD" +#define GLSL_USING_PLS_STORAGE_TEXTURES_raw DD +#define GLSL_VERTEX "AB" +#define GLSL_VERTEX_raw AB +#define GLSL_VULKAN_VENDOR_ID "BD" +#define GLSL_VULKAN_VENDOR_ID_raw BD +#define GLSL_a_args "RB" +#define GLSL_a_args_raw RB +#define GLSL_a_color0 "YC" +#define GLSL_a_color0_raw YC +#define GLSL_a_color1 "ZC" +#define GLSL_a_color1_raw ZC +#define GLSL_a_contourIDWithFlags "JD" +#define GLSL_a_contourIDWithFlags_raw JD +#define GLSL_a_imageRectVertex "YB" +#define GLSL_a_imageRectVertex_raw YB +#define GLSL_a_joinTan_and_ys "GC" +#define GLSL_a_joinTan_and_ys_raw GC +#define GLSL_a_mirroredVertexData "MB" +#define GLSL_a_mirroredVertexData_raw MB +#define GLSL_a_p0p1_ "RC" +#define GLSL_a_p0p1__raw RC +#define GLSL_a_p2p3_ "SC" +#define GLSL_a_p2p3__raw SC +#define GLSL_a_patchVertexData "LB" +#define GLSL_a_patchVertexData_raw LB +#define GLSL_a_position "SB" +#define GLSL_a_position_raw SB +#define GLSL_a_reflectionX0X1 "HD" +#define GLSL_a_reflectionX0X1_raw HD +#define GLSL_a_segmentCounts "ID" +#define GLSL_a_segmentCounts_raw ID +#define GLSL_a_span "AC" +#define GLSL_a_span_raw AC +#define GLSL_a_spanX "WC" +#define GLSL_a_spanX_raw WC +#define GLSL_a_texCoord "TB" +#define GLSL_a_texCoord_raw TB +#define GLSL_a_triangleVertex "IB" +#define GLSL_a_triangleVertex_raw IB +#define GLSL_a_x0x1 "GD" +#define GLSL_a_x0x1_raw GD +#define GLSL_a_yWithFlags "XC" +#define GLSL_a_yWithFlags_raw XC +#define GLSL_atlasFillFragmentMain "RE" +#define GLSL_atlasFillFragmentMain_raw RE +#define GLSL_atlasStrokeFragmentMain "TE" +#define GLSL_atlasStrokeFragmentMain_raw TE +#define GLSL_atlasTexture "ND" +#define GLSL_atlasTexture_raw ND +#define GLSL_atlasVertexMain "PE" +#define GLSL_atlasVertexMain_raw PE +#define GLSL_blitFragmentMain "MD" +#define GLSL_blitFragmentMain_raw MD +#define GLSL_blitVertexMain "ZD" +#define GLSL_blitVertexMain_raw ZD +#define GLSL_clearColor "SD" +#define GLSL_clearColor_raw SD +#define GLSL_colorRampFragmentMain "BE" +#define GLSL_colorRampFragmentMain_raw BE +#define GLSL_colorRampVertexMain "AE" +#define GLSL_colorRampVertexMain_raw AE +#define GLSL_contourBuffer "QC" +#define GLSL_contourBuffer_raw QC +#define GLSL_drawFragmentMain "NB" +#define GLSL_drawFragmentMain_raw NB +#define GLSL_drawVertexMain "PB" +#define GLSL_drawVertexMain_raw PB +#define GLSL_dstColorTexture "PC" +#define GLSL_dstColorTexture_raw PC +#define GLSL_featherTexture "JC" +#define GLSL_featherTexture_raw JC +#define GLSL_gradTexture "MC" +#define GLSL_gradTexture_raw MC +#define GLSL_imageTexture "UB" +#define GLSL_imageTexture_raw UB +#define GLSL_paintAuxBuffer "KB" +#define GLSL_paintAuxBuffer_raw KB +#define GLSL_paintBuffer "DC" +#define GLSL_paintBuffer_raw DC +#define GLSL_pathBuffer "JB" +#define GLSL_pathBuffer_raw JB +#define GLSL_sourceTexture "VC" +#define GLSL_sourceTexture_raw VC +#define GLSL_stencilVertexMain "UE" +#define GLSL_stencilVertexMain_raw UE +#define GLSL_tessVertexTexture "BC" +#define GLSL_tessVertexTexture_raw BC +#define GLSL_tessellateFragmentMain "WE" +#define GLSL_tessellateFragmentMain_raw WE +#define GLSL_tessellateVertexMain "VE" +#define GLSL_tessellateVertexMain_raw VE diff --git a/third_party/rive_renderer/source/generated/shaders/glsl.glsl.hpp b/third_party/rive_renderer/source/generated/shaders/glsl.glsl.hpp new file mode 100644 index 0000000..b899347 --- /dev/null +++ b/third_party/rive_renderer/source/generated/shaders/glsl.glsl.hpp @@ -0,0 +1,333 @@ +#pragma once + +#include "glsl.exports.h" + +namespace rive { +namespace gpu { +namespace glsl { +const char glsl[] = R"===(#define za +#ifndef WB +#define WB __VERSION__ +#endif +#define c vec2 +#define Z vec3 +#define a4 vec3 +#define f vec4 +#define g mediump float +#define G mediump vec2 +#define A mediump vec3 +#define i mediump vec4 +#define U5 mediump mat3x3 +#define V5 mediump mat2x3 +#define c0 ivec2 +#define h7 ivec4 +#define N0 uvec2 +#define M uvec4 +#define a0 mediump uint +#define a5 bvec2 +#define G7 bvec3 +#define S mat2 +#define d +#define k1(P1) out P1 +#define i4(P1) inout P1 +#ifdef GL_ANGLE_base_vertex_base_instance_shader_builtin +#extension GL_ANGLE_base_vertex_base_instance_shader_builtin:require +#endif +#ifdef KD +#extension GL_KHR_blend_equation_advanced:require +#endif +#if defined(DB)&&defined(BB)&&defined(GL_ES) +#ifdef GL_EXT_clip_cull_distance +#extension GL_EXT_clip_cull_distance:require +#elif defined(GL_ANGLE_clip_cull_distance) +#extension GL_ANGLE_clip_cull_distance:require +#endif +#endif +#if WB>=310 +#define e5(e,a) layout(binding=e,std140)uniform a{ +#else +#define e5(e,a) layout(std140)uniform a{ +#endif +#define W5(a) }a; +#define U0(a) +#define i0(e,W,a) layout(location=e)in W a +#define V0 +#define l0(H7,B,a,W) +#ifdef AB +#if WB>=310 +#define H(e,W,a) layout(location=e)out W a +#else +#define H(e,W,a) out W a +#endif +#else +#if WB>=310 +#define H(e,W,a) layout(location=e)in W a +#else +#define H(e,W,a) in W a +#endif +#endif +#define L2 flat +#define o1 +#define p1 +#ifdef CC +#define n0 +#else +#ifdef GL_NV_shader_noperspective_interpolation +#extension GL_NV_shader_noperspective_interpolation:require +#define n0 noperspective +#else +#define n0 +#endif +#endif +#ifdef AB +#define P2 +#define Q2 +#endif +#ifdef HB +#define R2 +#define S2 +#endif +#define p4 +#define q4 +#ifdef CC +#define I3(g0,e,a) layout(set=g0,binding=e)uniform highp utexture2D a +#define r4(g0,e,a) layout(set=g0,binding=e)uniform highp texture2D a +#define C2(g0,e,a) layout(set=g0,binding=e)uniform mediump texture2D a +#define y4(g0,e,a) layout(binding=e)uniform mediump texture2D a +#elif WB>=310 +#define I3(g0,e,a) layout(binding=e)uniform highp usampler2D a +#define r4(g0,e,a) layout(binding=e)uniform highp sampler2D a +#define C2(g0,e,a) layout(binding=e)uniform mediump sampler2D a +#define y4(g0,e,a) layout(binding=e)uniform mediump sampler2D a +#else +#define I3(g0,e,a) uniform highp usampler2D a +#define r4(g0,e,a) uniform highp sampler2D a +#define C2(g0,e,a) uniform mediump sampler2D a +#define y4(g0,e,a) uniform mediump sampler2D a +#endif +#ifdef CC +#define P3(m2,a) layout(set=ab,binding=m2)uniform mediump sampler a; +#define G3(m2,a) layout(set=Y5,binding=m2)uniform mediump sampler a; +#define D4(a,p,l) texture(sampler2D(a,p),l) +#define T1(a,p,l,G0) textureLod(sampler2D(a,p),l,G0) +#else +#define P3(m2,a) +#define G3(m2,a) +#define D4(a,p,l) texture(a,l) +#define T1(a,p,l,G0) textureLod(a,l,G0) +#endif +#define o4(A0,p,l) D4(A0,p,l) +#define C7(A0,p,l,G0) T1(A0,p,l,G0) +#define l5(g0,e,a) y4(g0,e,a) +#define T5(a,p,m,w5,K7,G0) T1(a,p,c(m,K7),G0) +#define xe(g0,e,a) I3(g0,e,a) +#define n5 +#define x1 +#define d1(a,l) texelFetch(a,l,0) +#ifdef CC +#define p5(a,p,l,X2) textureGather(sampler2D(a,p),(l)*(X2)) +#elif WB>=310 +#define p5(a,p,l,X2) textureGather(a,(l)*(X2)) +#else +#define p5(a,p,l,X2) E1(d1(a,c0(l)+c0(-1,0)).x,d1(a,c0(l)+c0(0,0)).x,d1(a,c0(l)+c0(0,-1)).x,d1(a,c0(l)+c0(-1,-1)).x) +#endif +#define E3 +#define F3 +#define w3 +#define x3 +#ifdef FE +#define g4(e,f1,a) I3(U2,e,a) +#define O3(e,f1,a) xe(U2,e,a) +#define h4(e,f1,a) r4(U2,e,a) +#define w0(a,v0) d1(a,c0((v0)&Oa,(v0)>>Na)) +#define k4(a,v0) d1(a,c0((v0)&Oa,(v0)>>Na)).xy +#else +#ifdef GL_ARB_shader_storage_buffer_object +#extension GL_ARB_shader_storage_buffer_object:require +#endif +#define g4(e,f1,a) layout(std430,binding=e)readonly buffer f1{N0 V3[];}a +#define O3(e,f1,a) layout(std430,binding=e)readonly buffer f1{M V3[];}a +#define h4(e,f1,a) layout(std430,binding=e)readonly buffer f1{f V3[];}a +#define Jd(e,f1,a) layout(std430,binding=e)buffer f1{uint V3[];}a +#define w0(a,v0) a.V3[v0] +#define k4(a,v0) a.V3[v0] +#define Pd(a,v0) a.V3[v0] +#define c9(a,v0,m) atomicMax(a.V3[v0],m) +#define eb(a,v0,m) atomicAdd(a.V3[v0],m) +#endif +#ifdef _EXPORTED_PLS_IMPL_ANGLE +#extension GL_ANGLE_shader_pixel_local_storage:require +#define x2 +#define M0(e,a) layout(binding=e,rgba8)uniform lowp pixelLocalANGLE a +#define Y0(e,a) layout(binding=e,r32ui)uniform highp upixelLocalANGLE a +#define y2 +#define I0(h) pixelLocalLoadANGLE(h) +#define j1(h) pixelLocalLoadANGLE(h).x +#define T0(h,F) pixelLocalStoreANGLE(h,F) +#define l1(h,F) pixelLocalStoreANGLE(h,uvec4(F)) +#define E2(h) +#define i2(h) +#define h2 +#define j2 +#endif +#ifdef GE +#extension GL_EXT_shader_pixel_local_storage:enable +#define x2 __pixel_localEXT z1{ +#define M0(e,a) layout(rgba8)lowp vec4 a +#define Y0(e,a) layout(r32ui)highp uint a +#define y2 }; +#define I0(h) h +#define j1(h) h +#define T0(h,F) h=(F) +#define l1(h,F) h=(F) +#define E2(h) h=h +#define i2(h) h=h +#define h2 +#define j2 +#endif +#ifdef HE +#extension GL_EXT_shader_framebuffer_fetch:require +#define x2 +#define M0(e,a) layout(location=e)inout lowp vec4 a +#define Y0(e,a) layout(location=e)inout highp uvec4 a +#define y2 +#define I0(h) h +#define j1(h) h.x +#define T0(h,F) h=(F) +#define l1(h,F) h.x=(F) +#define E2(h) T0(h,I0(h)) +#define i2(h) l1(h,j1(h)) +#define h2 +#define j2 +#endif +#ifdef IE +#ifdef GL_ARB_shader_image_load_store +#extension GL_ARB_shader_image_load_store:require +#endif +#if defined(GL_ARB_fragment_shader_interlock) +#extension GL_ARB_fragment_shader_interlock:require +#define h2 beginInvocationInterlockARB() +#define j2 endInvocationInterlockARB() +#elif defined(GL_INTEL_fragment_shader_ordering) +#extension GL_INTEL_fragment_shader_ordering:require +#define h2 beginFragmentShaderOrderingINTEL() +#define j2 +#else +#define h2 +#define j2 +#endif +#define x2 +#ifdef CC +#define M0(e,a) layout(set=a6,binding=e,rgba8)uniform lowp coherent image2D a +#define Y0(e,a) layout(set=a6,binding=e,r32ui)uniform highp coherent uimage2D a +#else +#define M0(e,a) layout(binding=e,rgba8)uniform lowp coherent image2D a +#define Y0(e,a) layout(binding=e,r32ui)uniform highp coherent uimage2D a +#endif +#define y2 +#define I0(h) imageLoad(h,I) +#define j1(h) imageLoad(h,I).x +#define T0(h,F) imageStore(h,I,F) +#define l1(h,F) imageStore(h,I,uvec4(F)) +#define E2(h) +#define i2(h) +#ifndef DD +#define DD +#endif +#endif +#ifdef JE +#define x2 +#define O4(e,a) layout(input_attachment_index=e,binding=e,set=a6)uniform lowp subpassInput q6##a; +#define M0(e,a) O4(e,a);layout(location=e)out lowp vec4 a +#define Y0(e,a) layout(input_attachment_index=e,binding=e,set=a6)uniform highp usubpassInput q6##a;layout(location=e)out highp uvec4 a +#define y2 +#define I0(h) subpassLoad(q6##h) +#define j1(h) subpassLoad(q6##h).x +#define T0(h,F) h=(F) +#define l1(h,F) h.x=(F) +#define E2(h) T0(h,subpassLoad(q6##h)) +#define i2(h) l1(h,subpassLoad(q6##h).x) +#define h2 +#define j2 +#endif +#ifdef KE +#define x2 +#define M0(e,a) layout(location=e)out lowp vec4 a +#define Y0(e,a) layout(location=e)out highp uvec4 a +#define y2 +#define I0(h) vec4(0) +#define j1(h) 0u +#define T0(h,F) h=(F) +#define l1(h,F) h.x=(F) +#define E2(h) h=vec4(0) +#define i2(h) h.x=0u +#define h2 +#define j2 +#endif +#ifdef CC +#define gl_VertexID gl_VertexIndex +#endif +#ifdef OD +#ifdef CC +#define L7 gl_InstanceIndex +#else +#ifdef ED +uniform highp int ED; +#define L7 (gl_InstanceID+ED) +#else +#define L7 (gl_InstanceID+gl_BaseInstance) +#endif +#endif +#else +#define L7 0 +#endif +#define q5 +#define Y1 +#define q1(a,f0,B,n,K) void main(){int n=gl_VertexID;int K=L7; +#define G6 q1 +#define N4(a,a2,c2,v2,w2,n) q1(a,a2,c2,n,K) +#define L(a,W) +#define P(a) +#define N(a,W) +#define h1(g1) gl_Position=g1;} +#define e2(E4,a) layout(location=0)out E4 ye;void main() +#define f2(F) ye=F +#define y0 gl_FragCoord.xy +#define C5 +#define Y2 +#ifdef DD +#ifdef CC +#define f4(e,a) layout(set=a6,binding=e,r32ui)uniform highp coherent uimage2D a +#else +#define f4(e,a) layout(binding=e,r32ui)uniform highp coherent uimage2D a +#endif +#define m4(h) imageLoad(h,I).x +#define n4(h,F) imageStore(h,I,uvec4(F)) +#define G5(h,m) imageAtomicMax(h,I,m) +#define H5(h,m) imageAtomicAdd(h,I,m) +#define y3 ,c0 I +#define G1 ,I +#define z2(a) void main(){c0 I=ivec2(floor(y0)); +#define M2 } +#else +#define y3 +#define G1 +#define z2(a) void main() +#define M2 +#endif +#define R4(a) z2(a) +#define A3(a) layout(location=0)out i K1;z2(a) +#define F5(a) layout(location=0)out i K1;z2(a) +#define P4 M2 +#define C0(o,r) ((o)*(r)) +precision highp float;precision highp int; +#if WB<310 +d i unpackUnorm4x8(uint u){M A1=M(u&0xffu,(u>>8)&0xffu,(u>>16)&0xffu,u>>24);return f(A1)*(1./255.);} +#endif +#if WB>=310&&defined(AB)&&defined(DB)&&defined(BB) +out gl_PerVertex{float gl_ClipDistance[4];f gl_Position;}; +#endif +)==="; +} // namespace glsl +} // namespace gpu +} // namespace rive \ No newline at end of file diff --git a/third_party/rive_renderer/source/generated/shaders/glsl.minified.glsl b/third_party/rive_renderer/source/generated/shaders/glsl.minified.glsl new file mode 100644 index 0000000..b692a00 --- /dev/null +++ b/third_party/rive_renderer/source/generated/shaders/glsl.minified.glsl @@ -0,0 +1,322 @@ +#define za +#ifndef GLSL_VERSION +#define GLSL_VERSION __VERSION__ +#endif +#define c vec2 +#define Z vec3 +#define a4 vec3 +#define f vec4 +#define g mediump float +#define G mediump vec2 +#define A mediump vec3 +#define i mediump vec4 +#define U5 mediump mat3x3 +#define V5 mediump mat2x3 +#define c0 ivec2 +#define h7 ivec4 +#define N0 uvec2 +#define M uvec4 +#define a0 mediump uint +#define a5 bvec2 +#define G7 bvec3 +#define S mat2 +#define d +#define k1(P1) out P1 +#define i4(P1) inout P1 +#ifdef GL_ANGLE_base_vertex_base_instance_shader_builtin +#extension GL_ANGLE_base_vertex_base_instance_shader_builtin:require +#endif +#ifdef ENABLE_KHR_BLEND +#extension GL_KHR_blend_equation_advanced:require +#endif +#if defined(RENDER_MODE_MSAA)&&defined(ENABLE_CLIP_RECT)&&defined(GL_ES) +#ifdef GL_EXT_clip_cull_distance +#extension GL_EXT_clip_cull_distance:require +#elif defined(GL_ANGLE_clip_cull_distance) +#extension GL_ANGLE_clip_cull_distance:require +#endif +#endif +#if GLSL_VERSION>=310 +#define e5(e,a) layout(binding=e,std140)uniform a{ +#else +#define e5(e,a) layout(std140)uniform a{ +#endif +#define W5(a) }a; +#define U0(a) +#define i0(e,W,a) layout(location=e)in W a +#define V0 +#define l0(H7,B,a,W) +#ifdef VERTEX +#if GLSL_VERSION>=310 +#define H(e,W,a) layout(location=e)out W a +#else +#define H(e,W,a) out W a +#endif +#else +#if GLSL_VERSION>=310 +#define H(e,W,a) layout(location=e)in W a +#else +#define H(e,W,a) in W a +#endif +#endif +#define L2 flat +#define o1 +#define p1 +#ifdef TARGET_VULKAN +#define n0 +#else +#ifdef GL_NV_shader_noperspective_interpolation +#extension GL_NV_shader_noperspective_interpolation:require +#define n0 noperspective +#else +#define n0 +#endif +#endif +#ifdef VERTEX +#define P2 +#define Q2 +#endif +#ifdef FRAGMENT +#define R2 +#define S2 +#endif +#define p4 +#define q4 +#ifdef TARGET_VULKAN +#define I3(g0,e,a) layout(set=g0,binding=e)uniform highp utexture2D a +#define r4(g0,e,a) layout(set=g0,binding=e)uniform highp texture2D a +#define C2(g0,e,a) layout(set=g0,binding=e)uniform mediump texture2D a +#define y4(g0,e,a) layout(binding=e)uniform mediump texture2D a +#elif GLSL_VERSION>=310 +#define I3(g0,e,a) layout(binding=e)uniform highp usampler2D a +#define r4(g0,e,a) layout(binding=e)uniform highp sampler2D a +#define C2(g0,e,a) layout(binding=e)uniform mediump sampler2D a +#define y4(g0,e,a) layout(binding=e)uniform mediump sampler2D a +#else +#define I3(g0,e,a) uniform highp usampler2D a +#define r4(g0,e,a) uniform highp sampler2D a +#define C2(g0,e,a) uniform mediump sampler2D a +#define y4(g0,e,a) uniform mediump sampler2D a +#endif +#ifdef TARGET_VULKAN +#define P3(m2,a) layout(set=ab,binding=m2)uniform mediump sampler a; +#define G3(m2,a) layout(set=Y5,binding=m2)uniform mediump sampler a; +#define D4(a,p,l) texture(sampler2D(a,p),l) +#define T1(a,p,l,G0) textureLod(sampler2D(a,p),l,G0) +#else +#define P3(m2,a) +#define G3(m2,a) +#define D4(a,p,l) texture(a,l) +#define T1(a,p,l,G0) textureLod(a,l,G0) +#endif +#define o4(A0,p,l) D4(A0,p,l) +#define C7(A0,p,l,G0) T1(A0,p,l,G0) +#define l5(g0,e,a) y4(g0,e,a) +#define T5(a,p,m,w5,K7,G0) T1(a,p,c(m,K7),G0) +#define xe(g0,e,a) I3(g0,e,a) +#define n5 +#define x1 +#define d1(a,l) texelFetch(a,l,0) +#ifdef TARGET_VULKAN +#define p5(a,p,l,X2) textureGather(sampler2D(a,p),(l)*(X2)) +#elif GLSL_VERSION>=310 +#define p5(a,p,l,X2) textureGather(a,(l)*(X2)) +#else +#define p5(a,p,l,X2) E1(d1(a,c0(l)+c0(-1,0)).x,d1(a,c0(l)+c0(0,0)).x,d1(a,c0(l)+c0(0,-1)).x,d1(a,c0(l)+c0(-1,-1)).x) +#endif +#define E3 +#define F3 +#define w3 +#define x3 +#ifdef DISABLE_SHADER_STORAGE_BUFFERS +#define g4(e,f1,a) I3(U2,e,a) +#define O3(e,f1,a) xe(U2,e,a) +#define h4(e,f1,a) r4(U2,e,a) +#define w0(a,v0) d1(a,c0((v0)&Oa,(v0)>>Na)) +#define k4(a,v0) d1(a,c0((v0)&Oa,(v0)>>Na)).xy +#else +#ifdef GL_ARB_shader_storage_buffer_object +#extension GL_ARB_shader_storage_buffer_object:require +#endif +#define g4(e,f1,a) layout(std430,binding=e)readonly buffer f1{N0 V3[];}a +#define O3(e,f1,a) layout(std430,binding=e)readonly buffer f1{M V3[];}a +#define h4(e,f1,a) layout(std430,binding=e)readonly buffer f1{f V3[];}a +#define Jd(e,f1,a) layout(std430,binding=e)buffer f1{uint V3[];}a +#define w0(a,v0) a.V3[v0] +#define k4(a,v0) a.V3[v0] +#define Pd(a,v0) a.V3[v0] +#define c9(a,v0,m) atomicMax(a.V3[v0],m) +#define eb(a,v0,m) atomicAdd(a.V3[v0],m) +#endif +#ifdef PLS_IMPL_ANGLE +#extension GL_ANGLE_shader_pixel_local_storage:require +#define x2 +#define M0(e,a) layout(binding=e,rgba8)uniform lowp pixelLocalANGLE a +#define Y0(e,a) layout(binding=e,r32ui)uniform highp upixelLocalANGLE a +#define y2 +#define I0(h) pixelLocalLoadANGLE(h) +#define j1(h) pixelLocalLoadANGLE(h).x +#define T0(h,F) pixelLocalStoreANGLE(h,F) +#define l1(h,F) pixelLocalStoreANGLE(h,uvec4(F)) +#define E2(h) +#define i2(h) +#define h2 +#define j2 +#endif +#ifdef PLS_IMPL_EXT_NATIVE +#extension GL_EXT_shader_pixel_local_storage:enable +#define x2 __pixel_localEXT z1{ +#define M0(e,a) layout(rgba8)lowp vec4 a +#define Y0(e,a) layout(r32ui)highp uint a +#define y2 }; +#define I0(h) h +#define j1(h) h +#define T0(h,F) h=(F) +#define l1(h,F) h=(F) +#define E2(h) h=h +#define i2(h) h=h +#define h2 +#define j2 +#endif +#ifdef PLS_IMPL_FRAMEBUFFER_FETCH +#extension GL_EXT_shader_framebuffer_fetch:require +#define x2 +#define M0(e,a) layout(location=e)inout lowp vec4 a +#define Y0(e,a) layout(location=e)inout highp uvec4 a +#define y2 +#define I0(h) h +#define j1(h) h.x +#define T0(h,F) h=(F) +#define l1(h,F) h.x=(F) +#define E2(h) T0(h,I0(h)) +#define i2(h) l1(h,j1(h)) +#define h2 +#define j2 +#endif +#ifdef PLS_IMPL_STORAGE_TEXTURE +#ifdef GL_ARB_shader_image_load_store +#extension GL_ARB_shader_image_load_store:require +#endif +#if defined(GL_ARB_fragment_shader_interlock) +#extension GL_ARB_fragment_shader_interlock:require +#define h2 beginInvocationInterlockARB() +#define j2 endInvocationInterlockARB() +#elif defined(GL_INTEL_fragment_shader_ordering) +#extension GL_INTEL_fragment_shader_ordering:require +#define h2 beginFragmentShaderOrderingINTEL() +#define j2 +#else +#define h2 +#define j2 +#endif +#define x2 +#ifdef TARGET_VULKAN +#define M0(e,a) layout(set=a6,binding=e,rgba8)uniform lowp coherent image2D a +#define Y0(e,a) layout(set=a6,binding=e,r32ui)uniform highp coherent uimage2D a +#else +#define M0(e,a) layout(binding=e,rgba8)uniform lowp coherent image2D a +#define Y0(e,a) layout(binding=e,r32ui)uniform highp coherent uimage2D a +#endif +#define y2 +#define I0(h) imageLoad(h,I) +#define j1(h) imageLoad(h,I).x +#define T0(h,F) imageStore(h,I,F) +#define l1(h,F) imageStore(h,I,uvec4(F)) +#define E2(h) +#define i2(h) +#ifndef USING_PLS_STORAGE_TEXTURES +#define USING_PLS_STORAGE_TEXTURES +#endif +#endif +#ifdef PLS_IMPL_SUBPASS_LOAD +#define x2 +#define O4(e,a) layout(input_attachment_index=e,binding=e,set=a6)uniform lowp subpassInput q6##a; +#define M0(e,a) O4(e,a);layout(location=e)out lowp vec4 a +#define Y0(e,a) layout(input_attachment_index=e,binding=e,set=a6)uniform highp usubpassInput q6##a;layout(location=e)out highp uvec4 a +#define y2 +#define I0(h) subpassLoad(q6##h) +#define j1(h) subpassLoad(q6##h).x +#define T0(h,F) h=(F) +#define l1(h,F) h.x=(F) +#define E2(h) T0(h,subpassLoad(q6##h)) +#define i2(h) l1(h,subpassLoad(q6##h).x) +#define h2 +#define j2 +#endif +#ifdef PLS_IMPL_NONE +#define x2 +#define M0(e,a) layout(location=e)out lowp vec4 a +#define Y0(e,a) layout(location=e)out highp uvec4 a +#define y2 +#define I0(h) vec4(0) +#define j1(h) 0u +#define T0(h,F) h=(F) +#define l1(h,F) h.x=(F) +#define E2(h) h=vec4(0) +#define i2(h) h.x=0u +#define h2 +#define j2 +#endif +#ifdef TARGET_VULKAN +#define gl_VertexID gl_VertexIndex +#endif +#ifdef ENABLE_INSTANCE_INDEX +#ifdef TARGET_VULKAN +#define L7 gl_InstanceIndex +#else +#ifdef BASE_INSTANCE_UNIFORM_NAME +uniform highp int BASE_INSTANCE_UNIFORM_NAME; +#define L7 (gl_InstanceID+BASE_INSTANCE_UNIFORM_NAME) +#else +#define L7 (gl_InstanceID+gl_BaseInstance) +#endif +#endif +#else +#define L7 0 +#endif +#define q5 +#define Y1 +#define q1(a,f0,B,n,K) void main(){int n=gl_VertexID;int K=L7; +#define G6 q1 +#define N4(a,a2,c2,v2,w2,n) q1(a,a2,c2,n,K) +#define L(a,W) +#define P(a) +#define N(a,W) +#define h1(g1) gl_Position=g1;} +#define e2(E4,a) layout(location=0)out E4 ye;void main() +#define f2(F) ye=F +#define y0 gl_FragCoord.xy +#define C5 +#define Y2 +#ifdef USING_PLS_STORAGE_TEXTURES +#ifdef TARGET_VULKAN +#define f4(e,a) layout(set=a6,binding=e,r32ui)uniform highp coherent uimage2D a +#else +#define f4(e,a) layout(binding=e,r32ui)uniform highp coherent uimage2D a +#endif +#define m4(h) imageLoad(h,I).x +#define n4(h,F) imageStore(h,I,uvec4(F)) +#define G5(h,m) imageAtomicMax(h,I,m) +#define H5(h,m) imageAtomicAdd(h,I,m) +#define y3 ,c0 I +#define G1 ,I +#define z2(a) void main(){c0 I=ivec2(floor(y0)); +#define M2 } +#else +#define y3 +#define G1 +#define z2(a) void main() +#define M2 +#endif +#define R4(a) z2(a) +#define A3(a) layout(location=0)out i K1;z2(a) +#define F5(a) layout(location=0)out i K1;z2(a) +#define P4 M2 +#define C0(o,r) ((o)*(r)) +precision highp float;precision highp int; +#if GLSL_VERSION<310 +d i unpackUnorm4x8(uint u){M A1=M(u&0xffu,(u>>8)&0xffu,(u>>16)&0xffu,u>>24);return f(A1)*(1./255.);} +#endif +#if GLSL_VERSION>=310&&defined(VERTEX)&&defined(RENDER_MODE_MSAA)&&defined(ENABLE_CLIP_RECT) +out gl_PerVertex{float gl_ClipDistance[4];f gl_Position;}; +#endif diff --git a/third_party/rive_renderer/source/generated/shaders/glsl.stamp b/third_party/rive_renderer/source/generated/shaders/glsl.stamp new file mode 100644 index 0000000..e69de29 diff --git a/third_party/rive_renderer/source/generated/shaders/hlsl.exports.h b/third_party/rive_renderer/source/generated/shaders/hlsl.exports.h new file mode 100644 index 0000000..7d86e26 --- /dev/null +++ b/third_party/rive_renderer/source/generated/shaders/hlsl.exports.h @@ -0,0 +1,208 @@ +#pragma once + +#define GLSL_ATLAS_BLIT "CB" +#define GLSL_ATLAS_BLIT_raw CB +#define GLSL_ATLAS_FEATHERED_FILL "QE" +#define GLSL_ATLAS_FEATHERED_FILL_raw QE +#define GLSL_ATLAS_FEATHERED_STROKE "SE" +#define GLSL_ATLAS_FEATHERED_STROKE_raw SE +#define GLSL_BASE_INSTANCE_UNIFORM_NAME "ED" +#define GLSL_BASE_INSTANCE_UNIFORM_NAME_raw ED +#define GLSL_BORROWED_COVERAGE_PREPASS "OC" +#define GLSL_BORROWED_COVERAGE_PREPASS_raw OC +#define GLSL_CLEAR_CLIP "OE" +#define GLSL_CLEAR_CLIP_raw OE +#define GLSL_CLEAR_COLOR "RD" +#define GLSL_CLEAR_COLOR_raw RD +#define GLSL_CLEAR_COVERAGE "NE" +#define GLSL_CLEAR_COVERAGE_raw NE +#define GLSL_CLOCKWISE_FILL "AD" +#define GLSL_CLOCKWISE_FILL_raw AD +#define GLSL_COALESCED_PLS_RESOLVE_AND_TRANSFER "LC" +#define GLSL_COALESCED_PLS_RESOLVE_AND_TRANSFER_raw LC +#define GLSL_COLOR_PLANE_IDX_OVERRIDE "LD" +#define GLSL_COLOR_PLANE_IDX_OVERRIDE_raw LD +#define GLSL_DISABLE_SHADER_STORAGE_BUFFERS "FE" +#define GLSL_DISABLE_SHADER_STORAGE_BUFFERS_raw FE +#define GLSL_DRAW_IMAGE "UC" +#define GLSL_DRAW_IMAGE_raw UC +#define GLSL_DRAW_IMAGE_MESH "UD" +#define GLSL_DRAW_IMAGE_MESH_raw UD +#define GLSL_DRAW_IMAGE_RECT "TC" +#define GLSL_DRAW_IMAGE_RECT_raw TC +#define GLSL_DRAW_INTERIOR_TRIANGLES "GB" +#define GLSL_DRAW_INTERIOR_TRIANGLES_raw GB +#define GLSL_DRAW_PATH "KC" +#define GLSL_DRAW_PATH_raw KC +#define GLSL_DRAW_RENDER_TARGET_UPDATE_BOUNDS "VD" +#define GLSL_DRAW_RENDER_TARGET_UPDATE_BOUNDS_raw VD +#define GLSL_ENABLE_ADVANCED_BLEND "FB" +#define GLSL_ENABLE_ADVANCED_BLEND_raw FB +#define GLSL_ENABLE_CLIPPING "T" +#define GLSL_ENABLE_CLIPPING_raw T +#define GLSL_ENABLE_CLIP_RECT "BB" +#define GLSL_ENABLE_CLIP_RECT_raw BB +#define GLSL_ENABLE_EVEN_ODD "IC" +#define GLSL_ENABLE_EVEN_ODD_raw IC +#define GLSL_ENABLE_FEATHER "EB" +#define GLSL_ENABLE_FEATHER_raw EB +#define GLSL_ENABLE_HSL_BLEND_MODES "XB" +#define GLSL_ENABLE_HSL_BLEND_MODES_raw XB +#define GLSL_ENABLE_INSTANCE_INDEX "OD" +#define GLSL_ENABLE_INSTANCE_INDEX_raw OD +#define GLSL_ENABLE_KHR_BLEND "KD" +#define GLSL_ENABLE_KHR_BLEND_raw KD +#define GLSL_ENABLE_MIN_16_PRECISION "PD" +#define GLSL_ENABLE_MIN_16_PRECISION_raw PD +#define GLSL_ENABLE_NESTED_CLIPPING "CD" +#define GLSL_ENABLE_NESTED_CLIPPING_raw CD +#define GLSL_ENABLE_RASTERIZER_ORDERED_VIEWS "QD" +#define GLSL_ENABLE_RASTERIZER_ORDERED_VIEWS_raw QD +#define GLSL_ENABLE_TYPED_UAV_LOAD_STORE "FC" +#define GLSL_ENABLE_TYPED_UAV_LOAD_STORE_raw FC +#define GLSL_FIXED_FUNCTION_COLOR_OUTPUT "QB" +#define GLSL_FIXED_FUNCTION_COLOR_OUTPUT_raw QB +#define GLSL_FRAGMENT "HB" +#define GLSL_FRAGMENT_raw HB +#define GLSL_FRAMEBUFFER_BOTTOM_UP "DE" +#define GLSL_FRAMEBUFFER_BOTTOM_UP_raw DE +#define GLSL_FlushUniforms "VB" +#define GLSL_FlushUniforms_raw VB +#define GLSL_GLSL_VERSION "WB" +#define GLSL_GLSL_VERSION_raw WB +#define GLSL_INITIALIZE_PLS "WD" +#define GLSL_INITIALIZE_PLS_raw WD +#define GLSL_ImageDrawUniforms "EC" +#define GLSL_ImageDrawUniforms_raw EC +#define GLSL_LOAD_COLOR "TD" +#define GLSL_LOAD_COLOR_raw TD +#define GLSL_OPTIONALLY_FLAT "OB" +#define GLSL_OPTIONALLY_FLAT_raw OB +#define GLSL_PLS_BLEND_SRC_OVER "ZB" +#define GLSL_PLS_BLEND_SRC_OVER_raw ZB +#define GLSL_PLS_IMPL_ANGLE "_EXPORTED_PLS_IMPL_ANGLE" +#define GLSL_PLS_IMPL_ANGLE_raw _EXPORTED_PLS_IMPL_ANGLE +#define GLSL_PLS_IMPL_DEVICE_BUFFER "LE" +#define GLSL_PLS_IMPL_DEVICE_BUFFER_raw LE +#define GLSL_PLS_IMPL_DEVICE_BUFFER_RASTER_ORDERED "ME" +#define GLSL_PLS_IMPL_DEVICE_BUFFER_RASTER_ORDERED_raw ME +#define GLSL_PLS_IMPL_EXT_NATIVE "GE" +#define GLSL_PLS_IMPL_EXT_NATIVE_raw GE +#define GLSL_PLS_IMPL_FRAMEBUFFER_FETCH "HE" +#define GLSL_PLS_IMPL_FRAMEBUFFER_FETCH_raw HE +#define GLSL_PLS_IMPL_NONE "KE" +#define GLSL_PLS_IMPL_NONE_raw KE +#define GLSL_PLS_IMPL_STORAGE_TEXTURE "IE" +#define GLSL_PLS_IMPL_STORAGE_TEXTURE_raw IE +#define GLSL_PLS_IMPL_SUBPASS_LOAD "JE" +#define GLSL_PLS_IMPL_SUBPASS_LOAD_raw JE +#define GLSL_POST_INVERT_Y "EE" +#define GLSL_POST_INVERT_Y_raw EE +#define GLSL_RENDER_MODE_MSAA "DB" +#define GLSL_RENDER_MODE_MSAA_raw DB +#define GLSL_RESOLVE_PLS "HC" +#define GLSL_RESOLVE_PLS_raw HC +#define GLSL_STORE_COLOR "FD" +#define GLSL_STORE_COLOR_raw FD +#define GLSL_STORE_COLOR_CLEAR "XD" +#define GLSL_STORE_COLOR_CLEAR_raw XD +#define GLSL_SWIZZLE_COLOR_BGRA_TO_RGBA "YD" +#define GLSL_SWIZZLE_COLOR_BGRA_TO_RGBA_raw YD +#define GLSL_TARGET_VULKAN "CC" +#define GLSL_TARGET_VULKAN_raw CC +#define GLSL_TESS_TEXTURE_FLOATING_POINT "CE" +#define GLSL_TESS_TEXTURE_FLOATING_POINT_raw CE +#define GLSL_USE_TEXEL_FETCH_WITH_FRAG_COORD "NC" +#define GLSL_USE_TEXEL_FETCH_WITH_FRAG_COORD_raw NC +#define GLSL_USING_PLS_STORAGE_TEXTURES "DD" +#define GLSL_USING_PLS_STORAGE_TEXTURES_raw DD +#define GLSL_VERTEX "AB" +#define GLSL_VERTEX_raw AB +#define GLSL_VULKAN_VENDOR_ID "BD" +#define GLSL_VULKAN_VENDOR_ID_raw BD +#define GLSL_a_args "RB" +#define GLSL_a_args_raw RB +#define GLSL_a_color0 "YC" +#define GLSL_a_color0_raw YC +#define GLSL_a_color1 "ZC" +#define GLSL_a_color1_raw ZC +#define GLSL_a_contourIDWithFlags "JD" +#define GLSL_a_contourIDWithFlags_raw JD +#define GLSL_a_imageRectVertex "YB" +#define GLSL_a_imageRectVertex_raw YB +#define GLSL_a_joinTan_and_ys "GC" +#define GLSL_a_joinTan_and_ys_raw GC +#define GLSL_a_mirroredVertexData "MB" +#define GLSL_a_mirroredVertexData_raw MB +#define GLSL_a_p0p1_ "RC" +#define GLSL_a_p0p1__raw RC +#define GLSL_a_p2p3_ "SC" +#define GLSL_a_p2p3__raw SC +#define GLSL_a_patchVertexData "LB" +#define GLSL_a_patchVertexData_raw LB +#define GLSL_a_position "SB" +#define GLSL_a_position_raw SB +#define GLSL_a_reflectionX0X1 "HD" +#define GLSL_a_reflectionX0X1_raw HD +#define GLSL_a_segmentCounts "ID" +#define GLSL_a_segmentCounts_raw ID +#define GLSL_a_span "AC" +#define GLSL_a_span_raw AC +#define GLSL_a_spanX "WC" +#define GLSL_a_spanX_raw WC +#define GLSL_a_texCoord "TB" +#define GLSL_a_texCoord_raw TB +#define GLSL_a_triangleVertex "IB" +#define GLSL_a_triangleVertex_raw IB +#define GLSL_a_x0x1 "GD" +#define GLSL_a_x0x1_raw GD +#define GLSL_a_yWithFlags "XC" +#define GLSL_a_yWithFlags_raw XC +#define GLSL_atlasFillFragmentMain "RE" +#define GLSL_atlasFillFragmentMain_raw RE +#define GLSL_atlasStrokeFragmentMain "TE" +#define GLSL_atlasStrokeFragmentMain_raw TE +#define GLSL_atlasTexture "ND" +#define GLSL_atlasTexture_raw ND +#define GLSL_atlasVertexMain "PE" +#define GLSL_atlasVertexMain_raw PE +#define GLSL_blitFragmentMain "MD" +#define GLSL_blitFragmentMain_raw MD +#define GLSL_blitVertexMain "ZD" +#define GLSL_blitVertexMain_raw ZD +#define GLSL_clearColor "SD" +#define GLSL_clearColor_raw SD +#define GLSL_colorRampFragmentMain "BE" +#define GLSL_colorRampFragmentMain_raw BE +#define GLSL_colorRampVertexMain "AE" +#define GLSL_colorRampVertexMain_raw AE +#define GLSL_contourBuffer "QC" +#define GLSL_contourBuffer_raw QC +#define GLSL_drawFragmentMain "NB" +#define GLSL_drawFragmentMain_raw NB +#define GLSL_drawVertexMain "PB" +#define GLSL_drawVertexMain_raw PB +#define GLSL_dstColorTexture "PC" +#define GLSL_dstColorTexture_raw PC +#define GLSL_featherTexture "JC" +#define GLSL_featherTexture_raw JC +#define GLSL_gradTexture "MC" +#define GLSL_gradTexture_raw MC +#define GLSL_imageTexture "UB" +#define GLSL_imageTexture_raw UB +#define GLSL_paintAuxBuffer "KB" +#define GLSL_paintAuxBuffer_raw KB +#define GLSL_paintBuffer "DC" +#define GLSL_paintBuffer_raw DC +#define GLSL_pathBuffer "JB" +#define GLSL_pathBuffer_raw JB +#define GLSL_sourceTexture "VC" +#define GLSL_sourceTexture_raw VC +#define GLSL_stencilVertexMain "UE" +#define GLSL_stencilVertexMain_raw UE +#define GLSL_tessVertexTexture "BC" +#define GLSL_tessVertexTexture_raw BC +#define GLSL_tessellateFragmentMain "WE" +#define GLSL_tessellateFragmentMain_raw WE +#define GLSL_tessellateVertexMain "VE" +#define GLSL_tessellateVertexMain_raw VE diff --git a/third_party/rive_renderer/source/generated/shaders/hlsl.glsl.hpp b/third_party/rive_renderer/source/generated/shaders/hlsl.glsl.hpp new file mode 100644 index 0000000..0d66a9a --- /dev/null +++ b/third_party/rive_renderer/source/generated/shaders/hlsl.glsl.hpp @@ -0,0 +1,161 @@ +#pragma once + +#include "hlsl.exports.h" + +namespace rive { +namespace gpu { +namespace glsl { +const char hlsl[] = R"===(#pragma warning(disable:3550) +#pragma warning(disable:4000) +#ifndef _ARE_TOKEN_NAMES_PRESERVED +#define g half +#define G half2 +#define A half3 +#define i half4 +#define c float2 +#define Z float3 +#define f float4 +#define a5 bool2 +#define G7 bool3 +#define N0 uint2 +#define M uint4 +#define c0 int2 +#define h7 int4 +#define S float2x2 +#define U5 half3x3 +#define V5 half2x3 +#endif +typedef Z a4; +#ifdef PD +#define a0 min16uint +#else +#define a0 uint +#endif +#define d inline +#define k1(P1) out P1 +#define i4(P1) inout P1 +#define U0(a) struct a{ +#define i0(e,W,a) W a:a +#define V0 }; +#define l0(H7,B,a,W) W a=B.a +#define Qb(e) register(b##e) +#define e5(e,a) cbuffer a:Qb(e){struct{ +#define W5(a) }a;} +#define o1 struct k0{ +#define n0 noperspective +#define OB nointerpolation +#define L2 nointerpolation +#define H(e,W,a) W a:TEXCOORD##e +#define p1 f g1:SV_Position;}; +#define L(a,W) W a +#define P(a) X.a=a +#define N(a,W) W a=X.a +#ifdef AB +#define P2 +#define Q2 +#endif +#ifdef HB +#define R2 +#define S2 +#endif +#define p4 +#define q4 +#define I3(g0,e,a) uniform Texture2Da:register(t##e) +#define r4(g0,e,a) uniform Texture2Da:register(t##e) +#define C2(g0,e,a) uniform Texture2Da:register(t##e) +#define y4(g0,e,a) uniform Texture2Da:register(t##e) +#define l5(g0,e,a) uniform Texture1DArraya:register(t##e) +#define F4(m2,a) SamplerState a:register(s##m2); +#define P3 F4 +#define G3 F4 +#define d1(a,l) a[l] +#define D4(a,p,l) a.Sample(p,l) +#define T1(a,p,l,G0) a.SampleLevel(p,l,G0) +#define p5(a,p,l,X2) a.Gather(p,(l)*(X2)) +#define T5(a,p,m,w5,K7,G0) a.SampleLevel(p,c(m,w5),G0) +#define o4(A0,p,l) D4(A0,p,l) +#define C7(A0,p,l,G0) T1(A0,p,l,G0) +#define h2 +#define j2 +#ifdef QD +#define n2 RasterizerOrderedTexture2D +#else +#define n2 RWTexture2D +#endif +#define x2 +#ifdef FC +#define M0(e,a) uniform n2a:register(u##e) +#else +#define M0(e,a) uniform n2a:register(u##e) +#endif +#define O4 M0 +#define Y0(e,a) uniform n2a:register(u##e) +#define f4 Y0 +#define m4 j1 +#define n4 l1 +#define y2 +#ifdef FC +#define I0(h) h[I] +#else +#define I0(h) unpackUnorm4x8(h[I]) +#endif +#define j1(h) h[I] +#ifdef FC +#define T0(h,F) h[I]=(F) +#else +#define T0(h,F) h[I]=packUnorm4x8(F) +#endif +#define l1(h,F) h[I]=(F) +d uint r6(n2G4,c0 I,uint x){uint B1;InterlockedMax(G4[I],x,B1);return B1;} +#define G5(h,m) r6(h,I,m) +d uint v6(n2G4,c0 I,uint x){uint B1;InterlockedAdd(G4[I],x,B1);return B1;} +#define H5(h,m) v6(h,I,m) +#define E2(h) +#define i2(h) +#define q5 +#define Y1 +#define n5 +#define x1 +#define q1(a,f0,B,n,K) cbuffer Mf:Qb(Ua){uint ze;uint a##Nf;uint a##Of;uint a##Pf;}k0 main(f0 B,uint n:SV_VertexID,uint A9:SV_InstanceID){uint K=A9+ze;k0 X; +#define G6(a,f0,B,n,K) k0 main(f0 B,uint n:SV_VertexID){k0 X;f g1; +#define N4(a,a2,c2,v2,w2,n) k0 main(a2 c2,v2 w2,uint n:SV_VertexID){k0 X;f g1; +#define h1(w6) X.g1=w6;}return X; +#define e2(E4,a) E4 main(k0 X):SV_Target{ +#define f2(F) return F;} +#define C5 ,c y0 +#define Y2 ,y0 +#define y3 ,c0 I +#define G1 ,I +#define z2(a) [earlydepthstencil]void main(k0 X){c y0=X.g1.xy;c0 I=c0(floor(y0)); +#define R4(a) z2(a) +#define M2 } +#define A3(a) [earlydepthstencil]i main(k0 X):SV_Target{c y0=X.g1.xy;c0 I=c0(floor(y0));i K1; +#define F5(a) A3(a) +#define P4 }return K1; +#define uintBitsToFloat asfloat +#define floatBitsToInt asint +#define floatBitsToUint asuint +#define inversesqrt rsqrt +#define equal(o,r) ((o)==(r)) +#define notEqual(o,r) ((o)!=(r)) +#define lessThan(o,r) ((o)<(r)) +#define C0(o,r) mul(r,o) +#define E3 +#define F3 +#define w3 +#define x3 +#define g4(e,f1,a) StructuredBuffera:register(t##e) +#define O3(e,f1,a) StructuredBuffera:register(t##e) +#define h4(e,f1,a) StructuredBuffera:register(t##e) +#define w0(a,v0) a[v0] +#define k4(a,v0) a[v0] +d G unpackHalf2x16(uint u){uint y=(u>>16);uint x=u&0xffffu;return G(f16tof32(x),f16tof32(y));}d uint packHalf2x16(c M1){uint x=f32tof16(M1.x);uint y=f32tof16(M1.y);return(y<<16)|x;}d i unpackUnorm4x8(uint u){M A1=M(u&0xffu,(u>>8)&0xffu,(u>>16)&0xffu,u>>24);return i(A1)*(1./255.);}d uint packUnorm4x8(i j){M A1=(M(j*255.)&0xff)<a:register(t##e) +#define r4(g0,e,a) uniform Texture2Da:register(t##e) +#define C2(g0,e,a) uniform Texture2Da:register(t##e) +#define y4(g0,e,a) uniform Texture2Da:register(t##e) +#define l5(g0,e,a) uniform Texture1DArraya:register(t##e) +#define F4(m2,a) SamplerState a:register(s##m2); +#define P3 F4 +#define G3 F4 +#define d1(a,l) a[l] +#define D4(a,p,l) a.Sample(p,l) +#define T1(a,p,l,G0) a.SampleLevel(p,l,G0) +#define p5(a,p,l,X2) a.Gather(p,(l)*(X2)) +#define T5(a,p,m,w5,K7,G0) a.SampleLevel(p,c(m,w5),G0) +#define o4(A0,p,l) D4(A0,p,l) +#define C7(A0,p,l,G0) T1(A0,p,l,G0) +#define h2 +#define j2 +#ifdef ENABLE_RASTERIZER_ORDERED_VIEWS +#define n2 RasterizerOrderedTexture2D +#else +#define n2 RWTexture2D +#endif +#define x2 +#ifdef ENABLE_TYPED_UAV_LOAD_STORE +#define M0(e,a) uniform n2a:register(u##e) +#else +#define M0(e,a) uniform n2a:register(u##e) +#endif +#define O4 M0 +#define Y0(e,a) uniform n2a:register(u##e) +#define f4 Y0 +#define m4 j1 +#define n4 l1 +#define y2 +#ifdef ENABLE_TYPED_UAV_LOAD_STORE +#define I0(h) h[I] +#else +#define I0(h) unpackUnorm4x8(h[I]) +#endif +#define j1(h) h[I] +#ifdef ENABLE_TYPED_UAV_LOAD_STORE +#define T0(h,F) h[I]=(F) +#else +#define T0(h,F) h[I]=packUnorm4x8(F) +#endif +#define l1(h,F) h[I]=(F) +d uint r6(n2G4,c0 I,uint x){uint B1;InterlockedMax(G4[I],x,B1);return B1;} +#define G5(h,m) r6(h,I,m) +d uint v6(n2G4,c0 I,uint x){uint B1;InterlockedAdd(G4[I],x,B1);return B1;} +#define H5(h,m) v6(h,I,m) +#define E2(h) +#define i2(h) +#define q5 +#define Y1 +#define n5 +#define x1 +#define q1(a,f0,B,n,K) cbuffer Mf:Qb(Ua){uint ze;uint a##Nf;uint a##Of;uint a##Pf;}k0 main(f0 B,uint n:SV_VertexID,uint A9:SV_InstanceID){uint K=A9+ze;k0 X; +#define G6(a,f0,B,n,K) k0 main(f0 B,uint n:SV_VertexID){k0 X;f g1; +#define N4(a,a2,c2,v2,w2,n) k0 main(a2 c2,v2 w2,uint n:SV_VertexID){k0 X;f g1; +#define h1(w6) X.g1=w6;}return X; +#define e2(E4,a) E4 main(k0 X):SV_Target{ +#define f2(F) return F;} +#define C5 ,c y0 +#define Y2 ,y0 +#define y3 ,c0 I +#define G1 ,I +#define z2(a) [earlydepthstencil]void main(k0 X){c y0=X.g1.xy;c0 I=c0(floor(y0)); +#define R4(a) z2(a) +#define M2 } +#define A3(a) [earlydepthstencil]i main(k0 X):SV_Target{c y0=X.g1.xy;c0 I=c0(floor(y0));i K1; +#define F5(a) A3(a) +#define P4 }return K1; +#define uintBitsToFloat asfloat +#define floatBitsToInt asint +#define floatBitsToUint asuint +#define inversesqrt rsqrt +#define equal(o,r) ((o)==(r)) +#define notEqual(o,r) ((o)!=(r)) +#define lessThan(o,r) ((o)<(r)) +#define C0(o,r) mul(r,o) +#define E3 +#define F3 +#define w3 +#define x3 +#define g4(e,f1,a) StructuredBuffera:register(t##e) +#define O3(e,f1,a) StructuredBuffera:register(t##e) +#define h4(e,f1,a) StructuredBuffera:register(t##e) +#define w0(a,v0) a[v0] +#define k4(a,v0) a[v0] +d G unpackHalf2x16(uint u){uint y=(u>>16);uint x=u&0xffffu;return G(f16tof32(x),f16tof32(y));}d uint packHalf2x16(c M1){uint x=f32tof16(M1.x);uint y=f32tof16(M1.y);return(y<<16)|x;}d i unpackUnorm4x8(uint u){M A1=M(u&0xffu,(u>>8)&0xffu,(u>>16)&0xffu,u>>24);return i(A1)*(1./255.);}d uint packUnorm4x8(i j){M A1=(M(j*255.)&0xff)<a +#define r4(g0,e,a) [[texture(e)]]texture2da +#define C2(g0,e,a) [[texture(e)]]texture2da +#define y4(g0,e,a) [[texture(e)]]texture2da +#define l5(g0,e,a) [[texture(e)]]texture1d_arraya +#define P3(m2,a) constexpr sampler a(filter::linear,mip_filter::none); +#define G3(Ae,a) [[sampler(Ae)]]sampler a; +#define d1(A0,l) J0.A0.read(N0(l)) +#define D4(A0,p,l) J0.A0.sample(p,l) +#define T1(A0,p,l,G0) J0.A0.sample(p,l,level(G0)) +#define p5(A0,p,l,X2) J0.A0.gather(p,(l)*(X2)) +#define o4(A0,p,l) J0.A0.sample(I4.p,l) +#define C7(A0,p,l,G0) J0.A0.sample(I4.p,l,level(G0)) +#define T5(A0,p,m,w5,K7,G0) J0.A0.sample(p,m,w5) +#define q5 ,constant VB&q,N7 J0,M7 W1 +#define Y1 ,q,J0,W1 +#ifdef OD +#define q1(a,f0,B,n,K) __attribute__((visibility("default")))k0 vertex a(uint n[[vertex_id]],uint K[[instance_id]],constant uint&Be[[buffer(P0(Ua))]],constant VB&q[[buffer(P0(K3))]],constant f0*B[[buffer(0)]],N7 J0,M7 W1){K+=Be;k0 X; +#else +#define q1(a,f0,B,n,K) __attribute__((visibility("default")))k0 vertex a(uint n[[vertex_id]],uint K[[instance_id]],constant VB&q[[buffer(P0(K3))]],constant f0*B[[buffer(0)]],N7 J0,M7 W1){k0 X; +#endif +#define G6(a,f0,B,n,K) __attribute__((visibility("default")))k0 vertex a(uint n[[vertex_id]],constant VB&q[[buffer(P0(K3))]],constant EC&m0[[buffer(P0(f5))]],constant f0*B[[buffer(0)]],N7 J0,M7 W1){k0 X; +#define N4(a,a2,c2,v2,w2,n) __attribute__((visibility("default")))k0 vertex a(uint n[[vertex_id]],constant VB&q[[buffer(P0(K3))]],constant EC&m0[[buffer(P0(f5))]],constant a2*c2[[buffer(0)]],constant v2*w2[[buffer(1)]]){k0 X; +#define h1(w6) X.g1=w6;}return X; +#define e2(E4,a) E4 __attribute__((visibility("default")))fragment a(k0 X[[stage_in]],l3 J0){ +#define f2(F) return F;} +#define C5 ,c y0,l3 J0,H4 W1,x6 I4 +#define Y2 ,y0,J0,W1,I4 +#define n5 ,l3 J0 +#define x1 ,J0 +#ifdef LE +#define x2 struct z1{ +#ifdef ME +#define M0(e,a) device uint*a[[buffer(P0(e+g5)),raster_order_group(0)]] +#define Y0(e,a) device uint*a[[buffer(P0(e+g5)),raster_order_group(0)]] +#define f4(e,a) device atomic_uint*a[[buffer(P0(e+g5)),raster_order_group(0)]] +#else +#define M0(e,a) device uint*a[[buffer(P0(e+g5))]] +#define Y0(e,a) device uint*a[[buffer(P0(e+g5))]] +#define f4(e,a) device atomic_uint*a[[buffer(P0(e+g5))]] +#endif +#define y2 }; +#define y3 ,z1 E0,uint K2 +#define G1 ,E0,K2 +#define I0(h) unpackUnorm4x8(E0.h[K2]) +#define j1(h) E0.h[K2] +#define m4(h) atomic_load_explicit(&E0.h[K2],memory_order::memory_order_relaxed) +#define T0(h,F) E0.h[K2]=packUnorm4x8(F) +#define l1(h,F) E0.h[K2]=(F) +#define n4(h,F) atomic_store_explicit(&E0.h[K2],F,memory_order::memory_order_relaxed) +#define E2(h) +#define i2(h) +#define G5(h,m) atomic_fetch_max_explicit(&E0.h[K2],m,memory_order::memory_order_relaxed) +#define H5(h,m) atomic_fetch_add_explicit(&E0.h[K2],m,memory_order::memory_order_relaxed) +#define h2 +#define j2 +#define y6(a) __attribute__((visibility("default")))fragment a(z1 E0,constant VB&q[[buffer(P0(K3))]],k0 X[[stage_in]],l3 J0,x6 I4,H4 W1){c y0=X.g1.xy;N0 I=N0(metal::floor(y0));uint K2=I.y*q.Ga+I.x; +#define Rb(a) __attribute__((visibility("default")))fragment a(z1 E0,constant VB&q[[buffer(P0(K3))]],constant EC&m0[[buffer(P0(f5))]],k0 X[[stage_in]],x6 I4,l3 J0,H4 W1){c y0=X.g1.xy;N0 I=N0(metal::floor(y0));uint K2=I.y*q.Ga+I.x; +#define z2(a) void y6(a) +#define R4(a) void Rb(a) +#define M2 } +#define A3(a) i y6(a){i K1; +#define F5(a) i Rb(a){i K1; +#define P4 }return K1;M2 +#else +#define x2 struct z1{ +#define M0(e,a) [[color(e)]]i a +#define Y0(e,a) [[color(e)]]uint a +#define f4 Y0 +#define y2 }; +#define y3 ,thread z1&m3,thread z1&E0 +#define G1 ,m3,E0 +#define I0(h) m3.h +#define j1(h) m3.h +#define m4(h) j1 +#define T0(h,F) E0.h=(F) +#define l1(h,F) E0.h=(F) +#define n4(h) l1 +#define E2(h) E0.h=m3.h +#define i2(h) E0.h=m3.h +d uint r6(thread uint&h0,uint x){uint B1=h0;h0=metal::max(B1,x);return B1;} +#define G5(h,m) r6(E0.h,m) +d uint v6(thread uint&h0,uint x){uint B1=h0;h0=B1+x;return B1;} +#define H5(h,m) v6(E0.h,m) +#define h2 +#define j2 +#define y6(a,...) z1 __attribute__((visibility("default")))fragment a(__VA_ARGS__){c y0[[maybe_unused]]=X.g1.xy;z1 E0; +#define z2(a,...) y6(a,z1 m3,constant VB&q[[buffer(P0(K3))]],k0 X[[stage_in]],x6 I4,l3 J0,H4 W1) +#define R4(a) y6(a,z1 m3,k0 X[[stage_in]],l3 J0,H4 W1,x6 I4,constant EC&m0[[buffer(P0(f5))]]) +#define M2 }return E0; +#define Sb(a,...) struct Ce{i De[[j(0)]];z1 E0;};Ce __attribute__((visibility("default")))fragment a(__VA_ARGS__){c y0[[maybe_unused]]=X.g1.xy;i K1;z1 E0; +#define A3(a) Sb(a,z1 m3,k0 X[[stage_in]],l3 J0,H4 W1) +#define F5(a) Sb(a,z1 m3,k0 X[[stage_in]],l3 J0,H4 W1,__VA_ARGS__ constant EC&m0[[buffer(P0(f5))]]) +#define P4 }return{.De=K1,.E0=E0}; +#endif +#define O4 M0 +#define discard discard_fragment() +using namespace metal;templated vecfloatBitsToUint(vecx){return as_type>(x);}templated vecfloatBitsToInt(vecx){return as_type>(x);}d uint floatBitsToUint(float x){return as_type(x);}d int floatBitsToInt(float x){return as_type(x);}templated vecuintBitsToFloat(vecx){return as_type>(x);}d float uintBitsToFloat(uint x){return as_type(x);}d G unpackHalf2x16(uint x){return as_type(x);}d uint packHalf2x16(G x){return as_type(x);}d i unpackUnorm4x8(uint x){return unpack_unorm4x8_to_half(x);}d uint packUnorm4x8(i x){return pack_half_to_unorm4x8(x);}d S inverse(S W0){S C9=S(W0[1][1],-W0[0][1],-W0[1][0],W0[0][0]);float Ee=(C9[0][0]*W0[0][0])+(C9[0][1]*W0[1][0]);return C9*(1/Ee);}d A mix(A k,A b,G7 B0){A z6;for(int C=0;C<3;++C)z6[C]=B0[C]?b[C]:k[C];return z6;}d c mix(c k,c b,a5 B0){c z6;for(int C=0;C<2;++C)z6[C]=B0[C]?b[C]:k[C];return z6;}d c mix(c k,c b,float t){return mix(k,b,c(t));}d float mod(float x,float y){return fmod(x,y);} +)==="; +} // namespace glsl +} // namespace gpu +} // namespace rive \ No newline at end of file diff --git a/third_party/rive_renderer/source/generated/shaders/metal.minified.glsl b/third_party/rive_renderer/source/generated/shaders/metal.minified.glsl new file mode 100644 index 0000000..89a2e72 --- /dev/null +++ b/third_party/rive_renderer/source/generated/shaders/metal.minified.glsl @@ -0,0 +1,159 @@ +#ifndef _ARE_TOKEN_NAMES_PRESERVED +#define g half +#define G half2 +#define A half3 +#define i half4 +#define a0 ushort +#define c float2 +#define Z float3 +#define a4 packed_float3 +#define f float4 +#define a5 bool2 +#define G7 bool3 +#define N0 uint2 +#define M uint4 +#define c0 int2 +#define h7 int4 +#define a0 ushort +#define S float2x2 +#define U5 half3x3 +#define V5 half2x3 +#endif +#define d inline +#define k1(P1) thread P1& +#define i4(P1) thread P1& +#define equal(o,r) ((o)==(r)) +#define notEqual(o,r) ((o)!=(r)) +#define lessThan(o,r) ((o)<(r)) +#define C0(o,r) ((o)*(r)) +#define inversesqrt rsqrt +#define e5(e,a) struct a{ +#define W5(a) }; +#define U0(a) struct a{ +#define i0(e,W,a) W a +#define V0 }; +#define l0(H7,B,a,W) W a=B[H7].a +#define o1 struct k0{ +#define H(e,W,a) W a +#define L2 [[flat]] +#define n0 [[center_no_perspective]] +#ifndef OPTIONALLY_FLAT +#define OPTIONALLY_FLAT +#endif +#define p1 f g1[[position]][[invariant]];}; +#define L(a,W) thread W&a=X.a +#define P(a) +#define N(a,W) W a=X.a +#define E3 struct M7{ +#define F3 }; +#define w3 struct H4{ +#define x3 }; +#define g4(e,f1,a) constant N0*a[[buffer(P0(e))]] +#define O3(e,f1,a) constant M*a[[buffer(P0(e))]] +#define h4(e,f1,a) constant f*a[[buffer(P0(e))]] +#define w0(a,v0) W1.a[v0] +#define k4(a,v0) W1.a[v0] +#define P2 struct N7{ +#define Q2 }; +#define R2 struct l3{ +#define S2 }; +#define p4 struct x6{ +#define q4 }; +#define I3(g0,e,a) [[texture(e)]]texture2da +#define r4(g0,e,a) [[texture(e)]]texture2da +#define C2(g0,e,a) [[texture(e)]]texture2da +#define y4(g0,e,a) [[texture(e)]]texture2da +#define l5(g0,e,a) [[texture(e)]]texture1d_arraya +#define P3(m2,a) constexpr sampler a(filter::linear,mip_filter::none); +#define G3(Ae,a) [[sampler(Ae)]]sampler a; +#define d1(A0,l) J0.A0.read(N0(l)) +#define D4(A0,p,l) J0.A0.sample(p,l) +#define T1(A0,p,l,G0) J0.A0.sample(p,l,level(G0)) +#define p5(A0,p,l,X2) J0.A0.gather(p,(l)*(X2)) +#define o4(A0,p,l) J0.A0.sample(I4.p,l) +#define C7(A0,p,l,G0) J0.A0.sample(I4.p,l,level(G0)) +#define T5(A0,p,m,w5,K7,G0) J0.A0.sample(p,m,w5) +#define q5 ,constant VB&q,N7 J0,M7 W1 +#define Y1 ,q,J0,W1 +#ifdef ENABLE_INSTANCE_INDEX +#define q1(a,f0,B,n,K) __attribute__((visibility("default")))k0 vertex a(uint n[[vertex_id]],uint K[[instance_id]],constant uint&Be[[buffer(P0(Ua))]],constant VB&q[[buffer(P0(K3))]],constant f0*B[[buffer(0)]],N7 J0,M7 W1){K+=Be;k0 X; +#else +#define q1(a,f0,B,n,K) __attribute__((visibility("default")))k0 vertex a(uint n[[vertex_id]],uint K[[instance_id]],constant VB&q[[buffer(P0(K3))]],constant f0*B[[buffer(0)]],N7 J0,M7 W1){k0 X; +#endif +#define G6(a,f0,B,n,K) __attribute__((visibility("default")))k0 vertex a(uint n[[vertex_id]],constant VB&q[[buffer(P0(K3))]],constant EC&m0[[buffer(P0(f5))]],constant f0*B[[buffer(0)]],N7 J0,M7 W1){k0 X; +#define N4(a,a2,c2,v2,w2,n) __attribute__((visibility("default")))k0 vertex a(uint n[[vertex_id]],constant VB&q[[buffer(P0(K3))]],constant EC&m0[[buffer(P0(f5))]],constant a2*c2[[buffer(0)]],constant v2*w2[[buffer(1)]]){k0 X; +#define h1(w6) X.g1=w6;}return X; +#define e2(E4,a) E4 __attribute__((visibility("default")))fragment a(k0 X[[stage_in]],l3 J0){ +#define f2(F) return F;} +#define C5 ,c y0,l3 J0,H4 W1,x6 I4 +#define Y2 ,y0,J0,W1,I4 +#define n5 ,l3 J0 +#define x1 ,J0 +#ifdef PLS_IMPL_DEVICE_BUFFER +#define x2 struct z1{ +#ifdef PLS_IMPL_DEVICE_BUFFER_RASTER_ORDERED +#define M0(e,a) device uint*a[[buffer(P0(e+g5)),raster_order_group(0)]] +#define Y0(e,a) device uint*a[[buffer(P0(e+g5)),raster_order_group(0)]] +#define f4(e,a) device atomic_uint*a[[buffer(P0(e+g5)),raster_order_group(0)]] +#else +#define M0(e,a) device uint*a[[buffer(P0(e+g5))]] +#define Y0(e,a) device uint*a[[buffer(P0(e+g5))]] +#define f4(e,a) device atomic_uint*a[[buffer(P0(e+g5))]] +#endif +#define y2 }; +#define y3 ,z1 E0,uint K2 +#define G1 ,E0,K2 +#define I0(h) unpackUnorm4x8(E0.h[K2]) +#define j1(h) E0.h[K2] +#define m4(h) atomic_load_explicit(&E0.h[K2],memory_order::memory_order_relaxed) +#define T0(h,F) E0.h[K2]=packUnorm4x8(F) +#define l1(h,F) E0.h[K2]=(F) +#define n4(h,F) atomic_store_explicit(&E0.h[K2],F,memory_order::memory_order_relaxed) +#define E2(h) +#define i2(h) +#define G5(h,m) atomic_fetch_max_explicit(&E0.h[K2],m,memory_order::memory_order_relaxed) +#define H5(h,m) atomic_fetch_add_explicit(&E0.h[K2],m,memory_order::memory_order_relaxed) +#define h2 +#define j2 +#define y6(a) __attribute__((visibility("default")))fragment a(z1 E0,constant VB&q[[buffer(P0(K3))]],k0 X[[stage_in]],l3 J0,x6 I4,H4 W1){c y0=X.g1.xy;N0 I=N0(metal::floor(y0));uint K2=I.y*q.Ga+I.x; +#define Rb(a) __attribute__((visibility("default")))fragment a(z1 E0,constant VB&q[[buffer(P0(K3))]],constant EC&m0[[buffer(P0(f5))]],k0 X[[stage_in]],x6 I4,l3 J0,H4 W1){c y0=X.g1.xy;N0 I=N0(metal::floor(y0));uint K2=I.y*q.Ga+I.x; +#define z2(a) void y6(a) +#define R4(a) void Rb(a) +#define M2 } +#define A3(a) i y6(a){i K1; +#define F5(a) i Rb(a){i K1; +#define P4 }return K1;M2 +#else +#define x2 struct z1{ +#define M0(e,a) [[color(e)]]i a +#define Y0(e,a) [[color(e)]]uint a +#define f4 Y0 +#define y2 }; +#define y3 ,thread z1&m3,thread z1&E0 +#define G1 ,m3,E0 +#define I0(h) m3.h +#define j1(h) m3.h +#define m4(h) j1 +#define T0(h,F) E0.h=(F) +#define l1(h,F) E0.h=(F) +#define n4(h) l1 +#define E2(h) E0.h=m3.h +#define i2(h) E0.h=m3.h +d uint r6(thread uint&h0,uint x){uint B1=h0;h0=metal::max(B1,x);return B1;} +#define G5(h,m) r6(E0.h,m) +d uint v6(thread uint&h0,uint x){uint B1=h0;h0=B1+x;return B1;} +#define H5(h,m) v6(E0.h,m) +#define h2 +#define j2 +#define y6(a,...) z1 __attribute__((visibility("default")))fragment a(__VA_ARGS__){c y0[[maybe_unused]]=X.g1.xy;z1 E0; +#define z2(a,...) y6(a,z1 m3,constant VB&q[[buffer(P0(K3))]],k0 X[[stage_in]],x6 I4,l3 J0,H4 W1) +#define R4(a) y6(a,z1 m3,k0 X[[stage_in]],l3 J0,H4 W1,x6 I4,constant EC&m0[[buffer(P0(f5))]]) +#define M2 }return E0; +#define Sb(a,...) struct Ce{i De[[j(0)]];z1 E0;};Ce __attribute__((visibility("default")))fragment a(__VA_ARGS__){c y0[[maybe_unused]]=X.g1.xy;i K1;z1 E0; +#define A3(a) Sb(a,z1 m3,k0 X[[stage_in]],l3 J0,H4 W1) +#define F5(a) Sb(a,z1 m3,k0 X[[stage_in]],l3 J0,H4 W1,__VA_ARGS__ constant EC&m0[[buffer(P0(f5))]]) +#define P4 }return{.De=K1,.E0=E0}; +#endif +#define O4 M0 +#define discard discard_fragment() +using namespace metal;templated vecfloatBitsToUint(vecx){return as_type>(x);}templated vecfloatBitsToInt(vecx){return as_type>(x);}d uint floatBitsToUint(float x){return as_type(x);}d int floatBitsToInt(float x){return as_type(x);}templated vecuintBitsToFloat(vecx){return as_type>(x);}d float uintBitsToFloat(uint x){return as_type(x);}d G unpackHalf2x16(uint x){return as_type(x);}d uint packHalf2x16(G x){return as_type(x);}d i unpackUnorm4x8(uint x){return unpack_unorm4x8_to_half(x);}d uint packUnorm4x8(i x){return pack_half_to_unorm4x8(x);}d S inverse(S W0){S C9=S(W0[1][1],-W0[0][1],-W0[1][0],W0[0][0]);float Ee=(C9[0][0]*W0[0][0])+(C9[0][1]*W0[1][0]);return C9*(1/Ee);}d A mix(A k,A b,G7 B0){A z6;for(int C=0;C<3;++C)z6[C]=B0[C]?b[C]:k[C];return z6;}d c mix(c k,c b,a5 B0){c z6;for(int C=0;C<2;++C)z6[C]=B0[C]?b[C]:k[C];return z6;}d c mix(c k,c b,float t){return mix(k,b,c(t));}d float mod(float x,float y){return fmod(x,y);} \ No newline at end of file diff --git a/third_party/rive_renderer/source/generated/shaders/pls_load_store_ext.exports.h b/third_party/rive_renderer/source/generated/shaders/pls_load_store_ext.exports.h new file mode 100644 index 0000000..7d86e26 --- /dev/null +++ b/third_party/rive_renderer/source/generated/shaders/pls_load_store_ext.exports.h @@ -0,0 +1,208 @@ +#pragma once + +#define GLSL_ATLAS_BLIT "CB" +#define GLSL_ATLAS_BLIT_raw CB +#define GLSL_ATLAS_FEATHERED_FILL "QE" +#define GLSL_ATLAS_FEATHERED_FILL_raw QE +#define GLSL_ATLAS_FEATHERED_STROKE "SE" +#define GLSL_ATLAS_FEATHERED_STROKE_raw SE +#define GLSL_BASE_INSTANCE_UNIFORM_NAME "ED" +#define GLSL_BASE_INSTANCE_UNIFORM_NAME_raw ED +#define GLSL_BORROWED_COVERAGE_PREPASS "OC" +#define GLSL_BORROWED_COVERAGE_PREPASS_raw OC +#define GLSL_CLEAR_CLIP "OE" +#define GLSL_CLEAR_CLIP_raw OE +#define GLSL_CLEAR_COLOR "RD" +#define GLSL_CLEAR_COLOR_raw RD +#define GLSL_CLEAR_COVERAGE "NE" +#define GLSL_CLEAR_COVERAGE_raw NE +#define GLSL_CLOCKWISE_FILL "AD" +#define GLSL_CLOCKWISE_FILL_raw AD +#define GLSL_COALESCED_PLS_RESOLVE_AND_TRANSFER "LC" +#define GLSL_COALESCED_PLS_RESOLVE_AND_TRANSFER_raw LC +#define GLSL_COLOR_PLANE_IDX_OVERRIDE "LD" +#define GLSL_COLOR_PLANE_IDX_OVERRIDE_raw LD +#define GLSL_DISABLE_SHADER_STORAGE_BUFFERS "FE" +#define GLSL_DISABLE_SHADER_STORAGE_BUFFERS_raw FE +#define GLSL_DRAW_IMAGE "UC" +#define GLSL_DRAW_IMAGE_raw UC +#define GLSL_DRAW_IMAGE_MESH "UD" +#define GLSL_DRAW_IMAGE_MESH_raw UD +#define GLSL_DRAW_IMAGE_RECT "TC" +#define GLSL_DRAW_IMAGE_RECT_raw TC +#define GLSL_DRAW_INTERIOR_TRIANGLES "GB" +#define GLSL_DRAW_INTERIOR_TRIANGLES_raw GB +#define GLSL_DRAW_PATH "KC" +#define GLSL_DRAW_PATH_raw KC +#define GLSL_DRAW_RENDER_TARGET_UPDATE_BOUNDS "VD" +#define GLSL_DRAW_RENDER_TARGET_UPDATE_BOUNDS_raw VD +#define GLSL_ENABLE_ADVANCED_BLEND "FB" +#define GLSL_ENABLE_ADVANCED_BLEND_raw FB +#define GLSL_ENABLE_CLIPPING "T" +#define GLSL_ENABLE_CLIPPING_raw T +#define GLSL_ENABLE_CLIP_RECT "BB" +#define GLSL_ENABLE_CLIP_RECT_raw BB +#define GLSL_ENABLE_EVEN_ODD "IC" +#define GLSL_ENABLE_EVEN_ODD_raw IC +#define GLSL_ENABLE_FEATHER "EB" +#define GLSL_ENABLE_FEATHER_raw EB +#define GLSL_ENABLE_HSL_BLEND_MODES "XB" +#define GLSL_ENABLE_HSL_BLEND_MODES_raw XB +#define GLSL_ENABLE_INSTANCE_INDEX "OD" +#define GLSL_ENABLE_INSTANCE_INDEX_raw OD +#define GLSL_ENABLE_KHR_BLEND "KD" +#define GLSL_ENABLE_KHR_BLEND_raw KD +#define GLSL_ENABLE_MIN_16_PRECISION "PD" +#define GLSL_ENABLE_MIN_16_PRECISION_raw PD +#define GLSL_ENABLE_NESTED_CLIPPING "CD" +#define GLSL_ENABLE_NESTED_CLIPPING_raw CD +#define GLSL_ENABLE_RASTERIZER_ORDERED_VIEWS "QD" +#define GLSL_ENABLE_RASTERIZER_ORDERED_VIEWS_raw QD +#define GLSL_ENABLE_TYPED_UAV_LOAD_STORE "FC" +#define GLSL_ENABLE_TYPED_UAV_LOAD_STORE_raw FC +#define GLSL_FIXED_FUNCTION_COLOR_OUTPUT "QB" +#define GLSL_FIXED_FUNCTION_COLOR_OUTPUT_raw QB +#define GLSL_FRAGMENT "HB" +#define GLSL_FRAGMENT_raw HB +#define GLSL_FRAMEBUFFER_BOTTOM_UP "DE" +#define GLSL_FRAMEBUFFER_BOTTOM_UP_raw DE +#define GLSL_FlushUniforms "VB" +#define GLSL_FlushUniforms_raw VB +#define GLSL_GLSL_VERSION "WB" +#define GLSL_GLSL_VERSION_raw WB +#define GLSL_INITIALIZE_PLS "WD" +#define GLSL_INITIALIZE_PLS_raw WD +#define GLSL_ImageDrawUniforms "EC" +#define GLSL_ImageDrawUniforms_raw EC +#define GLSL_LOAD_COLOR "TD" +#define GLSL_LOAD_COLOR_raw TD +#define GLSL_OPTIONALLY_FLAT "OB" +#define GLSL_OPTIONALLY_FLAT_raw OB +#define GLSL_PLS_BLEND_SRC_OVER "ZB" +#define GLSL_PLS_BLEND_SRC_OVER_raw ZB +#define GLSL_PLS_IMPL_ANGLE "_EXPORTED_PLS_IMPL_ANGLE" +#define GLSL_PLS_IMPL_ANGLE_raw _EXPORTED_PLS_IMPL_ANGLE +#define GLSL_PLS_IMPL_DEVICE_BUFFER "LE" +#define GLSL_PLS_IMPL_DEVICE_BUFFER_raw LE +#define GLSL_PLS_IMPL_DEVICE_BUFFER_RASTER_ORDERED "ME" +#define GLSL_PLS_IMPL_DEVICE_BUFFER_RASTER_ORDERED_raw ME +#define GLSL_PLS_IMPL_EXT_NATIVE "GE" +#define GLSL_PLS_IMPL_EXT_NATIVE_raw GE +#define GLSL_PLS_IMPL_FRAMEBUFFER_FETCH "HE" +#define GLSL_PLS_IMPL_FRAMEBUFFER_FETCH_raw HE +#define GLSL_PLS_IMPL_NONE "KE" +#define GLSL_PLS_IMPL_NONE_raw KE +#define GLSL_PLS_IMPL_STORAGE_TEXTURE "IE" +#define GLSL_PLS_IMPL_STORAGE_TEXTURE_raw IE +#define GLSL_PLS_IMPL_SUBPASS_LOAD "JE" +#define GLSL_PLS_IMPL_SUBPASS_LOAD_raw JE +#define GLSL_POST_INVERT_Y "EE" +#define GLSL_POST_INVERT_Y_raw EE +#define GLSL_RENDER_MODE_MSAA "DB" +#define GLSL_RENDER_MODE_MSAA_raw DB +#define GLSL_RESOLVE_PLS "HC" +#define GLSL_RESOLVE_PLS_raw HC +#define GLSL_STORE_COLOR "FD" +#define GLSL_STORE_COLOR_raw FD +#define GLSL_STORE_COLOR_CLEAR "XD" +#define GLSL_STORE_COLOR_CLEAR_raw XD +#define GLSL_SWIZZLE_COLOR_BGRA_TO_RGBA "YD" +#define GLSL_SWIZZLE_COLOR_BGRA_TO_RGBA_raw YD +#define GLSL_TARGET_VULKAN "CC" +#define GLSL_TARGET_VULKAN_raw CC +#define GLSL_TESS_TEXTURE_FLOATING_POINT "CE" +#define GLSL_TESS_TEXTURE_FLOATING_POINT_raw CE +#define GLSL_USE_TEXEL_FETCH_WITH_FRAG_COORD "NC" +#define GLSL_USE_TEXEL_FETCH_WITH_FRAG_COORD_raw NC +#define GLSL_USING_PLS_STORAGE_TEXTURES "DD" +#define GLSL_USING_PLS_STORAGE_TEXTURES_raw DD +#define GLSL_VERTEX "AB" +#define GLSL_VERTEX_raw AB +#define GLSL_VULKAN_VENDOR_ID "BD" +#define GLSL_VULKAN_VENDOR_ID_raw BD +#define GLSL_a_args "RB" +#define GLSL_a_args_raw RB +#define GLSL_a_color0 "YC" +#define GLSL_a_color0_raw YC +#define GLSL_a_color1 "ZC" +#define GLSL_a_color1_raw ZC +#define GLSL_a_contourIDWithFlags "JD" +#define GLSL_a_contourIDWithFlags_raw JD +#define GLSL_a_imageRectVertex "YB" +#define GLSL_a_imageRectVertex_raw YB +#define GLSL_a_joinTan_and_ys "GC" +#define GLSL_a_joinTan_and_ys_raw GC +#define GLSL_a_mirroredVertexData "MB" +#define GLSL_a_mirroredVertexData_raw MB +#define GLSL_a_p0p1_ "RC" +#define GLSL_a_p0p1__raw RC +#define GLSL_a_p2p3_ "SC" +#define GLSL_a_p2p3__raw SC +#define GLSL_a_patchVertexData "LB" +#define GLSL_a_patchVertexData_raw LB +#define GLSL_a_position "SB" +#define GLSL_a_position_raw SB +#define GLSL_a_reflectionX0X1 "HD" +#define GLSL_a_reflectionX0X1_raw HD +#define GLSL_a_segmentCounts "ID" +#define GLSL_a_segmentCounts_raw ID +#define GLSL_a_span "AC" +#define GLSL_a_span_raw AC +#define GLSL_a_spanX "WC" +#define GLSL_a_spanX_raw WC +#define GLSL_a_texCoord "TB" +#define GLSL_a_texCoord_raw TB +#define GLSL_a_triangleVertex "IB" +#define GLSL_a_triangleVertex_raw IB +#define GLSL_a_x0x1 "GD" +#define GLSL_a_x0x1_raw GD +#define GLSL_a_yWithFlags "XC" +#define GLSL_a_yWithFlags_raw XC +#define GLSL_atlasFillFragmentMain "RE" +#define GLSL_atlasFillFragmentMain_raw RE +#define GLSL_atlasStrokeFragmentMain "TE" +#define GLSL_atlasStrokeFragmentMain_raw TE +#define GLSL_atlasTexture "ND" +#define GLSL_atlasTexture_raw ND +#define GLSL_atlasVertexMain "PE" +#define GLSL_atlasVertexMain_raw PE +#define GLSL_blitFragmentMain "MD" +#define GLSL_blitFragmentMain_raw MD +#define GLSL_blitVertexMain "ZD" +#define GLSL_blitVertexMain_raw ZD +#define GLSL_clearColor "SD" +#define GLSL_clearColor_raw SD +#define GLSL_colorRampFragmentMain "BE" +#define GLSL_colorRampFragmentMain_raw BE +#define GLSL_colorRampVertexMain "AE" +#define GLSL_colorRampVertexMain_raw AE +#define GLSL_contourBuffer "QC" +#define GLSL_contourBuffer_raw QC +#define GLSL_drawFragmentMain "NB" +#define GLSL_drawFragmentMain_raw NB +#define GLSL_drawVertexMain "PB" +#define GLSL_drawVertexMain_raw PB +#define GLSL_dstColorTexture "PC" +#define GLSL_dstColorTexture_raw PC +#define GLSL_featherTexture "JC" +#define GLSL_featherTexture_raw JC +#define GLSL_gradTexture "MC" +#define GLSL_gradTexture_raw MC +#define GLSL_imageTexture "UB" +#define GLSL_imageTexture_raw UB +#define GLSL_paintAuxBuffer "KB" +#define GLSL_paintAuxBuffer_raw KB +#define GLSL_paintBuffer "DC" +#define GLSL_paintBuffer_raw DC +#define GLSL_pathBuffer "JB" +#define GLSL_pathBuffer_raw JB +#define GLSL_sourceTexture "VC" +#define GLSL_sourceTexture_raw VC +#define GLSL_stencilVertexMain "UE" +#define GLSL_stencilVertexMain_raw UE +#define GLSL_tessVertexTexture "BC" +#define GLSL_tessVertexTexture_raw BC +#define GLSL_tessellateFragmentMain "WE" +#define GLSL_tessellateFragmentMain_raw WE +#define GLSL_tessellateVertexMain "VE" +#define GLSL_tessellateVertexMain_raw VE diff --git a/third_party/rive_renderer/source/generated/shaders/pls_load_store_ext.glsl.hpp b/third_party/rive_renderer/source/generated/shaders/pls_load_store_ext.glsl.hpp new file mode 100644 index 0000000..061387c --- /dev/null +++ b/third_party/rive_renderer/source/generated/shaders/pls_load_store_ext.glsl.hpp @@ -0,0 +1,72 @@ +#pragma once + +#include "pls_load_store_ext.exports.h" + +namespace rive { +namespace gpu { +namespace glsl { +const char pls_load_store_ext[] = R"===(#ifdef AB +void main(){gl_Position=vec4(mix(vec2(-1,1),vec2(1,-1),equal(gl_VertexID&ivec2(1,2),ivec2(0))),0,1);} +#endif +#ifdef HB +#extension GL_EXT_shader_pixel_local_storage:require +#ifdef GL_ARM_shader_framebuffer_fetch +#extension GL_ARM_shader_framebuffer_fetch:require +#else +#extension GL_EXT_shader_framebuffer_fetch:require +#endif +#ifdef RD +#if __VERSION__>=310 +layout(binding=0,std140)uniform Rf{uniform highp vec4 Fe;}Ge; +#else +uniform mediump vec4 SD; +#endif +#endif +#ifdef GL_EXT_shader_pixel_local_storage +#ifdef FD +__pixel_local_inEXT z1 +#else +__pixel_local_outEXT z1 +#endif +{layout(rgba8)mediump vec4 H0;layout(r32ui)highp uint r1;layout(rgba8)mediump vec4 N3;layout(r32ui)highp uint x4;}; +#ifndef GL_ARM_shader_framebuffer_fetch +#ifdef TD +layout(location=0)inout mediump vec4 D9; +#endif +#endif +#ifdef FD +layout(location=0)out mediump vec4 D9; +#endif +void main(){ +#ifdef RD +#if __VERSION__>=310 +H0=Ge.Fe; +#else +H0=SD; +#endif +#endif +#ifdef TD +#ifdef GL_ARM_shader_framebuffer_fetch +H0=gl_LastFragColorARM; +#else +H0=D9; +#endif +#endif +#ifdef NE +x4=0u; +#endif +#ifdef OE +r1=0u; +#endif +#ifdef FD +D9=H0; +#endif +} +#else +layout(location=0)out mediump vec4 He;void main(){He=vec4(0,1,0,1);} +#endif +#endif +)==="; +} // namespace glsl +} // namespace gpu +} // namespace rive \ No newline at end of file diff --git a/third_party/rive_renderer/source/generated/shaders/pls_load_store_ext.minified.glsl b/third_party/rive_renderer/source/generated/shaders/pls_load_store_ext.minified.glsl new file mode 100644 index 0000000..e21df2b --- /dev/null +++ b/third_party/rive_renderer/source/generated/shaders/pls_load_store_ext.minified.glsl @@ -0,0 +1,61 @@ +#ifdef VERTEX +void main(){gl_Position=vec4(mix(vec2(-1,1),vec2(1,-1),equal(gl_VertexID&ivec2(1,2),ivec2(0))),0,1);} +#endif +#ifdef FRAGMENT +#extension GL_EXT_shader_pixel_local_storage:require +#ifdef GL_ARM_shader_framebuffer_fetch +#extension GL_ARM_shader_framebuffer_fetch:require +#else +#extension GL_EXT_shader_framebuffer_fetch:require +#endif +#ifdef CLEAR_COLOR +#if __VERSION__>=310 +layout(binding=0,std140)uniform Rf{uniform highp vec4 Fe;}Ge; +#else +uniform mediump vec4 SD; +#endif +#endif +#ifdef GL_EXT_shader_pixel_local_storage +#ifdef STORE_COLOR +__pixel_local_inEXT z1 +#else +__pixel_local_outEXT z1 +#endif +{layout(rgba8)mediump vec4 H0;layout(r32ui)highp uint r1;layout(rgba8)mediump vec4 N3;layout(r32ui)highp uint x4;}; +#ifndef GL_ARM_shader_framebuffer_fetch +#ifdef LOAD_COLOR +layout(location=0)inout mediump vec4 D9; +#endif +#endif +#ifdef STORE_COLOR +layout(location=0)out mediump vec4 D9; +#endif +void main(){ +#ifdef CLEAR_COLOR +#if __VERSION__>=310 +H0=Ge.Fe; +#else +H0=SD; +#endif +#endif +#ifdef LOAD_COLOR +#ifdef GL_ARM_shader_framebuffer_fetch +H0=gl_LastFragColorARM; +#else +H0=D9; +#endif +#endif +#ifdef CLEAR_COVERAGE +x4=0u; +#endif +#ifdef CLEAR_CLIP +r1=0u; +#endif +#ifdef STORE_COLOR +D9=H0; +#endif +} +#else +layout(location=0)out mediump vec4 He;void main(){He=vec4(0,1,0,1);} +#endif +#endif diff --git a/third_party/rive_renderer/source/generated/shaders/render_atlas.exports.h b/third_party/rive_renderer/source/generated/shaders/render_atlas.exports.h new file mode 100644 index 0000000..7d86e26 --- /dev/null +++ b/third_party/rive_renderer/source/generated/shaders/render_atlas.exports.h @@ -0,0 +1,208 @@ +#pragma once + +#define GLSL_ATLAS_BLIT "CB" +#define GLSL_ATLAS_BLIT_raw CB +#define GLSL_ATLAS_FEATHERED_FILL "QE" +#define GLSL_ATLAS_FEATHERED_FILL_raw QE +#define GLSL_ATLAS_FEATHERED_STROKE "SE" +#define GLSL_ATLAS_FEATHERED_STROKE_raw SE +#define GLSL_BASE_INSTANCE_UNIFORM_NAME "ED" +#define GLSL_BASE_INSTANCE_UNIFORM_NAME_raw ED +#define GLSL_BORROWED_COVERAGE_PREPASS "OC" +#define GLSL_BORROWED_COVERAGE_PREPASS_raw OC +#define GLSL_CLEAR_CLIP "OE" +#define GLSL_CLEAR_CLIP_raw OE +#define GLSL_CLEAR_COLOR "RD" +#define GLSL_CLEAR_COLOR_raw RD +#define GLSL_CLEAR_COVERAGE "NE" +#define GLSL_CLEAR_COVERAGE_raw NE +#define GLSL_CLOCKWISE_FILL "AD" +#define GLSL_CLOCKWISE_FILL_raw AD +#define GLSL_COALESCED_PLS_RESOLVE_AND_TRANSFER "LC" +#define GLSL_COALESCED_PLS_RESOLVE_AND_TRANSFER_raw LC +#define GLSL_COLOR_PLANE_IDX_OVERRIDE "LD" +#define GLSL_COLOR_PLANE_IDX_OVERRIDE_raw LD +#define GLSL_DISABLE_SHADER_STORAGE_BUFFERS "FE" +#define GLSL_DISABLE_SHADER_STORAGE_BUFFERS_raw FE +#define GLSL_DRAW_IMAGE "UC" +#define GLSL_DRAW_IMAGE_raw UC +#define GLSL_DRAW_IMAGE_MESH "UD" +#define GLSL_DRAW_IMAGE_MESH_raw UD +#define GLSL_DRAW_IMAGE_RECT "TC" +#define GLSL_DRAW_IMAGE_RECT_raw TC +#define GLSL_DRAW_INTERIOR_TRIANGLES "GB" +#define GLSL_DRAW_INTERIOR_TRIANGLES_raw GB +#define GLSL_DRAW_PATH "KC" +#define GLSL_DRAW_PATH_raw KC +#define GLSL_DRAW_RENDER_TARGET_UPDATE_BOUNDS "VD" +#define GLSL_DRAW_RENDER_TARGET_UPDATE_BOUNDS_raw VD +#define GLSL_ENABLE_ADVANCED_BLEND "FB" +#define GLSL_ENABLE_ADVANCED_BLEND_raw FB +#define GLSL_ENABLE_CLIPPING "T" +#define GLSL_ENABLE_CLIPPING_raw T +#define GLSL_ENABLE_CLIP_RECT "BB" +#define GLSL_ENABLE_CLIP_RECT_raw BB +#define GLSL_ENABLE_EVEN_ODD "IC" +#define GLSL_ENABLE_EVEN_ODD_raw IC +#define GLSL_ENABLE_FEATHER "EB" +#define GLSL_ENABLE_FEATHER_raw EB +#define GLSL_ENABLE_HSL_BLEND_MODES "XB" +#define GLSL_ENABLE_HSL_BLEND_MODES_raw XB +#define GLSL_ENABLE_INSTANCE_INDEX "OD" +#define GLSL_ENABLE_INSTANCE_INDEX_raw OD +#define GLSL_ENABLE_KHR_BLEND "KD" +#define GLSL_ENABLE_KHR_BLEND_raw KD +#define GLSL_ENABLE_MIN_16_PRECISION "PD" +#define GLSL_ENABLE_MIN_16_PRECISION_raw PD +#define GLSL_ENABLE_NESTED_CLIPPING "CD" +#define GLSL_ENABLE_NESTED_CLIPPING_raw CD +#define GLSL_ENABLE_RASTERIZER_ORDERED_VIEWS "QD" +#define GLSL_ENABLE_RASTERIZER_ORDERED_VIEWS_raw QD +#define GLSL_ENABLE_TYPED_UAV_LOAD_STORE "FC" +#define GLSL_ENABLE_TYPED_UAV_LOAD_STORE_raw FC +#define GLSL_FIXED_FUNCTION_COLOR_OUTPUT "QB" +#define GLSL_FIXED_FUNCTION_COLOR_OUTPUT_raw QB +#define GLSL_FRAGMENT "HB" +#define GLSL_FRAGMENT_raw HB +#define GLSL_FRAMEBUFFER_BOTTOM_UP "DE" +#define GLSL_FRAMEBUFFER_BOTTOM_UP_raw DE +#define GLSL_FlushUniforms "VB" +#define GLSL_FlushUniforms_raw VB +#define GLSL_GLSL_VERSION "WB" +#define GLSL_GLSL_VERSION_raw WB +#define GLSL_INITIALIZE_PLS "WD" +#define GLSL_INITIALIZE_PLS_raw WD +#define GLSL_ImageDrawUniforms "EC" +#define GLSL_ImageDrawUniforms_raw EC +#define GLSL_LOAD_COLOR "TD" +#define GLSL_LOAD_COLOR_raw TD +#define GLSL_OPTIONALLY_FLAT "OB" +#define GLSL_OPTIONALLY_FLAT_raw OB +#define GLSL_PLS_BLEND_SRC_OVER "ZB" +#define GLSL_PLS_BLEND_SRC_OVER_raw ZB +#define GLSL_PLS_IMPL_ANGLE "_EXPORTED_PLS_IMPL_ANGLE" +#define GLSL_PLS_IMPL_ANGLE_raw _EXPORTED_PLS_IMPL_ANGLE +#define GLSL_PLS_IMPL_DEVICE_BUFFER "LE" +#define GLSL_PLS_IMPL_DEVICE_BUFFER_raw LE +#define GLSL_PLS_IMPL_DEVICE_BUFFER_RASTER_ORDERED "ME" +#define GLSL_PLS_IMPL_DEVICE_BUFFER_RASTER_ORDERED_raw ME +#define GLSL_PLS_IMPL_EXT_NATIVE "GE" +#define GLSL_PLS_IMPL_EXT_NATIVE_raw GE +#define GLSL_PLS_IMPL_FRAMEBUFFER_FETCH "HE" +#define GLSL_PLS_IMPL_FRAMEBUFFER_FETCH_raw HE +#define GLSL_PLS_IMPL_NONE "KE" +#define GLSL_PLS_IMPL_NONE_raw KE +#define GLSL_PLS_IMPL_STORAGE_TEXTURE "IE" +#define GLSL_PLS_IMPL_STORAGE_TEXTURE_raw IE +#define GLSL_PLS_IMPL_SUBPASS_LOAD "JE" +#define GLSL_PLS_IMPL_SUBPASS_LOAD_raw JE +#define GLSL_POST_INVERT_Y "EE" +#define GLSL_POST_INVERT_Y_raw EE +#define GLSL_RENDER_MODE_MSAA "DB" +#define GLSL_RENDER_MODE_MSAA_raw DB +#define GLSL_RESOLVE_PLS "HC" +#define GLSL_RESOLVE_PLS_raw HC +#define GLSL_STORE_COLOR "FD" +#define GLSL_STORE_COLOR_raw FD +#define GLSL_STORE_COLOR_CLEAR "XD" +#define GLSL_STORE_COLOR_CLEAR_raw XD +#define GLSL_SWIZZLE_COLOR_BGRA_TO_RGBA "YD" +#define GLSL_SWIZZLE_COLOR_BGRA_TO_RGBA_raw YD +#define GLSL_TARGET_VULKAN "CC" +#define GLSL_TARGET_VULKAN_raw CC +#define GLSL_TESS_TEXTURE_FLOATING_POINT "CE" +#define GLSL_TESS_TEXTURE_FLOATING_POINT_raw CE +#define GLSL_USE_TEXEL_FETCH_WITH_FRAG_COORD "NC" +#define GLSL_USE_TEXEL_FETCH_WITH_FRAG_COORD_raw NC +#define GLSL_USING_PLS_STORAGE_TEXTURES "DD" +#define GLSL_USING_PLS_STORAGE_TEXTURES_raw DD +#define GLSL_VERTEX "AB" +#define GLSL_VERTEX_raw AB +#define GLSL_VULKAN_VENDOR_ID "BD" +#define GLSL_VULKAN_VENDOR_ID_raw BD +#define GLSL_a_args "RB" +#define GLSL_a_args_raw RB +#define GLSL_a_color0 "YC" +#define GLSL_a_color0_raw YC +#define GLSL_a_color1 "ZC" +#define GLSL_a_color1_raw ZC +#define GLSL_a_contourIDWithFlags "JD" +#define GLSL_a_contourIDWithFlags_raw JD +#define GLSL_a_imageRectVertex "YB" +#define GLSL_a_imageRectVertex_raw YB +#define GLSL_a_joinTan_and_ys "GC" +#define GLSL_a_joinTan_and_ys_raw GC +#define GLSL_a_mirroredVertexData "MB" +#define GLSL_a_mirroredVertexData_raw MB +#define GLSL_a_p0p1_ "RC" +#define GLSL_a_p0p1__raw RC +#define GLSL_a_p2p3_ "SC" +#define GLSL_a_p2p3__raw SC +#define GLSL_a_patchVertexData "LB" +#define GLSL_a_patchVertexData_raw LB +#define GLSL_a_position "SB" +#define GLSL_a_position_raw SB +#define GLSL_a_reflectionX0X1 "HD" +#define GLSL_a_reflectionX0X1_raw HD +#define GLSL_a_segmentCounts "ID" +#define GLSL_a_segmentCounts_raw ID +#define GLSL_a_span "AC" +#define GLSL_a_span_raw AC +#define GLSL_a_spanX "WC" +#define GLSL_a_spanX_raw WC +#define GLSL_a_texCoord "TB" +#define GLSL_a_texCoord_raw TB +#define GLSL_a_triangleVertex "IB" +#define GLSL_a_triangleVertex_raw IB +#define GLSL_a_x0x1 "GD" +#define GLSL_a_x0x1_raw GD +#define GLSL_a_yWithFlags "XC" +#define GLSL_a_yWithFlags_raw XC +#define GLSL_atlasFillFragmentMain "RE" +#define GLSL_atlasFillFragmentMain_raw RE +#define GLSL_atlasStrokeFragmentMain "TE" +#define GLSL_atlasStrokeFragmentMain_raw TE +#define GLSL_atlasTexture "ND" +#define GLSL_atlasTexture_raw ND +#define GLSL_atlasVertexMain "PE" +#define GLSL_atlasVertexMain_raw PE +#define GLSL_blitFragmentMain "MD" +#define GLSL_blitFragmentMain_raw MD +#define GLSL_blitVertexMain "ZD" +#define GLSL_blitVertexMain_raw ZD +#define GLSL_clearColor "SD" +#define GLSL_clearColor_raw SD +#define GLSL_colorRampFragmentMain "BE" +#define GLSL_colorRampFragmentMain_raw BE +#define GLSL_colorRampVertexMain "AE" +#define GLSL_colorRampVertexMain_raw AE +#define GLSL_contourBuffer "QC" +#define GLSL_contourBuffer_raw QC +#define GLSL_drawFragmentMain "NB" +#define GLSL_drawFragmentMain_raw NB +#define GLSL_drawVertexMain "PB" +#define GLSL_drawVertexMain_raw PB +#define GLSL_dstColorTexture "PC" +#define GLSL_dstColorTexture_raw PC +#define GLSL_featherTexture "JC" +#define GLSL_featherTexture_raw JC +#define GLSL_gradTexture "MC" +#define GLSL_gradTexture_raw MC +#define GLSL_imageTexture "UB" +#define GLSL_imageTexture_raw UB +#define GLSL_paintAuxBuffer "KB" +#define GLSL_paintAuxBuffer_raw KB +#define GLSL_paintBuffer "DC" +#define GLSL_paintBuffer_raw DC +#define GLSL_pathBuffer "JB" +#define GLSL_pathBuffer_raw JB +#define GLSL_sourceTexture "VC" +#define GLSL_sourceTexture_raw VC +#define GLSL_stencilVertexMain "UE" +#define GLSL_stencilVertexMain_raw UE +#define GLSL_tessVertexTexture "BC" +#define GLSL_tessVertexTexture_raw BC +#define GLSL_tessellateFragmentMain "WE" +#define GLSL_tessellateFragmentMain_raw WE +#define GLSL_tessellateVertexMain "VE" +#define GLSL_tessellateVertexMain_raw VE diff --git a/third_party/rive_renderer/source/generated/shaders/render_atlas.glsl.hpp b/third_party/rive_renderer/source/generated/shaders/render_atlas.glsl.hpp new file mode 100644 index 0000000..ad1c697 --- /dev/null +++ b/third_party/rive_renderer/source/generated/shaders/render_atlas.glsl.hpp @@ -0,0 +1,26 @@ +#pragma once + +#include "render_atlas.exports.h" + +namespace rive { +namespace gpu { +namespace glsl { +const char render_atlas[] = R"===(#ifdef AB +U0(f0)i0(0,f,LB);i0(1,f,MB);V0 +#endif +o1 n0 H(0,f,D);p1 +#ifdef AB +q1(PE,f0,B,n,K){l0(n,B,LB,f);l0(n,B,MB,f);L(D,f);f Q;uint R;c J;if(E6(LB,MB,K,R,J,D Y1)){M T3=w0(JB,R*4u+2u);Z n6=uintBitsToFloat(T3.yzw);J=J*n6.x+n6.yz;Q=d7(J,q.Ha.x,q.Ha.y);}else{Q=f(q.C1,q.C1,q.C1,q.C1);}P(D);h1(Q);} +#endif +#ifdef HB +#ifdef QE +e2(float,RE){N(D,f);f2(S4(D x1));} +#endif +#ifdef SE +e2(float,TE){N(D,f);f2(R6(D x1));} +#endif +#endif +)==="; +} // namespace glsl +} // namespace gpu +} // namespace rive \ No newline at end of file diff --git a/third_party/rive_renderer/source/generated/shaders/render_atlas.minified.glsl b/third_party/rive_renderer/source/generated/shaders/render_atlas.minified.glsl new file mode 100644 index 0000000..6ddd691 --- /dev/null +++ b/third_party/rive_renderer/source/generated/shaders/render_atlas.minified.glsl @@ -0,0 +1,15 @@ +#ifdef VERTEX +U0(f0)i0(0,f,LB);i0(1,f,MB);V0 +#endif +o1 n0 H(0,f,D);p1 +#ifdef VERTEX +q1(PE,f0,B,n,K){l0(n,B,LB,f);l0(n,B,MB,f);L(D,f);f Q;uint R;c J;if(E6(LB,MB,K,R,J,D Y1)){M T3=w0(JB,R*4u+2u);Z n6=uintBitsToFloat(T3.yzw);J=J*n6.x+n6.yz;Q=d7(J,q.Ha.x,q.Ha.y);}else{Q=f(q.C1,q.C1,q.C1,q.C1);}P(D);h1(Q);} +#endif +#ifdef FRAGMENT +#ifdef ATLAS_FEATHERED_FILL +e2(float,RE){N(D,f);f2(S4(D x1));} +#endif +#ifdef ATLAS_FEATHERED_STROKE +e2(float,TE){N(D,f);f2(R6(D x1));} +#endif +#endif diff --git a/third_party/rive_renderer/source/generated/shaders/rhi.exports.h b/third_party/rive_renderer/source/generated/shaders/rhi.exports.h new file mode 100644 index 0000000..7d86e26 --- /dev/null +++ b/third_party/rive_renderer/source/generated/shaders/rhi.exports.h @@ -0,0 +1,208 @@ +#pragma once + +#define GLSL_ATLAS_BLIT "CB" +#define GLSL_ATLAS_BLIT_raw CB +#define GLSL_ATLAS_FEATHERED_FILL "QE" +#define GLSL_ATLAS_FEATHERED_FILL_raw QE +#define GLSL_ATLAS_FEATHERED_STROKE "SE" +#define GLSL_ATLAS_FEATHERED_STROKE_raw SE +#define GLSL_BASE_INSTANCE_UNIFORM_NAME "ED" +#define GLSL_BASE_INSTANCE_UNIFORM_NAME_raw ED +#define GLSL_BORROWED_COVERAGE_PREPASS "OC" +#define GLSL_BORROWED_COVERAGE_PREPASS_raw OC +#define GLSL_CLEAR_CLIP "OE" +#define GLSL_CLEAR_CLIP_raw OE +#define GLSL_CLEAR_COLOR "RD" +#define GLSL_CLEAR_COLOR_raw RD +#define GLSL_CLEAR_COVERAGE "NE" +#define GLSL_CLEAR_COVERAGE_raw NE +#define GLSL_CLOCKWISE_FILL "AD" +#define GLSL_CLOCKWISE_FILL_raw AD +#define GLSL_COALESCED_PLS_RESOLVE_AND_TRANSFER "LC" +#define GLSL_COALESCED_PLS_RESOLVE_AND_TRANSFER_raw LC +#define GLSL_COLOR_PLANE_IDX_OVERRIDE "LD" +#define GLSL_COLOR_PLANE_IDX_OVERRIDE_raw LD +#define GLSL_DISABLE_SHADER_STORAGE_BUFFERS "FE" +#define GLSL_DISABLE_SHADER_STORAGE_BUFFERS_raw FE +#define GLSL_DRAW_IMAGE "UC" +#define GLSL_DRAW_IMAGE_raw UC +#define GLSL_DRAW_IMAGE_MESH "UD" +#define GLSL_DRAW_IMAGE_MESH_raw UD +#define GLSL_DRAW_IMAGE_RECT "TC" +#define GLSL_DRAW_IMAGE_RECT_raw TC +#define GLSL_DRAW_INTERIOR_TRIANGLES "GB" +#define GLSL_DRAW_INTERIOR_TRIANGLES_raw GB +#define GLSL_DRAW_PATH "KC" +#define GLSL_DRAW_PATH_raw KC +#define GLSL_DRAW_RENDER_TARGET_UPDATE_BOUNDS "VD" +#define GLSL_DRAW_RENDER_TARGET_UPDATE_BOUNDS_raw VD +#define GLSL_ENABLE_ADVANCED_BLEND "FB" +#define GLSL_ENABLE_ADVANCED_BLEND_raw FB +#define GLSL_ENABLE_CLIPPING "T" +#define GLSL_ENABLE_CLIPPING_raw T +#define GLSL_ENABLE_CLIP_RECT "BB" +#define GLSL_ENABLE_CLIP_RECT_raw BB +#define GLSL_ENABLE_EVEN_ODD "IC" +#define GLSL_ENABLE_EVEN_ODD_raw IC +#define GLSL_ENABLE_FEATHER "EB" +#define GLSL_ENABLE_FEATHER_raw EB +#define GLSL_ENABLE_HSL_BLEND_MODES "XB" +#define GLSL_ENABLE_HSL_BLEND_MODES_raw XB +#define GLSL_ENABLE_INSTANCE_INDEX "OD" +#define GLSL_ENABLE_INSTANCE_INDEX_raw OD +#define GLSL_ENABLE_KHR_BLEND "KD" +#define GLSL_ENABLE_KHR_BLEND_raw KD +#define GLSL_ENABLE_MIN_16_PRECISION "PD" +#define GLSL_ENABLE_MIN_16_PRECISION_raw PD +#define GLSL_ENABLE_NESTED_CLIPPING "CD" +#define GLSL_ENABLE_NESTED_CLIPPING_raw CD +#define GLSL_ENABLE_RASTERIZER_ORDERED_VIEWS "QD" +#define GLSL_ENABLE_RASTERIZER_ORDERED_VIEWS_raw QD +#define GLSL_ENABLE_TYPED_UAV_LOAD_STORE "FC" +#define GLSL_ENABLE_TYPED_UAV_LOAD_STORE_raw FC +#define GLSL_FIXED_FUNCTION_COLOR_OUTPUT "QB" +#define GLSL_FIXED_FUNCTION_COLOR_OUTPUT_raw QB +#define GLSL_FRAGMENT "HB" +#define GLSL_FRAGMENT_raw HB +#define GLSL_FRAMEBUFFER_BOTTOM_UP "DE" +#define GLSL_FRAMEBUFFER_BOTTOM_UP_raw DE +#define GLSL_FlushUniforms "VB" +#define GLSL_FlushUniforms_raw VB +#define GLSL_GLSL_VERSION "WB" +#define GLSL_GLSL_VERSION_raw WB +#define GLSL_INITIALIZE_PLS "WD" +#define GLSL_INITIALIZE_PLS_raw WD +#define GLSL_ImageDrawUniforms "EC" +#define GLSL_ImageDrawUniforms_raw EC +#define GLSL_LOAD_COLOR "TD" +#define GLSL_LOAD_COLOR_raw TD +#define GLSL_OPTIONALLY_FLAT "OB" +#define GLSL_OPTIONALLY_FLAT_raw OB +#define GLSL_PLS_BLEND_SRC_OVER "ZB" +#define GLSL_PLS_BLEND_SRC_OVER_raw ZB +#define GLSL_PLS_IMPL_ANGLE "_EXPORTED_PLS_IMPL_ANGLE" +#define GLSL_PLS_IMPL_ANGLE_raw _EXPORTED_PLS_IMPL_ANGLE +#define GLSL_PLS_IMPL_DEVICE_BUFFER "LE" +#define GLSL_PLS_IMPL_DEVICE_BUFFER_raw LE +#define GLSL_PLS_IMPL_DEVICE_BUFFER_RASTER_ORDERED "ME" +#define GLSL_PLS_IMPL_DEVICE_BUFFER_RASTER_ORDERED_raw ME +#define GLSL_PLS_IMPL_EXT_NATIVE "GE" +#define GLSL_PLS_IMPL_EXT_NATIVE_raw GE +#define GLSL_PLS_IMPL_FRAMEBUFFER_FETCH "HE" +#define GLSL_PLS_IMPL_FRAMEBUFFER_FETCH_raw HE +#define GLSL_PLS_IMPL_NONE "KE" +#define GLSL_PLS_IMPL_NONE_raw KE +#define GLSL_PLS_IMPL_STORAGE_TEXTURE "IE" +#define GLSL_PLS_IMPL_STORAGE_TEXTURE_raw IE +#define GLSL_PLS_IMPL_SUBPASS_LOAD "JE" +#define GLSL_PLS_IMPL_SUBPASS_LOAD_raw JE +#define GLSL_POST_INVERT_Y "EE" +#define GLSL_POST_INVERT_Y_raw EE +#define GLSL_RENDER_MODE_MSAA "DB" +#define GLSL_RENDER_MODE_MSAA_raw DB +#define GLSL_RESOLVE_PLS "HC" +#define GLSL_RESOLVE_PLS_raw HC +#define GLSL_STORE_COLOR "FD" +#define GLSL_STORE_COLOR_raw FD +#define GLSL_STORE_COLOR_CLEAR "XD" +#define GLSL_STORE_COLOR_CLEAR_raw XD +#define GLSL_SWIZZLE_COLOR_BGRA_TO_RGBA "YD" +#define GLSL_SWIZZLE_COLOR_BGRA_TO_RGBA_raw YD +#define GLSL_TARGET_VULKAN "CC" +#define GLSL_TARGET_VULKAN_raw CC +#define GLSL_TESS_TEXTURE_FLOATING_POINT "CE" +#define GLSL_TESS_TEXTURE_FLOATING_POINT_raw CE +#define GLSL_USE_TEXEL_FETCH_WITH_FRAG_COORD "NC" +#define GLSL_USE_TEXEL_FETCH_WITH_FRAG_COORD_raw NC +#define GLSL_USING_PLS_STORAGE_TEXTURES "DD" +#define GLSL_USING_PLS_STORAGE_TEXTURES_raw DD +#define GLSL_VERTEX "AB" +#define GLSL_VERTEX_raw AB +#define GLSL_VULKAN_VENDOR_ID "BD" +#define GLSL_VULKAN_VENDOR_ID_raw BD +#define GLSL_a_args "RB" +#define GLSL_a_args_raw RB +#define GLSL_a_color0 "YC" +#define GLSL_a_color0_raw YC +#define GLSL_a_color1 "ZC" +#define GLSL_a_color1_raw ZC +#define GLSL_a_contourIDWithFlags "JD" +#define GLSL_a_contourIDWithFlags_raw JD +#define GLSL_a_imageRectVertex "YB" +#define GLSL_a_imageRectVertex_raw YB +#define GLSL_a_joinTan_and_ys "GC" +#define GLSL_a_joinTan_and_ys_raw GC +#define GLSL_a_mirroredVertexData "MB" +#define GLSL_a_mirroredVertexData_raw MB +#define GLSL_a_p0p1_ "RC" +#define GLSL_a_p0p1__raw RC +#define GLSL_a_p2p3_ "SC" +#define GLSL_a_p2p3__raw SC +#define GLSL_a_patchVertexData "LB" +#define GLSL_a_patchVertexData_raw LB +#define GLSL_a_position "SB" +#define GLSL_a_position_raw SB +#define GLSL_a_reflectionX0X1 "HD" +#define GLSL_a_reflectionX0X1_raw HD +#define GLSL_a_segmentCounts "ID" +#define GLSL_a_segmentCounts_raw ID +#define GLSL_a_span "AC" +#define GLSL_a_span_raw AC +#define GLSL_a_spanX "WC" +#define GLSL_a_spanX_raw WC +#define GLSL_a_texCoord "TB" +#define GLSL_a_texCoord_raw TB +#define GLSL_a_triangleVertex "IB" +#define GLSL_a_triangleVertex_raw IB +#define GLSL_a_x0x1 "GD" +#define GLSL_a_x0x1_raw GD +#define GLSL_a_yWithFlags "XC" +#define GLSL_a_yWithFlags_raw XC +#define GLSL_atlasFillFragmentMain "RE" +#define GLSL_atlasFillFragmentMain_raw RE +#define GLSL_atlasStrokeFragmentMain "TE" +#define GLSL_atlasStrokeFragmentMain_raw TE +#define GLSL_atlasTexture "ND" +#define GLSL_atlasTexture_raw ND +#define GLSL_atlasVertexMain "PE" +#define GLSL_atlasVertexMain_raw PE +#define GLSL_blitFragmentMain "MD" +#define GLSL_blitFragmentMain_raw MD +#define GLSL_blitVertexMain "ZD" +#define GLSL_blitVertexMain_raw ZD +#define GLSL_clearColor "SD" +#define GLSL_clearColor_raw SD +#define GLSL_colorRampFragmentMain "BE" +#define GLSL_colorRampFragmentMain_raw BE +#define GLSL_colorRampVertexMain "AE" +#define GLSL_colorRampVertexMain_raw AE +#define GLSL_contourBuffer "QC" +#define GLSL_contourBuffer_raw QC +#define GLSL_drawFragmentMain "NB" +#define GLSL_drawFragmentMain_raw NB +#define GLSL_drawVertexMain "PB" +#define GLSL_drawVertexMain_raw PB +#define GLSL_dstColorTexture "PC" +#define GLSL_dstColorTexture_raw PC +#define GLSL_featherTexture "JC" +#define GLSL_featherTexture_raw JC +#define GLSL_gradTexture "MC" +#define GLSL_gradTexture_raw MC +#define GLSL_imageTexture "UB" +#define GLSL_imageTexture_raw UB +#define GLSL_paintAuxBuffer "KB" +#define GLSL_paintAuxBuffer_raw KB +#define GLSL_paintBuffer "DC" +#define GLSL_paintBuffer_raw DC +#define GLSL_pathBuffer "JB" +#define GLSL_pathBuffer_raw JB +#define GLSL_sourceTexture "VC" +#define GLSL_sourceTexture_raw VC +#define GLSL_stencilVertexMain "UE" +#define GLSL_stencilVertexMain_raw UE +#define GLSL_tessVertexTexture "BC" +#define GLSL_tessVertexTexture_raw BC +#define GLSL_tessellateFragmentMain "WE" +#define GLSL_tessellateFragmentMain_raw WE +#define GLSL_tessellateVertexMain "VE" +#define GLSL_tessellateVertexMain_raw VE diff --git a/third_party/rive_renderer/source/generated/shaders/rhi.glsl.hpp b/third_party/rive_renderer/source/generated/shaders/rhi.glsl.hpp new file mode 100644 index 0000000..04dc0b2 --- /dev/null +++ b/third_party/rive_renderer/source/generated/shaders/rhi.glsl.hpp @@ -0,0 +1,167 @@ +#pragma once + +#include "rhi.exports.h" + +namespace rive { +namespace gpu { +namespace glsl { +const char rhi[] = R"===(#pragma warning(disable:3550) +#pragma warning(disable:4000) +#ifndef _ARE_TOKEN_NAMES_PRESERVED +#define g half +#define G half2 +#define A half3 +#define i half4 +#define a0 ushort +#define c float2 +#define Z float3 +#define f float4 +#define a5 bool2 +#define G7 bool3 +#define N0 uint2 +#define M uint4 +#define c0 int2 +#define h7 int4 +#define a0 ushort +#define S float2x2 +#define U5 half3x3 +#define V5 half2x3 +#endif +typedef Z a4; +#ifdef PD +#if Ie +typedef min16uint a0; +#endif +#else +#if Ie +typedef uint a0; +#endif +#endif +#define Tb(o,r) o##r +#define d inline +#define k1(P1) out P1 +#define i4(P1) inout P1 +#define U0(a) struct a{ +#define i0(e,W,a) W a:Tb(Sf,e) +#define V0 }; +#define l0(H7,B,a,W) W a=B.a +#define e5(e,a) cbuffer a{struct{ +#define W5(a) }a;} +#define o1 struct k0{ +#define n0 noperspective +#define OB nointerpolation +#define L2 nointerpolation +#define H(e,W,a) W a:Tb(TEXCOORD,e) +#define p1 f g1:SV_Position;}; +#define L(a,W) W a +#define P(a) X.a=a +#define N(a,W) W a=X.a +#ifdef AB +#define P2 +#define Q2 +#endif +#ifdef HB +#define R2 +#define S2 +#endif +#define p4 +#define q4 +#define I3(g0,e,a) uniform Texture2Da +#define r4(g0,e,a) uniform Texture2Da +#define C2(g0,e,a) uniform Texture2Da +#define y4(g0,e,a) uniform Texture2Da +#define l5(g0,e,a) uniform Texture2DArraya +#define F4(m2,a) SamplerState a; +#define P3 F4 +#define G3 F4 +#define d1(a,l) a[l] +#define D4(a,p,l) a.Sample(p,l) +#define T1(a,p,l,G0) a.SampleLevel(p,l,G0) +#define p5(a,p,l,X2) a.Gather(p,(l)*(X2)) +#define T5(a,p,m,w5,K7,G0) a.SampleLevel(p,Z(m,0.5,w5),G0) +#define o4(A0,p,l) D4(A0,p,l) +#define C7(A0,p,l,G0) T1(A0,p,l,G0) +#define h2 +#define j2 +#ifdef QD +#define n2 RasterizerOrderedTexture2D +#else +#define n2 RWTexture2D +#endif +#define x2 +#ifdef FC +#define M0(e,a) uniform n2a +#else +#define M0(e,a) uniform n2a +#endif +#define O4 M0 +#define Y0(e,a) uniform n2a +#define f4 Y0 +#define m4 j1 +#define n4 l1 +#define y2 +#ifdef FC +#define I0(h) h[I] +#else +#define I0(h) unpackUnorm4x8(h[I]) +#endif +#define j1(h) h[I] +#ifdef FC +#define T0(h,F) h[I]=(F) +#else +#define T0(h,F) h[I]=packUnorm4x8(F) +#endif +#define l1(h,F) h[I]=(F) +d uint r6(n2G4,c0 I,uint x){uint B1;InterlockedMax(G4[I],x,B1);return B1;} +#define G5(h,m) r6(h,I,m) +d uint v6(n2G4,c0 I,uint x){uint B1;InterlockedAdd(G4[I],x,B1);return B1;} +#define H5(h,m) v6(h,I,m) +#define E2(h) +#define i2(h) +#define q5 +#define Y1 +#define n5 +#define x1 +#define q1(a,f0,B,n,K) uint baseInstance;k0 a(f0 B,uint n:SV_VertexID,uint A9:SV_InstanceID){uint K=A9+baseInstance;k0 X; +#define G6(a,f0,B,n,K) k0 a(f0 B,uint n:SV_VertexID){k0 X;f g1; +#define N4(a,a2,c2,v2,w2,n) k0 a(a2 c2,v2 w2,uint n:SV_VertexID){k0 X;f g1; +#define h1(w6) X.g1=w6;}return X; +#define e2(E4,a) E4 a(k0 X):SV_Target{ +#define f2(F) return F;} +#define C5 ,c y0 +#define Y2 ,y0 +#define y3 ,c0 I +#define G1 ,I +#define z2(a) Ke void a(k0 X){c y0=X.g1.xy;c0 I=c0(floor(y0)); +#define R4(a) z2(a) +#define M2 } +#define A3(a) Ke i a(k0 X):SV_Target{c y0=X.g1.xy;c0 I=c0(floor(y0));i K1; +#define F5(a) A3(a) +#define P4 }return K1; +#define uintBitsToFloat asfloat +#define floatBitsToInt asint +#define floatBitsToUint asuint +#define inversesqrt rsqrt +#define equal(o,r) ((o)==(r)) +#define notEqual(o,r) ((o)!=(r)) +#define lessThan(o,r) ((o)<(r)) +#define C0(o,r) mul(r,o) +#define E3 +#define F3 +#define w3 +#define x3 +#define g4(e,f1,a) StructuredBuffera +#define O3(e,f1,a) StructuredBuffera +#define h4(e,f1,a) StructuredBuffera +#define w0(a,v0) a[v0] +#define k4(a,v0) a[v0] +d G unpackHalf2x16(uint u){uint y=(u>>16);uint x=u&0xffffu;return G(f16tof32(x),f16tof32(y));}d uint packHalf2x16(c M1){uint x=f32tof16(M1.x);uint y=f32tof16(M1.y);return(y<<16)|x;}d i unpackUnorm4x8(uint u){M A1=M(u&0xffu,(u>>8)&0xffu,(u>>16)&0xffu,u>>24);return i(A1)*(1./255.);}d uint packUnorm4x8(i j){M A1=(M(j*255.)&0xff)<a +#define r4(g0,e,a) uniform Texture2Da +#define C2(g0,e,a) uniform Texture2Da +#define y4(g0,e,a) uniform Texture2Da +#define l5(g0,e,a) uniform Texture2DArraya +#define F4(m2,a) SamplerState a; +#define P3 F4 +#define G3 F4 +#define d1(a,l) a[l] +#define D4(a,p,l) a.Sample(p,l) +#define T1(a,p,l,G0) a.SampleLevel(p,l,G0) +#define p5(a,p,l,X2) a.Gather(p,(l)*(X2)) +#define T5(a,p,m,w5,K7,G0) a.SampleLevel(p,Z(m,0.5,w5),G0) +#define o4(A0,p,l) D4(A0,p,l) +#define C7(A0,p,l,G0) T1(A0,p,l,G0) +#define h2 +#define j2 +#ifdef ENABLE_RASTERIZER_ORDERED_VIEWS +#define n2 RasterizerOrderedTexture2D +#else +#define n2 RWTexture2D +#endif +#define x2 +#ifdef ENABLE_TYPED_UAV_LOAD_STORE +#define M0(e,a) uniform n2a +#else +#define M0(e,a) uniform n2a +#endif +#define O4 M0 +#define Y0(e,a) uniform n2a +#define f4 Y0 +#define m4 j1 +#define n4 l1 +#define y2 +#ifdef ENABLE_TYPED_UAV_LOAD_STORE +#define I0(h) h[I] +#else +#define I0(h) unpackUnorm4x8(h[I]) +#endif +#define j1(h) h[I] +#ifdef ENABLE_TYPED_UAV_LOAD_STORE +#define T0(h,F) h[I]=(F) +#else +#define T0(h,F) h[I]=packUnorm4x8(F) +#endif +#define l1(h,F) h[I]=(F) +d uint r6(n2G4,c0 I,uint x){uint B1;InterlockedMax(G4[I],x,B1);return B1;} +#define G5(h,m) r6(h,I,m) +d uint v6(n2G4,c0 I,uint x){uint B1;InterlockedAdd(G4[I],x,B1);return B1;} +#define H5(h,m) v6(h,I,m) +#define E2(h) +#define i2(h) +#define q5 +#define Y1 +#define n5 +#define x1 +#define q1(a,f0,B,n,K) uint baseInstance;k0 a(f0 B,uint n:SV_VertexID,uint A9:SV_InstanceID){uint K=A9+baseInstance;k0 X; +#define G6(a,f0,B,n,K) k0 a(f0 B,uint n:SV_VertexID){k0 X;f g1; +#define N4(a,a2,c2,v2,w2,n) k0 a(a2 c2,v2 w2,uint n:SV_VertexID){k0 X;f g1; +#define h1(w6) X.g1=w6;}return X; +#define e2(E4,a) E4 a(k0 X):SV_Target{ +#define f2(F) return F;} +#define C5 ,c y0 +#define Y2 ,y0 +#define y3 ,c0 I +#define G1 ,I +#define z2(a) Ke void a(k0 X){c y0=X.g1.xy;c0 I=c0(floor(y0)); +#define R4(a) z2(a) +#define M2 } +#define A3(a) Ke i a(k0 X):SV_Target{c y0=X.g1.xy;c0 I=c0(floor(y0));i K1; +#define F5(a) A3(a) +#define P4 }return K1; +#define uintBitsToFloat asfloat +#define floatBitsToInt asint +#define floatBitsToUint asuint +#define inversesqrt rsqrt +#define equal(o,r) ((o)==(r)) +#define notEqual(o,r) ((o)!=(r)) +#define lessThan(o,r) ((o)<(r)) +#define C0(o,r) mul(r,o) +#define E3 +#define F3 +#define w3 +#define x3 +#define g4(e,f1,a) StructuredBuffera +#define O3(e,f1,a) StructuredBuffera +#define h4(e,f1,a) StructuredBuffera +#define w0(a,v0) a[v0] +#define k4(a,v0) a[v0] +d G unpackHalf2x16(uint u){uint y=(u>>16);uint x=u&0xffffu;return G(f16tof32(x),f16tof32(y));}d uint packHalf2x16(c M1){uint x=f32tof16(M1.x);uint y=f32tof16(M1.y);return(y<<16)|x;}d i unpackUnorm4x8(uint u){M A1=M(u&0xffu,(u>>8)&0xffu,(u>>16)&0xffu,u>>24);return i(A1)*(1./255.);}d uint packUnorm4x8(i j){M A1=(M(j*255.)&0xff)<>16); +#else +float O7=float(E9<<16>>16); +#endif +float P7=float(E9>>16);c S1=c((n&1)==0?O7:P7,(n&2)==0?y+1.:y);if((P7-O7)*q.Fa<.0){S1.y=2.*y+1.-S1.y;}uint r2=RB.z&0x3ffu;uint Wb=(RB.z>>10)&0x3ffu;uint O1=RB.z>>20;uint Y=RB.w;uint R=Y!=sd?w0(QC,Aa(Y)).z:0u;M R3=R!=0u?w0(JB,R*4u+1u):M(0u,0u,0u,0u);float k2=uintBitsToFloat(R3.z);float l2=uintBitsToFloat(R3.w);if(l2!=.0&&k2==.0){float Xb;float We=Xc(o0,p0,x0,z0,Xb);float F9=l2*(1./U8);float Xe=Sc(o0,p0,x0,z0,Xb,F9);float B6=1.-Xe*(1./O2);float Ye=dot(z0-o0,z0-o0)/(F9*F9);float Ze=(Ye-1.)*.5;B6=min(B6,Ze);B6=min(B6,.99);float af=.5*B6;float x=Z4(af)*-2.+1.;float Yb=a7(x*l2,We);f Zb=mix(o0.xyxy,z0.xyxy,f(1./3.,1./3.,2./3.,2./3.));p0=mix(p0,Zb.xy,Yb);x0=mix(x0,Zb.zw,Yb);}if((Y&od)!=0u){S ac=D1(uintBitsToFloat(w0(JB,R*4u)));c bc=C0(ac,-2.*p0+x0+o0);c cc=C0(ac,-2.*x0+z0+p0);float W0=max(dot(bc,bc),dot(cc,cc));float e4=max(ceil(sqrt(.75*4.*sqrt(W0))),1.);r2=min(uint(e4),r2);}uint Q7=r2+Wb+O1-1u;S d2=D8(o0,p0,x0,z0);float O0=acos(C8(d2[0],d2[1]));float n3=O0/float(Wb);float G9=determinant(S(x0-o0,z0-p0));if(G9==.0)G9=determinant(d2);if(G9<.0)n3=-n3;x5=f(o0,p0);y5=f(x0,z0);W3=f(float(Q7)-abs(P7-S1.x),float(Q7),(O1<<10)|r2,n3);if(O1>1u){S H9=S(d2[1],GC.xy);float bf=acos(C8(H9[0],H9[1]));float dc=float(O1);if((Y&(a3|k7))==(i7|k7)){dc-=2.;}float I9=bf/dc;if(determinant(H9)<.0)I9=-I9;J4.xy=GC.xy;J4.z=I9;}if(P7>10);float n3=W3.w;uint Y=A6;float X3=Q7-O1;float X1=cf;if(X1<=X3){Y&=~a3;}else{o0=p0=x0=z0;d2=S(d2[1],J4.xy);r2=1.;X1-=X3;X3=O1;n3=J4.z;if((Y&a3)>i7){if(X1<2.5)Y|=V8;if(X1>1.5&&X1<3.5)Y|=Qa;}else if((Y&k7)!=0u||(Y&a3)==j7){X3-=2.;--X1;}Y|=n3<.0?l7:Ra;}c R7;float O0=.0;if(X1==.0||X1==X3||(Y&a3)>i7){bool x7=X1=0;--z5){float C6=S7+exp2(float(z5));if(C6<=ef){c K9=C6*o+df;K9=C6*K9+M5;float hf=dot(normalize(K9),J9);float L9=C6*ff+gf;L9=min(L9,O2);if(hf>=cos(L9))S7=C6;}}float jf=S7/r2;float fc=X1-S7;float T7=acos(clamp(J9.x,-1.,1.));T7=J9.y>=.0?T7:-T7;O0=fc*n3+T7;c B2=c(sin(O0),-cos(O0));float k=dot(B2,o),U7=dot(B2,r),B0=dot(B2,L1);float kf=max(U7*U7-k*B0,.0);float V1=sqrt(kf);if(U7>.0)V1=-V1;V1-=U7;float gc=-.5*V1*k;c M9=(abs(V1*V1+gc)>16); +#else +float O7=float(E9<<16>>16); +#endif +float P7=float(E9>>16);c S1=c((n&1)==0?O7:P7,(n&2)==0?y+1.:y);if((P7-O7)*q.Fa<.0){S1.y=2.*y+1.-S1.y;}uint r2=RB.z&0x3ffu;uint Wb=(RB.z>>10)&0x3ffu;uint O1=RB.z>>20;uint Y=RB.w;uint R=Y!=sd?w0(QC,Aa(Y)).z:0u;M R3=R!=0u?w0(JB,R*4u+1u):M(0u,0u,0u,0u);float k2=uintBitsToFloat(R3.z);float l2=uintBitsToFloat(R3.w);if(l2!=.0&&k2==.0){float Xb;float We=Xc(o0,p0,x0,z0,Xb);float F9=l2*(1./U8);float Xe=Sc(o0,p0,x0,z0,Xb,F9);float B6=1.-Xe*(1./O2);float Ye=dot(z0-o0,z0-o0)/(F9*F9);float Ze=(Ye-1.)*.5;B6=min(B6,Ze);B6=min(B6,.99);float af=.5*B6;float x=Z4(af)*-2.+1.;float Yb=a7(x*l2,We);f Zb=mix(o0.xyxy,z0.xyxy,f(1./3.,1./3.,2./3.,2./3.));p0=mix(p0,Zb.xy,Yb);x0=mix(x0,Zb.zw,Yb);}if((Y&od)!=0u){S ac=D1(uintBitsToFloat(w0(JB,R*4u)));c bc=C0(ac,-2.*p0+x0+o0);c cc=C0(ac,-2.*x0+z0+p0);float W0=max(dot(bc,bc),dot(cc,cc));float e4=max(ceil(sqrt(.75*4.*sqrt(W0))),1.);r2=min(uint(e4),r2);}uint Q7=r2+Wb+O1-1u;S d2=D8(o0,p0,x0,z0);float O0=acos(C8(d2[0],d2[1]));float n3=O0/float(Wb);float G9=determinant(S(x0-o0,z0-p0));if(G9==.0)G9=determinant(d2);if(G9<.0)n3=-n3;x5=f(o0,p0);y5=f(x0,z0);W3=f(float(Q7)-abs(P7-S1.x),float(Q7),(O1<<10)|r2,n3);if(O1>1u){S H9=S(d2[1],GC.xy);float bf=acos(C8(H9[0],H9[1]));float dc=float(O1);if((Y&(a3|k7))==(i7|k7)){dc-=2.;}float I9=bf/dc;if(determinant(H9)<.0)I9=-I9;J4.xy=GC.xy;J4.z=I9;}if(P7>10);float n3=W3.w;uint Y=A6;float X3=Q7-O1;float X1=cf;if(X1<=X3){Y&=~a3;}else{o0=p0=x0=z0;d2=S(d2[1],J4.xy);r2=1.;X1-=X3;X3=O1;n3=J4.z;if((Y&a3)>i7){if(X1<2.5)Y|=V8;if(X1>1.5&&X1<3.5)Y|=Qa;}else if((Y&k7)!=0u||(Y&a3)==j7){X3-=2.;--X1;}Y|=n3<.0?l7:Ra;}c R7;float O0=.0;if(X1==.0||X1==X3||(Y&a3)>i7){bool x7=X1=0;--z5){float C6=S7+exp2(float(z5));if(C6<=ef){c K9=C6*o+df;K9=C6*K9+M5;float hf=dot(normalize(K9),J9);float L9=C6*ff+gf;L9=min(L9,O2);if(hf>=cos(L9))S7=C6;}}float jf=S7/r2;float fc=X1-S7;float T7=acos(clamp(J9.x,-1.,1.));T7=J9.y>=.0?T7:-T7;O0=fc*n3+T7;c B2=c(sin(O0),-cos(O0));float k=dot(B2,o),U7=dot(B2,r),B0=dot(B2,L1);float kf=max(U7*U7-k*B0,.0);float V1=sqrt(kf);if(U7>.0)V1=-V1;V1-=U7;float gc=-.5*V1*k;c M9=(abs(V1*V1+gc) +#include +#include +#include + +#include "generated/shaders/glsl.glsl.hpp" + +#ifdef BYPASS_EMSCRIPTEN_SHADER_PARSER +#include +#include + +// Emscripten's shader preprocessor crashes on PLS shaders. This method allows +// us to bypass Emscripten and set a WebGL shader source directly. +EM_JS(void, + webgl_shader_source, + (EMSCRIPTEN_WEBGL_CONTEXT_HANDLE gl, GLuint shader, const char* source), + { + gl = GL.getContext(gl).GLctx; + shader = GL.shaders[shader]; + source = UTF8ToString(source); + gl.shaderSource(shader, source); + }); +#endif + +namespace glutils +{ +void CompileAndAttachShader(GLuint program, + GLenum type, + const char* source, + const GLCapabilities& capabilities) +{ + CompileAndAttachShader(program, type, nullptr, 0, &source, 1, capabilities); +} + +void CompileAndAttachShader(GLuint program, + GLenum type, + const char* defines[], + size_t numDefines, + const char* inputSources[], + size_t numInputSources, + const GLCapabilities& capabilities) +{ + GLuint shader = CompileShader(type, + defines, + numDefines, + inputSources, + numInputSources, + capabilities); + glAttachShader(program, shader); + glDeleteShader(shader); +} + +GLuint CompileShader(GLuint type, + const char* source, + const GLCapabilities& capabilities) +{ + return CompileShader(type, nullptr, 0, &source, 1, capabilities); +} + +GLuint CompileShader(GLuint type, + const char* defines[], + size_t numDefines, + const char* inputSources[], + size_t numInputSources, + const GLCapabilities& capabilities) +{ + std::ostringstream shaderSource; + shaderSource << "#version " << capabilities.contextVersionMajor + << capabilities.contextVersionMinor << '0'; + if (capabilities.isGLES) + { + shaderSource << " es"; + } + shaderSource << '\n'; + // Create our own "GLSL_VERSION" macro. In "#version 320 es", Qualcomm + // incorrectly substitutes + // __VERSION__ to 300. + shaderSource << "#define " << GLSL_GLSL_VERSION << ' ' + << capabilities.contextVersionMajor + << capabilities.contextVersionMinor << "0\n"; + if (type == GL_VERTEX_SHADER) + { + shaderSource << "#define " << GLSL_VERTEX "\n"; + } + else if (GL_FRAGMENT_SHADER) + { + shaderSource << "#define " << GLSL_FRAGMENT "\n"; + } + for (size_t i = 0; i < numDefines; ++i) + { + shaderSource << "#define " << defines[i] << " true\n"; + } + if (!capabilities.ANGLE_base_vertex_base_instance_shader_builtin) + { + shaderSource << "#define " << GLSL_BASE_INSTANCE_UNIFORM_NAME << ' ' + << BASE_INSTANCE_UNIFORM_NAME << '\n'; + } + if (capabilities.needsFloatingPointTessellationTexture) + { + shaderSource << "#define " << GLSL_TESS_TEXTURE_FLOATING_POINT << '\n'; + } + shaderSource << rive::gpu::glsl::glsl << "\n"; + for (size_t i = 0; i < numInputSources; ++i) + { + shaderSource << inputSources[i] << "\n"; + } + return CompileRawGLSL(type, shaderSource.str().c_str()); +} + +[[nodiscard]] GLuint CompileRawGLSL(GLenum shaderType, const char* rawGLSL) +{ + GLuint shader = glCreateShader(shaderType); +#ifdef BYPASS_EMSCRIPTEN_SHADER_PARSER + // Emscripten's shader preprocessor crashes on PLS shaders. Feed Emscripten + // something very simple and then hop to WebGL to bypass it and set the real + // shader source. + const char* kMinimalShader = + shaderType == GL_VERTEX_SHADER + ? "#version 300 es\nvoid main() { gl_Position = vec4(0); }" + : "#version 300 es\nvoid main() {}"; + glShaderSource(shader, 1, &kMinimalShader, nullptr); + webgl_shader_source(emscripten_webgl_get_current_context(), + shader, + rawGLSL); +#else + glShaderSource(shader, 1, &rawGLSL, nullptr); +#endif + glCompileShader(shader); +#ifdef DEBUG + GLint isCompiled = 0; + glGetShaderiv(shader, GL_COMPILE_STATUS, &isCompiled); + if (isCompiled == GL_FALSE) + { + GLint maxLength = 0; + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &maxLength); + std::vector infoLog(maxLength); + glGetShaderInfoLog(shader, maxLength, &maxLength, &infoLog[0]); + fprintf(stderr, "Failed to compile shader\n"); + // Print the error message *before* the shader in case stderr hasn't + // finished flushing when we call abort() further on. + fprintf(stderr, "%s\n", &infoLog[0]); + int l = 1; + std::stringstream stream(rawGLSL); + std::string lineStr; + while (std::getline(stream, lineStr, '\n')) + { + fprintf(stderr, "%4i| %s\n", l++, lineStr.c_str()); + } + // Print the error message, again, *after* the shader where it's easier + // to find in the console. + fprintf(stderr, "%s\n", &infoLog[0]); + fflush(stderr); + glDeleteShader(shader); + // Give stderr another second to finish flushing before we abort. + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + abort(); + } +#endif + return shader; +} + +void LinkProgram(GLuint program) +{ + glLinkProgram(program); +#ifdef DEBUG + GLint isLinked = 0; + glGetProgramiv(program, GL_LINK_STATUS, &isLinked); + if (isLinked == GL_FALSE) + { + GLint maxLength = 0; + glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength); + std::vector infoLog(maxLength); + glGetProgramInfoLog(program, maxLength, &maxLength, &infoLog[0]); + fprintf(stderr, "Failed to link program %s\n", &infoLog[0]); + fflush(stderr); + abort(); + } +#endif +} + +void Program::reset(GLuint adoptedProgramID) +{ + m_fragmentShader.reset(); + m_vertexShader.reset(); + if (m_id != 0) + { + glDeleteProgram(m_id); + } + m_id = adoptedProgramID; +} + +void Program::compileAndAttachShader(GLuint type, + const char* defines[], + size_t numDefines, + const char* sources[], + size_t numSources, + const GLCapabilities& capabilities) +{ + assert(type == GL_VERTEX_SHADER || type == GL_FRAGMENT_SHADER); + glutils::Shader& internalShader = + type == GL_VERTEX_SHADER ? m_vertexShader : m_fragmentShader; + internalShader + .compile(type, defines, numDefines, sources, numSources, capabilities); + glAttachShader(m_id, internalShader); +} + +void Shader::compile(GLenum type, + const char* defines[], + size_t numDefines, + const char* sources[], + size_t numSources, + const GLCapabilities& capabilities) +{ + reset(CompileShader(type, + defines, + numDefines, + sources, + numSources, + capabilities)); +} + +void SetTexture2DSamplingParams(GLenum minFilter, GLenum magFilter) +{ + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilter); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); +} + +GLint gl_wrap_from_image_wrap(rive::ImageWrap wrap) +{ + switch (wrap) + { + case rive::ImageWrap::clamp: + return GL_CLAMP_TO_EDGE; + case rive::ImageWrap::repeat: + return GL_REPEAT; + case rive::ImageWrap::mirror: + return GL_MIRRORED_REPEAT; + } + + RIVE_UNREACHABLE(); +} + +GLint gl_min_filter_for_image_filter(rive::ImageFilter filter) +{ + switch (filter) + { + case rive::ImageFilter::trilinear: + return GL_LINEAR_MIPMAP_LINEAR; + case rive::ImageFilter::nearest: + return GL_NEAREST; + } + + RIVE_UNREACHABLE(); +} + +GLint gl_mag_filter_for_image_filter(rive::ImageFilter filter) +{ + switch (filter) + { + case rive::ImageFilter::trilinear: + return GL_LINEAR; + case rive::ImageFilter::nearest: + return GL_NEAREST; + } + + RIVE_UNREACHABLE(); +} + +void SetTexture2DSamplingParams(rive::ImageSampler samplingParams) +{ + glTexParameteri(GL_TEXTURE_2D, + GL_TEXTURE_MIN_FILTER, + gl_min_filter_for_image_filter(samplingParams.filter)); + glTexParameteri(GL_TEXTURE_2D, + GL_TEXTURE_MAG_FILTER, + gl_mag_filter_for_image_filter(samplingParams.filter)); + glTexParameteri(GL_TEXTURE_2D, + GL_TEXTURE_WRAP_S, + gl_wrap_from_image_wrap(samplingParams.wrapX)); + glTexParameteri(GL_TEXTURE_2D, + GL_TEXTURE_WRAP_T, + gl_wrap_from_image_wrap(samplingParams.wrapY)); +} + +void BlitFramebuffer(rive::IAABB bounds, + uint32_t renderTargetHeight, + GLbitfield mask) +{ + // glBlitFramebuffer is oriented bottom-up. + uint32_t l = bounds.left; + uint32_t b = renderTargetHeight - bounds.bottom; + uint32_t r = bounds.right; + uint32_t t = renderTargetHeight - bounds.top; + glBlitFramebuffer(l, b, r, t, l, b, r, t, mask, GL_NEAREST); +} + +void Uniform1iByName(GLuint programID, const char* name, GLint value) +{ + GLint location = glGetUniformLocation(programID, name); + // Don't allow non-existent uniforms. glUniform1i() is supposed to silently + // ignore -1, but Moto G7 Play throws an error. We also just shouldn't be + // querying uniform locations we know aren't going to exist anyway for + // performance reasons. + assert(location != -1); + glUniform1i(location, value); +} + +// Setup a small test to verify that GL_PIXEL_LOCAL_FORMAT_ANGLE has the correct +// value. +bool validate_pixel_local_storage_angle() +{ +#if defined(RIVE_DESKTOP_GL) || defined(RIVE_WEBGL) + glutils::Texture tex; + glBindTexture(GL_TEXTURE_2D, tex); + glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, 1, 1); + + glutils::Framebuffer fbo; + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + glFramebufferTexturePixelLocalStorageANGLE(0, tex, 0, 0); + + // Clear the error queue. (Should already be empty.) + while (GLenum err = glGetError()) + { + fprintf(stderr, "WARNING: unhandled GL error 0x%x\n", err); + } + + GLint format = GL_NONE; + glGetFramebufferPixelLocalStorageParameterivANGLE( + 0, + GL_PIXEL_LOCAL_FORMAT_ANGLE, + &format); + return glGetError() == GL_NONE && format == GL_R32UI; +#else + return false; +#endif +} +} // namespace glutils diff --git a/third_party/rive_renderer/source/gl/load_gles_extensions.cpp b/third_party/rive_renderer/source/gl/load_gles_extensions.cpp new file mode 100644 index 0000000..e3e7b49 --- /dev/null +++ b/third_party/rive_renderer/source/gl/load_gles_extensions.cpp @@ -0,0 +1,61 @@ +/* + * Copyright 2023 Rive + */ + +#include "rive/renderer/gl/gles3.hpp" + +#ifdef RIVE_ANDROID + +#include + +PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEEXTPROC +glDrawArraysInstancedBaseInstanceEXT = nullptr; +PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEEXTPROC +glDrawElementsInstancedBaseInstanceEXT = nullptr; +PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEEXTPROC +glDrawElementsInstancedBaseVertexBaseInstanceEXT = nullptr; +PFNGLFRAMEBUFFERFETCHBARRIERQCOMPROC glFramebufferFetchBarrierQCOM = nullptr; +PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC +glFramebufferTexture2DMultisampleEXT = nullptr; +PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC glRenderbufferStorageMultisampleEXT = + nullptr; + +void LoadGLESExtensions(const GLCapabilities& extensions) +{ + static GLCapabilities loadedExtensions{}; + if (extensions.EXT_base_instance && !loadedExtensions.EXT_base_instance) + { + glDrawArraysInstancedBaseInstanceEXT = + (PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEEXTPROC)eglGetProcAddress( + "glDrawArraysInstancedBaseInstanceEXT"); + glDrawElementsInstancedBaseInstanceEXT = + (PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEEXTPROC)eglGetProcAddress( + "glDrawElementsInstancedBaseInstanceEXT"); + glDrawElementsInstancedBaseVertexBaseInstanceEXT = + (PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEEXTPROC) + eglGetProcAddress( + "glDrawElementsInstancedBaseVertexBaseInstanceEXT"); + loadedExtensions.EXT_base_instance = true; + } + if (extensions.QCOM_shader_framebuffer_fetch_noncoherent && + !loadedExtensions.QCOM_shader_framebuffer_fetch_noncoherent) + { + glFramebufferFetchBarrierQCOM = + (PFNGLFRAMEBUFFERFETCHBARRIERQCOMPROC)eglGetProcAddress( + "glFramebufferFetchBarrierQCOM"); + loadedExtensions.QCOM_shader_framebuffer_fetch_noncoherent = true; + } + if (extensions.EXT_multisampled_render_to_texture && + !loadedExtensions.EXT_multisampled_render_to_texture) + { + glFramebufferTexture2DMultisampleEXT = + (PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC)eglGetProcAddress( + "glFramebufferTexture2DMultisampleEXT"); + glRenderbufferStorageMultisampleEXT = + (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC)eglGetProcAddress( + "glRenderbufferStorageMultisampleEXT"); + loadedExtensions.EXT_multisampled_render_to_texture = true; + } +} + +#endif diff --git a/third_party/rive_renderer/source/gl/load_store_actions_ext.cpp b/third_party/rive_renderer/source/gl/load_store_actions_ext.cpp new file mode 100644 index 0000000..3690dab --- /dev/null +++ b/third_party/rive_renderer/source/gl/load_store_actions_ext.cpp @@ -0,0 +1,60 @@ +/* + * Copyright 2023 Rive + */ + +#include "rive/renderer/gl/load_store_actions_ext.hpp" + +#include "generated/shaders/pls_load_store_ext.glsl.hpp" + +namespace rive::gpu +{ +LoadStoreActionsEXT BuildLoadActionsEXT(const gpu::FlushDescriptor& desc, + std::array* clearColor4f) +{ + LoadStoreActionsEXT actions = LoadStoreActionsEXT::clearCoverage; + if (desc.colorLoadAction == LoadAction::clear) + { + UnpackColorToRGBA32FPremul(desc.colorClearValue, clearColor4f->data()); + actions |= LoadStoreActionsEXT::clearColor; + } + else if (desc.colorLoadAction == LoadAction::preserveRenderTarget) + { + actions |= LoadStoreActionsEXT::loadColor; + } + if (desc.combinedShaderFeatures & gpu::ShaderFeatures::ENABLE_CLIPPING) + { + actions |= LoadStoreActionsEXT::clearClip; + } + return actions; +} + +std::ostream& BuildLoadStoreEXTGLSL(std::ostream& shader, + LoadStoreActionsEXT actions) +{ + auto addDefine = [&shader](const char* name) { + shader << "#define " << name << "\n"; + }; + if (actions & LoadStoreActionsEXT::clearColor) + { + addDefine(GLSL_CLEAR_COLOR); + } + if (actions & LoadStoreActionsEXT::loadColor) + { + addDefine(GLSL_LOAD_COLOR); + } + if (actions & LoadStoreActionsEXT::storeColor) + { + addDefine(GLSL_STORE_COLOR); + } + if (actions & LoadStoreActionsEXT::clearCoverage) + { + addDefine(GLSL_CLEAR_COVERAGE); + } + if (actions & LoadStoreActionsEXT::clearClip) + { + addDefine(GLSL_CLEAR_CLIP); + } + shader << gpu::glsl::pls_load_store_ext; + return shader; +} +} // namespace rive::gpu diff --git a/third_party/rive_renderer/source/gl/pls_impl_ext_native.cpp b/third_party/rive_renderer/source/gl/pls_impl_ext_native.cpp new file mode 100644 index 0000000..c055443 --- /dev/null +++ b/third_party/rive_renderer/source/gl/pls_impl_ext_native.cpp @@ -0,0 +1,177 @@ +/* + * Copyright 2023 Rive + */ + +#include "rive/renderer/gl/render_context_gl_impl.hpp" + +#include "rive/renderer/gl/load_store_actions_ext.hpp" +#include "rive/renderer/gl/gl_utils.hpp" +#include "rive/math/simd.hpp" +#include "rive/renderer/gl/render_target_gl.hpp" +#include + +#include "generated/shaders/pls_load_store_ext.exports.h" + +namespace rive::gpu +{ +// Wraps an EXT_shader_pixel_local_storage load/store program, described by a +// set of LoadStoreActions. +class PLSLoadStoreProgram +{ +public: + PLSLoadStoreProgram(const PLSLoadStoreProgram&) = delete; + PLSLoadStoreProgram& operator=(const PLSLoadStoreProgram&) = delete; + + PLSLoadStoreProgram(LoadStoreActionsEXT actions, + GLuint vertexShader, + gpu::ShaderFeatures combinedShaderFeatures, + rcp state) : + m_state(std::move(state)) + { + m_id = glCreateProgram(); + glAttachShader(m_id, vertexShader); + + std::ostringstream glsl; + glsl << "#version 300 es\n"; + glsl << "#define " GLSL_FRAGMENT "\n"; + BuildLoadStoreEXTGLSL(glsl, actions); + GLuint fragmentShader = + glutils::CompileRawGLSL(GL_FRAGMENT_SHADER, glsl.str().c_str()); + glAttachShader(m_id, fragmentShader); + glDeleteShader(fragmentShader); + + glutils::LinkProgram(m_id); + if (actions & LoadStoreActionsEXT::clearColor) + { + m_colorClearUniLocation = + glGetUniformLocation(m_id, GLSL_clearColor); + } + } + + ~PLSLoadStoreProgram() { m_state->deleteProgram(m_id); } + + GLuint id() const { return m_id; } + GLint clearColorUniLocation() const { return m_colorClearUniLocation; } + +private: + GLuint m_id; + GLint m_colorClearUniLocation = -1; + const rcp m_state; +}; + +class RenderContextGLImpl::PLSImplEXTNative + : public RenderContextGLImpl::PixelLocalStorageImpl +{ +public: + PLSImplEXTNative(const GLCapabilities& capabilities) : + m_capabilities(capabilities) + {} + + ~PLSImplEXTNative() + { + if (m_plsLoadStoreVertexShader != 0) + { + glDeleteShader(m_plsLoadStoreVertexShader); + } + m_state->deleteVAO(m_plsLoadStoreVAO); + } + + void init(rcp state) override { m_state = std::move(state); } + + bool supportsRasterOrdering(const GLCapabilities&) const override + { + return true; + } + bool supportsFragmentShaderAtomics( + const GLCapabilities& capabilities) const override + { + return false; + } + + void activatePixelLocalStorage(RenderContextGLImpl* impl, + const FlushDescriptor& desc) override + { + assert(impl->m_capabilities.EXT_shader_pixel_local_storage); + assert(impl->m_capabilities.EXT_shader_framebuffer_fetch || + impl->m_capabilities.ARM_shader_framebuffer_fetch); + + auto renderTarget = static_cast(desc.renderTarget); + renderTarget->bindDestinationFramebuffer(GL_FRAMEBUFFER); + glEnable(GL_SHADER_PIXEL_LOCAL_STORAGE_EXT); + + std::array clearColor4f; + LoadStoreActionsEXT actions = BuildLoadActionsEXT(desc, &clearColor4f); + const PLSLoadStoreProgram& plsProgram = + findLoadStoreProgram(actions, desc.combinedShaderFeatures); + m_state->bindProgram(plsProgram.id()); + if (plsProgram.clearColorUniLocation() >= 0) + { + glUniform4fv(plsProgram.clearColorUniLocation(), + 1, + clearColor4f.data()); + } + m_state->bindVAO(m_plsLoadStoreVAO); + m_state->setCullFace(GL_BACK); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + } + + void deactivatePixelLocalStorage(RenderContextGLImpl* impl, + const FlushDescriptor& desc) override + { + // Issue a fullscreen draw that transfers the color information in pixel + // local storage to the main framebuffer. + LoadStoreActionsEXT actions = LoadStoreActionsEXT::storeColor; + m_state->bindProgram( + findLoadStoreProgram(actions, desc.combinedShaderFeatures).id()); + m_state->bindVAO(m_plsLoadStoreVAO); + m_state->setCullFace(GL_BACK); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + glDisable(GL_SHADER_PIXEL_LOCAL_STORAGE_EXT); + } + + void pushShaderDefines(gpu::InterlockMode, + std::vector* defines) const override + { + defines->push_back(GLSL_PLS_IMPL_EXT_NATIVE); + } + +private: + const PLSLoadStoreProgram& findLoadStoreProgram( + LoadStoreActionsEXT actions, + gpu::ShaderFeatures combinedShaderFeatures) + { + if (m_plsLoadStoreVertexShader == 0) + { + std::ostringstream glsl; + glsl << "#version 300 es\n"; + glsl << "#define " GLSL_VERTEX "\n"; + BuildLoadStoreEXTGLSL(glsl, LoadStoreActionsEXT::none); + m_plsLoadStoreVertexShader = + glutils::CompileRawGLSL(GL_VERTEX_SHADER, glsl.str().c_str()); + glGenVertexArrays(1, &m_plsLoadStoreVAO); + } + + const uint32_t programKey = static_cast(actions); + return m_plsLoadStorePrograms + .try_emplace(programKey, + actions, + m_plsLoadStoreVertexShader, + combinedShaderFeatures, + m_state) + .first->second; + } + + const GLCapabilities m_capabilities; + std::map m_plsLoadStorePrograms; + GLuint m_plsLoadStoreVertexShader = 0; + GLuint m_plsLoadStoreVAO = 0; + rcp m_state; +}; + +std::unique_ptr +RenderContextGLImpl::MakePLSImplEXTNative(const GLCapabilities& capabilities) +{ + return std::make_unique(capabilities); +} +} // namespace rive::gpu diff --git a/third_party/rive_renderer/source/gl/pls_impl_rw_texture.cpp b/third_party/rive_renderer/source/gl/pls_impl_rw_texture.cpp new file mode 100644 index 0000000..7cbf4cb --- /dev/null +++ b/third_party/rive_renderer/source/gl/pls_impl_rw_texture.cpp @@ -0,0 +1,202 @@ +/* + * Copyright 2023 Rive + */ + +#include "rive/renderer/gl/render_context_gl_impl.hpp" + +#include "rive/renderer/gl/render_target_gl.hpp" +#include "shaders/constants.glsl" +#include "rive/renderer/gl/gl_utils.hpp" + +#include "generated/shaders/glsl.exports.h" + +namespace rive::gpu +{ +using DrawBufferMask = RenderTargetGL::DrawBufferMask; + +static bool needs_coalesced_atomic_resolve_and_transfer( + const gpu::FlushDescriptor& desc) +{ + assert(desc.interlockMode == gpu::InterlockMode::atomics); + return (desc.combinedShaderFeatures & + ShaderFeatures::ENABLE_ADVANCED_BLEND) && + lite_rtti_cast( + static_cast(desc.renderTarget)) != nullptr; +} + +class RenderContextGLImpl::PLSImplRWTexture + : public RenderContextGLImpl::PixelLocalStorageImpl +{ + bool supportsRasterOrdering( + const GLCapabilities& capabilities) const override + { + return capabilities.ARB_fragment_shader_interlock || + capabilities.INTEL_fragment_shader_ordering; + } + + bool supportsFragmentShaderAtomics( + const GLCapabilities& capabilities) const override + { + return true; + } + + void activatePixelLocalStorage(RenderContextGLImpl* renderContextImpl, + const FlushDescriptor& desc) override + { + auto renderTarget = static_cast(desc.renderTarget); + renderTarget->allocateInternalPLSTextures(desc.interlockMode); + + if (!desc.atomicFixedFunctionColorOutput) + { + if (auto framebufferRenderTarget = + lite_rtti_cast(renderTarget)) + { + // We're targeting an external FBO but can't render to it + // directly. Make sure to allocate and attach an offscreen + // target texture. + framebufferRenderTarget->allocateOffscreenTargetTexture(); + if (desc.colorLoadAction == + gpu::LoadAction::preserveRenderTarget) + { + // Copy the framebuffer's contents to our offscreen texture. + framebufferRenderTarget->bindDestinationFramebuffer( + GL_READ_FRAMEBUFFER); + framebufferRenderTarget->bindInternalFramebuffer( + GL_DRAW_FRAMEBUFFER, + DrawBufferMask::color); + glutils::BlitFramebuffer(desc.renderTargetUpdateBounds, + renderTarget->height()); + } + } + } + + // Clear the necessary textures. + auto rwTexBuffers = DrawBufferMask::coverage; + if (desc.interlockMode == gpu::InterlockMode::rasterOrdering) + { + rwTexBuffers |= + DrawBufferMask::color | DrawBufferMask::scratchColor; + } + else if (desc.combinedShaderFeatures & + ShaderFeatures::ENABLE_ADVANCED_BLEND) + { + rwTexBuffers |= DrawBufferMask::color; + } + if (desc.combinedShaderFeatures & gpu::ShaderFeatures::ENABLE_CLIPPING) + { + rwTexBuffers |= DrawBufferMask::clip; + } + renderTarget->bindInternalFramebuffer(GL_FRAMEBUFFER, rwTexBuffers); + if (desc.colorLoadAction == gpu::LoadAction::clear && + (rwTexBuffers & DrawBufferMask::color)) + { + // If the color buffer is not a storage texture, we will clear it + // once the main framebuffer gets bound. + float clearColor4f[4]; + UnpackColorToRGBA32FPremul(desc.colorClearValue, clearColor4f); + glClearBufferfv(GL_COLOR, COLOR_PLANE_IDX, clearColor4f); + } + if (desc.combinedShaderFeatures & gpu::ShaderFeatures::ENABLE_CLIPPING) + { + constexpr static GLuint kZeroClear[4]{}; + glClearBufferuiv(GL_COLOR, CLIP_PLANE_IDX, kZeroClear); + } + { + GLuint coverageClear[4]{desc.coverageClearValue}; + glClearBufferuiv(GL_COLOR, COVERAGE_PLANE_IDX, coverageClear); + } + + switch (desc.interlockMode) + { + case gpu::InterlockMode::rasterOrdering: + // rasterOrdering mode renders by storing to an image texture. + // Bind a framebuffer with no color attachments. + renderTarget->bindHeadlessFramebuffer( + renderContextImpl->m_capabilities); + break; + case gpu::InterlockMode::atomics: + renderTarget->bindDestinationFramebuffer(GL_FRAMEBUFFER); + if (desc.colorLoadAction == gpu::LoadAction::clear && + !(rwTexBuffers & DrawBufferMask::color)) + { + // We're rendering directly to the main framebuffer. Clear + // it now. + float cc[4]; + UnpackColorToRGBA32FPremul(desc.colorClearValue, cc); + glClearColor(cc[0], cc[1], cc[2], cc[3]); + glClear(GL_COLOR_BUFFER_BIT); + } + break; + default: + RIVE_UNREACHABLE(); + } + + renderTarget->bindAsImageTextures(rwTexBuffers); + + glMemoryBarrierByRegion(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); + } + + gpu::ShaderMiscFlags shaderMiscFlags(const gpu::FlushDescriptor& desc, + gpu::DrawType drawType) const final + { + auto flags = gpu::ShaderMiscFlags::none; + if (desc.interlockMode == gpu::InterlockMode::atomics) + { + if (desc.atomicFixedFunctionColorOutput) + { + flags |= gpu::ShaderMiscFlags::fixedFunctionColorOutput; + } + if (drawType == gpu::DrawType::atomicResolve && + needs_coalesced_atomic_resolve_and_transfer(desc)) + { + flags |= gpu::ShaderMiscFlags::coalescedResolveAndTransfer; + } + } + return flags; + } + + void deactivatePixelLocalStorage(RenderContextGLImpl*, + const FlushDescriptor& desc) override + { + glMemoryBarrierByRegion(GL_ALL_BARRIER_BITS); + + // atomic mode never needs to copy anything here because it transfers + // the offscreen texture during resolve. + if (desc.interlockMode == gpu::InterlockMode::rasterOrdering) + { + if (auto framebufferRenderTarget = + lite_rtti_cast( + static_cast(desc.renderTarget))) + { + // We rendered to an offscreen texture. Copy back to the + // external target framebuffer. + framebufferRenderTarget->bindInternalFramebuffer( + GL_READ_FRAMEBUFFER, + DrawBufferMask::color); + framebufferRenderTarget->bindDestinationFramebuffer( + GL_DRAW_FRAMEBUFFER); + glutils::BlitFramebuffer(desc.renderTargetUpdateBounds, + framebufferRenderTarget->height()); + } + } + } + + void pushShaderDefines(gpu::InterlockMode, + std::vector* defines) const override + { + defines->push_back(GLSL_PLS_IMPL_STORAGE_TEXTURE); + defines->push_back(GLSL_USING_PLS_STORAGE_TEXTURES); + } + + void onBarrier(const gpu::FlushDescriptor&) override + { + return glMemoryBarrierByRegion(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); + } +}; + +std::unique_ptr +RenderContextGLImpl::MakePLSImplRWTexture() +{ + return std::make_unique(); +} +} // namespace rive::gpu diff --git a/third_party/rive_renderer/source/gl/pls_impl_webgl.cpp b/third_party/rive_renderer/source/gl/pls_impl_webgl.cpp new file mode 100644 index 0000000..be832fd --- /dev/null +++ b/third_party/rive_renderer/source/gl/pls_impl_webgl.cpp @@ -0,0 +1,314 @@ +/* + * Copyright 2022 Rive + */ + +#include "rive/renderer/gl/render_context_gl_impl.hpp" + +#include "rive/renderer/gl/gl_utils.hpp" +#include "rive/renderer/gl/render_target_gl.hpp" +#include "shaders/constants.glsl" + +#include "generated/shaders/glsl.exports.h" + +#ifdef RIVE_WEBGL +#include +#include + +EM_JS(bool, + enable_WEBGL_shader_pixel_local_storage_coherent, + (EMSCRIPTEN_WEBGL_CONTEXT_HANDLE gl), + { + gl = GL.getContext(gl).GLctx; + gl.pls = gl["getExtension"]("WEBGL_shader_pixel_local_storage"); + return Boolean(gl.pls && gl.pls["isCoherent"]()); + }); + +EM_JS(void, + framebufferTexturePixelLocalStorageWEBGL, + (EMSCRIPTEN_WEBGL_CONTEXT_HANDLE gl, + GLint plane, + GLuint backingtexture, + GLint level, + GLint layer), + { + const pls = GL.getContext(gl).GLctx.pls; + if (pls) + { + pls["framebufferTexturePixelLocalStorageWEBGL"]( + plane, + GL.textures[backingtexture], + level, + layer); + } + }); + +EM_JS(void, + framebufferPixelLocalClearValuefvWEBGL, + (EMSCRIPTEN_WEBGL_CONTEXT_HANDLE gl, + GLint plane, + float r, + float g, + float b, + float a), + { + const pls = GL.getContext(gl).GLctx.pls; + if (pls) + { + pls["framebufferPixelLocalClearValuefvWEBGL"](plane, + [ r, g, b, a ]); + } + }); + +EM_JS(void, + beginPixelLocalStorageWEBGL, + (EMSCRIPTEN_WEBGL_CONTEXT_HANDLE gl, uint32_t n, uint32_t loadopsIdx), + { + const pls = GL.getContext(gl).GLctx.pls; + if (pls) + { + pls["beginPixelLocalStorageWEBGL"]( + Module["HEAPU32"].subarray(loadopsIdx, loadopsIdx + n)); + } + }); + +EM_JS(void, + endPixelLocalStorageWEBGL, + (EMSCRIPTEN_WEBGL_CONTEXT_HANDLE gl, uint32_t n, uint32_t storeopsIdx), + { + const pls = GL.getContext(gl).GLctx.pls; + if (pls) + { + pls["endPixelLocalStorageWEBGL"]( + Module["HEAPU32"].subarray(storeopsIdx, storeopsIdx + n)); + } + }); + +EM_JS(int, + getFramebufferPixelLocalStorageParameterivWEBGL, + (EMSCRIPTEN_WEBGL_CONTEXT_HANDLE gl, int plane, int pname), + { + const pls = GL.getContext(gl).GLctx.pls; + if (pls) + { + return pls["getFramebufferPixelLocalStorageParameterWEBGL"]( + plane, + pname); + } + return 0; + }); + +EM_JS(bool, + enable_WEBGL_provoking_vertex, + (EMSCRIPTEN_WEBGL_CONTEXT_HANDLE gl), + { + gl = GL.getContext(gl).GLctx; + gl.pv = gl["getExtension"]("WEBGL_provoking_vertex"); + return Boolean(gl.pv); + }); + +EM_JS(void, + provokingVertexWEBGL, + (EMSCRIPTEN_WEBGL_CONTEXT_HANDLE gl, GLenum provokeMode), + { + const pv = GL.getContext(gl).GLctx.pv; + if (pv) + { + pv["provokingVertexWEBGL"](provokeMode); + } + }); + +bool webgl_enable_WEBGL_shader_pixel_local_storage_coherent() +{ + return enable_WEBGL_shader_pixel_local_storage_coherent( + emscripten_webgl_get_current_context()); +} + +bool webgl_enable_WEBGL_provoking_vertex() +{ + return enable_WEBGL_provoking_vertex( + emscripten_webgl_get_current_context()); +} + +void glFramebufferTexturePixelLocalStorageANGLE(GLint plane, + GLuint backingtexture, + GLint level, + GLint layer) +{ + framebufferTexturePixelLocalStorageWEBGL( + emscripten_webgl_get_current_context(), + plane, + backingtexture, + level, + layer); +} + +void glFramebufferPixelLocalClearValuefvANGLE(GLint plane, + const GLfloat value[4]) +{ + framebufferPixelLocalClearValuefvWEBGL( + emscripten_webgl_get_current_context(), + plane, + value[0], + value[1], + value[2], + value[3]); +} + +void glBeginPixelLocalStorageANGLE(GLsizei n, const uint32_t loadops[]) +{ + beginPixelLocalStorageWEBGL(emscripten_webgl_get_current_context(), + n, + reinterpret_cast(loadops) / + sizeof(uint32_t)); +} + +void glEndPixelLocalStorageANGLE(GLsizei n, const uint32_t storeops[]) +{ + endPixelLocalStorageWEBGL(emscripten_webgl_get_current_context(), + n, + reinterpret_cast(storeops) / + sizeof(uint32_t)); +} + +void glGetFramebufferPixelLocalStorageParameterivANGLE(GLint plane, + GLenum pname, + GLint* param) +{ + *param = getFramebufferPixelLocalStorageParameterivWEBGL( + emscripten_webgl_get_current_context(), + plane, + pname); +} + +void glProvokingVertexANGLE(GLenum provokeMode) +{ + provokingVertexWEBGL(emscripten_webgl_get_current_context(), provokeMode); +} +#endif // RIVE_WEBGL + +namespace rive::gpu +{ +using DrawBufferMask = RenderTargetGL::DrawBufferMask; + +static GLenum webgl_load_op(gpu::LoadAction loadAction) +{ + switch (loadAction) + { + case gpu::LoadAction::clear: + return GL_LOAD_OP_CLEAR_ANGLE; + case gpu::LoadAction::preserveRenderTarget: + return GL_LOAD_OP_LOAD_ANGLE; + case gpu::LoadAction::dontCare: + return GL_LOAD_OP_ZERO_ANGLE; + } + RIVE_UNREACHABLE(); +} + +class RenderContextGLImpl::PLSImplWebGL + : public RenderContextGLImpl::PixelLocalStorageImpl +{ + bool supportsRasterOrdering( + const GLCapabilities& capabilities) const override + { + return capabilities.ANGLE_shader_pixel_local_storage_coherent; + } + + bool supportsFragmentShaderAtomics( + const GLCapabilities& capabilities) const override + { + return false; + } + + void activatePixelLocalStorage(RenderContextGLImpl* renderContextImpl, + const FlushDescriptor& desc) override + { + auto renderTarget = static_cast(desc.renderTarget); + renderTarget->allocateInternalPLSTextures(desc.interlockMode); + + auto framebufferRenderTarget = + lite_rtti_cast(renderTarget); + if (framebufferRenderTarget != nullptr) + { + // We're targeting an external FBO directly. Make sure to allocate + // and attach an offscreen target texture. + framebufferRenderTarget->allocateOffscreenTargetTexture(); + if (desc.colorLoadAction == LoadAction::preserveRenderTarget) + { + // Copy the framebuffer's contents to our offscreen texture. + framebufferRenderTarget->bindDestinationFramebuffer( + GL_READ_FRAMEBUFFER); + framebufferRenderTarget->bindInternalFramebuffer( + GL_DRAW_FRAMEBUFFER, + DrawBufferMask::color); + glutils::BlitFramebuffer(desc.renderTargetUpdateBounds, + renderTarget->height()); + } + } + + // Begin pixel local storage. + renderTarget->bindHeadlessFramebuffer( + renderContextImpl->m_capabilities); + if (desc.colorLoadAction == LoadAction::clear) + { + float clearColor4f[4]; + UnpackColorToRGBA32FPremul(desc.colorClearValue, clearColor4f); + glFramebufferPixelLocalClearValuefvANGLE(COLOR_PLANE_IDX, + clearColor4f); + } + GLenum clipLoadAction = + (desc.combinedShaderFeatures & gpu::ShaderFeatures::ENABLE_CLIPPING) + ? GL_LOAD_OP_ZERO_ANGLE + : GL_DONT_CARE; + GLenum loadOps[4] = {webgl_load_op(desc.colorLoadAction), + clipLoadAction, + GL_DONT_CARE, + GL_LOAD_OP_ZERO_ANGLE}; + static_assert(COLOR_PLANE_IDX == 0); + static_assert(CLIP_PLANE_IDX == 1); + static_assert(SCRATCH_COLOR_PLANE_IDX == 2); + static_assert(COVERAGE_PLANE_IDX == 3); + glBeginPixelLocalStorageANGLE(4, loadOps); + } + + void deactivatePixelLocalStorage(RenderContextGLImpl*, + const FlushDescriptor& desc) override + { + constexpr static GLenum kStoreOps[4] = {GL_STORE_OP_STORE_ANGLE, + GL_DONT_CARE, + GL_DONT_CARE, + GL_DONT_CARE}; + static_assert(COLOR_PLANE_IDX == 0); + static_assert(CLIP_PLANE_IDX == 1); + static_assert(SCRATCH_COLOR_PLANE_IDX == 2); + static_assert(COVERAGE_PLANE_IDX == 3); + glEndPixelLocalStorageANGLE(4, kStoreOps); + + if (auto framebufferRenderTarget = + lite_rtti_cast( + static_cast(desc.renderTarget))) + { + // We rendered to an offscreen texture. Copy back to the external + // target FBO. + framebufferRenderTarget->bindInternalFramebuffer( + GL_READ_FRAMEBUFFER, + DrawBufferMask::color); + framebufferRenderTarget->bindDestinationFramebuffer( + GL_DRAW_FRAMEBUFFER); + glutils::BlitFramebuffer(desc.renderTargetUpdateBounds, + framebufferRenderTarget->height()); + } + } + + void pushShaderDefines(gpu::InterlockMode, + std::vector* defines) const override + { + defines->push_back(GLSL_PLS_IMPL_ANGLE); + } +}; + +std::unique_ptr +RenderContextGLImpl::MakePLSImplWebGL() +{ + return std::make_unique(); +} +} // namespace rive::gpu diff --git a/third_party/rive_renderer/source/gl/render_buffer_gl_impl.cpp b/third_party/rive_renderer/source/gl/render_buffer_gl_impl.cpp new file mode 100644 index 0000000..8cd7955 --- /dev/null +++ b/third_party/rive_renderer/source/gl/render_buffer_gl_impl.cpp @@ -0,0 +1,119 @@ +/* + * Copyright 2023 Rive + */ + +#include "rive/renderer/gl/render_buffer_gl_impl.hpp" + +#include "rive/renderer/gl/gl_state.hpp" + +namespace rive::gpu +{ +RenderBufferGLImpl::RenderBufferGLImpl(RenderBufferType type, + RenderBufferFlags flags, + size_t sizeInBytes) : + lite_rtti_override(type, flags, sizeInBytes), + m_target(type == RenderBufferType::vertex ? GL_ARRAY_BUFFER + : GL_ELEMENT_ARRAY_BUFFER) +{} + +RenderBufferGLImpl::RenderBufferGLImpl(RenderBufferType RenderBufferType, + RenderBufferFlags renderBufferFlags, + size_t sizeInBytes, + rcp state) : + RenderBufferGLImpl(RenderBufferType, renderBufferFlags, sizeInBytes) +{ + init(std::move(state)); +} + +RenderBufferGLImpl::~RenderBufferGLImpl() +{ + if (m_bufferID != 0) + { + m_state->deleteBuffer(m_bufferID); + } +} + +void RenderBufferGLImpl::init(rcp state) +{ + assert(!m_state); + assert(m_bufferID == 0); + m_state = std::move(state); + glGenBuffers(1, &m_bufferID); + m_state->bindVAO(0); + m_state->bindBuffer(m_target, m_bufferID); + glBufferData(m_target, + sizeInBytes(), + nullptr, + (flags() & RenderBufferFlags::mappedOnceAtInitialization) + ? GL_STATIC_DRAW + : GL_DYNAMIC_DRAW); +} + +GLuint RenderBufferGLImpl::detachBuffer() +{ + return std::exchange(m_bufferID, 0); +} + +void* RenderBufferGLImpl::onMap() +{ + if (!canMapBuffer()) + { + if (!m_fallbackMappedMemory) + { + m_fallbackMappedMemory.reset(new uint8_t[sizeInBytes()]); + } + return m_fallbackMappedMemory.get(); + } + else + { +#ifndef RIVE_WEBGL + m_state->bindVAO(0); + m_state->bindBuffer(m_target, m_bufferID); + return glMapBufferRange(m_target, + 0, + sizeInBytes(), + GL_MAP_WRITE_BIT | + GL_MAP_INVALIDATE_BUFFER_BIT); +#else + // WebGL doesn't declare glMapBufferRange(). + RIVE_UNREACHABLE(); +#endif + } +} + +void RenderBufferGLImpl::onUnmap() +{ + m_state->bindVAO(0); + m_state->bindBuffer(m_target, m_bufferID); + if (!canMapBuffer()) + { + glBufferSubData(m_target, + 0, + sizeInBytes(), + m_fallbackMappedMemory.get()); + if (flags() & RenderBufferFlags::mappedOnceAtInitialization) + { + m_fallbackMappedMemory + .reset(); // This buffer will only be mapped once. + } + } + else + { +#ifndef RIVE_WEBGL + glUnmapBuffer(m_target); +#else + // WebGL doesn't declare glUnmapBuffer(). + RIVE_UNREACHABLE(); +#endif + } +} + +bool RenderBufferGLImpl::canMapBuffer() const +{ + // WebGL doesn't support buffer mapping. + return !m_state->capabilities().isANGLEOrWebGL && + // NVIDIA gives performance warnings when mapping GL_STATIC_DRAW + // buffers. + !(flags() & RenderBufferFlags::mappedOnceAtInitialization); +} +} // namespace rive::gpu diff --git a/third_party/rive_renderer/source/gl/render_context_gl_impl.cpp b/third_party/rive_renderer/source/gl/render_context_gl_impl.cpp new file mode 100644 index 0000000..993fa8e --- /dev/null +++ b/third_party/rive_renderer/source/gl/render_context_gl_impl.cpp @@ -0,0 +1,2207 @@ +/* + * Copyright 2022 Rive + */ + +#include "rive/renderer/gl/render_context_gl_impl.hpp" + +#include "rive/renderer/gl/render_buffer_gl_impl.hpp" +#include "rive/renderer/gl/render_target_gl.hpp" +#include "rive/renderer/draw.hpp" +#include "rive/renderer/texture.hpp" +#include "shaders/constants.glsl" + +#include "generated/shaders/advanced_blend.glsl.hpp" +#include "generated/shaders/color_ramp.glsl.hpp" +#include "generated/shaders/constants.glsl.hpp" +#include "generated/shaders/common.glsl.hpp" +#include "generated/shaders/draw_path_common.glsl.hpp" +#include "generated/shaders/draw_path.glsl.hpp" +#include "generated/shaders/draw_image_mesh.glsl.hpp" +#include "generated/shaders/bezier_utils.glsl.hpp" +#include "generated/shaders/tessellate.glsl.hpp" +#include "generated/shaders/render_atlas.glsl.hpp" +#include "generated/shaders/blit_texture_as_draw.glsl.hpp" +#include "generated/shaders/stencil_draw.glsl.hpp" + +#ifdef RIVE_WEBGL +#include +#include + +// In an effort to save space on web, and since web doesn't have ES 3.1 level +// support, don't include the atomic sources. +namespace rive::gpu::glsl +{ +const char atomic_draw[] = ""; +} +#define DISABLE_PLS_ATOMICS +#else +#include "generated/shaders/atomic_draw.glsl.hpp" +#endif + +namespace rive::gpu +{ + +static bool is_tessellation_draw(gpu::DrawType drawType) +{ + switch (drawType) + { + case gpu::DrawType::midpointFanPatches: + case gpu::DrawType::midpointFanCenterAAPatches: + case gpu::DrawType::outerCurvePatches: + case gpu::DrawType::msaaStrokes: + case gpu::DrawType::msaaMidpointFanBorrowedCoverage: + case gpu::DrawType::msaaMidpointFans: + case gpu::DrawType::msaaMidpointFanStencilReset: + case gpu::DrawType::msaaMidpointFanPathsStencil: + case gpu::DrawType::msaaMidpointFanPathsCover: + case gpu::DrawType::msaaOuterCubics: + return true; + case gpu::DrawType::imageRect: + case gpu::DrawType::imageMesh: + case gpu::DrawType::interiorTriangulation: + case gpu::DrawType::atlasBlit: + case gpu::DrawType::atomicInitialize: + case gpu::DrawType::atomicResolve: + case gpu::DrawType::msaaStencilClipReset: + return false; + } + RIVE_UNREACHABLE(); +} + +RenderContextGLImpl::RenderContextGLImpl( + const char* rendererString, + GLCapabilities capabilities, + std::unique_ptr plsImpl) : + m_capabilities(capabilities), + m_plsImpl(std::move(plsImpl)), + m_state(make_rcp(m_capabilities)) + +{ + if (m_plsImpl != nullptr) + { + m_platformFeatures.supportsRasterOrdering = + m_plsImpl->supportsRasterOrdering(m_capabilities); + m_platformFeatures.supportsFragmentShaderAtomics = + m_plsImpl->supportsFragmentShaderAtomics(m_capabilities); + } + if (m_capabilities.KHR_blend_equation_advanced_coherent) + { + m_platformFeatures.supportsKHRBlendEquations = true; + } + if (m_capabilities.EXT_clip_cull_distance) + { + m_platformFeatures.supportsClipPlanes = true; + } + if (strstr(rendererString, "Apple") && strstr(rendererString, "Metal")) + { + // In Metal, non-flat varyings preserve their exact value if all + // vertices in the triangle emit the same value, and we also see a small + // (5-10%) improvement from not using flat varyings. + m_platformFeatures.avoidFlatVaryings = true; + } + if (m_capabilities.isPowerVR) + { + // Vivo Y21 (PowerVR Rogue GE8320; OpenGL ES 3.2 build 1.13@5776728a) + // seems to hit some sort of reset condition that corrupts pixel local + // storage when rendering a complex feather. For now, feather directly + // to the screen on PowerVR; always go offscreen. + m_platformFeatures.alwaysFeatherToAtlas = true; + } + m_platformFeatures.clipSpaceBottomUp = true; + m_platformFeatures.framebufferBottomUp = true; + + GLint maxTextureSize; + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize); + m_platformFeatures.maxTextureSize = maxTextureSize; + + std::vector generalDefines; + if (!m_capabilities.ARB_shader_storage_buffer_object) + { + generalDefines.push_back(GLSL_DISABLE_SHADER_STORAGE_BUFFERS); + } + + const char* colorRampSources[] = {glsl::constants, + glsl::common, + glsl::color_ramp}; + m_colorRampProgram.compileAndAttachShader(GL_VERTEX_SHADER, + generalDefines.data(), + generalDefines.size(), + colorRampSources, + std::size(colorRampSources), + m_capabilities); + m_colorRampProgram.compileAndAttachShader(GL_FRAGMENT_SHADER, + generalDefines.data(), + generalDefines.size(), + colorRampSources, + std::size(colorRampSources), + m_capabilities); + m_colorRampProgram.link(); + glUniformBlockBinding( + m_colorRampProgram, + glGetUniformBlockIndex(m_colorRampProgram, GLSL_FlushUniforms), + FLUSH_UNIFORM_BUFFER_IDX); + + m_state->bindVAO(m_colorRampVAO); + glEnableVertexAttribArray(0); + glVertexAttribDivisor(0, 1); + + // Emulate the feather texture1d array as a texture2d since GLES doesn't + // have texture1d. + glActiveTexture(GL_TEXTURE0 + FEATHER_TEXTURE_IDX); + glBindTexture(GL_TEXTURE_2D, m_featherTexture); + glTexStorage2D(GL_TEXTURE_2D, + 1, + GL_R16F, + gpu::GAUSSIAN_TABLE_SIZE, + FEATHER_TEXTURE_1D_ARRAY_LENGTH); + m_state->bindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); + glTexSubImage2D(GL_TEXTURE_2D, + 0, + 0, + FEATHER_FUNCTION_ARRAY_INDEX, + gpu::GAUSSIAN_TABLE_SIZE, + 1, + GL_RED, + GL_HALF_FLOAT, + gpu::g_gaussianIntegralTableF16); + glTexSubImage2D(GL_TEXTURE_2D, + 0, + 0, + FEATHER_INVERSE_FUNCTION_ARRAY_INDEX, + gpu::GAUSSIAN_TABLE_SIZE, + 1, + GL_RED, + GL_HALF_FLOAT, + gpu::g_inverseGaussianIntegralTableF16); + glutils::SetTexture2DSamplingParams(GL_LINEAR, GL_LINEAR); + + const char* tessellateSources[] = {glsl::constants, + glsl::common, + glsl::bezier_utils, + glsl::tessellate}; + m_tessellateProgram.compileAndAttachShader(GL_VERTEX_SHADER, + generalDefines.data(), + generalDefines.size(), + tessellateSources, + std::size(tessellateSources), + m_capabilities); + m_tessellateProgram.compileAndAttachShader(GL_FRAGMENT_SHADER, + generalDefines.data(), + generalDefines.size(), + tessellateSources, + std::size(tessellateSources), + m_capabilities); + m_tessellateProgram.link(); + m_state->bindProgram(m_tessellateProgram); + glutils::Uniform1iByName(m_tessellateProgram, + GLSL_featherTexture, + FEATHER_TEXTURE_IDX); + glUniformBlockBinding( + m_tessellateProgram, + glGetUniformBlockIndex(m_tessellateProgram, GLSL_FlushUniforms), + FLUSH_UNIFORM_BUFFER_IDX); + if (!m_capabilities.ARB_shader_storage_buffer_object) + { + // Our GL driver doesn't support storage buffers. We polyfill these + // buffers as textures. + glutils::Uniform1iByName(m_tessellateProgram, + GLSL_pathBuffer, + PATH_BUFFER_IDX); + glutils::Uniform1iByName(m_tessellateProgram, + GLSL_contourBuffer, + CONTOUR_BUFFER_IDX); + } + + m_state->bindVAO(m_tessellateVAO); + for (int i = 0; i < 4; ++i) + { + glEnableVertexAttribArray(i); + // Draw two instances per TessVertexSpan: one normal and one optional + // reflection. + glVertexAttribDivisor(i, 1); + } + + m_state->bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_tessSpanIndexBuffer); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, + sizeof(gpu::kTessSpanIndices), + gpu::kTessSpanIndices, + GL_STATIC_DRAW); + + m_state->bindVAO(m_drawVAO); + + PatchVertex patchVertices[kPatchVertexBufferCount]; + uint16_t patchIndices[kPatchIndexBufferCount]; + GeneratePatchBufferData(patchVertices, patchIndices); + + m_state->bindBuffer(GL_ARRAY_BUFFER, m_patchVerticesBuffer); + glBufferData(GL_ARRAY_BUFFER, + sizeof(patchVertices), + patchVertices, + GL_STATIC_DRAW); + + m_state->bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_patchIndicesBuffer); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, + sizeof(patchIndices), + patchIndices, + GL_STATIC_DRAW); + + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, + 4, + GL_FLOAT, + GL_FALSE, + sizeof(PatchVertex), + nullptr); + + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, + 4, + GL_FLOAT, + GL_FALSE, + sizeof(PatchVertex), + reinterpret_cast(sizeof(float) * 4)); + + m_state->bindVAO(m_trianglesVAO); + glEnableVertexAttribArray(0); + + // We draw imageRects when in atomic mode. + m_state->bindVAO(m_imageRectVAO); + + m_state->bindBuffer(GL_ARRAY_BUFFER, m_imageRectVertexBuffer); + glBufferData(GL_ARRAY_BUFFER, + sizeof(gpu::kImageRectVertices), + gpu::kImageRectVertices, + GL_STATIC_DRAW); + + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, + 4, + GL_FLOAT, + GL_FALSE, + sizeof(gpu::ImageRectVertex), + nullptr); + + m_state->bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_imageRectIndexBuffer); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, + sizeof(gpu::kImageRectIndices), + gpu::kImageRectIndices, + GL_STATIC_DRAW); + + m_state->bindVAO(m_imageMeshVAO); + glEnableVertexAttribArray(0); + glEnableVertexAttribArray(1); + + if (m_plsImpl != nullptr) + { + m_plsImpl->init(m_state); + } +} + +RenderContextGLImpl::~RenderContextGLImpl() +{ + glDeleteTextures(1, &m_gradientTexture); + glDeleteTextures(1, &m_tessVertexTexture); + + // Because glutils wrappers delete GL objects that might affect bindings. + m_state->invalidate(); +} + +void RenderContextGLImpl::invalidateGLState() +{ + glActiveTexture(GL_TEXTURE0 + TESS_VERTEX_TEXTURE_IDX); + glBindTexture(GL_TEXTURE_2D, m_tessVertexTexture); + + glActiveTexture(GL_TEXTURE0 + GRAD_TEXTURE_IDX); + glBindTexture(GL_TEXTURE_2D, m_gradientTexture); + + glActiveTexture(GL_TEXTURE0 + FEATHER_TEXTURE_IDX); + glBindTexture(GL_TEXTURE_2D, m_featherTexture); + + glActiveTexture(GL_TEXTURE0 + ATLAS_TEXTURE_IDX); + glBindTexture(GL_TEXTURE_2D, m_atlasTexture); + + m_state->invalidate(); +} + +void RenderContextGLImpl::unbindGLInternalResources() +{ + m_state->bindVAO(0); + m_state->bindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + m_state->bindBuffer(GL_ARRAY_BUFFER, 0); + m_state->bindBuffer(GL_UNIFORM_BUFFER, 0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + for (int i = 0; i <= DEFAULT_BINDINGS_SET_SIZE; ++i) + { + glActiveTexture(GL_TEXTURE0 + i); + glBindTexture(GL_TEXTURE_2D, 0); + } +} + +rcp RenderContextGLImpl::makeRenderBuffer(RenderBufferType type, + RenderBufferFlags flags, + size_t sizeInBytes) +{ + return make_rcp(type, flags, sizeInBytes, m_state); +} + +class TextureGLImpl : public Texture +{ +public: + TextureGLImpl(uint32_t width, + uint32_t height, + GLuint textureID, + const GLCapabilities& capabilities) : + Texture(width, height), m_texture(glutils::Texture::Adopt(textureID)) + {} + + operator GLuint() const { return m_texture; } + +private: + glutils::Texture m_texture; +}; + +rcp RenderContextGLImpl::makeImageTexture( + uint32_t width, + uint32_t height, + uint32_t mipLevelCount, + const uint8_t imageDataRGBAPremul[]) +{ + GLuint textureID; + glGenTextures(1, &textureID); + glActiveTexture(GL_TEXTURE0 + IMAGE_TEXTURE_IDX); + glBindTexture(GL_TEXTURE_2D, textureID); + glTexStorage2D(GL_TEXTURE_2D, mipLevelCount, GL_RGBA8, width, height); + glTexSubImage2D(GL_TEXTURE_2D, + 0, + 0, + 0, + width, + height, + GL_RGBA, + GL_UNSIGNED_BYTE, + imageDataRGBAPremul); + glutils::SetTexture2DSamplingParams(GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR); + glGenerateMipmap(GL_TEXTURE_2D); + return adoptImageTexture(width, height, textureID); +} + +rcp RenderContextGLImpl::adoptImageTexture(uint32_t width, + uint32_t height, + GLuint textureID) +{ + return make_rcp(width, height, textureID, m_capabilities); +} + +// BufferRingImpl in GL on a given buffer target. In order to support WebGL2, we +// don't do hardware mapping. +class BufferRingGLImpl : public BufferRing +{ +public: + static std::unique_ptr Make(size_t capacityInBytes, + GLenum target, + rcp state) + { + return capacityInBytes != 0 + ? std::unique_ptr( + new BufferRingGLImpl(target, + capacityInBytes, + std::move(state))) + : nullptr; + } + + ~BufferRingGLImpl() { m_state->deleteBuffer(m_bufferID); } + + GLuint bufferID() const { return m_bufferID; } + +protected: + BufferRingGLImpl(GLenum target, + size_t capacityInBytes, + rcp state) : + BufferRing(capacityInBytes), m_target(target), m_state(std::move(state)) + { + glGenBuffers(1, &m_bufferID); + m_state->bindBuffer(m_target, m_bufferID); + glBufferData(m_target, capacityInBytes, nullptr, GL_DYNAMIC_DRAW); + } + + void* onMapBuffer(int bufferIdx, size_t mapSizeInBytes) override + { + if (m_state->capabilities().isANGLEOrWebGL) + { + // WebGL doesn't support buffer mapping. + return shadowBuffer(); + } + else + { +#ifndef RIVE_WEBGL + m_state->bindBuffer(m_target, m_bufferID); + return glMapBufferRange(m_target, + 0, + mapSizeInBytes, + GL_MAP_WRITE_BIT | + GL_MAP_INVALIDATE_BUFFER_BIT); +#else + // WebGL doesn't declare glMapBufferRange(). + RIVE_UNREACHABLE(); +#endif + } + } + + void onUnmapAndSubmitBuffer(int bufferIdx, size_t mapSizeInBytes) override + { + m_state->bindBuffer(m_target, m_bufferID); + if (m_state->capabilities().isANGLEOrWebGL) + { + // WebGL doesn't support buffer mapping. + glBufferSubData(m_target, 0, mapSizeInBytes, shadowBuffer()); + } + else + { +#ifndef RIVE_WEBGL + glUnmapBuffer(m_target); +#else + // WebGL doesn't declare glUnmapBuffer(). + RIVE_UNREACHABLE(); +#endif + } + } + + const GLenum m_target; + GLuint m_bufferID; + const rcp m_state; +}; + +// GL internalformat to use for a texture that polyfills a storage buffer. +static GLenum storage_texture_internalformat( + gpu::StorageBufferStructure bufferStructure) +{ + switch (bufferStructure) + { + case gpu::StorageBufferStructure::uint32x4: + return GL_RGBA32UI; + case gpu::StorageBufferStructure::uint32x2: + return GL_RG32UI; + case gpu::StorageBufferStructure::float32x4: + return GL_RGBA32F; + } + RIVE_UNREACHABLE(); +} + +// GL format to use for a texture that polyfills a storage buffer. +static GLenum storage_texture_format( + gpu::StorageBufferStructure bufferStructure) +{ + switch (bufferStructure) + { + case gpu::StorageBufferStructure::uint32x4: + return GL_RGBA_INTEGER; + case gpu::StorageBufferStructure::uint32x2: + return GL_RG_INTEGER; + case gpu::StorageBufferStructure::float32x4: + return GL_RGBA; + } + RIVE_UNREACHABLE(); +} + +// GL type to use for a texture that polyfills a storage buffer. +static GLenum storage_texture_type(gpu::StorageBufferStructure bufferStructure) +{ + switch (bufferStructure) + { + case gpu::StorageBufferStructure::uint32x4: + return GL_UNSIGNED_INT; + case gpu::StorageBufferStructure::uint32x2: + return GL_UNSIGNED_INT; + case gpu::StorageBufferStructure::float32x4: + return GL_FLOAT; + } + RIVE_UNREACHABLE(); +} + +class StorageBufferRingGLImpl : public BufferRingGLImpl +{ +public: + StorageBufferRingGLImpl(size_t capacityInBytes, + gpu::StorageBufferStructure bufferStructure, + rcp state) : + BufferRingGLImpl( + // If we don't support storage buffers, instead make a pixel-unpack + // buffer that will be used to copy data into the polyfill texture. + GL_SHADER_STORAGE_BUFFER, + capacityInBytes, + std::move(state)), + m_bufferStructure(bufferStructure) + {} + + void bindToRenderContext(uint32_t bindingIdx, + size_t bindingSizeInBytes, + size_t offsetSizeInBytes) const + { + glBindBufferRange(GL_SHADER_STORAGE_BUFFER, + bindingIdx, + bufferID(), + offsetSizeInBytes, + bindingSizeInBytes); + } + +protected: + const gpu::StorageBufferStructure m_bufferStructure; +}; + +class TexelBufferRingWebGL : public BufferRing +{ +public: + TexelBufferRingWebGL(size_t capacityInBytes, + gpu::StorageBufferStructure bufferStructure, + rcp state) : + BufferRing( + gpu::StorageTextureBufferSize(capacityInBytes, bufferStructure)), + m_bufferStructure(bufferStructure), + m_state(std::move(state)) + { + auto [width, height] = + gpu::StorageTextureSize(capacityInBytes, m_bufferStructure); + GLenum internalformat = + storage_texture_internalformat(m_bufferStructure); + glGenTextures(1, &m_textureID); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, m_textureID); + glTexStorage2D(GL_TEXTURE_2D, 1, internalformat, width, height); + glutils::SetTexture2DSamplingParams(GL_NEAREST, GL_NEAREST); + glBindTexture(GL_TEXTURE_2D, 0); + } + + ~TexelBufferRingWebGL() { glDeleteTextures(1, &m_textureID); } + + void* onMapBuffer(int bufferIdx, size_t mapSizeInBytes) override + { + return shadowBuffer(); + } + void onUnmapAndSubmitBuffer(int bufferIdx, size_t mapSizeInBytes) override + {} + + void bindToRenderContext(uint32_t bindingIdx, + size_t bindingSizeInBytes, + size_t offsetSizeInBytes) const + { + auto [updateWidth, updateHeight] = + gpu::StorageTextureSize(bindingSizeInBytes, m_bufferStructure); + glActiveTexture(GL_TEXTURE0 + bindingIdx); + glBindTexture(GL_TEXTURE_2D, m_textureID); + glTexSubImage2D(GL_TEXTURE_2D, + 0, + 0, + 0, + updateWidth, + updateHeight, + storage_texture_format(m_bufferStructure), + storage_texture_type(m_bufferStructure), + shadowBuffer() + offsetSizeInBytes); + } + +protected: + const gpu::StorageBufferStructure m_bufferStructure; + const rcp m_state; + GLuint m_textureID; +}; + +std::unique_ptr RenderContextGLImpl::makeUniformBufferRing( + size_t capacityInBytes) +{ + return BufferRingGLImpl::Make(capacityInBytes, GL_UNIFORM_BUFFER, m_state); +} + +std::unique_ptr RenderContextGLImpl::makeStorageBufferRing( + size_t capacityInBytes, + gpu::StorageBufferStructure bufferStructure) +{ + if (capacityInBytes == 0) + { + return nullptr; + } + else if (m_capabilities.ARB_shader_storage_buffer_object) + { + return std::make_unique(capacityInBytes, + bufferStructure, + m_state); + } + else + { + return std::make_unique(capacityInBytes, + bufferStructure, + m_state); + } +} + +std::unique_ptr RenderContextGLImpl::makeVertexBufferRing( + size_t capacityInBytes) +{ + return BufferRingGLImpl::Make(capacityInBytes, GL_ARRAY_BUFFER, m_state); +} + +void RenderContextGLImpl::resizeGradientTexture(uint32_t width, uint32_t height) +{ + glDeleteTextures(1, &m_gradientTexture); + if (width == 0 || height == 0) + { + m_gradientTexture = 0; + return; + } + + glGenTextures(1, &m_gradientTexture); + glActiveTexture(GL_TEXTURE0 + GRAD_TEXTURE_IDX); + glBindTexture(GL_TEXTURE_2D, m_gradientTexture); + glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, width, height); + glutils::SetTexture2DSamplingParams(GL_LINEAR, GL_LINEAR); + + glBindFramebuffer(GL_FRAMEBUFFER, m_colorRampFBO); + glFramebufferTexture2D(GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, + m_gradientTexture, + 0); +} + +void RenderContextGLImpl::resizeTessellationTexture(uint32_t width, + uint32_t height) +{ + glDeleteTextures(1, &m_tessVertexTexture); + if (width == 0 || height == 0) + { + m_tessVertexTexture = 0; + return; + } + + glGenTextures(1, &m_tessVertexTexture); + glActiveTexture(GL_TEXTURE0 + TESS_VERTEX_TEXTURE_IDX); + glBindTexture(GL_TEXTURE_2D, m_tessVertexTexture); + glTexStorage2D(GL_TEXTURE_2D, + 1, + m_capabilities.needsFloatingPointTessellationTexture + ? GL_RGBA32F + : GL_RGBA32UI, + width, + height); + glutils::SetTexture2DSamplingParams(GL_NEAREST, GL_NEAREST); + + glBindFramebuffer(GL_FRAMEBUFFER, m_tessellateFBO); + glFramebufferTexture2D(GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, + m_tessVertexTexture, + 0); +} + +void RenderContextGLImpl::AtlasProgram::compile( + GLuint vertexShaderID, + const char* defines[], + size_t numDefines, + const char* sources[], + size_t numSources, + const GLCapabilities& capabilities, + GLState* state) +{ + m_program = glutils::Program(); + glAttachShader(m_program, vertexShaderID); + m_program.compileAndAttachShader(GL_FRAGMENT_SHADER, + defines, + numDefines, + sources, + numSources, + capabilities); + m_program.link(); + state->bindProgram(m_program); + glUniformBlockBinding(m_program, + glGetUniformBlockIndex(m_program, GLSL_FlushUniforms), + FLUSH_UNIFORM_BUFFER_IDX); + glutils::Uniform1iByName(m_program, + GLSL_tessVertexTexture, + TESS_VERTEX_TEXTURE_IDX); + glutils::Uniform1iByName(m_program, + GLSL_featherTexture, + FEATHER_TEXTURE_IDX); + if (!capabilities.ARB_shader_storage_buffer_object) + { + glutils::Uniform1iByName(m_program, GLSL_pathBuffer, PATH_BUFFER_IDX); + glutils::Uniform1iByName(m_program, + GLSL_contourBuffer, + CONTOUR_BUFFER_IDX); + } + if (!capabilities.ANGLE_base_vertex_base_instance_shader_builtin) + { + m_baseInstanceUniformLocation = + glGetUniformLocation(m_program, + glutils::BASE_INSTANCE_UNIFORM_NAME); + } +} + +void RenderContextGLImpl::resizeAtlasTexture(uint32_t width, uint32_t height) +{ + if (width == 0 || height == 0) + { + m_atlasTexture = glutils::Texture::Zero(); + return; + } + + m_atlasTexture = glutils::Texture(); + glActiveTexture(GL_TEXTURE0 + ATLAS_TEXTURE_IDX); + glBindTexture(GL_TEXTURE_2D, m_atlasTexture); + glTexStorage2D( + GL_TEXTURE_2D, + 1, + m_capabilities.EXT_float_blend + ? GL_R32F // fp32 is ideal for the atlas. When there's a lot of + // overlap, fp16 can run out of precision. + : GL_R16F, // FIXME: Fallback for when EXT_color_buffer_half_float + // isn't supported. + width, + height); + glutils::SetTexture2DSamplingParams(GL_NEAREST, GL_NEAREST); + + glBindFramebuffer(GL_FRAMEBUFFER, m_atlasFBO); + glFramebufferTexture2D(GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, + m_atlasTexture, + 0); + + // Don't compile the atlas programs until we get an indication that they + // will be used. + if (m_atlasVertexShader == 0) + { + std::vector defines; + defines.push_back(GLSL_DRAW_PATH); + defines.push_back(GLSL_ENABLE_FEATHER); + defines.push_back(GLSL_ENABLE_INSTANCE_INDEX); + if (!m_capabilities.ARB_shader_storage_buffer_object) + { + defines.push_back(GLSL_DISABLE_SHADER_STORAGE_BUFFERS); + } + const char* atlasSources[] = {glsl::constants, + glsl::common, + glsl::draw_path_common, + glsl::render_atlas}; + m_atlasVertexShader.compile(GL_VERTEX_SHADER, + defines.data(), + defines.size(), + atlasSources, + std::size(atlasSources), + m_capabilities); + + defines.push_back(GLSL_ATLAS_FEATHERED_FILL); + m_atlasFillProgram.compile(m_atlasVertexShader, + defines.data(), + defines.size(), + atlasSources, + std::size(atlasSources), + m_capabilities, + m_state.get()); + defines.pop_back(); + + defines.push_back(GLSL_ATLAS_FEATHERED_STROKE); + m_atlasStrokeProgram.compile(m_atlasVertexShader, + defines.data(), + defines.size(), + atlasSources, + std::size(atlasSources), + m_capabilities, + m_state.get()); + defines.pop_back(); + } +} + +RenderContextGLImpl::DrawShader::DrawShader( + RenderContextGLImpl* renderContextImpl, + GLenum shaderType, + gpu::DrawType drawType, + ShaderFeatures shaderFeatures, + gpu::InterlockMode interlockMode, + gpu::ShaderMiscFlags shaderMiscFlags) +{ +#ifdef DISABLE_PLS_ATOMICS + if (interlockMode == gpu::InterlockMode::atomics) + { + // Don't draw anything in atomic mode if support for it isn't compiled + // in. + return; + } +#endif + + std::vector defines; + if (renderContextImpl->m_plsImpl != nullptr) + { + renderContextImpl->m_plsImpl->pushShaderDefines(interlockMode, + &defines); + } + if (interlockMode == gpu::InterlockMode::atomics) + { + // Atomics are currently always done on storage textures. + defines.push_back(GLSL_USING_PLS_STORAGE_TEXTURES); + } + if (shaderMiscFlags & gpu::ShaderMiscFlags::fixedFunctionColorOutput) + { + defines.push_back(GLSL_FIXED_FUNCTION_COLOR_OUTPUT); + } + if (shaderMiscFlags & gpu::ShaderMiscFlags::clockwiseFill) + { + defines.push_back(GLSL_CLOCKWISE_FILL); + } + for (size_t i = 0; i < kShaderFeatureCount; ++i) + { + ShaderFeatures feature = static_cast(1 << i); + if (shaderFeatures & feature) + { + assert((kVertexShaderFeaturesMask & feature) || + shaderType == GL_FRAGMENT_SHADER); + if (interlockMode == gpu::InterlockMode::msaa && + feature == gpu::ShaderFeatures::ENABLE_ADVANCED_BLEND && + renderContextImpl->m_capabilities + .KHR_blend_equation_advanced_coherent) + { + defines.push_back(GLSL_ENABLE_KHR_BLEND); + } + else + { + defines.push_back(GetShaderFeatureGLSLName(feature)); + } + } + } + if (interlockMode == gpu::InterlockMode::msaa) + { + defines.push_back(GLSL_RENDER_MODE_MSAA); + } + assert(renderContextImpl->platformFeatures().framebufferBottomUp); + defines.push_back(GLSL_FRAMEBUFFER_BOTTOM_UP); + + std::vector sources; + sources.push_back(glsl::constants); + sources.push_back(glsl::common); + if (shaderType == GL_FRAGMENT_SHADER && + (shaderFeatures & ShaderFeatures::ENABLE_ADVANCED_BLEND)) + { + sources.push_back(glsl::advanced_blend); + } + if (renderContextImpl->platformFeatures().avoidFlatVaryings) + { + sources.push_back("#define " GLSL_OPTIONALLY_FLAT "\n"); + } + else + { + sources.push_back("#define " GLSL_OPTIONALLY_FLAT " flat\n"); + } + switch (drawType) + { + case gpu::DrawType::midpointFanPatches: + case gpu::DrawType::midpointFanCenterAAPatches: + case gpu::DrawType::outerCurvePatches: + case gpu::DrawType::msaaStrokes: + case gpu::DrawType::msaaMidpointFanBorrowedCoverage: + case gpu::DrawType::msaaMidpointFans: + case gpu::DrawType::msaaMidpointFanStencilReset: + case gpu::DrawType::msaaMidpointFanPathsStencil: + case gpu::DrawType::msaaMidpointFanPathsCover: + case gpu::DrawType::msaaOuterCubics: + if (shaderType == GL_VERTEX_SHADER) + { + defines.push_back(GLSL_ENABLE_INSTANCE_INDEX); + } + defines.push_back(GLSL_DRAW_PATH); + sources.push_back(gpu::glsl::draw_path_common); + sources.push_back(interlockMode == gpu::InterlockMode::atomics + ? gpu::glsl::atomic_draw + : gpu::glsl::draw_path); + break; + case gpu::DrawType::msaaStencilClipReset: + assert(interlockMode == gpu::InterlockMode::msaa); + sources.push_back(gpu::glsl::stencil_draw); + break; + case gpu::DrawType::atlasBlit: + defines.push_back(GLSL_ATLAS_BLIT); + [[fallthrough]]; + case gpu::DrawType::interiorTriangulation: + defines.push_back(GLSL_DRAW_INTERIOR_TRIANGLES); + sources.push_back(gpu::glsl::draw_path_common); + sources.push_back(interlockMode == gpu::InterlockMode::atomics + ? gpu::glsl::atomic_draw + : gpu::glsl::draw_path); + break; + case gpu::DrawType::imageRect: + assert(interlockMode == gpu::InterlockMode::atomics); + defines.push_back(GLSL_DRAW_IMAGE); + defines.push_back(GLSL_DRAW_IMAGE_RECT); + sources.push_back(gpu::glsl::draw_path_common); + sources.push_back(gpu::glsl::atomic_draw); + break; + case gpu::DrawType::imageMesh: + defines.push_back(GLSL_DRAW_IMAGE); + defines.push_back(GLSL_DRAW_IMAGE_MESH); + if (interlockMode == gpu::InterlockMode::atomics) + { + sources.push_back(gpu::glsl::draw_path_common); + sources.push_back(gpu::glsl::atomic_draw); + } + else + { + sources.push_back(gpu::glsl::draw_image_mesh); + } + break; + case gpu::DrawType::atomicResolve: + assert(interlockMode == gpu::InterlockMode::atomics); + defines.push_back(GLSL_DRAW_RENDER_TARGET_UPDATE_BOUNDS); + defines.push_back(GLSL_RESOLVE_PLS); + if (shaderMiscFlags & + gpu::ShaderMiscFlags::coalescedResolveAndTransfer) + { + assert(shaderType == GL_FRAGMENT_SHADER); + defines.push_back(GLSL_COALESCED_PLS_RESOLVE_AND_TRANSFER); + } + sources.push_back(gpu::glsl::draw_path_common); + sources.push_back(gpu::glsl::atomic_draw); + break; + case gpu::DrawType::atomicInitialize: + assert(interlockMode == gpu::InterlockMode::atomics); + RIVE_UNREACHABLE(); + } + if (!renderContextImpl->m_capabilities.ARB_shader_storage_buffer_object) + { + defines.push_back(GLSL_DISABLE_SHADER_STORAGE_BUFFERS); + } + + m_id = glutils::CompileShader(shaderType, + defines.data(), + defines.size(), + sources.data(), + sources.size(), + renderContextImpl->m_capabilities); +} + +RenderContextGLImpl::DrawProgram::DrawProgram( + RenderContextGLImpl* renderContextImpl, + gpu::DrawType drawType, + gpu::ShaderFeatures shaderFeatures, + gpu::InterlockMode interlockMode, + gpu::ShaderMiscFlags shaderMiscFlags) : + m_fragmentShader(renderContextImpl, + GL_FRAGMENT_SHADER, + drawType, + shaderFeatures, + interlockMode, + shaderMiscFlags), + m_state(renderContextImpl->m_state) +{ + // Not every vertex shader is unique. Cache them by just the vertex features + // and reuse when possible. + ShaderFeatures vertexShaderFeatures = + shaderFeatures & kVertexShaderFeaturesMask; + uint32_t vertexShaderKey = gpu::ShaderUniqueKey(drawType, + vertexShaderFeatures, + interlockMode, + gpu::ShaderMiscFlags::none); + const DrawShader& vertexShader = + renderContextImpl->m_vertexShaders + .try_emplace(vertexShaderKey, + renderContextImpl, + GL_VERTEX_SHADER, + drawType, + vertexShaderFeatures, + interlockMode, + gpu::ShaderMiscFlags::none) + .first->second; + + m_id = glCreateProgram(); + glAttachShader(m_id, vertexShader.id()); + glAttachShader(m_id, m_fragmentShader.id()); + glutils::LinkProgram(m_id); + + m_state->bindProgram(m_id); + glUniformBlockBinding(m_id, + glGetUniformBlockIndex(m_id, GLSL_FlushUniforms), + FLUSH_UNIFORM_BUFFER_IDX); + + const bool isImageDraw = gpu::DrawTypeIsImageDraw(drawType); + const bool isTessellationDraw = is_tessellation_draw(drawType); + const bool isPaintDraw = isTessellationDraw || + drawType == gpu::DrawType::interiorTriangulation || + drawType == gpu::DrawType::atlasBlit; + if (isImageDraw) + { + glUniformBlockBinding( + m_id, + glGetUniformBlockIndex(m_id, GLSL_ImageDrawUniforms), + IMAGE_DRAW_UNIFORM_BUFFER_IDX); + } + if (isTessellationDraw) + { + glutils::Uniform1iByName(m_id, + GLSL_tessVertexTexture, + TESS_VERTEX_TEXTURE_IDX); + } + // Since atomic mode emits the color of the *previous* path, it needs the + // gradient texture bound for every draw. + if (isPaintDraw || interlockMode == gpu::InterlockMode::atomics) + { + glutils::Uniform1iByName(m_id, GLSL_gradTexture, GRAD_TEXTURE_IDX); + } + if ((isTessellationDraw && + (shaderFeatures & ShaderFeatures::ENABLE_FEATHER)) || + drawType == gpu::DrawType::atlasBlit) + { + assert(isPaintDraw || interlockMode == gpu::InterlockMode::atomics); + glutils::Uniform1iByName(m_id, + GLSL_featherTexture, + FEATHER_TEXTURE_IDX); + } + // Atomic mode doesn't support image paints on paths. + if (drawType == gpu::DrawType::atlasBlit) + { + glutils::Uniform1iByName(m_id, GLSL_atlasTexture, ATLAS_TEXTURE_IDX); + } + if (isImageDraw || + (isPaintDraw && interlockMode != gpu::InterlockMode::atomics)) + { + glutils::Uniform1iByName(m_id, GLSL_imageTexture, IMAGE_TEXTURE_IDX); + } + if (!renderContextImpl->m_capabilities.ARB_shader_storage_buffer_object) + { + // Our GL driver doesn't support storage buffers. We polyfill these + // buffers as textures. + if (isPaintDraw) + { + glutils::Uniform1iByName(m_id, GLSL_pathBuffer, PATH_BUFFER_IDX); + } + if (isPaintDraw || interlockMode == gpu::InterlockMode::atomics) + { + glutils::Uniform1iByName(m_id, GLSL_paintBuffer, PAINT_BUFFER_IDX); + glutils::Uniform1iByName(m_id, + GLSL_paintAuxBuffer, + PAINT_AUX_BUFFER_IDX); + } + if (isTessellationDraw) + { + glutils::Uniform1iByName(m_id, + GLSL_contourBuffer, + CONTOUR_BUFFER_IDX); + } + } + if (interlockMode == gpu::InterlockMode::msaa && + (shaderFeatures & gpu::ShaderFeatures::ENABLE_ADVANCED_BLEND) && + !renderContextImpl->m_capabilities.KHR_blend_equation_advanced_coherent) + { + glutils::Uniform1iByName(m_id, + GLSL_dstColorTexture, + DST_COLOR_TEXTURE_IDX); + } + if (!renderContextImpl->m_capabilities + .ANGLE_base_vertex_base_instance_shader_builtin) + { + m_baseInstanceUniformLocation = + glGetUniformLocation(m_id, glutils::BASE_INSTANCE_UNIFORM_NAME); + } +} + +RenderContextGLImpl::DrawProgram::~DrawProgram() +{ + m_state->deleteProgram(m_id); +} + +static GLuint gl_buffer_id(const BufferRing* bufferRing) +{ + return static_cast(bufferRing)->bufferID(); +} + +static void bind_storage_buffer(const GLCapabilities& capabilities, + const BufferRing* bufferRing, + uint32_t bindingIdx, + size_t bindingSizeInBytes, + size_t offsetSizeInBytes) +{ + assert(bufferRing != nullptr); + assert(bindingSizeInBytes > 0); + if (capabilities.ARB_shader_storage_buffer_object) + { + static_cast(bufferRing) + ->bindToRenderContext(bindingIdx, + bindingSizeInBytes, + offsetSizeInBytes); + } + else + { + static_cast(bufferRing) + ->bindToRenderContext(bindingIdx, + bindingSizeInBytes, + offsetSizeInBytes); + } +} + +void RenderContextGLImpl::PixelLocalStorageImpl::ensureRasterOrderingEnabled( + RenderContextGLImpl* renderContextImpl, + const gpu::FlushDescriptor& desc, + bool enabled) +{ + assert(!enabled || + supportsRasterOrdering(renderContextImpl->m_capabilities)); + auto rasterOrderState = enabled ? gpu::TriState::yes : gpu::TriState::no; + if (m_rasterOrderingEnabled != rasterOrderState) + { + onEnableRasterOrdering(enabled); + m_rasterOrderingEnabled = rasterOrderState; + // We only need a barrier when turning raster ordering OFF, because PLS + // already inserts the necessary barriers after draws when it's + // disabled. + if (m_rasterOrderingEnabled == gpu::TriState::no) + { + onBarrier(desc); + } + } +} + +void RenderContextGLImpl::flush(const FlushDescriptor& desc) +{ + assert(desc.interlockMode != gpu::InterlockMode::clockwiseAtomic); + auto renderTarget = static_cast(desc.renderTarget); + + // All programs use the same set of per-flush uniforms. + glBindBufferRange(GL_UNIFORM_BUFFER, + FLUSH_UNIFORM_BUFFER_IDX, + gl_buffer_id(flushUniformBufferRing()), + desc.flushUniformDataOffsetInBytes, + sizeof(gpu::FlushUniforms)); + + // All programs use the same storage buffers. + if (desc.pathCount > 0) + { + bind_storage_buffer(m_capabilities, + pathBufferRing(), + PATH_BUFFER_IDX, + desc.pathCount * sizeof(gpu::PathData), + desc.firstPath * sizeof(gpu::PathData)); + + bind_storage_buffer(m_capabilities, + paintBufferRing(), + PAINT_BUFFER_IDX, + desc.pathCount * sizeof(gpu::PaintData), + desc.firstPaint * sizeof(gpu::PaintData)); + + bind_storage_buffer(m_capabilities, + paintAuxBufferRing(), + PAINT_AUX_BUFFER_IDX, + desc.pathCount * sizeof(gpu::PaintAuxData), + desc.firstPaintAux * sizeof(gpu::PaintAuxData)); + } + + if (desc.contourCount > 0) + { + bind_storage_buffer(m_capabilities, + contourBufferRing(), + CONTOUR_BUFFER_IDX, + desc.contourCount * sizeof(gpu::ContourData), + desc.firstContour * sizeof(gpu::ContourData)); + } + + // Render the complex color ramps into the gradient texture. + if (desc.gradSpanCount > 0) + { + if (m_capabilities.isPowerVR) + { + // PowerVR needs an extra little update to the gradient texture to + // help with synchronization. + glActiveTexture(GL_TEXTURE0 + GRAD_TEXTURE_IDX); + uint32_t nullData = 0; + glTexSubImage2D(GL_TEXTURE_2D, + 0, + 0, + 0, + 1, + 1, + GL_RGBA, + GL_UNSIGNED_BYTE, + &nullData); + } + + m_state->setPipelineState(gpu::COLOR_ONLY_PIPELINE_STATE); + m_state->bindBuffer(GL_ARRAY_BUFFER, + gl_buffer_id(gradSpanBufferRing())); + m_state->bindVAO(m_colorRampVAO); + glVertexAttribIPointer( + 0, + 4, + GL_UNSIGNED_INT, + 0, + reinterpret_cast(desc.firstGradSpan * + sizeof(gpu::GradientSpan))); + glViewport(0, 0, kGradTextureWidth, desc.gradDataHeight); + glBindFramebuffer(GL_FRAMEBUFFER, m_colorRampFBO); + m_state->bindProgram(m_colorRampProgram); + GLenum colorAttachment0 = GL_COLOR_ATTACHMENT0; + glInvalidateFramebuffer(GL_FRAMEBUFFER, 1, &colorAttachment0); + glDrawArraysInstanced(GL_TRIANGLE_STRIP, + 0, + gpu::GRAD_SPAN_TRI_STRIP_VERTEX_COUNT, + desc.gradSpanCount); + } + + // Tessellate all curves into vertices in the tessellation texture. + if (desc.tessVertexSpanCount > 0) + { + m_state->setPipelineState(gpu::COLOR_ONLY_PIPELINE_STATE); + m_state->bindBuffer(GL_ARRAY_BUFFER, + gl_buffer_id(tessSpanBufferRing())); + m_state->bindVAO(m_tessellateVAO); + size_t tessSpanOffsetInBytes = + desc.firstTessVertexSpan * sizeof(gpu::TessVertexSpan); + for (GLuint i = 0; i < 3; ++i) + { + glVertexAttribPointer(i, + 4, + GL_FLOAT, + GL_FALSE, + sizeof(TessVertexSpan), + reinterpret_cast( + tessSpanOffsetInBytes + i * 4 * 4)); + } + glVertexAttribIPointer( + 3, + 4, + GL_UNSIGNED_INT, + sizeof(TessVertexSpan), + reinterpret_cast(tessSpanOffsetInBytes + + offsetof(TessVertexSpan, x0x1))); + glViewport(0, 0, gpu::kTessTextureWidth, desc.tessDataHeight); + glBindFramebuffer(GL_FRAMEBUFFER, m_tessellateFBO); + m_state->bindProgram(m_tessellateProgram); + GLenum colorAttachment0 = GL_COLOR_ATTACHMENT0; + glInvalidateFramebuffer(GL_FRAMEBUFFER, 1, &colorAttachment0); + glDrawElementsInstanced(GL_TRIANGLES, + std::size(gpu::kTessSpanIndices), + GL_UNSIGNED_SHORT, + 0, + desc.tessVertexSpanCount); + } + + // Render the atlas if we have any offscreen feathers. + if ((desc.atlasFillBatchCount | desc.atlasStrokeBatchCount) != 0) + { + glBindFramebuffer(GL_FRAMEBUFFER, m_atlasFBO); + glViewport(0, 0, desc.atlasContentWidth, desc.atlasContentHeight); + glEnable(GL_SCISSOR_TEST); + glScissor(0, 0, desc.atlasContentWidth, desc.atlasContentHeight); + glClearColor(0, 0, 0, 0); + glClear(GL_COLOR_BUFFER_BIT); + m_state->bindVAO(m_drawVAO); + // Invert the front face for atlas draws because GL is bottom up. + glFrontFace(GL_CCW); + + if (desc.atlasFillBatchCount != 0) + { + m_state->setPipelineState(gpu::ATLAS_FILL_PIPELINE_STATE); + m_state->bindProgram(m_atlasFillProgram); + for (size_t i = 0; i < desc.atlasFillBatchCount; ++i) + { + const gpu::AtlasDrawBatch& fillBatch = desc.atlasFillBatches[i]; + glScissor(fillBatch.scissor.left, + fillBatch.scissor.top, + fillBatch.scissor.width(), + fillBatch.scissor.height()); + drawIndexedInstancedNoInstancedAttribs( + GL_TRIANGLES, + gpu::kMidpointFanCenterAAPatchIndexCount, + gpu::kMidpointFanCenterAAPatchBaseIndex, + fillBatch.patchCount, + fillBatch.basePatch, + m_atlasFillProgram.baseInstanceUniformLocation()); + } + } + + if (desc.atlasStrokeBatchCount != 0) + { + m_state->setPipelineState(gpu::ATLAS_STROKE_PIPELINE_STATE); + m_state->bindProgram(m_atlasStrokeProgram); + for (size_t i = 0; i < desc.atlasStrokeBatchCount; ++i) + { + const gpu::AtlasDrawBatch& strokeBatch = + desc.atlasStrokeBatches[i]; + glScissor(strokeBatch.scissor.left, + strokeBatch.scissor.top, + strokeBatch.scissor.width(), + strokeBatch.scissor.height()); + drawIndexedInstancedNoInstancedAttribs( + GL_TRIANGLES, + gpu::kMidpointFanPatchBorderIndexCount, + gpu::kMidpointFanPatchBaseIndex, + strokeBatch.patchCount, + strokeBatch.basePatch, + m_atlasFillProgram.baseInstanceUniformLocation()); + } + } + + glFrontFace(GL_CW); + glDisable(GL_SCISSOR_TEST); + } + + // Bind the currently-submitted buffer in the triangleBufferRing to its + // vertex array. + if (desc.hasTriangleVertices) + { + m_state->bindVAO(m_trianglesVAO); + m_state->bindBuffer(GL_ARRAY_BUFFER, + gl_buffer_id(triangleBufferRing())); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr); + } + + glViewport(0, 0, renderTarget->width(), renderTarget->height()); + +#ifdef RIVE_DESKTOP_GL + if (m_capabilities.ANGLE_polygon_mode && desc.wireframe) + { + glPolygonModeANGLE(GL_FRONT_AND_BACK, GL_LINE_ANGLE); + glLineWidth(2); + } +#endif + + auto msaaResolveAction = RenderTargetGL::MSAAResolveAction::automatic; + std::array msaaDepthStencilColor; + if (desc.interlockMode != gpu::InterlockMode::msaa) + { + assert(desc.msaaSampleCount == 0); + m_plsImpl->activatePixelLocalStorage(this, desc); + if (desc.interlockMode == gpu::InterlockMode::atomics) + { + m_plsImpl->ensureRasterOrderingEnabled(this, desc, false); + } + } + else + { + assert(desc.msaaSampleCount > 0); + bool preserveRenderTarget = + desc.colorLoadAction == gpu::LoadAction::preserveRenderTarget; + bool isFBO0; + msaaResolveAction = renderTarget->bindMSAAFramebuffer( + this, + desc.msaaSampleCount, + preserveRenderTarget ? &desc.renderTargetUpdateBounds : nullptr, + &isFBO0); + + // Hint to tilers to not load unnecessary buffers from memory. + if (isFBO0) + { + msaaDepthStencilColor = {GL_DEPTH, GL_STENCIL, GL_COLOR}; + } + else + { + msaaDepthStencilColor = {GL_DEPTH_ATTACHMENT, + GL_STENCIL_ATTACHMENT, + GL_COLOR_ATTACHMENT0}; + } + glInvalidateFramebuffer(GL_FRAMEBUFFER, + preserveRenderTarget ? 2 : 3, + msaaDepthStencilColor.data()); + + GLbitfield buffersToClear = GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT; + if (desc.colorLoadAction == gpu::LoadAction::clear) + { + float cc[4]; + UnpackColorToRGBA32FPremul(desc.colorClearValue, cc); + glClearColor(cc[0], cc[1], cc[2], cc[3]); + buffersToClear |= GL_COLOR_BUFFER_BIT; + } + m_state->setWriteMasks(true, true, 0xff); + glClear(buffersToClear); + + if (desc.combinedShaderFeatures & + gpu::ShaderFeatures::ENABLE_ADVANCED_BLEND) + { + if (m_capabilities.KHR_blend_equation_advanced_coherent) + { + glEnable(GL_BLEND_ADVANCED_COHERENT_KHR); + } + else + { + // Set up an internal texture to copy the framebuffer into, for + // in-shader blending. + renderTarget->bindInternalDstTexture(GL_TEXTURE0 + + DST_COLOR_TEXTURE_IDX); + } + } + } + + bool clipPlanesEnabled = false; + + // Execute the DrawList. + for (const DrawBatch& batch : *desc.drawList) + { + const gpu::DrawType drawType = batch.drawType; + gpu::ShaderFeatures shaderFeatures = + desc.interlockMode == gpu::InterlockMode::atomics + ? desc.combinedShaderFeatures + : batch.shaderFeatures; + gpu::ShaderMiscFlags shaderMiscFlags = batch.shaderMiscFlags; + if (m_plsImpl != nullptr) + { + shaderMiscFlags |= m_plsImpl->shaderMiscFlags(desc, drawType); + } + if (desc.interlockMode == gpu::InterlockMode::rasterOrdering && + (batch.drawContents & gpu::DrawContents::clockwiseFill)) + { + shaderMiscFlags |= gpu::ShaderMiscFlags::clockwiseFill; + } + uint32_t fragmentShaderKey = gpu::ShaderUniqueKey(drawType, + shaderFeatures, + desc.interlockMode, + shaderMiscFlags); + const DrawProgram& drawProgram = m_drawPrograms + .try_emplace(fragmentShaderKey, + this, + drawType, + shaderFeatures, + desc.interlockMode, + shaderMiscFlags) + .first->second; + m_state->bindProgram(drawProgram.id()); + + if (auto imageTextureGL = + static_cast(batch.imageTexture)) + { + glActiveTexture(GL_TEXTURE0 + IMAGE_TEXTURE_IDX); + glBindTexture(GL_TEXTURE_2D, *imageTextureGL); + glutils::SetTexture2DSamplingParams(batch.imageSampler); + } + + gpu::PipelineState pipelineState; + gpu::get_pipeline_state(batch, + desc, + m_platformFeatures, + &pipelineState); + if (desc.interlockMode == gpu::InterlockMode::msaa) + { + // Set up the next clipRect. + bool needsClipPlanes = + (shaderFeatures & gpu::ShaderFeatures::ENABLE_CLIP_RECT); + if (needsClipPlanes != clipPlanesEnabled) + { + auto toggleEnableOrDisable = + needsClipPlanes ? glEnable : glDisable; + toggleEnableOrDisable(GL_CLIP_DISTANCE0_EXT); + toggleEnableOrDisable(GL_CLIP_DISTANCE1_EXT); + toggleEnableOrDisable(GL_CLIP_DISTANCE2_EXT); + toggleEnableOrDisable(GL_CLIP_DISTANCE3_EXT); + clipPlanesEnabled = needsClipPlanes; + } + } + else if (desc.interlockMode == gpu::InterlockMode::atomics) + { + if (!desc.atomicFixedFunctionColorOutput && + drawType != gpu::DrawType::atomicResolve) + { + // When rendering to an offscreen texture in atomic mode, GL + // leaves the target framebuffer bound the whole time, but + // disables color writes until it's time to resolve. + pipelineState.colorWriteEnabled = false; + } + } + m_state->setPipelineState(pipelineState); + + if (batch.barriers & + (BarrierFlags::plsAtomic | BarrierFlags::plsAtomicPreResolve)) + { + assert(desc.interlockMode == gpu::InterlockMode::atomics); + m_plsImpl->barrier(desc); + } + else if (batch.barriers & BarrierFlags::dstColorTexture) + { + // Read back the framebuffer where we need a dstColor for blending. + assert(desc.interlockMode == gpu::InterlockMode::msaa); + assert(batch.dstReadList != nullptr); + renderTarget->bindInternalFramebuffer( + GL_DRAW_FRAMEBUFFER, + RenderTargetGL::DrawBufferMask::color); + for (const Draw* draw = batch.dstReadList; draw != nullptr; + draw = draw->nextDstRead()) + { + assert(draw->blendMode() != BlendMode::srcOver); + glutils::BlitFramebuffer(draw->pixelBounds(), + renderTarget->height()); + } + renderTarget->bindMSAAFramebuffer(this, desc.msaaSampleCount); + } + + switch (drawType) + { + case DrawType::midpointFanPatches: + case DrawType::midpointFanCenterAAPatches: + case DrawType::outerCurvePatches: + case DrawType::msaaStrokes: + case DrawType::msaaMidpointFanBorrowedCoverage: + case DrawType::msaaMidpointFans: + case DrawType::msaaMidpointFanStencilReset: + case DrawType::msaaMidpointFanPathsStencil: + case DrawType::msaaMidpointFanPathsCover: + case DrawType::msaaOuterCubics: + { + m_state->bindVAO(m_drawVAO); + if (desc.interlockMode == gpu::InterlockMode::rasterOrdering) + { + m_plsImpl->ensureRasterOrderingEnabled(this, desc, true); + } + drawIndexedInstancedNoInstancedAttribs( + GL_TRIANGLES, + gpu::PatchIndexCount(drawType), + gpu::PatchBaseIndex(drawType), + batch.elementCount, + batch.baseElement, + drawProgram.baseInstanceUniformLocation()); + break; + } + + case gpu::DrawType::msaaStencilClipReset: + { + m_state->bindVAO(m_trianglesVAO); + glDrawArrays(GL_TRIANGLES, + batch.baseElement, + batch.elementCount); + break; + } + + case gpu::DrawType::interiorTriangulation: + case gpu::DrawType::atlasBlit: + { + m_state->bindVAO(m_trianglesVAO); + if (desc.interlockMode == gpu::InterlockMode::rasterOrdering) + { + // Disable raster ordering if we're drawing true interior + // triangles (not atlas coverage). We know the triangulation + // is large enough that it's faster to issue a barrier than + // to force raster ordering in the fragment shader. + m_plsImpl->ensureRasterOrderingEnabled( + this, + desc, + drawType != gpu::DrawType::interiorTriangulation); + } + glDrawArrays(GL_TRIANGLES, + batch.baseElement, + batch.elementCount); + if (desc.interlockMode == gpu::InterlockMode::rasterOrdering && + drawType != gpu::DrawType::atlasBlit) + { + // We turned off raster ordering even though we're in + // "rasterOrdering" mode because it improves performance and + // we know the interior triangles don't overlap. But now we + // have to insert a barrier before we draw anything else. + m_plsImpl->barrier(desc); + } + break; + } + + case gpu::DrawType::imageRect: + { + // m_imageRectVAO should have gotten lazily allocated by now. + assert(desc.interlockMode == gpu::InterlockMode::atomics); + assert(m_plsImpl->rasterOrderingKnownDisabled()); + assert(m_imageRectVAO != 0); + m_state->bindVAO(m_imageRectVAO); + glBindBufferRange(GL_UNIFORM_BUFFER, + IMAGE_DRAW_UNIFORM_BUFFER_IDX, + gl_buffer_id(imageDrawUniformBufferRing()), + batch.imageDrawDataOffset, + sizeof(gpu::ImageDrawUniforms)); + glDrawElements(GL_TRIANGLES, + std::size(gpu::kImageRectIndices), + GL_UNSIGNED_SHORT, + nullptr); + break; + } + + case gpu::DrawType::imageMesh: + { + LITE_RTTI_CAST_OR_BREAK(vertexBuffer, + RenderBufferGLImpl*, + batch.vertexBuffer); + LITE_RTTI_CAST_OR_BREAK(uvBuffer, + RenderBufferGLImpl*, + batch.uvBuffer); + LITE_RTTI_CAST_OR_BREAK(indexBuffer, + RenderBufferGLImpl*, + batch.indexBuffer); + m_state->bindVAO(m_imageMeshVAO); + m_state->bindBuffer(GL_ARRAY_BUFFER, vertexBuffer->bufferID()); + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, nullptr); + m_state->bindBuffer(GL_ARRAY_BUFFER, uvBuffer->bufferID()); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, nullptr); + m_state->bindBuffer(GL_ELEMENT_ARRAY_BUFFER, + indexBuffer->bufferID()); + glBindBufferRange(GL_UNIFORM_BUFFER, + IMAGE_DRAW_UNIFORM_BUFFER_IDX, + gl_buffer_id(imageDrawUniformBufferRing()), + batch.imageDrawDataOffset, + sizeof(gpu::ImageDrawUniforms)); + if (desc.interlockMode == gpu::InterlockMode::rasterOrdering) + { + m_plsImpl->ensureRasterOrderingEnabled(this, desc, true); + } + glDrawElements(GL_TRIANGLES, + batch.elementCount, + GL_UNSIGNED_SHORT, + reinterpret_cast(batch.baseElement * + sizeof(uint16_t))); + break; + } + + case gpu::DrawType::atomicResolve: + { + assert(desc.interlockMode == gpu::InterlockMode::atomics); + assert(m_plsImpl->rasterOrderingKnownDisabled()); + m_state->bindVAO(m_emptyVAO); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + break; + } + + case gpu::DrawType::atomicInitialize: + { + RIVE_UNREACHABLE(); + } + } + } + + if (desc.interlockMode != gpu::InterlockMode::msaa) + { + m_plsImpl->deactivatePixelLocalStorage(this, desc); + } + else + { + // Depth/stencil can be discarded. + glInvalidateFramebuffer(GL_FRAMEBUFFER, + 2, + msaaDepthStencilColor.data()); + if (msaaResolveAction == + RenderTargetGL::MSAAResolveAction::framebufferBlit) + { + renderTarget->bindDestinationFramebuffer(GL_DRAW_FRAMEBUFFER); + glutils::BlitFramebuffer(desc.renderTargetUpdateBounds, + renderTarget->height(), + GL_COLOR_BUFFER_BIT); + // Now that color is resolved elsewhere we can discard the MSAA + // color buffer as well. + glInvalidateFramebuffer(GL_READ_FRAMEBUFFER, + 1, + msaaDepthStencilColor.data() + 2); + } + + if ((desc.combinedShaderFeatures & + gpu::ShaderFeatures::ENABLE_ADVANCED_BLEND) && + m_capabilities.KHR_blend_equation_advanced_coherent) + { + glDisable(GL_BLEND_ADVANCED_COHERENT_KHR); + } + if (clipPlanesEnabled) + { + glDisable(GL_CLIP_DISTANCE0_EXT); + glDisable(GL_CLIP_DISTANCE1_EXT); + glDisable(GL_CLIP_DISTANCE2_EXT); + glDisable(GL_CLIP_DISTANCE3_EXT); + } + } + +#ifdef RIVE_DESKTOP_GL + if (m_capabilities.ANGLE_polygon_mode && desc.wireframe) + { + glPolygonModeANGLE(GL_FRONT_AND_BACK, GL_FILL_ANGLE); + } +#endif + + if (m_capabilities.isAdreno) + { + // Qualcomm experiences synchronization issues with multiple flushes per + // frame if we don't call glFlush in between. + glFlush(); + } +} + +void RenderContextGLImpl::drawIndexedInstancedNoInstancedAttribs( + GLenum primitiveTopology, + uint32_t indexCount, + uint32_t baseIndex, + uint32_t instanceCount, + uint32_t baseInstance, + GLint baseInstanceUniformLocation) +{ + assert(m_capabilities.ANGLE_base_vertex_base_instance_shader_builtin == + (baseInstanceUniformLocation < 0)); + const void* indexOffset = + reinterpret_cast(baseIndex * sizeof(uint16_t)); + for (uint32_t endInstance = baseInstance + instanceCount; + baseInstance < endInstance;) + + { + uint32_t subInstanceCount = + std::min(endInstance - baseInstance, + m_capabilities.maxSupportedInstancesPerDrawCommand); +#ifndef RIVE_WEBGL + if (m_capabilities.ANGLE_base_vertex_base_instance_shader_builtin) + { + glDrawElementsInstancedBaseInstanceEXT(primitiveTopology, + indexCount, + GL_UNSIGNED_SHORT, + indexOffset, + subInstanceCount, + baseInstance); + } + else +#endif + { + glUniform1i(baseInstanceUniformLocation, baseInstance); + glDrawElementsInstanced(primitiveTopology, + indexCount, + GL_UNSIGNED_SHORT, + indexOffset, + subInstanceCount); + } + baseInstance += subInstanceCount; + } +} + +void RenderContextGLImpl::blitTextureToFramebufferAsDraw( + GLuint textureID, + const IAABB& bounds, + uint32_t renderTargetHeight) +{ + if (m_blitAsDrawProgram == 0) + { + // Define "USE_TEXEL_FETCH_WITH_FRAG_COORD" so the shader uses + // texelFetch() on the source texture instead of sampling it. This way + // we don't have to configure the texture's sampling parameters, and + // since textureID potentially refers to an external texture, it would + // be very messy to try and change its sampling params. + const char* blitDefines[] = {GLSL_USE_TEXEL_FETCH_WITH_FRAG_COORD}; + const char* blitSources[] = {glsl::constants, + glsl::blit_texture_as_draw}; + m_blitAsDrawProgram = glutils::Program(); + m_blitAsDrawProgram.compileAndAttachShader(GL_VERTEX_SHADER, + blitDefines, + std::size(blitDefines), + blitSources, + std::size(blitSources), + m_capabilities); + m_blitAsDrawProgram.compileAndAttachShader(GL_FRAGMENT_SHADER, + blitDefines, + std::size(blitDefines), + blitSources, + std::size(blitSources), + m_capabilities); + m_blitAsDrawProgram.link(); + m_state->bindProgram(m_blitAsDrawProgram); + glutils::Uniform1iByName(m_blitAsDrawProgram, GLSL_sourceTexture, 0); + } + + m_state->setPipelineState(gpu::COLOR_ONLY_PIPELINE_STATE); + m_state->bindProgram(m_blitAsDrawProgram); + m_state->bindVAO(m_emptyVAO); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, textureID); + glEnable(GL_SCISSOR_TEST); + glScissor(bounds.left, + renderTargetHeight - bounds.bottom, + bounds.width(), + bounds.height()); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + glDisable(GL_SCISSOR_TEST); +} + +std::unique_ptr RenderContextGLImpl::MakeContext( + const ContextOptions& contextOptions) +{ + GLCapabilities capabilities{}; + + const char* glVersionStr = (const char*)glGetString(GL_VERSION); +#ifdef RIVE_WEBGL + capabilities.isGLES = true; +#else + capabilities.isGLES = strstr(glVersionStr, "OpenGL ES") != NULL; +#endif + if (capabilities.isGLES) + { +#ifdef RIVE_WEBGL + capabilities.isANGLEOrWebGL = true; +#else + capabilities.isANGLEOrWebGL = strstr(glVersionStr, "ANGLE") != nullptr; +#endif +#ifdef _MSC_VER + sscanf_s( +#else + sscanf( +#endif + glVersionStr, + "OpenGL ES %d.%d", + &capabilities.contextVersionMajor, + &capabilities.contextVersionMinor); + } + else + { +#ifdef _MSC_VER + sscanf_s( +#else + sscanf( +#endif + glVersionStr, + "%d.%d", + &capabilities.contextVersionMajor, + &capabilities.contextVersionMinor); + } +#ifdef RIVE_DESKTOP_GL + assert(capabilities.contextVersionMajor == GLAD_GL_version_major); + assert(capabilities.contextVersionMinor == GLAD_GL_version_minor); + assert(capabilities.isGLES == static_cast(GLAD_GL_version_es)); +#endif + + if (capabilities.isGLES) + { + if (!capabilities.isContextVersionAtLeast(3, 0)) + { + fprintf(stderr, + "OpenGL ES %i.%i not supported. Minimum supported version " + "is 3.0.\n", + capabilities.contextVersionMajor, + capabilities.contextVersionMinor); + return nullptr; + } + } + else + { + if (!capabilities.isContextVersionAtLeast(4, 2)) + { + fprintf(stderr, + "OpenGL %i.%i not supported. Minimum supported version is " + "4.2.\n", + capabilities.contextVersionMajor, + capabilities.contextVersionMinor); + return nullptr; + } + } + + GLenum rendererToken = GL_RENDERER; +#ifdef RIVE_WEBGL + if (emscripten_webgl_enable_extension( + emscripten_webgl_get_current_context(), + "WEBGL_debug_renderer_info")) + { + rendererToken = GL_UNMASKED_RENDERER_WEBGL; + } +#endif + const char* rendererString = + reinterpret_cast(glGetString(rendererToken)); + capabilities.isAdreno = strstr(rendererString, "Adreno"); + capabilities.isMali = strstr(rendererString, "Mali"); + capabilities.isPowerVR = strstr(rendererString, "PowerVR"); + if (capabilities.isMali || capabilities.isPowerVR) + { + // We have observed crashes on Mali-G71 when issuing instanced draws + // with somewhere between 2^15 and 2^16 instances. + // + // Skia also reports crashes on PowerVR when drawing somewhere between + // 2^14 and 2^15 instances. + // + // Limit the maximum number of instances we issue per-draw-call on these + // devices to a safe value, far below the observed crash thresholds. + capabilities.maxSupportedInstancesPerDrawCommand = 999; + } + else + { + capabilities.maxSupportedInstancesPerDrawCommand = ~0u; + } + + // Our baseline feature set is GLES 3.0. Capabilities from newer context + // versions are reported as extensions. + if (capabilities.isGLES) + { + if (capabilities.isContextVersionAtLeast(3, 1)) + { + capabilities.ARB_shader_storage_buffer_object = true; + } + } + else + { + if (capabilities.isContextVersionAtLeast(4, 2)) + { + capabilities.ARB_shader_image_load_store = true; + } + if (capabilities.isContextVersionAtLeast(4, 3)) + { + capabilities.ARB_shader_storage_buffer_object = true; + } + capabilities.EXT_clip_cull_distance = true; + } + +#ifndef RIVE_WEBGL + GLint extensionCount; + glGetIntegerv(GL_NUM_EXTENSIONS, &extensionCount); + for (int i = 0; i < extensionCount; ++i) + { + auto* ext = + reinterpret_cast(glGetStringi(GL_EXTENSIONS, i)); + if (strcmp(ext, "GL_ANGLE_base_vertex_base_instance_shader_builtin") == + 0) + { + capabilities.ANGLE_base_vertex_base_instance_shader_builtin = true; + } + else if (strcmp(ext, "GL_ANGLE_shader_pixel_local_storage") == 0) + { + capabilities.ANGLE_shader_pixel_local_storage = true; + } + else if (strcmp(ext, "GL_ANGLE_shader_pixel_local_storage_coherent") == + 0) + { + capabilities.ANGLE_shader_pixel_local_storage_coherent = true; + } + else if (strcmp(ext, "GL_ANGLE_provoking_vertex") == 0) + { + capabilities.ANGLE_provoking_vertex = true; + } + else if (strcmp(ext, "GL_ANGLE_polygon_mode") == 0) + { + capabilities.ANGLE_polygon_mode = true; + } + else if (strcmp(ext, "GL_ARM_shader_framebuffer_fetch") == 0) + { + capabilities.ARM_shader_framebuffer_fetch = true; + } + else if (strcmp(ext, "GL_ARB_fragment_shader_interlock") == 0) + { + capabilities.ARB_fragment_shader_interlock = true; + } + else if (strcmp(ext, "GL_ARB_shader_image_load_store") == 0) + { + capabilities.ARB_shader_image_load_store = true; + } + else if (strcmp(ext, "GL_ARB_shader_storage_buffer_object") == 0) + { + capabilities.ARB_shader_storage_buffer_object = true; + } + else if (strcmp(ext, "GL_KHR_blend_equation_advanced") == 0) + { + capabilities.KHR_blend_equation_advanced = true; + } + else if (strcmp(ext, "GL_KHR_blend_equation_advanced_coherent") == 0) + { + capabilities.KHR_blend_equation_advanced_coherent = true; + } + else if (strcmp(ext, "GL_EXT_base_instance") == 0) + { + capabilities.EXT_base_instance = true; + } +#ifdef RIVE_ANDROID + // Don't use EXT_clip_cull_distance if we're on ANGLE. Galaxy S22 + // (OpenGL Samsung Electronics Co., Ltd.; + // ANGLE (Samsung Xclipse 920) on Vulkan 1.1.179; + // OpenGL ES 3.2 ANGLE git hash: c7c78c41d520) advertises support for + // this extension but then doesn't support gl_ClipDistance in the + // shader. Only use clip planes on ANGLE if ANGLE_clip_cull_distance is + // supported. + else if (!capabilities.isANGLEOrWebGL && + strcmp(ext, "GL_EXT_clip_cull_distance") == 0) + { + capabilities.EXT_clip_cull_distance = true; + } +#endif + else if (strcmp(ext, "GL_EXT_multisampled_render_to_texture") == 0) + { + capabilities.EXT_multisampled_render_to_texture = true; + } + else if (strcmp(ext, "GL_ANGLE_clip_cull_distance") == 0) + { + capabilities.EXT_clip_cull_distance = true; + } + else if (strcmp(ext, "GL_INTEL_fragment_shader_ordering") == 0) + { + capabilities.INTEL_fragment_shader_ordering = true; + } + else if (strcmp(ext, "GL_EXT_color_buffer_half_float") == 0) + { + capabilities.EXT_color_buffer_half_float = true; + } + else if (strcmp(ext, "GL_EXT_float_blend") == 0) + { + capabilities.EXT_float_blend = true; + } + else if (strcmp(ext, "GL_ARB_color_buffer_float") == 0) + { + capabilities.EXT_color_buffer_half_float = true; + capabilities.EXT_float_blend = true; + } + else if (strcmp(ext, "GL_EXT_shader_framebuffer_fetch") == 0) + { + capabilities.EXT_shader_framebuffer_fetch = true; + } + else if (strcmp(ext, "GL_EXT_shader_pixel_local_storage") == 0) + { + capabilities.EXT_shader_pixel_local_storage = true; + } + else if (strcmp(ext, "GL_QCOM_shader_framebuffer_fetch_noncoherent") == + 0) + { + capabilities.QCOM_shader_framebuffer_fetch_noncoherent = true; + } + } +#else // !RIVE_WEBGL -> RIVE_WEBGL + if (webgl_enable_WEBGL_shader_pixel_local_storage_coherent()) + { + capabilities.ANGLE_shader_pixel_local_storage = true; + capabilities.ANGLE_shader_pixel_local_storage_coherent = true; + } + if (webgl_enable_WEBGL_provoking_vertex()) + { + capabilities.ANGLE_provoking_vertex = true; + } + if (emscripten_webgl_enable_extension( + emscripten_webgl_get_current_context(), + "WEBGL_clip_cull_distance")) + { + capabilities.EXT_clip_cull_distance = true; + } + if (emscripten_webgl_enable_extension( + emscripten_webgl_get_current_context(), + "EXT_color_buffer_half_float")) + { + capabilities.EXT_color_buffer_half_float = true; + } + if (emscripten_webgl_enable_extension( + emscripten_webgl_get_current_context(), + "EXT_color_buffer_float") && + emscripten_webgl_enable_extension( + emscripten_webgl_get_current_context(), + "EXT_float_blend")) + { + capabilities.EXT_float_blend = true; + } +#endif // RIVE_WEBGL + +#ifdef RIVE_DESKTOP_GL + if (GLAD_GL_ANGLE_base_vertex_base_instance_shader_builtin) + { + capabilities.ANGLE_base_vertex_base_instance_shader_builtin = true; + } + if (GLAD_GL_ANGLE_polygon_mode) + { + capabilities.ANGLE_polygon_mode = true; + } + if (GLAD_GL_EXT_base_instance) + { + capabilities.EXT_base_instance = true; + } +#endif + + if (capabilities.ARB_shader_storage_buffer_object) + { + // We need four storage buffers in the vertex shader. Disable the + // extension if this isn't supported. + int maxVertexShaderStorageBlocks; + glGetIntegerv(GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS, + &maxVertexShaderStorageBlocks); + if (maxVertexShaderStorageBlocks < gpu::kMaxStorageBuffers) + { + capabilities.ARB_shader_storage_buffer_object = false; + } + } + + if (capabilities.ANGLE_shader_pixel_local_storage || + capabilities.ANGLE_shader_pixel_local_storage_coherent) + { + // ANGLE_shader_pixel_local_storage enum values had a breaking change in + // early 2025. Disable the extension if we can't verify that we're + // running on the latest spec. + if (!glutils::validate_pixel_local_storage_angle()) + { + fprintf(stderr, + "WARNING: detected an old version of " + "ANGLE_shader_pixel_local_storage. Disabling the " + "extension. Please update your drivers.\n"); + capabilities.ANGLE_shader_pixel_local_storage = + capabilities.ANGLE_shader_pixel_local_storage_coherent = false; + } + } + + if (contextOptions.disableFragmentShaderInterlock) + { + // Disable the extensions we don't want to use internally. + capabilities.ARB_fragment_shader_interlock = false; + capabilities.INTEL_fragment_shader_ordering = false; + } + + if (strstr(rendererString, "Metal") != nullptr || + strstr(rendererString, "Direct3D") != nullptr) + { + // Disable ANGLE_base_vertex_base_instance_shader_builtin on ANGLE/D3D + // and ANGLE/Metal. + // The extension is polyfilled on D3D anyway, and on Metal it crashes. + capabilities.ANGLE_base_vertex_base_instance_shader_builtin = false; + } + + if (strstr(rendererString, "Direct3D") != nullptr) + { + // Our use of EXT_multisampled_render_to_texture causes a segfault in + // the Microsoft WARP (software) renderer. Just don't use this extension + // on D3D since it's polyfilled anyway. + capabilities.EXT_multisampled_render_to_texture = false; + } + + if (strstr(rendererString, "ANGLE Metal Renderer") != nullptr && + capabilities.EXT_float_blend) + { + capabilities.needsFloatingPointTessellationTexture = true; + } + else + { + capabilities.needsFloatingPointTessellationTexture = false; + } +#ifdef RIVE_ANDROID + // Android doesn't load extension functions for us. + LoadGLESExtensions(capabilities); +#endif + + if (!contextOptions.disablePixelLocalStorage) + { +#ifdef RIVE_ANDROID + if (capabilities.EXT_shader_pixel_local_storage && + (capabilities.ARM_shader_framebuffer_fetch || + capabilities.EXT_shader_framebuffer_fetch)) + { + return MakeContext(rendererString, + capabilities, + MakePLSImplEXTNative(capabilities)); + } +#else + if (capabilities.ANGLE_shader_pixel_local_storage_coherent) + { + // EXT_shader_framebuffer_fetch is costly on Qualcomm, with or + // without the "noncoherent" extension. Use MSAA on Adreno. + if (!capabilities.isAdreno) + { + return MakeContext(rendererString, + capabilities, + MakePLSImplWebGL()); + } + } +#endif + +#ifdef RIVE_DESKTOP_GL + if (capabilities.ARB_shader_image_load_store) + { + return MakeContext(rendererString, + capabilities, + MakePLSImplRWTexture()); + } +#endif + } + + return MakeContext(rendererString, capabilities, nullptr); +} + +std::unique_ptr RenderContextGLImpl::MakeContext( + const char* rendererString, + GLCapabilities capabilities, + std::unique_ptr plsImpl) +{ + auto renderContextImpl = std::unique_ptr( + new RenderContextGLImpl(rendererString, + capabilities, + std::move(plsImpl))); + return std::make_unique(std::move(renderContextImpl)); +} +} // namespace rive::gpu diff --git a/third_party/rive_renderer/source/gl/render_target_gl.cpp b/third_party/rive_renderer/source/gl/render_target_gl.cpp new file mode 100644 index 0000000..542d2b5 --- /dev/null +++ b/third_party/rive_renderer/source/gl/render_target_gl.cpp @@ -0,0 +1,432 @@ +/* + * Copyright 2023 Rive + */ + +#include "rive/renderer/gl/render_target_gl.hpp" + +#include "rive/renderer/gpu.hpp" +#include "rive/renderer/gl/render_context_gl_impl.hpp" +#include "shaders/constants.glsl" + +namespace rive::gpu +{ +TextureRenderTargetGL::~TextureRenderTargetGL() {} + +static glutils::Texture make_backing_texture(GLenum internalformat, + uint32_t width, + uint32_t height) +{ + glutils::Texture texture; + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, texture); + glTexStorage2D(GL_TEXTURE_2D, 1, internalformat, width, height); + return texture; +} + +void TextureRenderTargetGL::allocateInternalPLSTextures( + gpu::InterlockMode interlockMode) +{ + if (m_coverageTexture == 0) + { + m_coverageTexture = make_backing_texture(GL_R32UI, width(), height()); + m_framebufferInternalAttachmentsDirty = true; + m_framebufferInternalPLSBindingsDirty = true; + } + if (m_clipTexture == 0) + { + m_clipTexture = make_backing_texture(GL_R32UI, width(), height()); + m_framebufferInternalAttachmentsDirty = true; + m_framebufferInternalPLSBindingsDirty = true; + } + if (interlockMode == InterlockMode::rasterOrdering && + m_scratchColorTexture == 0) + { + m_scratchColorTexture = + make_backing_texture(GL_RGBA8, width(), height()); + m_framebufferInternalAttachmentsDirty = true; + m_framebufferInternalPLSBindingsDirty = true; + } +} + +void TextureRenderTargetGL::bindInternalFramebuffer( + GLenum target, + DrawBufferMask drawBufferMask) +{ + if (m_framebufferID == 0) + { + m_framebufferID = glutils::Framebuffer(); + } + glBindFramebuffer(target, m_framebufferID); + + if (target != GL_READ_FRAMEBUFFER && + m_internalDrawBufferMask != drawBufferMask) + { + GLenum drawBufferList[4]; + for (int i = 0; i < 4; ++i) + { + drawBufferList[i] = + (drawBufferMask & static_cast(1 << i)) + ? GL_COLOR_ATTACHMENT0 + i + : GL_NONE; + static_assert((int)DrawBufferMask::color == 1 << COLOR_PLANE_IDX); + static_assert((int)DrawBufferMask::clip == 1 << CLIP_PLANE_IDX); + static_assert((int)DrawBufferMask::scratchColor == + 1 << SCRATCH_COLOR_PLANE_IDX); + static_assert((int)DrawBufferMask::coverage == + 1 << COVERAGE_PLANE_IDX); + } + glDrawBuffers(4, drawBufferList); + m_internalDrawBufferMask = drawBufferMask; + } + + if (m_framebufferTargetAttachmentDirty) + { + glFramebufferTexture2D(target, + GL_COLOR_ATTACHMENT0 + COLOR_PLANE_IDX, + GL_TEXTURE_2D, + m_externalTextureID, + 0); + m_framebufferTargetAttachmentDirty = false; + } + + if (m_framebufferInternalAttachmentsDirty) + { + glFramebufferTexture2D(target, + GL_COLOR_ATTACHMENT0 + CLIP_PLANE_IDX, + GL_TEXTURE_2D, + m_clipTexture, + 0); + glFramebufferTexture2D(target, + GL_COLOR_ATTACHMENT0 + SCRATCH_COLOR_PLANE_IDX, + GL_TEXTURE_2D, + m_scratchColorTexture, + 0); + glFramebufferTexture2D(target, + GL_COLOR_ATTACHMENT0 + COVERAGE_PLANE_IDX, + GL_TEXTURE_2D, + m_coverageTexture, + 0); + m_framebufferInternalAttachmentsDirty = false; + } +} + +void TextureRenderTargetGL::bindHeadlessFramebuffer( + const GLCapabilities& capabilities) +{ + if (m_headlessFramebuffer == 0) + { + m_headlessFramebuffer = glutils::Framebuffer(); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_headlessFramebuffer); +#ifndef RIVE_WEBGL + if (capabilities.ARB_shader_image_load_store) + { + glFramebufferParameteri(GL_DRAW_FRAMEBUFFER, + GL_FRAMEBUFFER_DEFAULT_WIDTH, + width()); + glFramebufferParameteri(GL_DRAW_FRAMEBUFFER, + GL_FRAMEBUFFER_DEFAULT_HEIGHT, + height()); + } +#endif + glDrawBuffers(0, nullptr); + } + else + { + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_headlessFramebuffer); + } + +#ifdef GL_ANGLE_shader_pixel_local_storage + if (capabilities.ANGLE_shader_pixel_local_storage) + { + if (m_framebufferTargetPLSBindingDirty) + { + glFramebufferTexturePixelLocalStorageANGLE(COLOR_PLANE_IDX, + m_externalTextureID, + 0, + 0); + m_framebufferTargetPLSBindingDirty = false; + } + + if (m_framebufferInternalPLSBindingsDirty) + { + glFramebufferTexturePixelLocalStorageANGLE(CLIP_PLANE_IDX, + m_clipTexture, + 0, + 0); + glFramebufferTexturePixelLocalStorageANGLE(SCRATCH_COLOR_PLANE_IDX, + m_scratchColorTexture, + 0, + 0); + glFramebufferTexturePixelLocalStorageANGLE(COVERAGE_PLANE_IDX, + m_coverageTexture, + 0, + 0); + m_framebufferInternalPLSBindingsDirty = false; + } + } +#endif +} + +void TextureRenderTargetGL::bindAsImageTextures(DrawBufferMask drawBufferMask) +{ +#ifndef RIVE_WEBGL + if (drawBufferMask & DrawBufferMask::color) + { + assert(m_externalTextureID != 0); + glBindImageTexture(COLOR_PLANE_IDX, + m_externalTextureID, + 0, + GL_FALSE, + 0, + GL_READ_WRITE, + GL_RGBA8); + } + if (drawBufferMask & DrawBufferMask::clip) + { + assert(m_clipTexture != 0); + glBindImageTexture(CLIP_PLANE_IDX, + m_clipTexture, + 0, + GL_FALSE, + 0, + GL_READ_WRITE, + GL_R32UI); + } + if (drawBufferMask & DrawBufferMask::scratchColor) + { + assert(m_scratchColorTexture != 0); + glBindImageTexture(SCRATCH_COLOR_PLANE_IDX, + m_scratchColorTexture, + 0, + GL_FALSE, + 0, + GL_READ_WRITE, + GL_RGBA8); + } + if (drawBufferMask & DrawBufferMask::coverage) + { + assert(m_coverageTexture != 0); + glBindImageTexture(COVERAGE_PLANE_IDX, + m_coverageTexture, + 0, + GL_FALSE, + 0, + GL_READ_WRITE, + GL_R32UI); + } +#endif +} + +RenderTargetGL::MSAAResolveAction TextureRenderTargetGL::bindMSAAFramebuffer( + RenderContextGLImpl* renderContextImpl, + int sampleCount, + const IAABB* preserveBounds, + bool* isFBO0) +{ + assert(sampleCount > 0); + if (m_msaaFramebuffer == 0) + { + m_msaaFramebuffer = glutils::Framebuffer(); + } + + if (isFBO0 != nullptr) + { + *isFBO0 = false; + } + + sampleCount = std::max(sampleCount, 1); + if (m_msaaFramebufferSampleCount != sampleCount) + { + m_msaaDepthStencilBuffer = glutils::Renderbuffer(); + glBindRenderbuffer(GL_RENDERBUFFER, m_msaaDepthStencilBuffer); + + glBindFramebuffer(GL_FRAMEBUFFER, m_msaaFramebuffer); +#ifndef RIVE_WEBGL + if (renderContextImpl->capabilities() + .EXT_multisampled_render_to_texture) + { + glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, + sampleCount, + GL_DEPTH24_STENCIL8, + width(), + height()); + + // With EXT_multisampled_render_to_texture we can render directly to + // the target texture. + glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, + m_externalTextureID, + 0, + sampleCount); + } + else +#endif + { + glRenderbufferStorageMultisample(GL_RENDERBUFFER, + sampleCount, + GL_DEPTH24_STENCIL8, + width(), + height()); + + // Render to an offscreen renderbuffer that gets resolved into the + // target texture. + m_msaaColorBuffer = glutils::Renderbuffer(); + glBindRenderbuffer(GL_RENDERBUFFER, m_msaaColorBuffer); + glRenderbufferStorageMultisample(GL_RENDERBUFFER, + sampleCount, + GL_RGBA8, + width(), + height()); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + GL_RENDERBUFFER, + m_msaaColorBuffer); + } + glFramebufferRenderbuffer(GL_FRAMEBUFFER, + GL_DEPTH_STENCIL_ATTACHMENT, + GL_RENDERBUFFER, + m_msaaDepthStencilBuffer); + + m_msaaFramebufferSampleCount = sampleCount; + } + + glBindFramebuffer(GL_FRAMEBUFFER, m_msaaFramebuffer); + + if (renderContextImpl->capabilities().EXT_multisampled_render_to_texture) + { + return MSAAResolveAction::automatic; // MSAA render-to-texture resolves + // automatically. + } + else + { + if (preserveBounds != nullptr) + { + // The MSAA render target is offscreen. In order to preserve, we + // need to draw the target texture into the MSAA buffer. + // (glBlitFramebuffer() doesn't support texture -> MSAA.) + renderContextImpl->blitTextureToFramebufferAsDraw( + m_externalTextureID, + *preserveBounds, + height()); + } + + return MSAAResolveAction::framebufferBlit; // Caller must resolve this + // framebuffer. + } +} + +void TextureRenderTargetGL::bindInternalDstTexture(GLenum activeTexture) +{ + glActiveTexture(activeTexture); + glBindTexture(GL_TEXTURE_2D, m_externalTextureID); +} + +FramebufferRenderTargetGL::~FramebufferRenderTargetGL() {} + +void FramebufferRenderTargetGL::bindDestinationFramebuffer(GLenum target) +{ + glBindFramebuffer(target, m_externalFramebufferID); +} + +void FramebufferRenderTargetGL::allocateOffscreenTargetTexture() +{ + if (m_offscreenTargetTexture == 0) + { + m_offscreenTargetTexture = + make_backing_texture(GL_RGBA8, width(), height()); + m_textureRenderTarget.setTargetTexture(m_offscreenTargetTexture); + } +} + +void FramebufferRenderTargetGL::allocateInternalPLSTextures( + gpu::InterlockMode interlockMode) +{ + m_textureRenderTarget.allocateInternalPLSTextures(interlockMode); +} + +void FramebufferRenderTargetGL::bindInternalFramebuffer( + GLenum target, + DrawBufferMask drawBufferMask) +{ + + m_textureRenderTarget.bindInternalFramebuffer(target, drawBufferMask); +} + +void FramebufferRenderTargetGL::bindHeadlessFramebuffer( + const GLCapabilities& capabilities) +{ + m_textureRenderTarget.bindHeadlessFramebuffer(capabilities); +} + +void FramebufferRenderTargetGL::bindAsImageTextures( + DrawBufferMask drawBufferMask) +{ + m_textureRenderTarget.bindAsImageTextures(drawBufferMask); +} + +RenderTargetGL::MSAAResolveAction FramebufferRenderTargetGL:: + bindMSAAFramebuffer(RenderContextGLImpl* renderContextImpl, + int sampleCount, + const IAABB* preserveBounds, + bool* isFBO0) +{ + assert(sampleCount > 0); + if (m_sampleCount > 1) + { + // Just bind the destination framebuffer it's already msaa, even if its + // sampleCount doesn't match the desired count. + bindDestinationFramebuffer(GL_FRAMEBUFFER); + if (isFBO0 != nullptr) + { + *isFBO0 = m_externalFramebufferID == 0; + } + return MSAAResolveAction::automatic; + } + else + { + // The destination framebuffer is not multisampled. Bind the offscreen + // one. + if (preserveBounds != nullptr) + { + // API support for copying a non-msaa framebuffer into an msaa + // framebuffer (for preservation) is awful. It needs to be done in 2 + // steps: + // 1. Blit non-msaa framebuffer -> texture. + // 2. Draw texture -> msaa framebuffer. + // (NOTE: step 2 gets skipped when we have + // EXT_multisampled_render_to_texture.) + allocateOffscreenTargetTexture(); + m_textureRenderTarget.bindInternalFramebuffer( + GL_DRAW_FRAMEBUFFER, + DrawBufferMask::color); + bindDestinationFramebuffer(GL_READ_FRAMEBUFFER); + glutils::BlitFramebuffer( + *preserveBounds, + height()); // Step 1. + // Step 2 will happen when we bind. + } + else if (renderContextImpl->capabilities() + .EXT_multisampled_render_to_texture) + { + // When we have EXT_multisampled_render_to_texture, the "msaa + // buffer" is just the target texture. + allocateOffscreenTargetTexture(); + } + m_textureRenderTarget.bindMSAAFramebuffer(renderContextImpl, + sampleCount, + preserveBounds, + isFBO0); + // Since we're rendering to an offscreen framebuffer, the client has to + // resolve this buffer even if we have + // EXT_multisampled_render_to_texture. + return MSAAResolveAction::framebufferBlit; + } +} + +void FramebufferRenderTargetGL::bindInternalDstTexture(GLenum activeTexture) +{ + allocateOffscreenTargetTexture(); + m_textureRenderTarget.bindInternalDstTexture(activeTexture); +} +} // namespace rive::gpu diff --git a/third_party/rive_renderer/source/gpu.cpp b/third_party/rive_renderer/source/gpu.cpp new file mode 100644 index 0000000..5c8e7d7 --- /dev/null +++ b/third_party/rive_renderer/source/gpu.cpp @@ -0,0 +1,1485 @@ +/* + * Copyright 2022 Rive + */ + +#include "rive/renderer/gpu.hpp" + +#include "rive/renderer/render_target.hpp" +#include "shaders/constants.glsl" +#include "rive/renderer/texture.hpp" +#include "rive_render_paint.hpp" +#include "gradient.hpp" + +#include "generated/shaders/draw_path.exports.h" + +namespace rive::gpu +{ +static_assert(kGradTextureWidth == GRAD_TEXTURE_WIDTH); +static_assert(kTessTextureWidth == TESS_TEXTURE_WIDTH); +static_assert(kTessTextureWidthLog2 == TESS_TEXTURE_WIDTH_LOG2); + +uint32_t ShaderUniqueKey(DrawType drawType, + ShaderFeatures shaderFeatures, + InterlockMode interlockMode, + ShaderMiscFlags miscFlags) +{ + if (miscFlags & ShaderMiscFlags::coalescedResolveAndTransfer) + { + assert(drawType == DrawType::atomicResolve); + assert(shaderFeatures & ShaderFeatures::ENABLE_ADVANCED_BLEND); + assert(interlockMode == InterlockMode::atomics); + } + if (miscFlags & (ShaderMiscFlags::storeColorClear | + ShaderMiscFlags::swizzleColorBGRAToRGBA)) + { + assert(drawType == DrawType::atomicInitialize); + } + uint32_t drawTypeKey; + switch (drawType) + { + case DrawType::midpointFanPatches: + case DrawType::midpointFanCenterAAPatches: + case DrawType::outerCurvePatches: + case DrawType::msaaStrokes: + case DrawType::msaaMidpointFanBorrowedCoverage: + case DrawType::msaaMidpointFans: + case DrawType::msaaMidpointFanStencilReset: + case DrawType::msaaMidpointFanPathsStencil: + case DrawType::msaaMidpointFanPathsCover: + case DrawType::msaaOuterCubics: + drawTypeKey = 0; + break; + case DrawType::interiorTriangulation: + drawTypeKey = 1; + break; + case DrawType::atlasBlit: + drawTypeKey = 2; + break; + case DrawType::imageRect: + drawTypeKey = 3; + break; + case DrawType::imageMesh: + drawTypeKey = 4; + break; + case DrawType::atomicInitialize: + assert(interlockMode == gpu::InterlockMode::atomics); + drawTypeKey = 5; + break; + case DrawType::atomicResolve: + assert(interlockMode == gpu::InterlockMode::atomics); + drawTypeKey = 6; + break; + case DrawType::msaaStencilClipReset: + assert(interlockMode == gpu::InterlockMode::msaa); + drawTypeKey = 7; + break; + } + uint32_t key = static_cast(miscFlags); + assert(static_cast(interlockMode) < 1 << 2); + key = (key << 2) | static_cast(interlockMode); + key = (key << kShaderFeatureCount) | + (shaderFeatures & ShaderFeaturesMaskFor(drawType, interlockMode)) + .bits(); + assert(drawTypeKey < 1 << 3); + key = (key << 3) | drawTypeKey; + return key; +} + +const char* GetShaderFeatureGLSLName(ShaderFeatures feature) +{ + switch (feature) + { + case ShaderFeatures::NONE: + RIVE_UNREACHABLE(); + case ShaderFeatures::ENABLE_CLIPPING: + return GLSL_ENABLE_CLIPPING; + case ShaderFeatures::ENABLE_CLIP_RECT: + return GLSL_ENABLE_CLIP_RECT; + case ShaderFeatures::ENABLE_ADVANCED_BLEND: + return GLSL_ENABLE_ADVANCED_BLEND; + case ShaderFeatures::ENABLE_FEATHER: + return GLSL_ENABLE_FEATHER; + case ShaderFeatures::ENABLE_EVEN_ODD: + return GLSL_ENABLE_EVEN_ODD; + case ShaderFeatures::ENABLE_NESTED_CLIPPING: + return GLSL_ENABLE_NESTED_CLIPPING; + case ShaderFeatures::ENABLE_HSL_BLEND_MODES: + return GLSL_ENABLE_HSL_BLEND_MODES; + } + RIVE_UNREACHABLE(); +} + +constexpr static float pack_params(int32_t patchSegmentSpan, int32_t vertexType) +{ + return static_cast((patchSegmentSpan << 2) | vertexType); +} + +static void generate_buffer_data_for_patch_type(PatchType patchType, + PatchVertex vertices[], + uint16_t indices[], + uint16_t baseVertex) +{ + // AA border vertices. "Inner tessellation curves" have one more segment + // without a fan triangle whose purpose is to be a bowtie join. + size_t vertexCount = 0; + int32_t patchSegmentSpan = patchType == PatchType::outerCurves + ? kOuterCurvePatchSegmentSpan + : kMidpointFanPatchSegmentSpan; + for (int i = 0; i < patchSegmentSpan; ++i) + { + float params = pack_params(patchSegmentSpan, STROKE_VERTEX); + float l = static_cast(i); + float r = l + 1; + if (patchType == PatchType::outerCurves) + { + vertices[vertexCount + 0].set(l, 0.f, .5f, params); + vertices[vertexCount + 1].set(l, 1.f, .0f, params); + vertices[vertexCount + 2].set(r, 0.f, .5f, params); + vertices[vertexCount + 3].set(r, 1.f, .0f, params); + + // Give the vertex an alternate position when mirrored so the border + // has the same diagonals whether mirrored or not. + vertices[vertexCount + 0].setMirroredPosition(r, 0.f, .5f); + vertices[vertexCount + 1].setMirroredPosition(l, 0.f, .5f); + vertices[vertexCount + 2].setMirroredPosition(r, 1.f, .0f); + vertices[vertexCount + 3].setMirroredPosition(l, 1.f, .0f); + } + else if (patchType == PatchType::midpointFanCenterAA) + { + vertices[vertexCount + 0].set(l, 0.f, .5f, params); + vertices[vertexCount + 1].set(l, 1.f, .0f, params); + vertices[vertexCount + 2].set(r, 0.f, .5f, params); + vertices[vertexCount + 3].set(r, 1.f, .0f, params); + + // Give the vertex an alternate position when mirrored so the border + // has the same diagonals whether mirrored or not. + vertices[vertexCount + 0].setMirroredPosition(r - 1.f, 0.f, .5f); + vertices[vertexCount + 1].setMirroredPosition(l - 1.f, 0.f, .5f); + vertices[vertexCount + 2].setMirroredPosition(r - 1.f, 1.f, .0f); + vertices[vertexCount + 3].setMirroredPosition(l - 1.f, 1.f, .0f); + } + else + { + assert(patchType == PatchType::midpointFan); + vertices[vertexCount + 0].set(l, -1.f, 1.f, params); + vertices[vertexCount + 1].set(l, +1.f, 0.f, params); + vertices[vertexCount + 2].set(r, -1.f, 1.f, params); + vertices[vertexCount + 3].set(r, +1.f, 0.f, params); + + // Give the vertex an alternate position when mirrored so the border + // has the same diagonals whether morrored or not. + vertices[vertexCount + 0].setMirroredPosition(r - 1.f, -1.f, 1.f); + vertices[vertexCount + 1].setMirroredPosition(l - 1.f, -1.f, 1.f); + vertices[vertexCount + 2].setMirroredPosition(r - 1.f, +1.f, 0.f); + vertices[vertexCount + 3].setMirroredPosition(l - 1.f, +1.f, 0.f); + } + vertexCount += 4; + } + + // Bottom (negative coverage) side of the AA border. + for (int i = 0; i < patchSegmentSpan; ++i) + { + float params = pack_params(patchSegmentSpan, STROKE_VERTEX); + float l = static_cast(i); + float r = l + 1; + if (patchType == PatchType::outerCurves) + { + vertices[vertexCount + 0].set(l, -0.f, .5f, params); + vertices[vertexCount + 1].set(r, -0.f, .5f, params); + vertices[vertexCount + 2].set(l, -1.f, .0f, params); + vertices[vertexCount + 3].set(r, -1.f, .0f, params); + + // Give the vertex an alternate position when mirrored so the border + // has the same diagonals whether mirrored or not. + vertices[vertexCount + 0].setMirroredPosition(r, -0.f, .5f); + vertices[vertexCount + 1].setMirroredPosition(r, -1.f, .0f); + vertices[vertexCount + 2].setMirroredPosition(l, -0.f, .5f); + vertices[vertexCount + 3].setMirroredPosition(l, -1.f, .0f); + vertexCount += 4; + } + else if (patchType == PatchType::midpointFanCenterAA) + { + vertices[vertexCount + 0].set(l, -0.f, .5f, params); + vertices[vertexCount + 1].set(r, -0.f, .5f, params); + vertices[vertexCount + 2].set(l, -1.f, .0f, params); + vertices[vertexCount + 3].set(r, -1.f, .0f, params); + + // Give the vertex an alternate position when mirrored so the border + // has the same diagonals whether mirrored or not. + vertices[vertexCount + 0].setMirroredPosition(r - 1.f, -0.f, .5f); + vertices[vertexCount + 1].setMirroredPosition(r - 1.f, -1.f, .0f); + vertices[vertexCount + 2].setMirroredPosition(l - 1.f, -0.f, .5f); + vertices[vertexCount + 3].setMirroredPosition(l - 1.f, -1.f, .0f); + vertexCount += 4; + } + } + + // Triangle fan vertices. (These only touch the first "fanSegmentSpan" + // segments on inner tessellation curves. + size_t fanVerticesIdx = vertexCount; + size_t fanSegmentSpan = patchType == PatchType::outerCurves + ? patchSegmentSpan - 1 + : patchSegmentSpan; + // The fan must be a power of two. + assert((fanSegmentSpan & (fanSegmentSpan - 1)) == 0); + for (int i = 0; i <= fanSegmentSpan; ++i) + { + float params = pack_params(patchSegmentSpan, FAN_VERTEX); + if (patchType == PatchType::outerCurves) + { + vertices[vertexCount].set(static_cast(i), 0.f, 1, params); + } + else if (patchType == PatchType::midpointFanCenterAA) + { + vertices[vertexCount].set(static_cast(i), 0, 1, params); + vertices[vertexCount].setMirroredPosition(static_cast(i) - 1, + 0, + 1); + } + else + { + vertices[vertexCount].set(static_cast(i), -1.f, 1, params); + vertices[vertexCount].setMirroredPosition(static_cast(i) - 1, + -1.f, + 1); + } + ++vertexCount; + } + + // The midpoint vertex isn't included in outer cubic patches. + size_t midpointIdx = vertexCount; + if (patchType != PatchType::outerCurves) + { + vertices[vertexCount++] + .set(0, 0, 1, pack_params(patchSegmentSpan, FAN_MIDPOINT_VERTEX)); + } + if (patchType == PatchType::outerCurves) + assert(vertexCount == kOuterCurvePatchVertexCount); + else if (patchType == PatchType::midpointFanCenterAA) + assert(vertexCount == kMidpointFanCenterAAPatchVertexCount); + else + assert(vertexCount == kMidpointFanPatchVertexCount); + + // AA border indices. + constexpr static size_t kBorderPatternVertexCount = 4; + constexpr static size_t kBorderPatternIndexCount = 6; + constexpr static uint16_t kBorderPattern[kBorderPatternIndexCount] = + {0, 1, 2, 2, 1, 3}; + constexpr static uint16_t kNegativeBorderPattern[kBorderPatternIndexCount] = + {0, 2, 1, 1, 2, 3}; + + size_t indexCount = 0; + size_t borderEdgeVerticesIdx = 0; + for (size_t borderSegmentIdx = 0; borderSegmentIdx < patchSegmentSpan; + ++borderSegmentIdx) + { + for (size_t i = 0; i < kBorderPatternIndexCount; ++i) + { + indices[indexCount++] = + baseVertex + borderEdgeVerticesIdx + kBorderPattern[i]; + } + borderEdgeVerticesIdx += kBorderPatternVertexCount; + } + + // Bottom (negative coverage) side of the AA border. + if (patchType == PatchType::midpointFan) + { + assert(indexCount == kMidpointFanPatchBorderIndexCount); + } + else + { + for (size_t borderSegmentIdx = 0; borderSegmentIdx < patchSegmentSpan; + ++borderSegmentIdx) + { + for (size_t i = 0; i < kBorderPatternIndexCount; ++i) + { + indices[indexCount++] = baseVertex + borderEdgeVerticesIdx + + kNegativeBorderPattern[i]; + } + borderEdgeVerticesIdx += kBorderPatternVertexCount; + } + if (patchType == PatchType::midpointFanCenterAA) + assert(indexCount == kMidpointFanCenterAAPatchBorderIndexCount); + else + assert(indexCount == kOuterCurvePatchBorderIndexCount); + } + + assert(borderEdgeVerticesIdx == fanVerticesIdx); + + // Triangle fan indices, in a middle-out topology. + // Don't include the final bowtie join if this is an "outerStroke" patch. + // (i.e., use fanSegmentSpan and not "patchSegmentSpan".) + for (int step = 1; step < fanSegmentSpan; step <<= 1) + { + for (int i = 0; i < fanSegmentSpan; i += step * 2) + { + indices[indexCount++] = fanVerticesIdx + i + baseVertex; + indices[indexCount++] = fanVerticesIdx + i + step + baseVertex; + indices[indexCount++] = fanVerticesIdx + i + step * 2 + baseVertex; + } + } + if (patchType == PatchType::midpointFan || + patchType == PatchType::midpointFanCenterAA) + { + // Triangle to the contour midpoint. + indices[indexCount++] = fanVerticesIdx + baseVertex; + indices[indexCount++] = fanVerticesIdx + fanSegmentSpan + baseVertex; + indices[indexCount++] = midpointIdx + baseVertex; + if (patchType == PatchType::midpointFan) + assert(indexCount == kMidpointFanPatchIndexCount); + else + assert(indexCount == kMidpointFanCenterAAPatchIndexCount); + } + else + { + assert(patchType == PatchType::outerCurves); + assert(indexCount == kOuterCurvePatchIndexCount); + } +} + +void GeneratePatchBufferData(PatchVertex vertices[kPatchVertexBufferCount], + uint16_t indices[kPatchIndexBufferCount]) +{ + generate_buffer_data_for_patch_type(PatchType::midpointFan, + vertices, + indices, + 0); + generate_buffer_data_for_patch_type(PatchType::midpointFanCenterAA, + vertices + kMidpointFanPatchVertexCount, + indices + kMidpointFanPatchIndexCount, + kMidpointFanPatchVertexCount); + generate_buffer_data_for_patch_type( + PatchType::outerCurves, + vertices + kMidpointFanPatchVertexCount + + kMidpointFanCenterAAPatchVertexCount, + indices + kMidpointFanPatchIndexCount + + kMidpointFanCenterAAPatchIndexCount, + kMidpointFanPatchVertexCount + kMidpointFanCenterAAPatchVertexCount); +} + +void ClipRectInverseMatrix::reset(const Mat2D& clipMatrix, const AABB& clipRect) +{ + // Find the matrix that transforms from pixel space to "normalized clipRect + // space", where the clipRect is the normalized rectangle: [-1, -1, +1, +1]. + Mat2D m = clipMatrix * Mat2D(clipRect.width() * .5f, + 0, + 0, + clipRect.height() * .5f, + clipRect.center().x, + clipRect.center().y); + if (clipRect.width() <= 0 || clipRect.height() <= 0 || + !m.invert(&m_inverseMatrix)) + { + // If the width or height went zero or negative, or if "m" is + // non-invertible, clip away everything. + *this = Empty(); + } +} + +static uint32_t paint_type_to_glsl_id(PaintType paintType) +{ + return static_cast(paintType); + static_assert((int)PaintType::clipUpdate == CLIP_UPDATE_PAINT_TYPE); + static_assert((int)PaintType::solidColor == SOLID_COLOR_PAINT_TYPE); + static_assert((int)PaintType::linearGradient == LINEAR_GRADIENT_PAINT_TYPE); + static_assert((int)PaintType::radialGradient == RADIAL_GRADIENT_PAINT_TYPE); + static_assert((int)PaintType::image == IMAGE_PAINT_TYPE); +} + +uint32_t ConvertBlendModeToPLSBlendMode(BlendMode riveMode) +{ + switch (riveMode) + { + case BlendMode::srcOver: + return BLEND_SRC_OVER; + case BlendMode::screen: + return BLEND_MODE_SCREEN; + case BlendMode::overlay: + return BLEND_MODE_OVERLAY; + case BlendMode::darken: + return BLEND_MODE_DARKEN; + case BlendMode::lighten: + return BLEND_MODE_LIGHTEN; + case BlendMode::colorDodge: + return BLEND_MODE_COLORDODGE; + case BlendMode::colorBurn: + return BLEND_MODE_COLORBURN; + case BlendMode::hardLight: + return BLEND_MODE_HARDLIGHT; + case BlendMode::softLight: + return BLEND_MODE_SOFTLIGHT; + case BlendMode::difference: + return BLEND_MODE_DIFFERENCE; + case BlendMode::exclusion: + return BLEND_MODE_EXCLUSION; + case BlendMode::multiply: + return BLEND_MODE_MULTIPLY; + case BlendMode::hue: + return BLEND_MODE_HUE; + case BlendMode::saturation: + return BLEND_MODE_SATURATION; + case BlendMode::color: + return BLEND_MODE_COLOR; + case BlendMode::luminosity: + return BLEND_MODE_LUMINOSITY; + } + RIVE_UNREACHABLE(); +} + +uint32_t SwizzleRiveColorToRGBAPremul(ColorInt riveColor) +{ + uint4 rgba = (rive::uint4(riveColor) >> uint4{16, 8, 0, 24}) & 0xffu; + uint32_t alpha = rgba.w; + rgba.w = 255; + uint4 premul = rgba * alpha / 255; + return simd::reduce_or(premul << uint4{0, 8, 16, 24}); +} + +FlushUniforms::InverseViewports::InverseViewports( + const FlushDescriptor& flushDesc, + const PlatformFeatures& platformFeatures) +{ + float4 numerators = 2; + // When rendering to the gradient and tessellation textures, ensure that + // row 0 in input coordinates gets written to row 0 in texture memory. + // This requires a Y inversion if clip space and framebuffer space have + // opposing senses of which way is up. + if (platformFeatures.clipSpaceBottomUp != + platformFeatures.framebufferBottomUp) + { + numerators.xy = -numerators.xy; + } + // When drawing to a render target, ensure that Y=0 (in Rive pixel space) + // gets drawn to the top of thew viewport. + // This requires a Y inversion if Rive pixel space and clip space have + // opposing senses of which way is up. + if (platformFeatures.clipSpaceBottomUp) + { + numerators.w = -numerators.w; + } + float4 vals = numerators / + float4{static_cast(flushDesc.gradDataHeight), + static_cast(flushDesc.tessDataHeight), + static_cast(flushDesc.renderTarget->width()), + static_cast(flushDesc.renderTarget->height())}; + m_vals[0] = vals[0]; + m_vals[1] = vals[1]; + m_vals[2] = vals[2]; + m_vals[3] = vals[3]; +} + +FlushUniforms::FlushUniforms(const FlushDescriptor& flushDesc, + const PlatformFeatures& platformFeatures) : + m_inverseViewports(flushDesc, platformFeatures), + m_renderTargetWidth(flushDesc.renderTarget->width()), + m_renderTargetHeight(flushDesc.renderTarget->height()), + m_colorClearValue(SwizzleRiveColorToRGBAPremul(flushDesc.colorClearValue)), + m_coverageClearValue(flushDesc.coverageClearValue), + m_renderTargetUpdateBounds(flushDesc.renderTargetUpdateBounds), + m_atlasTextureInverseSize(1.f / flushDesc.atlasTextureWidth, + 1.f / flushDesc.atlasTextureHeight), + m_atlasContentInverseViewport(2.f / flushDesc.atlasContentWidth, + (platformFeatures.clipSpaceBottomUp != + platformFeatures.framebufferBottomUp + ? -2.f + : 2.f) / + flushDesc.atlasContentHeight), + m_coverageBufferPrefix(flushDesc.coverageBufferPrefix), + m_pathIDGranularity(platformFeatures.pathIDGranularity), + m_vertexDiscardValue(std::numeric_limits::quiet_NaN()), + m_wireframeEnabled(flushDesc.wireframe) +{} + +static void write_matrix(volatile float* dst, const Mat2D& matrix) +{ + const float* vals = matrix.values(); + for (size_t i = 0; i < 6; ++i) + { + dst[i] = vals[i]; + } +} + +void PathData::set(const Mat2D& m, + float strokeRadius, + float featherRadius, + uint32_t zIndex, + const AtlasTransform& atlasTransform, + const CoverageBufferRange& coverageBufferRange) +{ + write_matrix(m_matrix, m); + m_strokeRadius = strokeRadius; // 0 if the path is filled. + m_zIndex = zIndex; + m_featherRadius = featherRadius; + m_atlasTransform.scaleFactor = atlasTransform.scaleFactor; + m_atlasTransform.translateX = atlasTransform.translateX; + m_atlasTransform.translateY = atlasTransform.translateY; + m_coverageBufferRange.offset = coverageBufferRange.offset; + m_coverageBufferRange.pitch = coverageBufferRange.pitch; + m_coverageBufferRange.offsetX = coverageBufferRange.offsetX; + m_coverageBufferRange.offsetY = coverageBufferRange.offsetY; +} + +void PaintData::set(DrawContents singleDrawContents, + PaintType paintType, + SimplePaintValue simplePaintValue, + GradTextureLayout gradTextureLayout, + uint32_t clipID, + bool hasClipRect, + BlendMode blendMode) +{ + uint32_t shiftedClipID = clipID << 16; + uint32_t shiftedBlendMode = ConvertBlendModeToPLSBlendMode(blendMode) << 4; + uint32_t localParams = paint_type_to_glsl_id(paintType); + switch (paintType) + { + case PaintType::solidColor: + { + // Swizzle the riveColor to little-endian RGBA (the order expected + // by GLSL). + m_color = SwizzleRiveColorToRGBA(simplePaintValue.color); + localParams |= shiftedClipID | shiftedBlendMode; + break; + } + case PaintType::linearGradient: + case PaintType::radialGradient: + { + uint32_t row = simplePaintValue.colorRampLocation.row; + if (simplePaintValue.colorRampLocation.isComplex()) + { + // Complex gradients rows are offset after the simple gradients. + row += gradTextureLayout.complexOffsetY; + } + m_gradTextureY = (static_cast(row) + .5f) * + gradTextureLayout.inverseHeight; + localParams |= shiftedClipID | shiftedBlendMode; + break; + } + case PaintType::image: + { + m_opacity = simplePaintValue.imageOpacity; + localParams |= shiftedClipID | shiftedBlendMode; + break; + } + case PaintType::clipUpdate: + { + m_shiftedClipReplacementID = shiftedClipID; + localParams |= simplePaintValue.outerClipID << 16; + break; + } + } + if (singleDrawContents & gpu::DrawContents::nonZeroFill) + { + localParams |= PAINT_FLAG_NON_ZERO_FILL; + } + else if (singleDrawContents & gpu::DrawContents::evenOddFill) + { + localParams |= PAINT_FLAG_EVEN_ODD_FILL; + } + if (hasClipRect) + { + localParams |= PAINT_FLAG_HAS_CLIP_RECT; + } + m_params = localParams; +} + +void PaintAuxData::set(const Mat2D& viewMatrix, + PaintType paintType, + SimplePaintValue simplePaintValue, + const Gradient* gradient, + const Texture* imageTexture, + const ClipRectInverseMatrix* clipRectInverseMatrix, + const RenderTarget* renderTarget, + const gpu::PlatformFeatures& platformFeatures) +{ + switch (paintType) + { + case PaintType::solidColor: + { + break; + } + case PaintType::linearGradient: + case PaintType::radialGradient: + case PaintType::image: + { + Mat2D paintMatrix; + viewMatrix.invert(&paintMatrix); + if (platformFeatures.framebufferBottomUp) + { + // Flip _fragCoord.y. + paintMatrix = + paintMatrix * Mat2D(1, 0, 0, -1, 0, renderTarget->height()); + } + if (paintType == PaintType::image) + { + // Since we don't use perspective transformations, the image + // mipmap level-of-detail is constant throughout the entire + // path. Compute it ahead of time here. + float dudx = paintMatrix.xx() * imageTexture->width(); + float dudy = paintMatrix.yx() * imageTexture->height(); + float dvdx = paintMatrix.xy() * imageTexture->width(); + float dvdy = paintMatrix.yy() * imageTexture->height(); + float maxScaleFactorPow2 = std::max(dudx * dudx + dvdx * dvdx, + dudy * dudy + dvdy * dvdy); + // Instead of finding sqrt(maxScaleFactorPow2), just multiply + // the log by .5. + m_imageTextureLOD = + log2f(std::max(maxScaleFactorPow2, 1.f)) * .5f; + } + else + { + assert(gradient != nullptr); + const float* gradCoeffs = gradient->coeffs(); + if (paintType == PaintType::linearGradient) + { + paintMatrix = Mat2D(gradCoeffs[0], + 0, + gradCoeffs[1], + 0, + gradCoeffs[2], + 0) * + paintMatrix; + } + else + { + assert(paintType == PaintType::radialGradient); + float w = 1 / gradCoeffs[2]; + paintMatrix = Mat2D(w, + 0, + 0, + w, + -gradCoeffs[0] * w, + -gradCoeffs[1] * w) * + paintMatrix; + } + float left, right; + if (simplePaintValue.colorRampLocation.isComplex()) + { + left = 0; + right = kGradTextureWidth; + } + else + { + left = simplePaintValue.colorRampLocation.col; + right = left + 2; + } + m_gradTextureHorizontalSpan[0] = + (right - left - 1) * GRAD_TEXTURE_INVERSE_WIDTH; + m_gradTextureHorizontalSpan[1] = + (left + .5f) * GRAD_TEXTURE_INVERSE_WIDTH; + } + write_matrix(m_matrix, paintMatrix); + break; + } + case PaintType::clipUpdate: + { + break; + } + } + + if (clipRectInverseMatrix != nullptr) + { + Mat2D m = clipRectInverseMatrix->inverseMatrix(); + if (platformFeatures.framebufferBottomUp) + { + // Flip _fragCoord.y. + m = m * Mat2D(1, 0, 0, -1, 0, renderTarget->height()); + } + write_matrix(m_clipRectInverseMatrix, m); + m_inverseFwidth.x = -1.f / (fabsf(m.xx()) + fabsf(m.xy())); + m_inverseFwidth.y = -1.f / (fabsf(m.yx()) + fabsf(m.yy())); + } + else + { + write_matrix(m_clipRectInverseMatrix, + ClipRectInverseMatrix::WideOpen().inverseMatrix()); + m_inverseFwidth.x = 0; + m_inverseFwidth.y = 0; + } +} + +ImageDrawUniforms::ImageDrawUniforms( + const Mat2D& matrix, + float opacity, + const ClipRectInverseMatrix* clipRectInverseMatrix, + uint32_t clipID, + BlendMode blendMode, + uint32_t zIndex) +{ + write_matrix(m_matrix, matrix); + m_opacity = opacity; + write_matrix(m_clipRectInverseMatrix, + clipRectInverseMatrix != nullptr + ? clipRectInverseMatrix->inverseMatrix() + : ClipRectInverseMatrix::WideOpen().inverseMatrix()); + m_clipID = clipID; + m_blendMode = ConvertBlendModeToPLSBlendMode(blendMode); + m_zIndex = zIndex; +} + +std::tuple StorageTextureSize( + size_t bufferSizeInBytes, + StorageBufferStructure bufferStructure) +{ + assert(bufferSizeInBytes % + gpu::StorageBufferElementSizeInBytes(bufferStructure) == + 0); + uint32_t elementCount = + math::lossless_numeric_cast(bufferSizeInBytes) / + gpu::StorageBufferElementSizeInBytes(bufferStructure); + uint32_t height = + (elementCount + STORAGE_TEXTURE_WIDTH - 1) / STORAGE_TEXTURE_WIDTH; + // RenderContext is responsible for breaking up a flush before any storage + // buffer grows larger than can be supported by a GL texture of width + // "STORAGE_TEXTURE_WIDTH". (2048 is the min required value for + // GL_MAX_TEXTURE_SIZE.) + constexpr int kMaxRequredTextureHeight RIVE_MAYBE_UNUSED = 2048; + assert(height <= kMaxRequredTextureHeight); + uint32_t width = std::min(elementCount, STORAGE_TEXTURE_WIDTH); + return {width, height}; +} + +size_t StorageTextureBufferSize(size_t bufferSizeInBytes, + StorageBufferStructure bufferStructure) +{ + // The polyfill texture needs to be updated in entire rows at a time. Extend + // the buffer's length to be able to service a worst-case scenario. + return bufferSizeInBytes + + (STORAGE_TEXTURE_WIDTH - 1) * + gpu::StorageBufferElementSizeInBytes(bufferStructure); +} + +float find_transformed_area(const AABB& bounds, const Mat2D& matrix) +{ + Vec2D pts[4] = {{bounds.left(), bounds.top()}, + {bounds.right(), bounds.top()}, + {bounds.right(), bounds.bottom()}, + {bounds.left(), bounds.bottom()}}; + Vec2D screenSpacePts[4]; + matrix.mapPoints(screenSpacePts, pts, 4); + Vec2D v[3] = {screenSpacePts[1] - screenSpacePts[0], + screenSpacePts[2] - screenSpacePts[0], + screenSpacePts[3] - screenSpacePts[0]}; + return (fabsf(Vec2D::cross(v[0], v[1])) + fabsf(Vec2D::cross(v[1], v[2]))) * + .5f; +} + +static void get_depth_state(const DrawBatch& batch, + const FlushDescriptor& flushDesc, + PipelineState* pipelineState) +{ + if (flushDesc.interlockMode != InterlockMode::msaa) + { + pipelineState->depthTestEnabled = false; + pipelineState->depthWriteEnabled = false; + return; + } + + switch (batch.drawType) + { + case DrawType::imageRect: + case DrawType::imageMesh: + case DrawType::atlasBlit: + case DrawType::outerCurvePatches: + pipelineState->depthTestEnabled = true; + pipelineState->depthWriteEnabled = false; + break; + + case DrawType::msaaMidpointFanBorrowedCoverage: + case DrawType::msaaMidpointFanPathsStencil: + case DrawType::msaaStencilClipReset: + pipelineState->depthTestEnabled = true; + pipelineState->depthWriteEnabled = false; + break; + + case DrawType::msaaStrokes: + case DrawType::msaaOuterCubics: + pipelineState->depthTestEnabled = true; + pipelineState->depthWriteEnabled = true; + break; + + case DrawType::msaaMidpointFans: + case DrawType::msaaMidpointFanPathsCover: + pipelineState->depthTestEnabled = true; + pipelineState->depthWriteEnabled = + !(batch.drawContents & gpu::DrawContents::clipUpdate); + break; + + case DrawType::msaaMidpointFanStencilReset: + pipelineState->depthTestEnabled = true; + pipelineState->depthWriteEnabled = + !(batch.drawContents & (gpu::DrawContents::clockwiseFill | + gpu::DrawContents::clipUpdate)); + break; + + case DrawType::interiorTriangulation: + case DrawType::atomicInitialize: + case DrawType::atomicResolve: + case DrawType::midpointFanPatches: + case DrawType::midpointFanCenterAAPatches: + RIVE_UNREACHABLE(); + } +} + +static void get_stencil_state(const DrawBatch& batch, + const FlushDescriptor& flushDesc, + PipelineState* pipelineState) +{ + if (flushDesc.interlockMode != InterlockMode::msaa) + { + pipelineState->stencilTestEnabled = false; + pipelineState->stencilWriteMask = 0; + return; + } + + const bool hasActiveClip = + (batch.drawContents & gpu::DrawContents::activeClip); + const bool isClipUpdate = + (batch.drawContents & gpu::DrawContents::clipUpdate); + switch (batch.drawType) + { + case DrawType::imageRect: + case DrawType::imageMesh: + case DrawType::atlasBlit: + case DrawType::msaaStrokes: + case DrawType::msaaOuterCubics: + pipelineState->stencilTestEnabled = true; + pipelineState->stencilDoubleSided = false; + pipelineState->stencilCompareMask = 0xff; + pipelineState->stencilWriteMask = 0xff; + pipelineState->stencilReference = 0x80; + pipelineState->stencilFrontOps = { + .failOp = StencilOp::keep, + .passOp = StencilOp::keep, + .depthFailOp = StencilOp::keep, + .compareOp = hasActiveClip ? StencilCompareOp::equal + : StencilCompareOp::always, + }; + break; + + case DrawType::msaaMidpointFanBorrowedCoverage: + // Count backward triangle hits (negative coverage) in the stencil + // buffer. + pipelineState->stencilTestEnabled = true; + pipelineState->stencilDoubleSided = false; + pipelineState->stencilCompareMask = 0xff; + pipelineState->stencilWriteMask = 0x7f; + pipelineState->stencilReference = 0x80; + pipelineState->stencilFrontOps = { + .failOp = StencilOp::keep, + .passOp = StencilOp::incrWrap, + .depthFailOp = StencilOp::keep, + .compareOp = hasActiveClip ? StencilCompareOp::lessOrEqual + : StencilCompareOp::always, + }; + break; + + case DrawType::msaaMidpointFans: + // Draw forward triangles, clipped by the backward triangle counts. + // (The depth test prevents double hits.) + pipelineState->stencilTestEnabled = true; + pipelineState->stencilDoubleSided = true; + pipelineState->stencilCompareMask = hasActiveClip ? 0xff : 0x7f; + pipelineState->stencilWriteMask = isClipUpdate ? 0xff : 0x7f; + pipelineState->stencilReference = 0x80; + pipelineState->stencilFrontOps = { + .failOp = StencilOp::decrClamp, // Don't wrap; 0 must stay 0 + // outside the clip. + .passOp = isClipUpdate ? StencilOp::replace : StencilOp::keep, + .depthFailOp = StencilOp::keep, + .compareOp = StencilCompareOp::equal, + }; + pipelineState->stencilBackOps = { + .failOp = StencilOp::keep, + .passOp = isClipUpdate ? StencilOp::replace : StencilOp::zero, + .depthFailOp = StencilOp::keep, + .compareOp = StencilCompareOp::less, + }; + break; + + case DrawType::msaaMidpointFanStencilReset: + // Clean up backward triangles in the stencil buffer, (also filling + // negative winding numbers for nonZero fill). + pipelineState->stencilTestEnabled = true; + pipelineState->stencilDoubleSided = true; + pipelineState->stencilCompareMask = hasActiveClip ? 0xff : 0x7f; + pipelineState->stencilWriteMask = + (batch.drawContents & gpu::DrawContents::clockwiseFill) + // For clockwise fill, disable clip-bit writes when cleaning + // up backward triangles. Clockwise only fills in forward + // triangles. + ? 0x7f + : (isClipUpdate ? 0xff : 0x7f); + pipelineState->stencilReference = 0x80; + pipelineState->stencilFrontOps = { + .failOp = StencilOp::decrClamp, // Don't wrap; 0 must stay 0 + // outside the clip. + .passOp = isClipUpdate ? StencilOp::replace : StencilOp::keep, + .depthFailOp = StencilOp::keep, + .compareOp = StencilCompareOp::equal, + }; + pipelineState->stencilBackOps = { + .failOp = StencilOp::keep, + .passOp = isClipUpdate ? StencilOp::replace : StencilOp::zero, + .depthFailOp = StencilOp::keep, + .compareOp = StencilCompareOp::less, + }; + break; + + case DrawType::msaaMidpointFanPathsStencil: + // Just stencil the path into the stencil buffer. This is used for + // nested clip updates and for evenOdd paths. + assert(batch.drawContents & (gpu::DrawContents::evenOddFill) || + (batch.drawContents & gpu::kNestedClipUpdateMask) == + gpu::kNestedClipUpdateMask); + pipelineState->stencilTestEnabled = true; + pipelineState->stencilDoubleSided = true; + pipelineState->stencilCompareMask = 0xff; + pipelineState->stencilWriteMask = + (batch.drawContents & gpu::DrawContents::evenOddFill) ? 0x1 + : 0x7f; + pipelineState->stencilReference = 0x80; + // Decrement front-facing triangles so the MSB is set when + // clockwise. + pipelineState->stencilFrontOps = { + .failOp = StencilOp::keep, + .passOp = StencilOp::decrWrap, + .depthFailOp = StencilOp::keep, + .compareOp = hasActiveClip ? StencilCompareOp::lessOrEqual + : StencilCompareOp::always, + }; + pipelineState->stencilBackOps = { + .failOp = pipelineState->stencilFrontOps.failOp, + .passOp = StencilOp::incrWrap, + .depthFailOp = pipelineState->stencilFrontOps.depthFailOp, + .compareOp = pipelineState->stencilFrontOps.compareOp, + }; + break; + + case DrawType::msaaMidpointFanPathsCover: + // Draw & reset stencil winding numbers. This is only needed for + // evenOdd paths. + assert(batch.drawContents & gpu::DrawContents::evenOddFill); + pipelineState->stencilTestEnabled = true; + pipelineState->stencilDoubleSided = false; + pipelineState->stencilCompareMask = 0x7f; + pipelineState->stencilWriteMask = isClipUpdate ? 0xff : 0x1; + pipelineState->stencilReference = 0x80; + pipelineState->stencilFrontOps = { + .failOp = StencilOp::keep, + .passOp = isClipUpdate ? StencilOp::replace : StencilOp::zero, + .depthFailOp = StencilOp::keep, + .compareOp = StencilCompareOp::notEqual, + }; + break; + + case DrawType::msaaStencilClipReset: + pipelineState->stencilTestEnabled = true; + pipelineState->stencilDoubleSided = false; + if ((batch.drawContents & gpu::kNestedClipUpdateMask) == + gpu::kNestedClipUpdateMask) + { + // The nested clip just got stencilled and left in the stencil + // buffer. Intersect it with the existing clip. (Erasing regions + // of the existing clip that are outside the nested clip.) + pipelineState->stencilCompareMask = + (batch.drawContents & gpu::DrawContents::clockwiseFill) + // clockwise: (0x80 & 0xc0) < (stencilValue & 0xc0) + // => "If clipbit is set and winding is negative" + // => "If clipbit is set and winding is clockwise" + // (because clockwise decrements) + // + ? 0xc0 + // non-clockwise: 0x80 < stencilValue + // => "If clipbit is set and winding is nonzero" + : 0xff; + pipelineState->stencilWriteMask = 0xff; + pipelineState->stencilReference = 0x80; + pipelineState->stencilFrontOps = { + .failOp = StencilOp::zero, + .passOp = StencilOp::replace, + .depthFailOp = StencilOp::keep, + .compareOp = StencilCompareOp::less, + }; + } + else + { + // Clear the entire previous clip. + pipelineState->stencilCompareMask = 0xff; + pipelineState->stencilWriteMask = 0xff; + pipelineState->stencilReference = 0x00; + pipelineState->stencilFrontOps = { + .failOp = StencilOp::keep, + .passOp = StencilOp::zero, + .depthFailOp = StencilOp::keep, + .compareOp = StencilCompareOp::notEqual, + }; + } + break; + + case DrawType::interiorTriangulation: + case DrawType::atomicInitialize: + case DrawType::atomicResolve: + case DrawType::midpointFanPatches: + case DrawType::midpointFanCenterAAPatches: + case DrawType::outerCurvePatches: + RIVE_UNREACHABLE(); + } +} + +static CullFace get_cull_face(DrawType drawType) +{ + switch (drawType) + { + case DrawType::midpointFanPatches: + case DrawType::midpointFanCenterAAPatches: + case DrawType::outerCurvePatches: + case DrawType::interiorTriangulation: + case DrawType::atlasBlit: + case DrawType::msaaStrokes: + case DrawType::msaaMidpointFans: + case DrawType::msaaStencilClipReset: + return CullFace::counterclockwise; + case DrawType::msaaMidpointFanBorrowedCoverage: + case DrawType::msaaMidpointFanStencilReset: + // clockwise is always the front face in Rive, but for a couple + // draws we encode some stencil work in the counterclockwise face. + // It's done this way because the cull face is often supported as + // dynamic state, so we're keeping the option open to stuff two + // operations (clockwise and counterclockwise) into a single + // pipeline, and then select between them with the dynamic cull + // face. + return CullFace::clockwise; + case DrawType::imageRect: + case DrawType::imageMesh: + case DrawType::atomicResolve: + case DrawType::atomicInitialize: + case DrawType::msaaMidpointFanPathsStencil: + case DrawType::msaaMidpointFanPathsCover: + case DrawType::msaaOuterCubics: + return CullFace::none; + } + RIVE_UNREACHABLE(); +} + +static BlendEquation get_blend_equation( + const FlushDescriptor& flushDesc, + const DrawBatch& batch, + const PlatformFeatures& platformFeatures) +{ + switch (flushDesc.interlockMode) + { + case InterlockMode::rasterOrdering: + case InterlockMode::atomics: + return flushDesc.atomicFixedFunctionColorOutput + ? BlendEquation::srcOver + : BlendEquation::none; + + case InterlockMode::clockwiseAtomic: + return BlendEquation::srcOver; + + case InterlockMode::msaa: + if (batch.drawContents & DrawContents::opaquePaint) + { + return BlendEquation::none; + } + else if (!platformFeatures.supportsKHRBlendEquations || + batch.firstBlendMode == BlendMode::srcOver) + { + // Normal and in-shader blending both use src-over hardware + // blend coefficients. + // + // When drawing an advanced blend mode, the shader only does the + // "color" portion of the blend equation, and relies on the + // hardware blend unit to finish the "alpha" portion. + return BlendEquation::srcOver; + } + else + { + // When m_platformFeatures.supportsKHRBlendEquations is true in + // MSAA mode, the renderContext does not combine draws that have + // different blend modes. + return static_cast(batch.firstBlendMode); + } + } + + RIVE_UNREACHABLE(); +} + +static bool get_color_writemask(const DrawBatch& batch) +{ + switch (batch.drawType) + { + case DrawType::midpointFanPatches: + case DrawType::midpointFanCenterAAPatches: + case DrawType::outerCurvePatches: + case DrawType::interiorTriangulation: + case DrawType::atlasBlit: + case DrawType::imageRect: + case DrawType::imageMesh: + case DrawType::atomicInitialize: + case DrawType::atomicResolve: + return true; + case DrawType::msaaStrokes: + case DrawType::msaaOuterCubics: + return true; + case DrawType::msaaMidpointFanBorrowedCoverage: + case DrawType::msaaMidpointFanPathsStencil: + case DrawType::msaaStencilClipReset: + return false; + case DrawType::msaaMidpointFans: + case DrawType::msaaMidpointFanPathsCover: + return !(batch.drawContents & DrawContents::clipUpdate); + case DrawType::msaaMidpointFanStencilReset: + // For clockwise fill, disable color writes when cleaning up + // backward triangles. Clockwise only fills in forward triangles. + return !(batch.drawContents & + (DrawContents::clockwiseFill | DrawContents::clipUpdate)); + } + return false; +} + +void get_pipeline_state(const DrawBatch& batch, + const FlushDescriptor& flushDesc, + const PlatformFeatures& platformFeatures, + PipelineState* pipelineState) +{ +#ifndef NDEBUG + // Ensure drawType is compatible with the interlock mode. + switch (batch.drawType) + { + case DrawType::atlasBlit: + case DrawType::imageMesh: + break; + + case DrawType::midpointFanPatches: + case DrawType::midpointFanCenterAAPatches: + case DrawType::outerCurvePatches: + case DrawType::interiorTriangulation: + assert(flushDesc.interlockMode != InterlockMode::msaa); + break; + + case DrawType::imageRect: + case DrawType::atomicResolve: + case DrawType::atomicInitialize: + assert(flushDesc.interlockMode == InterlockMode::atomics); + break; + + case DrawType::msaaStrokes: + case DrawType::msaaMidpointFans: + case DrawType::msaaMidpointFanBorrowedCoverage: + case DrawType::msaaMidpointFanStencilReset: + case DrawType::msaaMidpointFanPathsStencil: + case DrawType::msaaMidpointFanPathsCover: + case DrawType::msaaOuterCubics: + case DrawType::msaaStencilClipReset: + assert(flushDesc.interlockMode == InterlockMode::msaa); + break; + } +#endif + + get_depth_state(batch, flushDesc, pipelineState); + get_stencil_state(batch, flushDesc, pipelineState); + pipelineState->cullFace = get_cull_face(batch.drawType); + pipelineState->blendEquation = + get_blend_equation(flushDesc, batch, platformFeatures); + pipelineState->colorWriteEnabled = get_color_writemask(batch); +} + +// Borrowed from: +// https://stackoverflow.com/questions/1659440/32-bit-to-16-bit-floating-point-conversion +// +// IEEE-754 16-bit floating-point format (without infinity): 1-5-10, exp-15, +// +-131008.0, +-6.1035156E-5, +-5.9604645E-8, 3.311 digits +float4 cast_f16_to_f32(uint16x4 x16) +{ + uint4 x = simd::cast(x16); + uint4 e = (x & 0x7C00) >> 10; // exponent + uint4 m = (x & 0x03FF) << 13; // mantissa + // evil log2 bit hack to count leading zeros in denormalized format + uint4 v = math::bit_cast(simd::cast(m)) >> 23; + // sign : normalized : denormalized + return math::bit_cast( + (x & 0x8000u) << 16 | + simd::cast((e != 0u) & 1) * ((e + 112) << 23 | m) | + simd::cast((e == 0u) & (m != 0u) & 1) * + ((v - 37u) << 23 | ((m << (150u - v)) & 0x007FE000u))); +} + +// Borrowed from: +// https://stackoverflow.com/questions/1659440/32-bit-to-16-bit-floating-point-conversion +// +// IEEE-754 16-bit floating-point format (without infinity): 1-5-10, exp-15, +// +-131008.0, +-6.1035156E-5, +-5.9604645E-8, 3.311 digits +uint16x4 cast_f32_to_f16(float4 x) +{ + // round-to-nearest-even: add last bit after truncated mantissa + uint4 b = math::bit_cast(x) + 0x00001000; + uint4 e = (b & 0x7F800000) >> 23; // exponent + // mantissa; in line below: 0x007FF000 = 0x00800000-0x00001000 = decimal + // indicator flag - initial rounding + uint4 m = b & 0x007FFFFF; + // sign : normalized : denormalized : saturate + return simd::cast( + ((b & 0x80000000u) >> 16) | + simd::cast((e > 112u) & 1) * + ((((e - 112u) << 10) & 0x7C00u) | m >> 13) | + simd::cast((e < 113u) & (e > 101u) & 1) * + ((((0x007FF000u + m) >> (125u - e)) + 1u) >> 1) | + simd::cast((e > 143u) & 1) * 0x7FFFu); +} + +// Code to generate g_gaussianIntegralTableF16. +#if 0 +static float eval_normal_distribution(float x, float mu, float inverseSigma) +{ + constexpr static float ONE_OVER_SQRT_2_PI = 0.398942280401433f; + float y = (x - mu) * inverseSigma; + return expf(-.5 * y * y) * inverseSigma * ONE_OVER_SQRT_2_PI; +} + +void generate_gausian_integral_table(float (&table)[GAUSSIAN_TABLE_SIZE]) +{ + float sigma = GAUSSIAN_TABLE_SIZE / (FEATHER_TEXTURE_STDDEVS * 2); + float inverseSigma = 1 / sigma; + float mu = GAUSSIAN_TABLE_SIZE * .5f; + float integral = 0; + for (size_t i = 0; i < GAUSSIAN_TABLE_SIZE; ++i) + { + // Sample the normal distribution in multiple locations for each entry + // of the table, in order to get a more accurate integral. + constexpr static int SAMPLES = 7; + float barCenterX = static_cast(i); + for (int sample = 0; sample < SAMPLES; ++sample) + { + float dx = static_cast(sample - (SAMPLES >> 1)) / SAMPLES; + integral += + eval_normal_distribution(barCenterX + dx, mu, inverseSigma) / + SAMPLES; + } + table[i] = integral; + } + // Account for the area under the curve prior to our table by shifting so + // the middle value of the table is exactly 1/2. + float shift = + .5 - ((GAUSSIAN_TABLE_SIZE & 1) ? table[GAUSSIAN_TABLE_SIZE / 2] + : (table[GAUSSIAN_TABLE_SIZE / 2 - 1] + + table[GAUSSIAN_TABLE_SIZE / 2]) / + 2); + table[0] = fminf(fmaxf(0, table[0] + shift), 1); + for (size_t i = 1; i < GAUSSIAN_TABLE_SIZE; ++i) + { + table[i] = fminf(fmaxf(table[i - 1], table[i] + shift), 1); + } + printf("\nconst float g_gaussianIntegralTableF16[GAUSSIAN_TABLE_SIZE] = " + "{\n"); + for (size_t i = 0; i < GAUSSIAN_TABLE_SIZE; ++i) + { + printf("%f, ", table[i]); + } + printf("\n};\n"); + printf("\nconst uint16_t g_gaussianIntegralTableF16[GAUSSIAN_TABLE_SIZE] = " + "{\n"); + for (size_t i = 0; i < GAUSSIAN_TABLE_SIZE; ++i) + { + printf("0x%x, ", gpu::cast_f32_to_f16(table[i]).x); + } + printf("\n};\n"); +} +#endif + +const uint16_t g_gaussianIntegralTableF16[GAUSSIAN_TABLE_SIZE] = { + 0x15a3, 0x15db, 0x1616, 0x1652, 0x1691, 0x16d1, 0x1715, 0x175a, 0x17a2, + 0x17ec, 0x181c, 0x1844, 0x186d, 0x1898, 0x18c4, 0x18f1, 0x1920, 0x1951, + 0x1983, 0x19b7, 0x19ec, 0x1a23, 0x1a5d, 0x1a98, 0x1ad4, 0x1b13, 0x1b54, + 0x1b97, 0x1bdc, 0x1c12, 0x1c36, 0x1c5c, 0x1c83, 0x1cac, 0x1cd5, 0x1d00, + 0x1d2c, 0x1d5a, 0x1d89, 0x1db9, 0x1deb, 0x1e1e, 0x1e53, 0x1e89, 0x1ec1, + 0x1efb, 0x1f36, 0x1f73, 0x1fb2, 0x1ff3, 0x201b, 0x203d, 0x2060, 0x2084, + 0x20a9, 0x20d0, 0x20f7, 0x211f, 0x2149, 0x2173, 0x219f, 0x21cc, 0x21fb, + 0x222a, 0x225b, 0x228d, 0x22c0, 0x22f5, 0x232b, 0x2363, 0x239c, 0x23d6, + 0x2409, 0x2428, 0x2447, 0x2468, 0x2489, 0x24ab, 0x24cd, 0x24f1, 0x2516, + 0x253b, 0x2561, 0x2589, 0x25b1, 0x25da, 0x2604, 0x262f, 0x265b, 0x2688, + 0x26b7, 0x26e6, 0x2716, 0x2748, 0x277a, 0x27ae, 0x27e3, 0x280c, 0x2828, + 0x2844, 0x2861, 0x287e, 0x289c, 0x28bb, 0x28da, 0x28fa, 0x291b, 0x293c, + 0x295f, 0x2981, 0x29a5, 0x29c9, 0x29ee, 0x2a13, 0x2a3a, 0x2a61, 0x2a89, + 0x2ab1, 0x2adb, 0x2b05, 0x2b30, 0x2b5c, 0x2b89, 0x2bb6, 0x2be4, 0x2c0a, + 0x2c22, 0x2c3a, 0x2c53, 0x2c6c, 0x2c86, 0x2ca0, 0x2cbb, 0x2cd6, 0x2cf2, + 0x2d0e, 0x2d2a, 0x2d47, 0x2d65, 0x2d82, 0x2da1, 0x2dc0, 0x2ddf, 0x2dff, + 0x2e1f, 0x2e40, 0x2e62, 0x2e84, 0x2ea6, 0x2ec9, 0x2eec, 0x2f10, 0x2f35, + 0x2f5a, 0x2f7f, 0x2fa5, 0x2fcc, 0x2ff3, 0x300d, 0x3021, 0x3036, 0x304a, + 0x305f, 0x3074, 0x308a, 0x309f, 0x30b5, 0x30cc, 0x30e2, 0x30f9, 0x3110, + 0x3127, 0x313f, 0x3157, 0x316f, 0x3187, 0x31a0, 0x31b9, 0x31d2, 0x31eb, + 0x3205, 0x321f, 0x323a, 0x3254, 0x326f, 0x328a, 0x32a5, 0x32c1, 0x32dd, + 0x32f9, 0x3315, 0x3332, 0x334f, 0x336c, 0x338a, 0x33a7, 0x33c5, 0x33e3, + 0x3401, 0x3410, 0x3420, 0x342f, 0x343f, 0x344f, 0x345f, 0x346f, 0x347f, + 0x348f, 0x349f, 0x34b0, 0x34c0, 0x34d1, 0x34e2, 0x34f3, 0x3504, 0x3515, + 0x3526, 0x3537, 0x3548, 0x355a, 0x356b, 0x357d, 0x358f, 0x35a0, 0x35b2, + 0x35c4, 0x35d6, 0x35e8, 0x35fa, 0x360d, 0x361f, 0x3631, 0x3644, 0x3656, + 0x3669, 0x367b, 0x368e, 0x36a0, 0x36b3, 0x36c6, 0x36d9, 0x36ec, 0x36ff, + 0x3711, 0x3724, 0x3737, 0x374a, 0x375d, 0x3771, 0x3784, 0x3797, 0x37aa, + 0x37bd, 0x37d0, 0x37e3, 0x37f6, 0x3805, 0x380e, 0x3818, 0x3822, 0x382b, + 0x3835, 0x383e, 0x3848, 0x3851, 0x385b, 0x3864, 0x386e, 0x3877, 0x3881, + 0x388a, 0x3894, 0x389d, 0x38a6, 0x38b0, 0x38b9, 0x38c2, 0x38cc, 0x38d5, + 0x38de, 0x38e7, 0x38f1, 0x38fa, 0x3903, 0x390c, 0x3915, 0x391e, 0x3927, + 0x3930, 0x3939, 0x3942, 0x394a, 0x3953, 0x395c, 0x3964, 0x396d, 0x3976, + 0x397e, 0x3987, 0x398f, 0x3998, 0x39a0, 0x39a8, 0x39b0, 0x39b9, 0x39c1, + 0x39c9, 0x39d1, 0x39d9, 0x39e1, 0x39e8, 0x39f0, 0x39f8, 0x3a00, 0x3a07, + 0x3a0f, 0x3a16, 0x3a1e, 0x3a25, 0x3a2c, 0x3a33, 0x3a3b, 0x3a42, 0x3a49, + 0x3a50, 0x3a57, 0x3a5d, 0x3a64, 0x3a6b, 0x3a72, 0x3a78, 0x3a7f, 0x3a85, + 0x3a8b, 0x3a92, 0x3a98, 0x3a9e, 0x3aa4, 0x3aaa, 0x3ab0, 0x3ab6, 0x3abc, + 0x3ac2, 0x3ac7, 0x3acd, 0x3ad3, 0x3ad8, 0x3ade, 0x3ae3, 0x3ae8, 0x3aed, + 0x3af3, 0x3af8, 0x3afd, 0x3b02, 0x3b07, 0x3b0b, 0x3b10, 0x3b15, 0x3b19, + 0x3b1e, 0x3b22, 0x3b27, 0x3b2b, 0x3b30, 0x3b34, 0x3b38, 0x3b3c, 0x3b40, + 0x3b44, 0x3b48, 0x3b4c, 0x3b50, 0x3b53, 0x3b57, 0x3b5b, 0x3b5e, 0x3b62, + 0x3b65, 0x3b69, 0x3b6c, 0x3b6f, 0x3b72, 0x3b76, 0x3b79, 0x3b7c, 0x3b7f, + 0x3b82, 0x3b85, 0x3b87, 0x3b8a, 0x3b8d, 0x3b90, 0x3b92, 0x3b95, 0x3b97, + 0x3b9a, 0x3b9c, 0x3b9f, 0x3ba1, 0x3ba3, 0x3ba6, 0x3ba8, 0x3baa, 0x3bac, + 0x3bae, 0x3bb0, 0x3bb2, 0x3bb4, 0x3bb6, 0x3bb8, 0x3bba, 0x3bbc, 0x3bbe, + 0x3bbf, 0x3bc1, 0x3bc3, 0x3bc4, 0x3bc6, 0x3bc7, 0x3bc9, 0x3bca, 0x3bcc, + 0x3bcd, 0x3bcf, 0x3bd0, 0x3bd1, 0x3bd2, 0x3bd4, 0x3bd5, 0x3bd6, 0x3bd7, + 0x3bd8, 0x3bda, 0x3bdb, 0x3bdc, 0x3bdd, 0x3bde, 0x3bdf, 0x3be0, 0x3be1, + 0x3be2, 0x3be2, 0x3be3, 0x3be4, 0x3be5, 0x3be6, 0x3be7, 0x3be7, 0x3be8, + 0x3be9, 0x3bea, 0x3bea, 0x3beb, 0x3bec, 0x3bec, 0x3bed, 0x3bed, 0x3bee, + 0x3bee, 0x3bef, 0x3bf0, 0x3bf0, 0x3bf1, 0x3bf1, 0x3bf2, 0x3bf2, 0x3bf2, + 0x3bf3, 0x3bf3, 0x3bf4, 0x3bf4, 0x3bf5, 0x3bf5, 0x3bf5, 0x3bf6, 0x3bf6, + 0x3bf6, 0x3bf7, 0x3bf7, 0x3bf7, 0x3bf8, 0x3bf8, 0x3bf8, 0x3bf8, 0x3bf9, + 0x3bf9, 0x3bf9, 0x3bf9, 0x3bfa, 0x3bfa, 0x3bfa, 0x3bfa, 0x3bfa, 0x3bfb, + 0x3bfb, 0x3bfb, 0x3bfb, 0x3bfb, 0x3bfc, 0x3bfc, 0x3bfc, 0x3bfc, 0x3bfc, + 0x3bfc, 0x3bfc, 0x3bfd, 0x3bfd, 0x3bfd, 0x3bfd, 0x3bfd, 0x3bfd, +}; + +// Code to generate g_inverseGaussianIntegralTableF32. +#if 0 +void generate_inverse_gausian_integral_table( + float (&table)[GAUSSIAN_TABLE_SIZE]) +{ + // Evaluate 32 samples for every table value, for better precision. + size_t MULTIPLIER = 32; + float sigma = GAUSSIAN_TABLE_SIZE / (FEATHER_TEXTURE_STDDEVS * 2); + float inverseSigma = 1 / sigma; + float mu = GAUSSIAN_TABLE_SIZE * .5f; + size_t samples = GAUSSIAN_TABLE_SIZE * MULTIPLIER; + + // Integrate half the curve in order to determine the initial value of our + // integral (the table doesn't begin until -FEATHER_TEXTURE_STDDEVS). + float integral = 0; + for (size_t i = 0; i < (samples + 1) / 2; ++i) + { + float barCenterX = static_cast(i) / MULTIPLIER; + integral += + eval_normal_distribution(barCenterX, mu, inverseSigma) / MULTIPLIER; + } + integral = .5 - integral; + + // Reboot now that we know the initial integral value and fill in the + // inverse table this time around. + float lastInverseX = std::numeric_limits::quiet_NaN(), + lastInverseY = 0; + table[0] = 0; + table[GAUSSIAN_TABLE_SIZE - 1] = 1; + for (size_t i = 0; i < samples; ++i) + { + float barCenterX = static_cast(i) / MULTIPLIER; + integral += + eval_normal_distribution(barCenterX, mu, inverseSigma) / MULTIPLIER; + float inverseX = fminf(fmaxf(0, integral), 1) * GAUSSIAN_TABLE_SIZE; + float inverseY = (i + .5f) / samples; + size_t cell = static_cast(inverseX); + float cellCenterX = cell + .5f; + if (cellCenterX == mu) + { + // Make sure the center value is exactly .5, just because. + table[cell] = .5f; + } + else if (lastInverseX <= cellCenterX && inverseX >= cellCenterX) + { + float t = (cellCenterX - lastInverseX) / (inverseX - lastInverseX); + float y = lerp(lastInverseY, inverseY, t); + assert(0 <= cell && cell < GAUSSIAN_TABLE_SIZE); + table[cell] = y; + } + lastInverseX = inverseX; + lastInverseY = inverseY; + } + + // Use a large enough GAUSSIAN_TABLE_SIZE that the beginning and ending + // values are 0 and 1! + assert(table[0] == 0 && table[GAUSSIAN_TABLE_SIZE - 1] == 1); + + printf("\nconst float " + "g_inverseGaussianIntegralTableF32[GAUSSIAN_TABLE_SIZE] = {\n"); + for (size_t i = 0; i < GAUSSIAN_TABLE_SIZE; ++i) + { + printf("%ff, ", table[i]); + } + printf("\n};\n"); + printf("\nconst uint16_t " + "g_inverseGaussianIntegralTableF16[GAUSSIAN_TABLE_SIZE] = " + "{\n"); + for (size_t i = 0; i < GAUSSIAN_TABLE_SIZE; ++i) + { + printf("0x%x, ", gpu::cast_f32_to_f16(table[i]).x); + } + printf("\n};\n"); +} +#endif + +const uint16_t g_inverseGaussianIntegralTableF16[GAUSSIAN_TABLE_SIZE] = { + 0x0, 0x290a, 0x2c62, 0x2da8, 0x2ea4, 0x2f72, 0x3011, 0x305e, 0x30a2, + 0x30e0, 0x3118, 0x314c, 0x317c, 0x31aa, 0x31d4, 0x31fc, 0x3222, 0x3246, + 0x3269, 0x328a, 0x32a9, 0x32c8, 0x32e5, 0x3301, 0x331c, 0x3337, 0x3350, + 0x3369, 0x3381, 0x3399, 0x33af, 0x33c6, 0x33db, 0x33f1, 0x3403, 0x340d, + 0x3417, 0x3420, 0x342a, 0x3433, 0x343c, 0x3445, 0x344e, 0x3457, 0x345f, + 0x3468, 0x3470, 0x3478, 0x3480, 0x3488, 0x348f, 0x3497, 0x349f, 0x34a6, + 0x34ad, 0x34b5, 0x34bc, 0x34c3, 0x34ca, 0x34d1, 0x34d7, 0x34de, 0x34e5, + 0x34eb, 0x34f2, 0x34f8, 0x34fe, 0x3505, 0x350b, 0x3511, 0x3517, 0x351d, + 0x3523, 0x3529, 0x352f, 0x3535, 0x353b, 0x3540, 0x3546, 0x354c, 0x3551, + 0x3557, 0x355c, 0x3562, 0x3567, 0x356c, 0x3572, 0x3577, 0x357c, 0x3581, + 0x3586, 0x358c, 0x3591, 0x3596, 0x359b, 0x35a0, 0x35a5, 0x35aa, 0x35ae, + 0x35b3, 0x35b8, 0x35bd, 0x35c2, 0x35c6, 0x35cb, 0x35d0, 0x35d5, 0x35d9, + 0x35de, 0x35e2, 0x35e7, 0x35ec, 0x35f0, 0x35f5, 0x35f9, 0x35fd, 0x3602, + 0x3606, 0x360b, 0x360f, 0x3613, 0x3618, 0x361c, 0x3620, 0x3625, 0x3629, + 0x362d, 0x3631, 0x3635, 0x363a, 0x363e, 0x3642, 0x3646, 0x364a, 0x364e, + 0x3652, 0x3656, 0x365b, 0x365f, 0x3663, 0x3667, 0x366b, 0x366f, 0x3673, + 0x3676, 0x367a, 0x367e, 0x3682, 0x3686, 0x368a, 0x368e, 0x3692, 0x3696, + 0x3699, 0x369d, 0x36a1, 0x36a5, 0x36a9, 0x36ad, 0x36b0, 0x36b4, 0x36b8, + 0x36bc, 0x36bf, 0x36c3, 0x36c7, 0x36ca, 0x36ce, 0x36d2, 0x36d6, 0x36d9, + 0x36dd, 0x36e1, 0x36e4, 0x36e8, 0x36eb, 0x36ef, 0x36f3, 0x36f6, 0x36fa, + 0x36fd, 0x3701, 0x3705, 0x3708, 0x370c, 0x370f, 0x3713, 0x3716, 0x371a, + 0x371e, 0x3721, 0x3725, 0x3728, 0x372c, 0x372f, 0x3733, 0x3736, 0x373a, + 0x373d, 0x3741, 0x3744, 0x3748, 0x374b, 0x374e, 0x3752, 0x3755, 0x3759, + 0x375c, 0x3760, 0x3763, 0x3767, 0x376a, 0x376d, 0x3771, 0x3774, 0x3778, + 0x377b, 0x377e, 0x3782, 0x3785, 0x3789, 0x378c, 0x378f, 0x3793, 0x3796, + 0x379a, 0x379d, 0x37a0, 0x37a4, 0x37a7, 0x37aa, 0x37ae, 0x37b1, 0x37b5, + 0x37b8, 0x37bb, 0x37bf, 0x37c2, 0x37c5, 0x37c9, 0x37cc, 0x37cf, 0x37d3, + 0x37d6, 0x37d9, 0x37dd, 0x37e0, 0x37e3, 0x37e7, 0x37ea, 0x37ed, 0x37f1, + 0x37f4, 0x37f8, 0x37fb, 0x37fe, 0x3801, 0x3802, 0x3804, 0x3806, 0x3807, + 0x3809, 0x380b, 0x380c, 0x380e, 0x3810, 0x3811, 0x3813, 0x3815, 0x3817, + 0x3818, 0x381a, 0x381c, 0x381d, 0x381f, 0x3821, 0x3822, 0x3824, 0x3826, + 0x3827, 0x3829, 0x382b, 0x382c, 0x382e, 0x3830, 0x3831, 0x3833, 0x3835, + 0x3836, 0x3838, 0x383a, 0x383c, 0x383d, 0x383f, 0x3841, 0x3842, 0x3844, + 0x3846, 0x3847, 0x3849, 0x384b, 0x384d, 0x384e, 0x3850, 0x3852, 0x3853, + 0x3855, 0x3857, 0x3859, 0x385a, 0x385c, 0x385e, 0x3860, 0x3861, 0x3863, + 0x3865, 0x3867, 0x3868, 0x386a, 0x386c, 0x386e, 0x386f, 0x3871, 0x3873, + 0x3875, 0x3876, 0x3878, 0x387a, 0x387c, 0x387e, 0x387f, 0x3881, 0x3883, + 0x3885, 0x3887, 0x3888, 0x388a, 0x388c, 0x388e, 0x3890, 0x3891, 0x3893, + 0x3895, 0x3897, 0x3899, 0x389b, 0x389c, 0x389e, 0x38a0, 0x38a2, 0x38a4, + 0x38a6, 0x38a8, 0x38aa, 0x38ab, 0x38ad, 0x38af, 0x38b1, 0x38b3, 0x38b5, + 0x38b7, 0x38b9, 0x38bb, 0x38bd, 0x38bf, 0x38c1, 0x38c3, 0x38c5, 0x38c7, + 0x38c9, 0x38cb, 0x38cd, 0x38cf, 0x38d1, 0x38d3, 0x38d5, 0x38d7, 0x38d9, + 0x38db, 0x38dd, 0x38df, 0x38e1, 0x38e3, 0x38e5, 0x38e7, 0x38e9, 0x38eb, + 0x38ee, 0x38f0, 0x38f2, 0x38f4, 0x38f6, 0x38f8, 0x38fa, 0x38fd, 0x38ff, + 0x3901, 0x3903, 0x3906, 0x3908, 0x390a, 0x390c, 0x390f, 0x3911, 0x3913, + 0x3916, 0x3918, 0x391a, 0x391d, 0x391f, 0x3921, 0x3924, 0x3926, 0x3929, + 0x392b, 0x392d, 0x3930, 0x3932, 0x3935, 0x3937, 0x393a, 0x393d, 0x393f, + 0x3942, 0x3944, 0x3947, 0x394a, 0x394c, 0x394f, 0x3952, 0x3954, 0x3957, + 0x395a, 0x395d, 0x3960, 0x3963, 0x3965, 0x3968, 0x396b, 0x396e, 0x3971, + 0x3974, 0x3977, 0x397a, 0x397d, 0x3981, 0x3984, 0x3987, 0x398a, 0x398d, + 0x3991, 0x3994, 0x3997, 0x399b, 0x399e, 0x39a2, 0x39a5, 0x39a9, 0x39ad, + 0x39b0, 0x39b4, 0x39b8, 0x39bc, 0x39c0, 0x39c4, 0x39c8, 0x39cc, 0x39d0, + 0x39d4, 0x39d9, 0x39dd, 0x39e2, 0x39e6, 0x39eb, 0x39ef, 0x39f4, 0x39f9, + 0x39fe, 0x3a03, 0x3a09, 0x3a0e, 0x3a14, 0x3a19, 0x3a1f, 0x3a25, 0x3a2b, + 0x3a32, 0x3a38, 0x3a3f, 0x3a46, 0x3a4e, 0x3a55, 0x3a5d, 0x3a65, 0x3a6e, + 0x3a77, 0x3a80, 0x3a8a, 0x3a95, 0x3aa0, 0x3aac, 0x3ab9, 0x3ac7, 0x3ad6, + 0x3ae7, 0x3afa, 0x3b10, 0x3b29, 0x3b48, 0x3b70, 0x3baa, 0x3c00, +}; +} // namespace rive::gpu diff --git a/third_party/rive_renderer/source/gpu_resource.cpp b/third_party/rive_renderer/source/gpu_resource.cpp new file mode 100644 index 0000000..4e5ae8d --- /dev/null +++ b/third_party/rive_renderer/source/gpu_resource.cpp @@ -0,0 +1,103 @@ +/* + * Copyright 2025 Rive + */ + +#include "rive/renderer/gpu_resource.hpp" + +namespace rive::gpu +{ +GPUResource::~GPUResource() {} + +void GPUResource::onRefCntReachedZero() const +{ + // GPUResourceManager will hold off on deleting "this" until its safe frame + // number has been reached. + m_manager->onRenderingResourceReleased(const_cast(this)); +} + +GPUResourceManager::~GPUResourceManager() +{ + // Call shutdown() before destroying the resource manager. + assert(m_currentFrameNumber == SHUTDOWN_FRAME_NUMBER); + assert(m_safeFrameNumber == SHUTDOWN_FRAME_NUMBER); + assert(m_resourcePurgatory.empty()); +} + +void GPUResourceManager::advanceFrameNumber(uint64_t nextFrameNumber, + uint64_t safeFrameNumber) +{ + assert(nextFrameNumber >= m_currentFrameNumber); + assert(safeFrameNumber >= m_safeFrameNumber); + assert(safeFrameNumber <= nextFrameNumber); + + m_currentFrameNumber = nextFrameNumber; + m_safeFrameNumber = safeFrameNumber; + + // Delete all resources whose safe frame number has been reached. + while (!m_resourcePurgatory.empty() && + m_resourcePurgatory.front().lastFrameNumber <= m_safeFrameNumber) + { + assert(m_resourcePurgatory.front().resource->debugging_refcnt() == 0); + m_resourcePurgatory.pop_front(); + } +} + +void GPUResourceManager::onRenderingResourceReleased(GPUResource* resource) +{ + assert(resource->manager() == this); + if (m_currentFrameNumber > m_safeFrameNumber) + { + // Hold this resource until its safe frame number is reached. + assert(resource->debugging_refcnt() == 0); + assert(m_resourcePurgatory.empty() || + m_currentFrameNumber >= + m_resourcePurgatory.back().lastFrameNumber); + m_resourcePurgatory.emplace_back(resource, m_currentFrameNumber); + } + else + { + // We're in a shutdown cycle. Delete immediately. + delete resource; + } +} + +void GPUResourceManager::shutdown() +{ + advanceFrameNumber(SHUTDOWN_FRAME_NUMBER, SHUTDOWN_FRAME_NUMBER); +} + +rcp GPUResourcePool::acquire() +{ + rcp resource; + if (!m_pool.empty() && + m_pool.front().lastFrameNumber <= m_manager->safeFrameNumber()) + { + // Recycle the oldest buffer in the pool. + resource = rcp(m_pool.front().resource.release()); + m_pool.pop_front(); + + // Trim the pool in case it's grown out of control (meaning it was + // advanced multiple times in a single frame). + while (m_pool.size() > m_maxPoolCount && + m_pool.front().lastFrameNumber <= m_manager->safeFrameNumber()) + { + m_pool.pop_front(); + } + } + assert(resource == nullptr || resource->debugging_refcnt() == 1); + return resource; +} + +void GPUResourcePool::recycle(rcp resource) +{ + if (resource != nullptr) + { + // Return the current buffer to the pool. + assert(resource->debugging_refcnt() == 1); + assert(m_pool.empty() || m_manager->currentFrameNumber() >= + m_pool.back().lastFrameNumber); + m_pool.emplace_back(resource.release(), + m_manager->currentFrameNumber()); + } +} +} // namespace rive::gpu diff --git a/third_party/rive_renderer/source/gr_inner_fan_triangulator.hpp b/third_party/rive_renderer/source/gr_inner_fan_triangulator.hpp new file mode 100644 index 0000000..a555a16 --- /dev/null +++ b/third_party/rive_renderer/source/gr_inner_fan_triangulator.hpp @@ -0,0 +1,97 @@ +/* + * Copyright 2021 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrInnerFanTriangulator_DEFINED +#define GrInnerFanTriangulator_DEFINED + +#if !defined(SK_ENABLE_OPTIMIZE_SIZE) + +#include "gr_triangulator.hpp" + +namespace rive +{ +// Triangulates the inner polygon(s) of a path (i.e., the triangle fan for a +// Redbook rendering method). When combined with the outer curves and grout +// triangles, these produce a complete path. If a groutCollector is not +// provided, pathToPolys fails upon self intersection. +class GrInnerFanTriangulator : private GrTriangulator +{ +public: + using GroutTriangleList = GrTriangulator::BreadcrumbTriangleList; + + GrInnerFanTriangulator(const RawPath& path, + const Mat2D& viewMatrix, + Comparator::Direction direction, + FillRule fillRule, + TrivialBlockAllocator* alloc) : + GrTriangulator(direction, fillRule, alloc), + m_shouldReverseTriangles( + viewMatrix[0] * viewMatrix[3] - viewMatrix[2] * viewMatrix[1] < 0) + { + fPreserveCollinearVertices = true; + fCollectBreadcrumbTriangles = true; + bool isLinear; + auto [polys, success] = + GrTriangulator::pathToPolys(path, 0, AABB{}, &isLinear); + if (success) + { + m_polys = polys; + m_maxVertexCount = countMaxTriangleVertices(m_polys); + } + } + + void negateWinding() { m_shouldNegateWinding = !m_shouldNegateWinding; } + + FillRule fillRule() const { return fFillRule; } + + size_t maxVertexCount() const { return m_maxVertexCount; } + + size_t polysToTriangles( + uint16_t pathID, + gpu::WindingFaces windingFaces, + gpu::WriteOnlyMappedMemory* mappedMemory) const + + { + if (m_polys == nullptr || m_maxVertexCount == 0) + { + return 0; + } + return GrTriangulator::polysToTriangles(m_polys, + m_maxVertexCount, + pathID, + m_shouldReverseTriangles, + m_shouldNegateWinding, + windingFaces, + mappedMemory); + } + + const GroutTriangleList& groutList() const { return fBreadcrumbList; } + +private: + // We reverse triangles whe using a left-handed view matrix, in order to + // ensure we always emit clockwise triangles. + bool m_shouldReverseTriangles; + bool m_shouldNegateWinding = false; + Poly* m_polys = nullptr; + size_t m_maxVertexCount = 0; +}; +} // namespace rive + +#else + +// Stub out GrInnerFanTriangulator::GroutTriangleList for function declarations. +namespace GrInnerFanTriangulator +{ +struct GroutTriangleList +{ + GroutTriangleList() = delete; +}; +}; // namespace GrInnerFanTriangulator + +#endif // SK_ENABLE_OPTIMIZE_SIZE + +#endif // GrInnerFanTriangulator_DEFINED diff --git a/third_party/rive_renderer/source/gr_triangulator.cpp b/third_party/rive_renderer/source/gr_triangulator.cpp new file mode 100644 index 0000000..ac463ea --- /dev/null +++ b/third_party/rive_renderer/source/gr_triangulator.cpp @@ -0,0 +1,2585 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Initial import from + * skia:c2a399a74da523ec445f1202367764d04b5df2ec@src/gpu/ganesh/geometry/GrTriangulator.h + * + * Copyright 2023 Rive + */ + +#include "gr_triangulator.hpp" + +#include + +#if !defined(SK_ENABLE_OPTIMIZE_SIZE) + +#if TRIANGULATOR_LOGGING +#define TESS_LOG printf +#define DUMP_MESH(M) (M).dump() +#else +#define TESS_LOG(...) +#define DUMP_MESH(M) +#endif + +namespace rive +{ +using EdgeType = GrTriangulator::EdgeType; +using Vertex = GrTriangulator::Vertex; +using VertexList = GrTriangulator::VertexList; +using Line = GrTriangulator::Line; +using Edge = GrTriangulator::Edge; +using EdgeList = GrTriangulator::EdgeList; +using Poly = GrTriangulator::Poly; +using MonotonePoly = GrTriangulator::MonotonePoly; +using Comparator = GrTriangulator::Comparator; + +static bool is_finite(Vec2D pt) +{ + float accum = 0; + accum *= pt.x; + accum *= pt.y; + + // accum is either NaN or it is finite (zero). + assert(0 == accum || std::isnan(accum)); + + // value==value will be true iff value is not NaN + // TODO: is it faster to say !accum or accum==accum? + return !std::isnan(accum); +} + +template +static void list_insert(T* t, T* prev, T* next, T** head, T** tail) +{ + t->*Prev = prev; + t->*Next = next; + if (prev) + { + prev->*Next = t; + } + else if (head) + { + *head = t; + } + if (next) + { + next->*Prev = t; + } + else if (tail) + { + *tail = t; + } +} + +template +static void list_remove(T* t, T** head, T** tail) +{ + if (t->*Prev) + { + t->*Prev->*Next = t->*Next; + } + else if (head) + { + *head = t->*Next; + } + if (t->*Next) + { + t->*Next->*Prev = t->*Prev; + } + else if (tail) + { + *tail = t->*Prev; + } + t->*Prev = t->*Next = nullptr; +} + +typedef bool (*CompareFunc)(const Vec2D& a, const Vec2D& b); + +static bool sweep_lt_horiz(const Vec2D& a, const Vec2D& b) +{ + return a.x < b.x || (a.x == b.x && a.y > b.y); +} + +static bool sweep_lt_vert(const Vec2D& a, const Vec2D& b) +{ + return a.y < b.y || (a.y == b.y && a.x < b.x); +} + +bool GrTriangulator::Comparator::sweep_lt(const Vec2D& a, const Vec2D& b) const +{ + return fDirection == Direction::kHorizontal ? sweep_lt_horiz(a, b) + : sweep_lt_vert(a, b); +} + +static size_t emit_triangle( + Vertex* v0, + Vertex* v1, + Vertex* v2, + int16_t riveWeight, + uint16_t pathID, + gpu::WriteOnlyMappedMemory* mappedMemory) +{ + TESS_LOG("emit_triangle %g (%g, %g) %d\n", + v0->fID, + v0->fPoint.x, + v0->fPoint.y, + v0->fAlpha); + TESS_LOG(" %g (%g, %g) %d\n", + v1->fID, + v1->fPoint.x, + v1->fPoint.y, + v1->fAlpha); + TESS_LOG(" %g (%g, %g) %d\n", + v2->fID, + v2->fPoint.x, + v2->fPoint.y, + v2->fAlpha); + mappedMemory->emplace_back(v0->fPoint, riveWeight, pathID); + mappedMemory->emplace_back(v1->fPoint, riveWeight, pathID); + mappedMemory->emplace_back(v2->fPoint, riveWeight, pathID); + return 3; +} + +void GrTriangulator::VertexList::insert(Vertex* v, Vertex* prev, Vertex* next) +{ + list_insert(v, + prev, + next, + &fHead, + &fTail); +} + +void GrTriangulator::VertexList::remove(Vertex* v) +{ + list_remove(v, &fHead, &fTail); +} + +// Round to nearest quarter-pixel. This is used for screenspace tessellation. + +#if 0 +static inline void round(Vec2D* p) +{ + p->x = SkScalarRoundToScalar(p->x * 4.0f) * 0.25f; + p->y = SkScalarRoundToScalar(p->y * 4.0f) * 0.25f; +} +#endif + +static inline float double_to_clamped_scalar(double d) +{ + // Clamps large values to what's finitely representable when cast back to a + // float. + static const double kMaxLimit = (double)std::numeric_limits::max(); + // It's not perfect, but a using a value larger than float_min helps protect + // from denormalized values and ill-conditions in intermediate calculations + // on coordinates. + static const double kNearZeroLimit = + 16 * (double)std::numeric_limits::min(); + if (std::abs(d) < kNearZeroLimit) + { + d = 0.f; + } + return static_cast(std::max(-kMaxLimit, std::min(d, kMaxLimit))); +} + +#if 0 +bool GrTriangulator::Line::intersect(const Line& other, Vec2D* point) const +{ + double denom = fA * other.fB - fB * other.fA; + if (denom == 0.0) + { + return false; + } + double scale = 1.0 / denom; + point->x = double_to_clamped_scalar((fB * other.fC - other.fB * fC) * scale); + point->y = double_to_clamped_scalar((other.fA * fC - fA * other.fC) * scale); + round(point); + return point->isFinite(); +} +#endif + +// If the edge's vertices differ by many orders of magnitude, the computed line +// equation can have significant error in its distance and intersection tests. +// To avoid this, we recursively subdivide long edges and effectively perform a +// binary search to perform a more accurate intersection test. +static bool edge_line_needs_recursion(const Vec2D& p0, const Vec2D& p1) +{ + // ilogbf(0) returns an implementation-defined constant, but we are choosing + // to saturate negative exponents to 0 for comparisons sake. We're only + // trying to recurse on lines with very large coordinates. + int expDiffX = std::abs((std::abs(p0.x) < 1.f ? 0 : std::ilogbf(p0.x)) - + (std::abs(p1.x) < 1.f ? 0 : std::ilogbf(p1.x))); + int expDiffY = std::abs((std::abs(p0.y) < 1.f ? 0 : std::ilogbf(p0.y)) - + (std::abs(p1.y) < 1.f ? 0 : std::ilogbf(p1.y))); + // Differ by more than 2^20, or roughly a factor of one million. + return expDiffX > 20 || expDiffY > 20; +} + +static bool recursive_edge_intersect(const Line& u, + Vec2D u0, + Vec2D u1, + const Line& v, + Vec2D v0, + Vec2D v1, + Vec2D* p, + double* s, + double* t) +{ + // First check if the bounding boxes of [u0,u1] intersects [v0,v1]. If they + // do not, then the two line segments cannot intersect in their domain (even + // if the lines themselves might). + // - don't use AABB::intersect since the vertices aren't sorted and + // horiz/vertical lines + // appear as empty rects, which then never "intersect" according to AABB. + if (std::min(u0.x, u1.x) > std::max(v0.x, v1.x) || + std::max(u0.x, u1.x) < std::min(v0.x, v1.x) || + std::min(u0.y, u1.y) > std::max(v0.y, v1.y) || + std::max(u0.y, u1.y) < std::min(v0.y, v1.y)) + { + return false; + } + + // Compute intersection based on current segment vertices; if an + // intersection is found but the vertices differ too much in magnitude, we + // recurse using the midpoint of the segment to reject false positives. We + // don't currently try to avoid false negatives (e.g. large magnitude line + // reports no intersection but there is one). + double denom = u.fA * v.fB - u.fB * v.fA; + if (denom == 0.0) + { + return false; + } + double dx = static_cast(v0.x) - u0.x; + double dy = static_cast(v0.y) - u0.y; + double sNumer = dy * v.fB + dx * v.fA; + double tNumer = dy * u.fB + dx * u.fA; + // If (sNumer / denom) or (tNumer / denom) is not in [0..1], exit early. + // This saves us doing the divide below unless absolutely necessary. + if (denom > 0.0 + ? (sNumer < 0.0 || sNumer > denom || tNumer < 0.0 || tNumer > denom) + : (sNumer > 0.0 || sNumer < denom || tNumer > 0.0 || + tNumer < denom)) + { + return false; + } + + *s = sNumer / denom; + *t = tNumer / denom; + assert(*s >= 0.0 && *s <= 1.0 && *t >= 0.0 && *t <= 1.0); + + const bool uNeedsSplit = edge_line_needs_recursion(u0, u1); + const bool vNeedsSplit = edge_line_needs_recursion(v0, v1); + if (!uNeedsSplit && !vNeedsSplit) + { + p->x = double_to_clamped_scalar(u0.x - (*s) * u.fB); + p->y = double_to_clamped_scalar(u0.y + (*s) * u.fA); + return true; + } + else + { + double sScale = 1.0, sShift = 0.0; + double tScale = 1.0, tShift = 0.0; + + if (uNeedsSplit) + { + Vec2D uM = {(float)(0.5 * u0.x + 0.5 * u1.x), + (float)(0.5 * u0.y + 0.5 * u1.y)}; + sScale = 0.5; + if (*s >= 0.5) + { + u0 = uM; + sShift = 0.5; + } + else + { + u1 = uM; + } + } + if (vNeedsSplit) + { + Vec2D vM = {(float)(0.5 * v0.x + 0.5 * v1.x), + (float)(0.5 * v0.y + 0.5 * v1.y)}; + tScale = 0.5; + if (*t >= 0.5) + { + v0 = vM; + tShift = 0.5; + } + else + { + v1 = vM; + } + } + + // Just recompute both lines, even if only one was split; we're already + // in a slow path. + if (recursive_edge_intersect(Line(u0, u1), + u0, + u1, + Line(v0, v1), + v0, + v1, + p, + s, + t)) + { + // Adjust s and t back to full range + *s = sScale * (*s) + sShift; + *t = tScale * (*t) + tShift; + return true; + } + else + { + // False positive + return false; + } + } +} + +bool GrTriangulator::Edge::intersect(const Edge& other, + Vec2D* p, + uint8_t* alpha) const +{ + TESS_LOG("intersecting %g -> %g with %g -> %g\n", + fTop->fID, + fBottom->fID, + other.fTop->fID, + other.fBottom->fID); + if (fTop == other.fTop || fBottom == other.fBottom || + fTop == other.fBottom || fBottom == other.fTop) + { + // If the two edges share a vertex by construction, they have already + // been split and shouldn't be considered "intersecting" anymore. + return false; + } + + double s, t; // needed to interpolate vertex alpha + const bool intersects = recursive_edge_intersect(fLine, + fTop->fPoint, + fBottom->fPoint, + other.fLine, + other.fTop->fPoint, + other.fBottom->fPoint, + p, + &s, + &t); + if (!intersects) + { + return false; + } + + if (alpha) + { + if (fType == EdgeType::kInner || other.fType == EdgeType::kInner) + { + // If the intersection is on any interior edge, it needs to stay + // fully opaque or later triangulation could leech transparency into + // the inner fill region. + *alpha = 255; + } + else if (fType == EdgeType::kOuter && other.fType == EdgeType::kOuter) + { + // Trivially, the intersection will be fully transparent since since + // it is by construction on the outer edge. + *alpha = 0; + } + else + { + // Could be two connectors crossing, or a connector crossing an + // outer edge. Take the max interpolated alpha + assert(fType == EdgeType::kConnector || + other.fType == EdgeType::kConnector); + *alpha = std::max((1.0 - s) * fTop->fAlpha + s * fBottom->fAlpha, + (1.0 - t) * other.fTop->fAlpha + + t * other.fBottom->fAlpha); + } + } + return true; +} + +void GrTriangulator::EdgeList::insert(Edge* edge, Edge* prev, Edge* next) +{ + list_insert(edge, + prev, + next, + &fHead, + &fTail); +} + +bool GrTriangulator::EdgeList::remove(Edge* edge) +{ + TESS_LOG("removing edge %g -> %g\n", edge->fTop->fID, edge->fBottom->fID); + // assert(this->contains(edge)); // Leave this here for future debugging. + if (!this->contains(edge)) + { + return false; + } + list_remove(edge, &fHead, &fTail); + return true; +} + +void GrTriangulator::MonotonePoly::addEdge(Edge* edge) +{ + if (fSide == kRight_Side) + { + assert(!edge->fUsedInRightPoly); + list_insert( + edge, + fLastEdge, + nullptr, + &fFirstEdge, + &fLastEdge); + edge->fUsedInRightPoly = true; + } + else + { + assert(!edge->fUsedInLeftPoly); + list_insert( + edge, + fLastEdge, + nullptr, + &fFirstEdge, + &fLastEdge); + edge->fUsedInLeftPoly = true; + } +} + +size_t GrTriangulator::emitMonotonePoly( + const MonotonePoly* monotonePoly, + uint16_t pathID, + bool reverseTriangles, + bool negateWinding, + gpu::WindingFaces windingFaces, + gpu::WriteOnlyMappedMemory* mappedMemory) const +{ + // GrTriangulator and Rive unfortunately have opposite winding senses. + int16_t riveWeight = -monotonePoly->fWinding; + assert(riveWeight != 0); + if (negateWinding) + { + riveWeight = -riveWeight; + } + if ((riveWeight < 0 && !(windingFaces & gpu::WindingFaces::negative)) || + (riveWeight >= 0 && !(windingFaces & gpu::WindingFaces::positive))) + { + return 0; + } + Edge* e = monotonePoly->fFirstEdge; + VertexList vertices; + vertices.append(e->fTop); + int count = 1; + while (e != nullptr) + { + if (kRight_Side == monotonePoly->fSide) + { + vertices.append(e->fBottom); + e = e->fRightPolyNext; + } + else + { + vertices.prepend(e->fBottom); + e = e->fLeftPolyNext; + } + count++; + } + Vertex* first = vertices.fHead; + Vertex* v = first->fNext; + size_t vertexCount = 0; + while (v != vertices.fTail) + { + assert(v && v->fPrev && v->fNext); + Vertex* prev = v->fPrev; + Vertex* curr = v; + Vertex* next = v->fNext; + if (count == 3) + { + vertexCount += emitTriangle(prev, + curr, + next, + riveWeight, + pathID, + reverseTriangles, + mappedMemory); + break; + } + double ax = static_cast(curr->fPoint.x) - prev->fPoint.x; + double ay = static_cast(curr->fPoint.y) - prev->fPoint.y; + double bx = static_cast(next->fPoint.x) - curr->fPoint.x; + double by = static_cast(next->fPoint.y) - curr->fPoint.y; + if (ax * by - ay * bx >= 0.0) + { + vertexCount += emitTriangle(prev, + curr, + next, + riveWeight, + pathID, + reverseTriangles, + mappedMemory); + v->fPrev->fNext = v->fNext; + v->fNext->fPrev = v->fPrev; + count--; + if (v->fPrev == first) + { + v = v->fNext; + } + else + { + v = v->fPrev; + } + } + else + { + v = v->fNext; + } + } + return vertexCount; +} + +size_t GrTriangulator::emitTriangle( + Vertex* prev, + Vertex* curr, + Vertex* next, + int16_t riveWeight, + uint16_t pathID, + bool reverseTriangles, + gpu::WriteOnlyMappedMemory* mappedMemory) const +{ + if (reverseTriangles) + { + std::swap(prev, next); + } + return emit_triangle(prev, curr, next, riveWeight, pathID, mappedMemory); +} + +GrTriangulator::Poly::Poly(Vertex* v, int winding) : + fFirstVertex(v), + fWinding(winding), + fHead(nullptr), + fTail(nullptr), + fNext(nullptr), + fPartner(nullptr), + fCount(0) +{ +#if TRIANGULATOR_LOGGING + static int gID = 0; + fID = gID++; + TESS_LOG("*** created Poly %d\n", fID); +#endif +} + +Poly* GrTriangulator::Poly::addEdge(Edge* e, Side side, GrTriangulator* tri) +{ + TESS_LOG("addEdge (%g -> %g) to poly %d, %s side\n", + e->fTop->fID, + e->fBottom->fID, + fID, + side == kLeft_Side ? "left" : "right"); + Poly* partner = fPartner; + Poly* poly = this; + if (side == kRight_Side) + { + if (e->fUsedInRightPoly) + { + return this; + } + } + else + { + if (e->fUsedInLeftPoly) + { + return this; + } + } + if (partner) + { + fPartner = partner->fPartner = nullptr; + } + if (!fTail) + { + fHead = fTail = tri->allocateMonotonePoly(e, side, fWinding); + fCount += 2; + } + else if (e->fBottom == fTail->fLastEdge->fBottom) + { + return poly; + } + else if (side == fTail->fSide) + { + fTail->addEdge(e); + fCount++; + } + else + { + e = tri->allocateEdge(fTail->fLastEdge->fBottom, + e->fBottom, + 1, + EdgeType::kInner); + fTail->addEdge(e); + fCount++; + if (partner) + { + partner->addEdge(e, side, tri); + poly = partner; + } + else + { + MonotonePoly* m = tri->allocateMonotonePoly(e, side, fWinding); + m->fPrev = fTail; + fTail->fNext = m; + fTail = m; + } + } + return poly; +} + +size_t GrTriangulator::emitPoly( + const Poly* poly, + uint16_t pathID, + bool reverseTriangles, + bool negateWinding, + gpu::WindingFaces windingFaces, + gpu::WriteOnlyMappedMemory* mappedMemory) const +{ + if (poly->fCount < 3) + { + return 0; + } + TESS_LOG("emit() %d, size %d\n", poly->fID, poly->fCount); + size_t vertexCount = 0; + for (MonotonePoly* m = poly->fHead; m != nullptr; m = m->fNext) + { + vertexCount += emitMonotonePoly(m, + pathID, + reverseTriangles, + negateWinding, + windingFaces, + mappedMemory); + } + return vertexCount; +} + +static bool coincident(const Vec2D& a, const Vec2D& b) { return a == b; } + +Poly* GrTriangulator::makePoly(Poly** head, Vertex* v, int winding) const +{ + Poly* poly = fAlloc->make(v, winding); + poly->fNext = *head; + *head = poly; + return poly; +} + +void GrTriangulator::appendPointToContour(const Vec2D& p, + VertexList* contour) const +{ + Vertex* v = fAlloc->make(p, 255); +#if TRIANGULATOR_LOGGING + static float gID = 0.0f; + v->fID = gID++; +#endif + contour->append(v); +} + +#if 0 +static float quad_error_at(const Vec2D pts[3], float t, float u) +{ + SkQuadCoeff quad(pts); + Vec2D p0 = to_point(quad.eval(t - 0.5f * u)); + Vec2D mid = to_point(quad.eval(t)); + Vec2D p1 = to_point(quad.eval(t + 0.5f * u)); + if (!p0.isFinite() || !mid.isFinite() || !p1.isFinite()) + { + return 0; + } + return SkPointPriv::DistanceToLineSegmentBetweenSqd(mid, p0, p1); +} + +void GrTriangulator::appendQuadraticToContour(const Vec2D pts[3], + float toleranceSqd, + VertexList* contour) const +{ + SkQuadCoeff quad(pts); + skvx::float2 aa = quad.fA * quad.fA; + float denom = 2.0f * (aa[0] + aa[1]); + skvx::float2 ab = quad.fA * quad.fB; + float t = denom ? (-ab[0] - ab[1]) / denom : 0.0f; + int nPoints = 1; + float u = 1.0f; + // Test possible subdivision values only at the point of maximum curvature. + // If it passes the flatness metric there, it'll pass everywhere. + while (nPoints < GrPathUtils::kMaxPointsPerCurve) + { + u = 1.0f / nPoints; + if (quad_error_at(pts, t, u) < toleranceSqd) + { + break; + } + nPoints++; + } + for (int j = 1; j <= nPoints; j++) + { + this->appendPointToContour(to_point(quad.eval(j * u)), contour); + } +} + +void GrTriangulator::generateCubicPoints(const Vec2D& p0, + const Vec2D& p1, + const Vec2D& p2, + const Vec2D& p3, + float tolSqd, + VertexList* contour, + int pointsLeft) const +{ + float d1 = SkPointPriv::DistanceToLineSegmentBetweenSqd(p1, p0, p3); + float d2 = SkPointPriv::DistanceToLineSegmentBetweenSqd(p2, p0, p3); + if (pointsLeft < 2 || (d1 < tolSqd && d2 < tolSqd) || !SkIsFinite(d1, d2)) + { + this->appendPointToContour(p3, contour); + return; + } + const Vec2D q[] = {{SkScalarAve(p0.x, p1.x), SkScalarAve(p0.y, p1.y)}, + {SkScalarAve(p1.x, p2.x), SkScalarAve(p1.y, p2.y)}, + {SkScalarAve(p2.x, p3.x), SkScalarAve(p2.y, p3.y)}}; + const Vec2D r[] = {{SkScalarAve(q[0].x, q[1].x), SkScalarAve(q[0].y, q[1].y)}, + {SkScalarAve(q[1].x, q[2].x), SkScalarAve(q[1].y, q[2].y)}}; + const Vec2D s = {SkScalarAve(r[0].x, r[1].x), SkScalarAve(r[0].y, r[1].y)}; + pointsLeft >>= 1; + this->generateCubicPoints(p0, q[0], r[0], s, tolSqd, contour, pointsLeft); + this->generateCubicPoints(s, r[1], q[2], p3, tolSqd, contour, pointsLeft); +} +#endif + +// Stage 1: convert the input path to a set of linear contours (linked list of +// Vertices). + +void GrTriangulator::pathToContours(const RawPath& path, + float tolerance, + const AABB& clipBounds, + VertexList* contours, + bool* isLinear) const +{ +#if 0 + float toleranceSqd = tolerance * tolerance; + Vec2D pts[4]; +#endif + *isLinear = true; + VertexList* contour = contours; +#if 0 + RawPath::Iter iter(fPath, false); + if (path.isInverseFillType()) + { + Vec2D quad[4]; + clipBounds.toQuad(quad); + for (int i = 3; i >= 0; i--) + { + this->appendPointToContour(quad[i], contours); + } + contour++; + } + SkAutoConicToQuads converter; +#endif + for (const auto [verb, pts] : path) + { + switch (verb) + { +#if 0 + case SkPath::kConic_Verb: + { + *isLinear = false; + if (toleranceSqd == 0) + { + this->appendPointToContour(pts[2], contour); + break; + } + float weight = iter.conicWeight(); + const Vec2D* quadPts = converter.computeQuads(pts, weight, toleranceSqd); + for (int i = 0; i < converter.countQuads(); ++i) + { + this->appendQuadraticToContour(quadPts, toleranceSqd, contour); + quadPts += 2; + } + break; + } +#endif + case PathVerb::move: + if (contour->fHead) + { + contour++; + } + if (is_finite(pts[0])) + { + this->appendPointToContour(pts[0], contour); + } + break; + case PathVerb::line: + { + if (is_finite(pts[1])) + { + this->appendPointToContour(pts[1], contour); + } + break; + } + case PathVerb::quad: + { +#if 0 + *isLinear = false; + if (toleranceSqd == 0) + { + this->appendPointToContour(pts[2], contour); + break; + } + this->appendQuadraticToContour(pts, toleranceSqd, contour); + break; +#else + RIVE_UNREACHABLE(); +#endif + } + case PathVerb::cubic: + { +#if 0 + *isLinear = false; + if (toleranceSqd == 0) + { + this->appendPointToContour(pts[3], contour); + break; + } + int pointsLeft = GrPathUtils::cubicPointCount(pts, tolerance); + this->generateCubicPoints(pts[0], + pts[1], + pts[2], + pts[3], + toleranceSqd, + contour, + pointsLeft); + break; +#else + RIVE_UNREACHABLE(); +#endif + } + case PathVerb::close: + break; + } + } +} + +static inline bool apply_fill_type(FillRule fillRule, int winding) +{ + switch (fillRule) + { + case FillRule::nonZero: + return winding != 0; + case FillRule::evenOdd: + return (winding & 1) != 0; + default: + RIVE_UNREACHABLE(); + } +} + +bool GrTriangulator::applyFillType(int winding) const +{ + return apply_fill_type(fFillRule, winding); +} + +static inline bool apply_fill_type(FillRule fillType, const Poly* poly) +{ + return poly && apply_fill_type(fillType, poly->fWinding); +} + +MonotonePoly* GrTriangulator::allocateMonotonePoly(Edge* edge, + Side side, + int winding) +{ + ++fNumMonotonePolys; + return fAlloc->make(edge, side, winding); +} + +Edge* GrTriangulator::allocateEdge(Vertex* top, + Vertex* bottom, + int winding, + EdgeType type) +{ + ++fNumEdges; + return fAlloc->make(top, bottom, winding, type); +} + +Edge* GrTriangulator::makeEdge(Vertex* prev, + Vertex* next, + EdgeType type, + const Comparator& c) +{ + assert(prev->fPoint != next->fPoint); + int winding = c.sweep_lt(prev->fPoint, next->fPoint) ? 1 : -1; + Vertex* top = winding < 0 ? next : prev; + Vertex* bottom = winding < 0 ? prev : next; + return this->allocateEdge(top, bottom, winding, type); +} + +bool EdgeList::insert(Edge* edge, Edge* prev) +{ + TESS_LOG("inserting edge %g -> %g\n", edge->fTop->fID, edge->fBottom->fID); + // assert(!this->contains(edge)); // Leave this here for debugging. + if (this->contains(edge)) + { + return false; + } + Edge* next = prev ? prev->fRight : fHead; + this->insert(edge, prev, next); + return true; +} + +void GrTriangulator::FindEnclosingEdges(const Vertex& v, + const EdgeList& edges, + Edge** left, + Edge** right) +{ + if (v.fFirstEdgeAbove && v.fLastEdgeAbove) + { + *left = v.fFirstEdgeAbove->fLeft; + *right = v.fLastEdgeAbove->fRight; + return; + } + Edge* next = nullptr; + Edge* prev; + for (prev = edges.fTail; prev != nullptr; prev = prev->fLeft) + { + if (prev->isLeftOf(v)) + { + break; + } + next = prev; + } + *left = prev; + *right = next; +} + +void GrTriangulator::Edge::insertAbove(Vertex* v, const Comparator& c) +{ + if (fTop->fPoint == fBottom->fPoint || + c.sweep_lt(fBottom->fPoint, fTop->fPoint)) + { + return; + } + TESS_LOG("insert edge (%g -> %g) above vertex %g\n", + fTop->fID, + fBottom->fID, + v->fID); + Edge* prev = nullptr; + Edge* next; + for (next = v->fFirstEdgeAbove; next; next = next->fNextEdgeAbove) + { + if (next->isRightOf(*fTop)) + { + break; + } + prev = next; + } + list_insert( + this, + prev, + next, + &v->fFirstEdgeAbove, + &v->fLastEdgeAbove); +} + +void GrTriangulator::Edge::insertBelow(Vertex* v, const Comparator& c) +{ + if (fTop->fPoint == fBottom->fPoint || + c.sweep_lt(fBottom->fPoint, fTop->fPoint)) + { + return; + } + TESS_LOG("insert edge (%g -> %g) below vertex %g\n", + fTop->fID, + fBottom->fID, + v->fID); + Edge* prev = nullptr; + Edge* next; + for (next = v->fFirstEdgeBelow; next; next = next->fNextEdgeBelow) + { + if (next->isRightOf(*fBottom)) + { + break; + } + prev = next; + } + list_insert( + this, + prev, + next, + &v->fFirstEdgeBelow, + &v->fLastEdgeBelow); +} + +static void remove_edge_above(Edge* edge) +{ + assert(edge->fTop && edge->fBottom); + TESS_LOG("removing edge (%g -> %g) above vertex %g\n", + edge->fTop->fID, + edge->fBottom->fID, + edge->fBottom->fID); + list_remove( + edge, + &edge->fBottom->fFirstEdgeAbove, + &edge->fBottom->fLastEdgeAbove); +} + +static void remove_edge_below(Edge* edge) +{ + assert(edge->fTop && edge->fBottom); + TESS_LOG("removing edge (%g -> %g) below vertex %g\n", + edge->fTop->fID, + edge->fBottom->fID, + edge->fTop->fID); + list_remove( + edge, + &edge->fTop->fFirstEdgeBelow, + &edge->fTop->fLastEdgeBelow); +} + +void GrTriangulator::Edge::disconnect() +{ + remove_edge_above(this); + remove_edge_below(this); +} + +static bool rewind(EdgeList* activeEdges, + Vertex** current, + Vertex* dst, + const Comparator& c) +{ + if (!current || *current == dst || + c.sweep_lt((*current)->fPoint, dst->fPoint)) + { + return true; + } + Vertex* v = *current; + TESS_LOG("rewinding active edges from vertex %g to vertex %g\n", + v->fID, + dst->fID); + while (v != dst) + { + v = v->fPrev; + for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) + { + if (!activeEdges->remove(e)) + { + return false; + } + } + Edge* leftEdge = v->fLeftEnclosingEdge; + for (Edge* e = v->fFirstEdgeAbove; e; e = e->fNextEdgeAbove) + { + if (!activeEdges->insert(e, leftEdge)) + { + return false; + } + leftEdge = e; + Vertex* top = e->fTop; + if (c.sweep_lt(top->fPoint, dst->fPoint) && + ((top->fLeftEnclosingEdge && + !top->fLeftEnclosingEdge->isLeftOf(*e->fTop)) || + (top->fRightEnclosingEdge && + !top->fRightEnclosingEdge->isRightOf(*e->fTop)))) + { + dst = top; + } + } + } + *current = v; + return true; +} + +static bool rewind_if_necessary(Edge* edge, + EdgeList* activeEdges, + Vertex** current, + const Comparator& c) +{ + if (!activeEdges || !current) + { + return true; + } + if (!edge) + { + return false; + } + Vertex* top = edge->fTop; + Vertex* bottom = edge->fBottom; + if (edge->fLeft) + { + Vertex* leftTop = edge->fLeft->fTop; + Vertex* leftBottom = edge->fLeft->fBottom; + if (leftTop && leftBottom) + { + if (c.sweep_lt(leftTop->fPoint, top->fPoint) && + !edge->fLeft->isLeftOf(*top)) + { + if (!rewind(activeEdges, current, leftTop, c)) + { + return false; + } + } + else if (c.sweep_lt(top->fPoint, leftTop->fPoint) && + !edge->isRightOf(*leftTop)) + { + if (!rewind(activeEdges, current, top, c)) + { + return false; + } + } + else if (c.sweep_lt(bottom->fPoint, leftBottom->fPoint) && + !edge->fLeft->isLeftOf(*bottom)) + { + if (!rewind(activeEdges, current, leftTop, c)) + { + return false; + } + } + else if (c.sweep_lt(leftBottom->fPoint, bottom->fPoint) && + !edge->isRightOf(*leftBottom)) + { + if (!rewind(activeEdges, current, top, c)) + { + return false; + } + } + } + } + if (edge->fRight) + { + Vertex* rightTop = edge->fRight->fTop; + Vertex* rightBottom = edge->fRight->fBottom; + if (rightTop && rightBottom) + { + if (c.sweep_lt(rightTop->fPoint, top->fPoint) && + !edge->fRight->isRightOf(*top)) + { + if (!rewind(activeEdges, current, rightTop, c)) + { + return false; + } + } + else if (c.sweep_lt(top->fPoint, rightTop->fPoint) && + !edge->isLeftOf(*rightTop)) + { + if (!rewind(activeEdges, current, top, c)) + { + return false; + } + } + else if (c.sweep_lt(bottom->fPoint, rightBottom->fPoint) && + !edge->fRight->isRightOf(*bottom)) + { + if (!rewind(activeEdges, current, rightTop, c)) + { + return false; + } + } + else if (c.sweep_lt(rightBottom->fPoint, bottom->fPoint) && + !edge->isLeftOf(*rightBottom)) + { + if (!rewind(activeEdges, current, top, c)) + { + return false; + } + } + } + } + return true; +} + +bool GrTriangulator::setTop(Edge* edge, + Vertex* v, + EdgeList* activeEdges, + Vertex** current, + const Comparator& c) const +{ + remove_edge_below(edge); + if (fCollectBreadcrumbTriangles) + { + fBreadcrumbList.append(fAlloc, + edge->fTop->fPoint, + edge->fBottom->fPoint, + v->fPoint, + edge->fWinding); + } + edge->fTop = v; + edge->recompute(); + edge->insertBelow(v, c); + if (!rewind_if_necessary(edge, activeEdges, current, c)) + { + return false; + } + return this->mergeCollinearEdges(edge, activeEdges, current, c); +} + +bool GrTriangulator::setBottom(Edge* edge, + Vertex* v, + EdgeList* activeEdges, + Vertex** current, + const Comparator& c) const +{ + remove_edge_above(edge); + if (fCollectBreadcrumbTriangles) + { + fBreadcrumbList.append(fAlloc, + edge->fTop->fPoint, + edge->fBottom->fPoint, + v->fPoint, + edge->fWinding); + } + edge->fBottom = v; + edge->recompute(); + edge->insertAbove(v, c); + if (!rewind_if_necessary(edge, activeEdges, current, c)) + { + return false; + } + return this->mergeCollinearEdges(edge, activeEdges, current, c); +} + +bool GrTriangulator::mergeEdgesAbove(Edge* edge, + Edge* other, + EdgeList* activeEdges, + Vertex** current, + const Comparator& c) const +{ + if (!edge || !other) + { + return false; + } + if (coincident(edge->fTop->fPoint, other->fTop->fPoint)) + { + TESS_LOG("merging coincident above edges (%g, %g) -> (%g, %g)\n", + edge->fTop->fPoint.x, + edge->fTop->fPoint.y, + edge->fBottom->fPoint.x, + edge->fBottom->fPoint.y); + if (!rewind(activeEdges, current, edge->fTop, c)) + { + return false; + } + other->fWinding += edge->fWinding; + edge->disconnect(); + edge->fTop = edge->fBottom = nullptr; + } + else if (c.sweep_lt(edge->fTop->fPoint, other->fTop->fPoint)) + { + if (!rewind(activeEdges, current, edge->fTop, c)) + { + return false; + } + other->fWinding += edge->fWinding; + if (!this->setBottom(edge, other->fTop, activeEdges, current, c)) + { + return false; + } + } + else + { + if (!rewind(activeEdges, current, other->fTop, c)) + { + return false; + } + edge->fWinding += other->fWinding; + if (!this->setBottom(other, edge->fTop, activeEdges, current, c)) + { + return false; + } + } + return true; +} + +bool GrTriangulator::mergeEdgesBelow(Edge* edge, + Edge* other, + EdgeList* activeEdges, + Vertex** current, + const Comparator& c) const +{ + if (!edge || !other) + { + return false; + } + if (coincident(edge->fBottom->fPoint, other->fBottom->fPoint)) + { + TESS_LOG("merging coincident below edges (%g, %g) -> (%g, %g)\n", + edge->fTop->fPoint.x, + edge->fTop->fPoint.y, + edge->fBottom->fPoint.x, + edge->fBottom->fPoint.y); + if (!rewind(activeEdges, current, edge->fTop, c)) + { + return false; + } + other->fWinding += edge->fWinding; + edge->disconnect(); + edge->fTop = edge->fBottom = nullptr; + } + else if (c.sweep_lt(edge->fBottom->fPoint, other->fBottom->fPoint)) + { + if (!rewind(activeEdges, current, other->fTop, c)) + { + return false; + } + edge->fWinding += other->fWinding; + if (!this->setTop(other, edge->fBottom, activeEdges, current, c)) + { + return false; + } + } + else + { + if (!rewind(activeEdges, current, edge->fTop, c)) + { + return false; + } + other->fWinding += edge->fWinding; + if (!this->setTop(edge, other->fBottom, activeEdges, current, c)) + { + return false; + } + } + return true; +} + +static bool top_collinear(Edge* left, Edge* right) +{ + if (!left || !right) + { + return false; + } + return left->fTop->fPoint == right->fTop->fPoint || + !left->isLeftOf(*right->fTop) || !right->isRightOf(*left->fTop); +} + +static bool bottom_collinear(Edge* left, Edge* right) +{ + if (!left || !right) + { + return false; + } + return left->fBottom->fPoint == right->fBottom->fPoint || + !left->isLeftOf(*right->fBottom) || + !right->isRightOf(*left->fBottom); +} + +bool GrTriangulator::mergeCollinearEdges(Edge* edge, + EdgeList* activeEdges, + Vertex** current, + const Comparator& c) const +{ + for (;;) + { + if (top_collinear(edge->fPrevEdgeAbove, edge)) + { + if (!this->mergeEdgesAbove(edge->fPrevEdgeAbove, + edge, + activeEdges, + current, + c)) + { + return false; + } + } + else if (top_collinear(edge, edge->fNextEdgeAbove)) + { + if (!this->mergeEdgesAbove(edge->fNextEdgeAbove, + edge, + activeEdges, + current, + c)) + { + return false; + } + } + else if (bottom_collinear(edge->fPrevEdgeBelow, edge)) + { + if (!this->mergeEdgesBelow(edge->fPrevEdgeBelow, + edge, + activeEdges, + current, + c)) + { + return false; + } + } + else if (bottom_collinear(edge, edge->fNextEdgeBelow)) + { + if (!this->mergeEdgesBelow(edge->fNextEdgeBelow, + edge, + activeEdges, + current, + c)) + { + return false; + } + } + else + { + break; + } + } + assert(!top_collinear(edge->fPrevEdgeAbove, edge)); + assert(!top_collinear(edge, edge->fNextEdgeAbove)); + assert(!bottom_collinear(edge->fPrevEdgeBelow, edge)); + assert(!bottom_collinear(edge, edge->fNextEdgeBelow)); + return true; +} + +GrTriangulator::BoolFail GrTriangulator::splitEdge(Edge* edge, + Vertex* v, + EdgeList* activeEdges, + Vertex** current, + const Comparator& c) +{ + if (!edge->fTop || !edge->fBottom || v == edge->fTop || v == edge->fBottom) + { + return BoolFail::kFalse; + } + TESS_LOG("splitting edge (%g -> %g) at vertex %g (%g, %g)\n", + edge->fTop->fID, + edge->fBottom->fID, + v->fID, + v->fPoint.x, + v->fPoint.y); + Vertex* top; + Vertex* bottom; + int winding = edge->fWinding; + // Theoretically, and ideally, the edge betwee p0 and p1 is being split by + // v, and v is "between" the segment end points according to c. This is + // equivalent to p0 < v < p1. Unfortunately, if v was clamped/rounded this + // relation doesn't always hold. + if (c.sweep_lt(v->fPoint, edge->fTop->fPoint)) + { + // Actually "v < p0 < p1": update 'edge' to be v->p1 and add v->p0. We + // flip the winding on the new edge so that it winds as if it were + // p0->v. + top = v; + bottom = edge->fTop; + winding *= -1; + if (!this->setTop(edge, v, activeEdges, current, c)) + { + return BoolFail::kFail; + } + } + else if (c.sweep_lt(edge->fBottom->fPoint, v->fPoint)) + { + // Actually "p0 < p1 < v": update 'edge' to be p0->v and add p1->v. We + // flip the winding on the new edge so that it winds as if it were + // v->p1. + top = edge->fBottom; + bottom = v; + winding *= -1; + if (!this->setBottom(edge, v, activeEdges, current, c)) + { + return BoolFail::kFail; + } + } + else + { + // The ideal case, "p0 < v < p1": update 'edge' to be p0->v and add + // v->p1. Original winding is valid for both edges. + top = v; + bottom = edge->fBottom; + if (!this->setBottom(edge, v, activeEdges, current, c)) + { + return BoolFail::kFail; + } + } + Edge* newEdge = this->allocateEdge(top, bottom, winding, edge->fType); + newEdge->insertBelow(top, c); + newEdge->insertAbove(bottom, c); + if (!this->mergeCollinearEdges(newEdge, activeEdges, current, c)) + { + return BoolFail::kFail; + } + return BoolFail::kTrue; +} + +GrTriangulator::BoolFail GrTriangulator::intersectEdgePair( + Edge* left, + Edge* right, + EdgeList* activeEdges, + Vertex** current, + const Comparator& c) +{ + if (!left->fTop || !left->fBottom || !right->fTop || !right->fBottom) + { + return BoolFail::kFalse; + } + if (left->fTop == right->fTop || left->fBottom == right->fBottom) + { + return BoolFail::kFalse; + } + + // Check if the lines intersect as determined by isLeftOf and isRightOf, + // since that is the source of ground truth. It may suggest an intersection + // even if Edge::intersect() did not have the precision to check it. In this + // case we are explicitly correcting the edge topology to match the + // sided-ness checks. + Edge* split = nullptr; + Vertex* splitAt = nullptr; + if (c.sweep_lt(left->fTop->fPoint, right->fTop->fPoint)) + { + if (!left->isLeftOf(*right->fTop)) + { + split = left; + splitAt = right->fTop; + } + } + else + { + if (!right->isRightOf(*left->fTop)) + { + split = right; + splitAt = left->fTop; + } + } + if (c.sweep_lt(right->fBottom->fPoint, left->fBottom->fPoint)) + { + if (!left->isLeftOf(*right->fBottom)) + { + split = left; + splitAt = right->fBottom; + } + } + else + { + if (!right->isRightOf(*left->fBottom)) + { + split = right; + splitAt = left->fBottom; + } + } + + if (!split) + { + return BoolFail::kFalse; + } + + // Rewind to the top of the edge that is "moving" since this topology + // correction can change the geometry of the split edge. + if (!rewind(activeEdges, current, split->fTop, c)) + { + return BoolFail::kFail; + } + return this->splitEdge(split, splitAt, activeEdges, current, c); +} + +Edge* GrTriangulator::makeConnectingEdge(Vertex* prev, + Vertex* next, + EdgeType type, + const Comparator& c, + int windingScale) +{ + if (!prev || !next || prev->fPoint == next->fPoint) + { + return nullptr; + } + Edge* edge = this->makeEdge(prev, next, type, c); + edge->insertBelow(edge->fTop, c); + edge->insertAbove(edge->fBottom, c); + edge->fWinding *= windingScale; + this->mergeCollinearEdges(edge, nullptr, nullptr, c); + return edge; +} + +void GrTriangulator::mergeVertices(Vertex* src, + Vertex* dst, + VertexList* mesh, + const Comparator& c) const +{ + TESS_LOG("found coincident verts at %g, %g; merging %g into %g\n", + src->fPoint.x, + src->fPoint.y, + src->fID, + dst->fID); + dst->fAlpha = std::max(src->fAlpha, dst->fAlpha); + if (src->fPartner) + { + src->fPartner->fPartner = dst; + } + while (Edge* edge = src->fFirstEdgeAbove) + { + std::ignore = this->setBottom(edge, dst, nullptr, nullptr, c); + } + while (Edge* edge = src->fFirstEdgeBelow) + { + std::ignore = this->setTop(edge, dst, nullptr, nullptr, c); + } + mesh->remove(src); + dst->fSynthetic = true; +} + +Vertex* GrTriangulator::makeSortedVertex(const Vec2D& p, + uint8_t alpha, + VertexList* mesh, + Vertex* reference, + const Comparator& c) const +{ + Vertex* prevV = reference; + while (prevV && c.sweep_lt(p, prevV->fPoint)) + { + prevV = prevV->fPrev; + } + Vertex* nextV = prevV ? prevV->fNext : mesh->fHead; + while (nextV && c.sweep_lt(nextV->fPoint, p)) + { + prevV = nextV; + nextV = nextV->fNext; + } + Vertex* v; + if (prevV && coincident(prevV->fPoint, p)) + { + v = prevV; + } + else if (nextV && coincident(nextV->fPoint, p)) + { + v = nextV; + } + else + { + v = fAlloc->make(p, alpha); +#if TRIANGULATOR_LOGGING + if (!prevV) + { + v->fID = mesh->fHead->fID - 1.0f; + } + else if (!nextV) + { + v->fID = mesh->fTail->fID + 1.0f; + } + else + { + v->fID = (prevV->fID + nextV->fID) * 0.5f; + } +#endif + mesh->insert(v, prevV, nextV); + } + return v; +} + +// Clamps x and y coordinates independently, so the returned point will lie +// within the bounding box formed by the corners of 'min' and 'max' (although +// min/max here refer to the ordering imposed by 'c'). +static Vec2D clamp(Vec2D p, Vec2D min, Vec2D max, const Comparator& c) +{ + if (c.fDirection == Comparator::Direction::kHorizontal) + { + // With horizontal sorting, we know min.x <= max.x, but there's no + // relation between Y components unless min.x == max.x. + return {std::clamp(p.x, min.x, max.x), + min.y < max.y ? std::clamp(p.y, min.y, max.y) + : std::clamp(p.y, max.y, min.y)}; + } + else + { + // And with vertical sorting, we know Y's relation but not necessarily + // X's. + return {min.x < max.x ? std::clamp(p.x, min.x, max.x) + : std::clamp(p.x, max.x, min.x), + std::clamp(p.y, min.y, max.y)}; + } +} + +#if 0 +void GrTriangulator::computeBisector(Edge* edge1, Edge* edge2, Vertex* v) const +{ + assert(fEmitCoverage); // Edge-AA only! + Line line1 = edge1->fLine; + Line line2 = edge2->fLine; + line1.normalize(); + line2.normalize(); + double cosAngle = line1.fA * line2.fA + line1.fB * line2.fB; + if (cosAngle > 0.999) + { + return; + } + line1.fC += edge1->fWinding > 0 ? -1 : 1; + line2.fC += edge2->fWinding > 0 ? -1 : 1; + Vec2D p; + if (line1.intersect(line2, &p)) + { + uint8_t alpha = edge1->fType == EdgeType::kOuter ? 255 : 0; + v->fPartner = fAlloc->make(p, alpha); + TESS_LOG("computed bisector (%g,%g) alpha %d for vertex %g\n", p.x, p.y, alpha, v->fID); + } +} +#endif + +GrTriangulator::BoolFail GrTriangulator::checkForIntersection( + Edge* left, + Edge* right, + EdgeList* activeEdges, + Vertex** current, + VertexList* mesh, + const Comparator& c) +{ + if (!left || !right) + { + return BoolFail::kFalse; + } + Vec2D p; + uint8_t alpha; + // If we are going to call intersect, then there must be tops and bottoms. + if (!left->fTop || !left->fBottom || !right->fTop || !right->fBottom) + { + return BoolFail::kFail; + } + if (left->intersect(*right, &p, &alpha) && is_finite(p)) + { + Vertex* v; + TESS_LOG("found intersection, pt is %g, %g\n", p.x, p.y); + Vertex* top = *current; + // If the intersection point is above the current vertex, rewind to the + // vertex above the intersection. + while (top && c.sweep_lt(p, top->fPoint)) + { + top = top->fPrev; + } + + // Always clamp the intersection to lie between the vertices of each + // segment, since in theory that's where the intersection is, but in + // reality, floating point error may have computed an intersection + // beyond a vertex's component(s). + p = clamp(p, left->fTop->fPoint, left->fBottom->fPoint, c); + p = clamp(p, right->fTop->fPoint, right->fBottom->fPoint, c); + + if (coincident(p, left->fTop->fPoint)) + { + v = left->fTop; + } + else if (coincident(p, left->fBottom->fPoint)) + { + v = left->fBottom; + } + else if (coincident(p, right->fTop->fPoint)) + { + v = right->fTop; + } + else if (coincident(p, right->fBottom->fPoint)) + { + v = right->fBottom; + } + else + { + v = this->makeSortedVertex(p, alpha, mesh, top, c); +#if 0 + if (left->fTop->fPartner) + { + assert(fEmitCoverage); // Edge-AA only! + v->fSynthetic = true; + this->computeBisector(left, right, v); + } +#endif + } + if (!rewind(activeEdges, current, top ? top : v, c)) + { + return BoolFail::kFail; + } + if (this->splitEdge(left, v, activeEdges, current, c) == + BoolFail::kFail) + { + return BoolFail::kFail; + } + if (this->splitEdge(right, v, activeEdges, current, c) == + BoolFail::kFail) + { + return BoolFail::kFail; + } + v->fAlpha = std::max(v->fAlpha, alpha); + return BoolFail::kTrue; + } + return this->intersectEdgePair(left, right, activeEdges, current, c); +} + +void GrTriangulator::sanitizeContours(VertexList* contours, + int contourCnt) const +{ + for (VertexList* contour = contours; contourCnt > 0; + --contourCnt, ++contour) + { + if (contour->fHead == nullptr) + { + continue; // empty + } + + Vertex* prev = contour->fTail; + prev->fPoint.x = double_to_clamped_scalar((double)prev->fPoint.x); + prev->fPoint.y = double_to_clamped_scalar((double)prev->fPoint.y); +#if 0 + if (fRoundVerticesToQuarterPixel) + { + round(&prev->fPoint); + } +#endif + for (Vertex* v = contour->fHead; v;) + { + v->fPoint.x = double_to_clamped_scalar((double)v->fPoint.x); + v->fPoint.y = double_to_clamped_scalar((double)v->fPoint.y); +#if 0 + if (fRoundVerticesToQuarterPixel) + { + round(&v->fPoint); + } +#endif + Vertex* next = v->fNext; + Vertex* nextWrap = next ? next : contour->fHead; + if (coincident(prev->fPoint, v->fPoint)) + { + TESS_LOG("vertex %g,%g coincident; removing\n", + v->fPoint.x, + v->fPoint.y); + contour->remove(v); + } + else if (!is_finite(v->fPoint)) + { + TESS_LOG("vertex %g,%g non-finite; removing\n", + v->fPoint.x, + v->fPoint.y); + contour->remove(v); + } + else if (!fPreserveCollinearVertices && + Line(prev->fPoint, nextWrap->fPoint).dist(v->fPoint) == + 0.0) + { + TESS_LOG("vertex %g,%g collinear; removing\n", + v->fPoint.x, + v->fPoint.y); + contour->remove(v); + } + else + { + prev = v; + } + v = next; + } + } +} + +bool GrTriangulator::mergeCoincidentVertices(VertexList* mesh, + const Comparator& c) const +{ + if (!mesh->fHead) + { + return false; + } + bool merged = false; + for (Vertex* v = mesh->fHead->fNext; v;) + { + Vertex* next = v->fNext; + if (c.sweep_lt(v->fPoint, v->fPrev->fPoint)) + { + v->fPoint = v->fPrev->fPoint; + } + if (coincident(v->fPrev->fPoint, v->fPoint)) + { + this->mergeVertices(v, v->fPrev, mesh, c); + merged = true; + } + v = next; + } + return merged; +} + +// Stage 2: convert the contours to a mesh of edges connecting the vertices. + +void GrTriangulator::buildEdges(VertexList* contours, + int contourCnt, + VertexList* mesh, + const Comparator& c) +{ + for (VertexList* contour = contours; contourCnt > 0; + --contourCnt, ++contour) + { + Vertex* prev = contour->fTail; + for (Vertex* v = contour->fHead; v;) + { + Vertex* next = v->fNext; + this->makeConnectingEdge(prev, v, EdgeType::kInner, c); + mesh->append(v); + prev = v; + v = next; + } + } +} + +template +static void sorted_merge(VertexList* front, + VertexList* back, + VertexList* result) +{ + Vertex* a = front->fHead; + Vertex* b = back->fHead; + while (a && b) + { + if (sweep_lt(a->fPoint, b->fPoint)) + { + front->remove(a); + result->append(a); + a = front->fHead; + } + else + { + back->remove(b); + result->append(b); + b = back->fHead; + } + } + result->append(*front); + result->append(*back); +} + +void GrTriangulator::SortedMerge(VertexList* front, + VertexList* back, + VertexList* result, + const Comparator& c) +{ + if (c.fDirection == Comparator::Direction::kHorizontal) + { + sorted_merge(front, back, result); + } + else + { + sorted_merge(front, back, result); + } +#if TRIANGULATOR_LOGGING + float id = 0.0f; + for (Vertex* v = result->fHead; v; v = v->fNext) + { + v->fID = id++; + } +#endif +} + +// Stage 3: sort the vertices by increasing sweep direction. + +template static void merge_sort(VertexList* vertices) +{ + Vertex* slow = vertices->fHead; + if (!slow) + { + return; + } + Vertex* fast = slow->fNext; + if (!fast) + { + return; + } + do + { + fast = fast->fNext; + if (fast) + { + fast = fast->fNext; + slow = slow->fNext; + } + } while (fast); + VertexList front(vertices->fHead, slow); + VertexList back(slow->fNext, vertices->fTail); + front.fTail->fNext = back.fHead->fPrev = nullptr; + + merge_sort(&front); + merge_sort(&back); + + vertices->fHead = vertices->fTail = nullptr; + sorted_merge(&front, &back, vertices); +} + +#if TRIANGULATOR_LOGGING +void VertexList::dump() const +{ + for (Vertex* v = fHead; v; v = v->fNext) + { + TESS_LOG("vertex %g (%g, %g) alpha %d", + v->fID, + v->fPoint.x, + v->fPoint.y, + v->fAlpha); + if (Vertex* p = v->fPartner) + { + TESS_LOG(", partner %g (%g, %g) alpha %d\n", + p->fID, + p->fPoint.x, + p->fPoint.y, + p->fAlpha); + } + else + { + TESS_LOG(", null partner\n"); + } + for (Edge* e = v->fFirstEdgeAbove; e; e = e->fNextEdgeAbove) + { + TESS_LOG(" edge %g -> %g, winding %d\n", + e->fTop->fID, + e->fBottom->fID, + e->fWinding); + } + for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) + { + TESS_LOG(" edge %g -> %g, winding %d\n", + e->fTop->fID, + e->fBottom->fID, + e->fWinding); + } + } +} +#endif + +#ifdef SK_DEBUG +static void validate_edge_pair(Edge* left, Edge* right, const Comparator& c) +{ + if (!left || !right) + { + return; + } + if (left->fTop == right->fTop) + { + assert(left->isLeftOf(*right->fBottom)); + assert(right->isRightOf(*left->fBottom)); + } + else if (c.sweep_lt(left->fTop->fPoint, right->fTop->fPoint)) + { + assert(left->isLeftOf(*right->fTop)); + } + else + { + assert(right->isRightOf(*left->fTop)); + } + if (left->fBottom == right->fBottom) + { + assert(left->isLeftOf(*right->fTop)); + assert(right->isRightOf(*left->fTop)); + } + else if (c.sweep_lt(right->fBottom->fPoint, left->fBottom->fPoint)) + { + assert(left->isLeftOf(*right->fBottom)); + } + else + { + assert(right->isRightOf(*left->fBottom)); + } +} + +static void validate_edge_list(EdgeList* edges, const Comparator& c) +{ + Edge* left = edges->fHead; + if (!left) + { + return; + } + for (Edge* right = left->fRight; right; right = right->fRight) + { + validate_edge_pair(left, right, c); + left = right; + } +} +#endif + +// Stage 4: Simplify the mesh by inserting new vertices at intersecting edges. + +GrTriangulator::SimplifyResult GrTriangulator::simplify(VertexList* mesh, + const Comparator& c) +{ + TESS_LOG("simplifying complex polygons\n"); + + int initialNumEdges = fNumEdges; + int numSelfIntersections = 0; + + EdgeList activeEdges; + auto result = SimplifyResult::kAlreadySimple; + for (Vertex* v = mesh->fHead; v != nullptr; v = v->fNext) + { + if (!v->isConnected()) + { + continue; + } + + // The max increase across all skps, svgs and gms with only the + // triangulating and SW path renderers enabled and with the + // triangulator's maxVerbCount set to the Chrome value is 17x. + if (fNumEdges > 170 * initialNumEdges) + { + return SimplifyResult::kFailed; + } + + // In pathological cases, a path can intersect itself millions of times. + // After 500,000 self-intersections are found, reject the path. + if (numSelfIntersections > 500000) + { + return SimplifyResult::kFailed; + } + + Edge* leftEnclosingEdge; + Edge* rightEnclosingEdge; + bool restartChecks; + do + { + TESS_LOG("\nvertex %g: (%g,%g), alpha %d\n", + v->fID, + v->fPoint.x, + v->fPoint.y, + v->fAlpha); + restartChecks = false; + FindEnclosingEdges(*v, + activeEdges, + &leftEnclosingEdge, + &rightEnclosingEdge); + v->fLeftEnclosingEdge = leftEnclosingEdge; + v->fRightEnclosingEdge = rightEnclosingEdge; + if (v->fFirstEdgeBelow) + { + for (Edge* edge = v->fFirstEdgeBelow; edge; + edge = edge->fNextEdgeBelow) + { + BoolFail l = this->checkForIntersection(leftEnclosingEdge, + edge, + &activeEdges, + &v, + mesh, + c); + if (l == BoolFail::kFail) + { + return SimplifyResult::kFailed; + } + if (l == BoolFail::kFalse) + { + BoolFail r = + this->checkForIntersection(edge, + rightEnclosingEdge, + &activeEdges, + &v, + mesh, + c); + if (r == BoolFail::kFail) + { + return SimplifyResult::kFailed; + } + if (r == BoolFail::kFalse) + { + // Neither l and r are both false. + continue; + } + } + + // Either l or r are true. + result = SimplifyResult::kFoundSelfIntersection; + restartChecks = true; + ++numSelfIntersections; + break; + } // for + } + else + { + BoolFail bf = this->checkForIntersection(leftEnclosingEdge, + rightEnclosingEdge, + &activeEdges, + &v, + mesh, + c); + if (bf == BoolFail::kFail) + { + return SimplifyResult::kFailed; + } + if (bf == BoolFail::kTrue) + { + result = SimplifyResult::kFoundSelfIntersection; + restartChecks = true; + ++numSelfIntersections; + } + } + } while (restartChecks); +#ifdef SK_DEBUG + validate_edge_list(&activeEdges, c); +#endif + for (Edge* e = v->fFirstEdgeAbove; e; e = e->fNextEdgeAbove) + { + if (!activeEdges.remove(e)) + { + return SimplifyResult::kFailed; + } + } + Edge* leftEdge = leftEnclosingEdge; + for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) + { + activeEdges.insert(e, leftEdge); + leftEdge = e; + } + } + assert(!activeEdges.fHead && !activeEdges.fTail); + return result; +} + +// Stage 5: Tessellate the simplified mesh into monotone polygons. + +std::tuple GrTriangulator::tessellate(const VertexList& vertices, + const Comparator&) +{ + TESS_LOG("\ntessellating simple polygons\n"); + EdgeList activeEdges; + Poly* polys = nullptr; + for (Vertex* v = vertices.fHead; v != nullptr; v = v->fNext) + { + if (!v->isConnected()) + { + continue; + } +#if TRIANGULATOR_LOGGING + TESS_LOG("\nvertex %g: (%g,%g), alpha %d\n", + v->fID, + v->fPoint.x, + v->fPoint.y, + v->fAlpha); +#endif + Edge* leftEnclosingEdge; + Edge* rightEnclosingEdge; + FindEnclosingEdges(*v, + activeEdges, + &leftEnclosingEdge, + &rightEnclosingEdge); + Poly* leftPoly; + Poly* rightPoly; + if (v->fFirstEdgeAbove) + { + leftPoly = v->fFirstEdgeAbove->fLeftPoly; + rightPoly = v->fLastEdgeAbove->fRightPoly; + } + else + { + leftPoly = + leftEnclosingEdge ? leftEnclosingEdge->fRightPoly : nullptr; + rightPoly = + rightEnclosingEdge ? rightEnclosingEdge->fLeftPoly : nullptr; + } +#if TRIANGULATOR_LOGGING + TESS_LOG("edges above:\n"); + for (Edge* e = v->fFirstEdgeAbove; e; e = e->fNextEdgeAbove) + { + TESS_LOG("%g -> %g, lpoly %d, rpoly %d\n", + e->fTop->fID, + e->fBottom->fID, + e->fLeftPoly ? e->fLeftPoly->fID : -1, + e->fRightPoly ? e->fRightPoly->fID : -1); + } + TESS_LOG("edges below:\n"); + for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) + { + TESS_LOG("%g -> %g, lpoly %d, rpoly %d\n", + e->fTop->fID, + e->fBottom->fID, + e->fLeftPoly ? e->fLeftPoly->fID : -1, + e->fRightPoly ? e->fRightPoly->fID : -1); + } +#endif + if (v->fFirstEdgeAbove) + { + if (leftPoly) + { + leftPoly = + leftPoly->addEdge(v->fFirstEdgeAbove, kRight_Side, this); + } + if (rightPoly) + { + rightPoly = + rightPoly->addEdge(v->fLastEdgeAbove, kLeft_Side, this); + } + for (Edge* e = v->fFirstEdgeAbove; e != v->fLastEdgeAbove; + e = e->fNextEdgeAbove) + { + Edge* rightEdge = e->fNextEdgeAbove; + activeEdges.remove(e); + if (e->fRightPoly) + { + e->fRightPoly->addEdge(e, kLeft_Side, this); + } + if (rightEdge->fLeftPoly && + rightEdge->fLeftPoly != e->fRightPoly) + { + rightEdge->fLeftPoly->addEdge(e, kRight_Side, this); + } + } + activeEdges.remove(v->fLastEdgeAbove); + if (!v->fFirstEdgeBelow) + { + if (leftPoly && rightPoly && leftPoly != rightPoly) + { + assert(leftPoly->fPartner == nullptr && + rightPoly->fPartner == nullptr); + rightPoly->fPartner = leftPoly; + leftPoly->fPartner = rightPoly; + } + } + } + if (v->fFirstEdgeBelow) + { + if (!v->fFirstEdgeAbove) + { + if (leftPoly && rightPoly) + { + if (leftPoly == rightPoly) + { + if (leftPoly->fTail && + leftPoly->fTail->fSide == kLeft_Side) + { + leftPoly = this->makePoly(&polys, + leftPoly->lastVertex(), + leftPoly->fWinding); + leftEnclosingEdge->fRightPoly = leftPoly; + } + else + { + rightPoly = this->makePoly(&polys, + rightPoly->lastVertex(), + rightPoly->fWinding); + rightEnclosingEdge->fLeftPoly = rightPoly; + } + } + Edge* join = this->allocateEdge(leftPoly->lastVertex(), + v, + 1, + EdgeType::kInner); + leftPoly = leftPoly->addEdge(join, kRight_Side, this); + rightPoly = rightPoly->addEdge(join, kLeft_Side, this); + } + } + Edge* leftEdge = v->fFirstEdgeBelow; + leftEdge->fLeftPoly = leftPoly; + activeEdges.insert(leftEdge, leftEnclosingEdge); + for (Edge* rightEdge = leftEdge->fNextEdgeBelow; rightEdge; + rightEdge = rightEdge->fNextEdgeBelow) + { + activeEdges.insert(rightEdge, leftEdge); + int winding = + leftEdge->fLeftPoly ? leftEdge->fLeftPoly->fWinding : 0; + winding += leftEdge->fWinding; + if (winding != 0) + { + Poly* poly = this->makePoly(&polys, v, winding); + leftEdge->fRightPoly = rightEdge->fLeftPoly = poly; + } + leftEdge = rightEdge; + } + v->fLastEdgeBelow->fRightPoly = rightPoly; + } +#if TRIANGULATOR_LOGGING + TESS_LOG("\nactive edges:\n"); + for (Edge* e = activeEdges.fHead; e != nullptr; e = e->fRight) + { + TESS_LOG("%g -> %g, lpoly %d, rpoly %d\n", + e->fTop->fID, + e->fBottom->fID, + e->fLeftPoly ? e->fLeftPoly->fID : -1, + e->fRightPoly ? e->fRightPoly->fID : -1); + } +#endif + } + return {polys, true}; +} + +// This is a driver function that calls stages 2-5 in turn. + +void GrTriangulator::contoursToMesh(VertexList* contours, + int contourCnt, + VertexList* mesh, + const Comparator& c) +{ +#if TRIANGULATOR_LOGGING + for (int i = 0; i < contourCnt; ++i) + { + Vertex* v = contours[i].fHead; + assert(v); + TESS_LOG("path.moveTo(%20.20g, %20.20g);\n", v->fPoint.x, v->fPoint.y); + for (v = v->fNext; v; v = v->fNext) + { + TESS_LOG("path.lineTo(%20.20g, %20.20g);\n", + v->fPoint.x, + v->fPoint.y); + } + } +#endif + this->sanitizeContours(contours, contourCnt); + this->buildEdges(contours, contourCnt, mesh, c); +} + +void GrTriangulator::SortMesh(VertexList* vertices, const Comparator& c) +{ + if (!vertices || !vertices->fHead) + { + return; + } + + // Sort vertices in Y (secondarily in X). + if (c.fDirection == Comparator::Direction::kHorizontal) + { + merge_sort(vertices); + } + else + { + merge_sort(vertices); + } +#if TRIANGULATOR_LOGGING + for (Vertex* v = vertices->fHead; v != nullptr; v = v->fNext) + { + static float gID = 0.0f; + v->fID = gID++; + } +#endif +} + +std::tuple GrTriangulator::contoursToPolys(VertexList* contours, + int contourCnt) +{ + Comparator c(fDirection); + VertexList mesh; + this->contoursToMesh(contours, contourCnt, &mesh, c); + TESS_LOG("\ninitial mesh:\n"); + DUMP_MESH(mesh); + SortMesh(&mesh, c); + TESS_LOG("\nsorted mesh:\n"); + DUMP_MESH(mesh); + this->mergeCoincidentVertices(&mesh, c); + TESS_LOG("\nsorted+merged mesh:\n"); + DUMP_MESH(mesh); + auto result = this->simplify(&mesh, c); + if (result == SimplifyResult::kFailed) + { + return {nullptr, false}; + } + TESS_LOG("\nsimplified mesh:\n"); + DUMP_MESH(mesh); + return this->tessellate(mesh, c); +} + +// Stage 6: Triangulate the monotone polygons into a vertex buffer. +size_t GrTriangulator::polysToTriangles( + Poly* polys, + FillRule overrideFillType, + uint16_t pathID, + bool reverseTriangles, + bool negateWinding, + gpu::WindingFaces windingFaces, + gpu::WriteOnlyMappedMemory* mappedMemory) const +{ + size_t vertexCount = 0; + for (Poly* poly = polys; poly; poly = poly->fNext) + { + if (apply_fill_type(overrideFillType, poly)) + { + vertexCount += emitPoly(poly, + pathID, + reverseTriangles, + negateWinding, + windingFaces, + mappedMemory); + } + } + return vertexCount; +} + +static int get_contour_count(const RawPath& path, float tolerance) +{ + // We could theoretically be more aggressive about not counting empty + // contours, but we need to actually match the exact number of contour + // linked lists the tessellator will create later on. + int contourCnt = 1; + bool hasPoints = false; + + bool first = true; + for (auto [verb, pts] : path) + { + switch (verb) + { + case PathVerb::move: + if (!first) + { + ++contourCnt; + } + [[fallthrough]]; + case PathVerb::line: + case PathVerb::quad: + case PathVerb::cubic: + hasPoints = true; + break; + default: + break; + } + first = false; + } + if (!hasPoints) + { + return 0; + } + return contourCnt; +} + +std::tuple GrTriangulator::pathToPolys(const RawPath& path, + float tolerance, + const AABB& clipBounds, + bool* isLinear) +{ + int contourCnt = get_contour_count(path, tolerance); + if (contourCnt <= 0) + { + *isLinear = true; + return {nullptr, true}; + } + +#if 0 + if (SkPathFillType_IsInverse(fPath.getFillType())) + { + contourCnt++; + } +#endif + std::unique_ptr contours(new VertexList[contourCnt]); + + this->pathToContours(path, tolerance, clipBounds, contours.get(), isLinear); + return this->contoursToPolys(contours.get(), contourCnt); +} + +int64_t GrTriangulator::CountPoints(Poly* polys, FillRule overrideFillType) +{ + int64_t count = 0; + for (Poly* poly = polys; poly; poly = poly->fNext) + { + if (apply_fill_type(overrideFillType, poly) && poly->fCount >= 3) + { + count += (poly->fCount - 2) * (TRIANGULATOR_WIREFRAME ? 6 : 3); + } + } + return count; +} + +// Stage 6: Triangulate the monotone polygons into a vertex buffer. + +size_t GrTriangulator::countMaxTriangleVertices(Poly* polys) const +{ + return math::lossless_numeric_cast(CountPoints(polys, fFillRule)); +} + +size_t GrTriangulator::polysToTriangles( + Poly* polys, + uint64_t maxVertexCount, + uint16_t pathID, + bool reverseTriangles, + bool negateWinding, + gpu::WindingFaces windingFaces, + gpu::WriteOnlyMappedMemory* mappedMemory) const +{ + if (0 == maxVertexCount || + maxVertexCount > std::numeric_limits::max()) + { + return 0; + } + + size_t actualCount = polysToTriangles(polys, + fFillRule, + pathID, + reverseTriangles, + negateWinding, + windingFaces, + mappedMemory); + assert(actualCount <= maxVertexCount); + return actualCount; +} +} // namespace rive + +#endif // SK_ENABLE_OPTIMIZE_SIZE diff --git a/third_party/rive_renderer/source/gr_triangulator.hpp b/third_party/rive_renderer/source/gr_triangulator.hpp new file mode 100644 index 0000000..f6b04df --- /dev/null +++ b/third_party/rive_renderer/source/gr_triangulator.hpp @@ -0,0 +1,696 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Initial import from + * skia:c2a399a74da523ec445f1202367764d04b5df2ec@src/gpu/ganesh/geometry/GrTriangulator.h + * + * Copyright 2023 Rive + */ + +#ifndef GrTriangulator_DEFINED +#define GrTriangulator_DEFINED + +#if !defined(SK_ENABLE_OPTIMIZE_SIZE) + +#include "rive/math/raw_path.hpp" +#include "rive/math/vec2d.hpp" +#include "rive/math/aabb.hpp" +#include "rive/renderer/gpu.hpp" +#include "rive/renderer/trivial_block_allocator.hpp" + +namespace rive +{ +#define TRIANGULATOR_LOGGING 0 +#define TRIANGULATOR_WIREFRAME 0 + +/** + * Provides utility functions for converting paths to a collection of triangles. + */ +class GrTriangulator +{ +public: + constexpr static int kArenaDefaultChunkSize = 16 * 1024; + + // Enums used by GrTriangulator internals. + typedef enum + { + kLeft_Side, + kRight_Side + } Side; + + enum class EdgeType + { + kInner, + kOuter, + kConnector + }; + + // Structs used by GrTriangulator internals. + struct Vertex; + struct VertexList; + struct Line; + struct Edge; + struct EdgeList; + struct MonotonePoly; + struct Poly; + + struct Comparator + { + enum class Direction + { + kVertical, + kHorizontal + }; + Comparator(Direction direction) : fDirection(direction) {} + bool sweep_lt(const Vec2D& a, const Vec2D& b) const; + Direction fDirection; + }; + +protected: + GrTriangulator(Comparator::Direction direction, + FillRule fillRule, + TrivialBlockAllocator* alloc) : + fDirection(direction), fFillRule(fillRule), fAlloc(alloc) + {} + + // There are six stages to the basic algorithm: + // + // 1) Linearize the path contours into piecewise linear segments: + void pathToContours(const RawPath& path, + float tolerance, + const AABB& clipBounds, + VertexList* contours, + bool* isLinear) const; + + // 2) Build a mesh of edges connecting the vertices: + void contoursToMesh(VertexList* contours, + int contourCnt, + VertexList* mesh, + const Comparator&); + + // 3) Sort the vertices in Y (and secondarily in X): + static void SortedMerge(VertexList* front, + VertexList* back, + VertexList* result, + const Comparator&); + static void SortMesh(VertexList* vertices, const Comparator&); + + // 4) Simplify the mesh by inserting new vertices at intersecting edges: + enum class SimplifyResult + { + kFailed, + kAlreadySimple, + kFoundSelfIntersection + }; + + enum class BoolFail + { + kFalse, + kTrue, + kFail + }; + + [[nodiscard]] SimplifyResult simplify(VertexList* mesh, const Comparator&); + + // 5) Tessellate the simplified mesh into monotone polygons: + virtual std::tuple tessellate(const VertexList& vertices, + const Comparator&); + + // 6) Triangulate the monotone polygons directly into a vertex buffer: + size_t polysToTriangles( + Poly* polys, + FillRule overrideFillRule, + uint16_t pathID, + bool reverseTriangles, + bool negateWinding, + gpu::WindingFaces, + gpu::WriteOnlyMappedMemory*) const; + + // The vertex sorting in step (3) is a merge sort, since it plays well with + // the linked list of vertices (and the necessity of inserting new vertices + // on intersection). + // + // Stages (4) and (5) use an active edge list -- a list of all edges for + // which the sweep line has crossed the top vertex, but not the bottom + // vertex. It's sorted left-to-right based on the point where both edges + // are active (when both top vertices have been seen, so the "lower" top + // vertex of the two). If the top vertices are equal (shared), it's sorted + // based on the last point where both edges are active, so the "upper" + // bottom vertex. + // + // The most complex step is the simplification (4). It's based on the + // Bentley-Ottman line-sweep algorithm, but due to floating point + // inaccuracy, the intersection points are not exact and may violate the + // mesh topology or active edge list ordering. We accommodate this by + // adjusting the topology of the mesh and AEL to match the intersection + // points. This occurs in two ways: + // + // A) Intersections may cause a shortened edge to no longer be ordered with + // respect to its + // neighbouring edges at the top or bottom vertex. This is handled by + // merging the edges (mergeCollinearVertices()). + // B) Intersections may cause an edge to violate the left-to-right ordering + // of the + // active edge list. This is handled by detecting potential violations + // and rewinding the active edge list to the vertex before they occur + // (rewind() during merging, rewind_if_necessary() during splitting). + // + // The tessellation steps (5) and (6) are based on "Triangulating Simple + // Polygons and Equivalent Problems" (Fournier and Montuno); also a + // line-sweep algorithm. Note that it currently uses a linked list for the + // active edge list, rather than a 2-3 tree as the paper describes. The 2-3 + // tree gives O(lg N) lookups, but insertion and removal also become O(lg + // N). In all the test cases, it was found that the cost of frequent O(lg N) + // insertions and removals was greater than the cost of infrequent O(N) + // lookups with the linked list implementation. With the latter, all + // removals are O(1), and most insertions are O(1), since we know the + // adjacent edge in the active edge list based on the topology. Only type 2 + // vertices (see paper) require the O(N) lookups, and these are much less + // frequent. There may be other data structures worth investigating, + // however. + // + // Note that the orientation of the line sweep algorithms is determined by + // the aspect ratio of the path bounds. When the path is taller than it is + // wide, we sort vertices based on increasing Y coordinate, and secondarily + // by increasing X coordinate. When the path is wider than it is tall, we + // sort by increasing X coordinate, but secondarily by *decreasing* Y + // coordinate. This is so that the "left" and "right" orientation in the + // code remains correct (edges to the left are increasing in Y; edges to the + // right are decreasing in Y). That is, the setting rotates 90 degrees + // counterclockwise, rather that transposing. + + // Additional helpers and driver functions. + size_t emitMonotonePoly( + const MonotonePoly*, + uint16_t pathID, + bool reverseTriangles, + bool negateWinding, + gpu::WindingFaces, + gpu::WriteOnlyMappedMemory*) const; + size_t emitTriangle(Vertex* prev, + Vertex* curr, + Vertex* next, + int16_t riveWeight, + uint16_t pathID, + bool reverseTriangles, + gpu::WriteOnlyMappedMemory*) const; + size_t emitPoly(const Poly*, + uint16_t pathID, + bool reverseTriangles, + bool negateWinding, + gpu::WindingFaces, + gpu::WriteOnlyMappedMemory*) const; + + Poly* makePoly(Poly** head, Vertex* v, int winding) const; + void appendPointToContour(const Vec2D& p, VertexList* contour) const; + void appendQuadraticToContour(const Vec2D[3], + float toleranceSqd, + VertexList* contour) const; + void generateCubicPoints(const Vec2D&, + const Vec2D&, + const Vec2D&, + const Vec2D&, + float tolSqd, + VertexList* contour, + int pointsLeft) const; + bool applyFillType(int winding) const; + MonotonePoly* allocateMonotonePoly(Edge* edge, Side side, int winding); + Edge* allocateEdge(Vertex* top, Vertex* bottom, int winding, EdgeType type); + Edge* makeEdge(Vertex* prev, + Vertex* next, + EdgeType type, + const Comparator&); + [[nodiscard]] bool setTop(Edge* edge, + Vertex* v, + EdgeList* activeEdges, + Vertex** current, + const Comparator&) const; + [[nodiscard]] bool setBottom(Edge* edge, + Vertex* v, + EdgeList* activeEdges, + Vertex** current, + const Comparator&) const; + [[nodiscard]] bool mergeEdgesAbove(Edge* edge, + Edge* other, + EdgeList* activeEdges, + Vertex** current, + const Comparator&) const; + [[nodiscard]] bool mergeEdgesBelow(Edge* edge, + Edge* other, + EdgeList* activeEdges, + Vertex** current, + const Comparator&) const; + Edge* makeConnectingEdge(Vertex* prev, + Vertex* next, + EdgeType, + const Comparator&, + int windingScale = 1); + void mergeVertices(Vertex* src, + Vertex* dst, + VertexList* mesh, + const Comparator&) const; + static void FindEnclosingEdges(const Vertex& v, + const EdgeList& edges, + Edge** left, + Edge** right); + bool mergeCollinearEdges(Edge* edge, + EdgeList* activeEdges, + Vertex** current, + const Comparator&) const; + BoolFail splitEdge(Edge* edge, + Vertex* v, + EdgeList* activeEdges, + Vertex** current, + const Comparator&); + BoolFail intersectEdgePair(Edge* left, + Edge* right, + EdgeList* activeEdges, + Vertex** current, + const Comparator&); + Vertex* makeSortedVertex(const Vec2D&, + uint8_t alpha, + VertexList* mesh, + Vertex* reference, + const Comparator&) const; + void computeBisector(Edge* edge1, Edge* edge2, Vertex*) const; + BoolFail checkForIntersection(Edge* left, + Edge* right, + EdgeList* activeEdges, + Vertex** current, + VertexList* mesh, + const Comparator&); + void sanitizeContours(VertexList* contours, int contourCnt) const; + bool mergeCoincidentVertices(VertexList* mesh, const Comparator&) const; + void buildEdges(VertexList* contours, + int contourCnt, + VertexList* mesh, + const Comparator&); + std::tuple contoursToPolys(VertexList* contours, + int contourCnt); + std::tuple pathToPolys(const RawPath&, + float tolerance, + const AABB& clipBounds, + bool* isLinear); + static int64_t CountPoints(Poly* polys, FillRule overrideFillRule); + size_t countMaxTriangleVertices(Poly*) const; + + size_t polysToTriangles( + Poly*, + uint64_t maxVertexCount, + uint16_t pathID, + bool reverseTriangles, + bool negateWinding, + gpu::WindingFaces, + gpu::WriteOnlyMappedMemory*) const; + + Comparator::Direction fDirection; + FillRule fFillRule; + TrivialBlockAllocator* const fAlloc; + int fNumMonotonePolys = 0; + int fNumEdges = 0; + + // Internal control knobs. +#if 0 + bool fRoundVerticesToQuarterPixel = false; + bool fEmitCoverage = false; +#endif + bool fPreserveCollinearVertices = false; + bool fCollectBreadcrumbTriangles = false; + + // The breadcrumb triangles serve as a glue that erases T-junctions between + // a path's outer curves and its inner polygon triangulation. Drawing a + // path's outer curves, breadcrumb triangles, and inner polygon + // triangulation all together into the stencil buffer has the same identical + // rasterized effect as stenciling a classic Redbook fan. + // + // The breadcrumb triangles track all the edge splits that led from the + // original inner polygon edges to the final triangulation. Every time an + // edge splits, we emit a razor-thin breadcrumb triangle consisting of the + // edge's original endpoints and the split point. (We also add supplemental + // breadcrumb triangles to areas where abs(winding) > 1.) + // + // a + // / + // / + // / + // x <- Edge splits at x. New breadcrumb triangle is: [a, b, x]. + // / + // / + // b + // + // The opposite-direction shared edges between the triangulation and + // breadcrumb triangles should all cancel out, leaving just the set of edges + // from the original polygon. + class BreadcrumbTriangleList + { + public: + struct Node + { + Node(Vec2D a, Vec2D b, Vec2D c) : fPts{a, b, c} {} + Vec2D fPts[3]; + Node* fNext = nullptr; + }; + const Node* head() const { return fHead; } + int count() const { return fCount; } + + void append(TrivialBlockAllocator* alloc, + Vec2D a, + Vec2D b, + Vec2D c, + int winding) + { + if (a == b || a == c || b == c || winding == 0) + { + return; + } + if (winding < 0) + { + std::swap(a, b); + winding = -winding; + } + for (int i = 0; i < winding; ++i) + { + assert(fTail && !(*fTail)); + *fTail = alloc->make(a, b, c); + fTail = &(*fTail)->fNext; + } + fCount += winding; + } + + void concat(BreadcrumbTriangleList&& list) + { + assert(fTail && !(*fTail)); + if (list.fHead) + { + *fTail = list.fHead; + fTail = list.fTail; + fCount += list.fCount; + list.fHead = nullptr; + list.fTail = &list.fHead; + list.fCount = 0; + } + } + + private: + Node* fHead = nullptr; + Node** fTail = &fHead; + int fCount = 0; + }; + + mutable BreadcrumbTriangleList fBreadcrumbList; +}; + +/** + * Vertices are used in three ways: first, the path contours are converted into + * a circularly-linked list of Vertices for each contour. After edge + * construction, the same Vertices are re-ordered by the merge sort according to + * the sweep_lt comparator (usually, increasing in Y) using the same fPrev/fNext + * pointers that were used for the contours, to avoid reallocation. Finally, + * MonotonePolys are built containing a circularly-linked list of Vertices. + * (Currently, those Vertices are newly-allocated for the MonotonePolys, since + * an individual Vertex from the path mesh may belong to multiple + * MonotonePolys, so the original Vertices cannot be re-used. + */ + +struct GrTriangulator::Vertex +{ + Vertex(const Vec2D& point, uint8_t alpha) : + fPoint(point), + fPrev(nullptr), + fNext(nullptr), + fFirstEdgeAbove(nullptr), + fLastEdgeAbove(nullptr), + fFirstEdgeBelow(nullptr), + fLastEdgeBelow(nullptr), + fLeftEnclosingEdge(nullptr), + fRightEnclosingEdge(nullptr), + fPartner(nullptr), + fAlpha(alpha), + fSynthetic(false) +#if TRIANGULATOR_LOGGING + , + fID(-1.0f) +#endif + {} + Vec2D fPoint; // Vertex position + Vertex* fPrev; // Linked list of contours, then Y-sorted vertices. + Vertex* fNext; // " + Edge* fFirstEdgeAbove; // Linked list of edges above this vertex. + Edge* fLastEdgeAbove; // " + Edge* fFirstEdgeBelow; // Linked list of edges below this vertex. + Edge* fLastEdgeBelow; // " + Edge* fLeftEnclosingEdge; // Nearest edge in the AEL left of this vertex. + Edge* fRightEnclosingEdge; // Nearest edge in the AEL right of this vertex. + Vertex* fPartner; // Corresponding inner or outer vertex (for AA). + uint8_t fAlpha; + bool fSynthetic; // Is this a synthetic vertex? +#if TRIANGULATOR_LOGGING + float fID; // Identifier used for logging. +#endif + bool isConnected() const + { + return this->fFirstEdgeAbove || this->fFirstEdgeBelow; + } +}; + +struct GrTriangulator::VertexList +{ + VertexList() : fHead(nullptr), fTail(nullptr) {} + VertexList(Vertex* head, Vertex* tail) : fHead(head), fTail(tail) {} + Vertex* fHead; + Vertex* fTail; + void insert(Vertex* v, Vertex* prev, Vertex* next); + void append(Vertex* v) { insert(v, fTail, nullptr); } + void append(const VertexList& list) + { + if (!list.fHead) + { + return; + } + if (fTail) + { + fTail->fNext = list.fHead; + list.fHead->fPrev = fTail; + } + else + { + fHead = list.fHead; + } + fTail = list.fTail; + } + void prepend(Vertex* v) { insert(v, nullptr, fHead); } + void remove(Vertex* v); + void close() + { + if (fHead && fTail) + { + fTail->fNext = fHead; + fHead->fPrev = fTail; + } + } +#if TRIANGULATOR_LOGGING + void dump() const; +#endif +}; + +// A line equation in implicit form. fA * x + fB * y + fC = 0, for all points +// (x, y) on the line. +struct GrTriangulator::Line +{ + Line(double a, double b, double c) : fA(a), fB(b), fC(c) {} + Line(Vertex* p, Vertex* q) : Line(p->fPoint, q->fPoint) {} + Line(const Vec2D& p, const Vec2D& q) : + fA(static_cast(q.y) - p.y) // a = dY + , + fB(static_cast(p.x) - q.x) // b = -dX + , + fC(static_cast(p.y) * q.x - // c = cross(q, p) + static_cast(p.x) * q.y) + {} + double dist(const Vec2D& p) const { return fA * p.x + fB * p.y + fC; } + Line operator*(double v) const { return Line(fA * v, fB * v, fC * v); } + double magSq() const { return fA * fA + fB * fB; } + void normalize() + { + double len = sqrt(this->magSq()); + if (len == 0.0) + { + return; + } + double scale = 1.0f / len; + fA *= scale; + fB *= scale; + fC *= scale; + } + bool nearParallel(const Line& o) const + { + return fabs(o.fA - fA) < 0.00001 && fabs(o.fB - fB) < 0.00001; + } + + // Compute the intersection of two (infinite) Lines. + bool intersect(const Line& other, Vec2D* point) const; + double fA, fB, fC; +}; + +/** + * An Edge joins a top Vertex to a bottom Vertex. Edge ordering for the list of + * "edges above" and "edge below" a vertex as well as for the active edge list + * is handled by isLeftOf()/isRightOf(). Note that an Edge will give + * occasionally dist() != 0 for its own endpoints (because floating point). For + * speed, that case is only tested by the callers that require it (e.g., + * rewind_if_necessary()). Edges also handle checking for intersection with + * other edges. Currently, this converts the edges to the parametric form, in + * order to avoid doing a division until an intersection has been confirmed. + * This is slightly slower in the "found" case, but a lot faster in the "not + * found" case. + * + * The coefficients of the line equation stored in double precision to avoid + * catastrophic cancellation in the isLeftOf() and isRightOf() checks. Using + * doubles ensures that the result is correct in float, since it's a polynomial + * of degree 2. The intersect() function, being degree 5, is still subject to + * catastrophic cancellation. We deal with that by assuming its output may be + * incorrect, and adjusting the mesh topology to match (see comment at the top + * of this file). + */ + +struct GrTriangulator::Edge +{ + Edge(Vertex* top, Vertex* bottom, int winding, EdgeType type) : + fWinding(winding), + fTop(top), + fBottom(bottom), + fType(type), + fLeft(nullptr), + fRight(nullptr), + fPrevEdgeAbove(nullptr), + fNextEdgeAbove(nullptr), + fPrevEdgeBelow(nullptr), + fNextEdgeBelow(nullptr), + fLeftPoly(nullptr), + fRightPoly(nullptr), + fLeftPolyPrev(nullptr), + fLeftPolyNext(nullptr), + fRightPolyPrev(nullptr), + fRightPolyNext(nullptr), + fUsedInLeftPoly(false), + fUsedInRightPoly(false), + fLine(top, bottom) + {} + int fWinding; // 1 == edge goes downward; -1 = edge goes upward. + Vertex* fTop; // The top vertex in vertex-sort-order (sweep_lt). + Vertex* fBottom; // The bottom vertex in vertex-sort-order. + EdgeType fType; + Edge* fLeft; // The linked list of edges in the active edge list. + Edge* fRight; // " + Edge* fPrevEdgeAbove; // The linked list of edges in the bottom Vertex's + // "edges above". + Edge* fNextEdgeAbove; // " + Edge* fPrevEdgeBelow; // The linked list of edges in the top Vertex's "edges + // below". + Edge* fNextEdgeBelow; // " + Poly* fLeftPoly; // The Poly to the left of this edge, if any. + Poly* fRightPoly; // The Poly to the right of this edge, if any. + Edge* fLeftPolyPrev; + Edge* fLeftPolyNext; + Edge* fRightPolyPrev; + Edge* fRightPolyNext; + bool fUsedInLeftPoly; + bool fUsedInRightPoly; + Line fLine; + + double dist(const Vec2D& p) const + { + // Coerce points coincident with the vertices to have dist = 0, since + // converting from a double intersection point back to float storage + // might construct a point that's no longer on the ideal line. + return (p == fTop->fPoint || p == fBottom->fPoint) ? 0.0 + : fLine.dist(p); + } + bool isRightOf(const Vertex& v) const { return this->dist(v.fPoint) < 0.0; } + bool isLeftOf(const Vertex& v) const { return this->dist(v.fPoint) > 0.0; } + void recompute() { fLine = Line(fTop, fBottom); } + void insertAbove(Vertex*, const Comparator&); + void insertBelow(Vertex*, const Comparator&); + void disconnect(); + bool intersect(const Edge& other, Vec2D* p, uint8_t* alpha = nullptr) const; +}; + +struct GrTriangulator::EdgeList +{ + EdgeList() : fHead(nullptr), fTail(nullptr) {} + Edge* fHead; + Edge* fTail; + void insert(Edge* edge, Edge* prev, Edge* next); + bool insert(Edge* edge, Edge* prev); + void append(Edge* e) { insert(e, fTail, nullptr); } + bool remove(Edge* edge); + void removeAll() + { + while (fHead) + { + this->remove(fHead); + } + } + void close() + { + if (fHead && fTail) + { + fTail->fRight = fHead; + fHead->fLeft = fTail; + } + } + bool contains(Edge* edge) const + { + return edge->fLeft || edge->fRight || fHead == edge; + } +}; + +struct GrTriangulator::MonotonePoly +{ + MonotonePoly(Edge* edge, Side side, int winding) : + fSide(side), + fFirstEdge(nullptr), + fLastEdge(nullptr), + fPrev(nullptr), + fNext(nullptr), + fWinding(winding) + { + this->addEdge(edge); + } + Side fSide; + Edge* fFirstEdge; + Edge* fLastEdge; + MonotonePoly* fPrev; + MonotonePoly* fNext; + int fWinding; + void addEdge(Edge*); +}; + +struct GrTriangulator::Poly +{ + Poly(Vertex* v, int winding); + + Poly* addEdge(Edge* e, Side side, GrTriangulator*); + Vertex* lastVertex() const + { + return fTail ? fTail->fLastEdge->fBottom : fFirstVertex; + } + Vertex* fFirstVertex; + int fWinding; + MonotonePoly* fHead; + MonotonePoly* fTail; + Poly* fNext; + Poly* fPartner; + int fCount; +#if TRIANGULATOR_LOGGING + int fID; +#endif +}; +} // namespace rive + +#endif // SK_ENABLE_OPTIMIZE_SIZE + +#endif // GrTriangulator_DEFINED diff --git a/third_party/rive_renderer/source/gradient.cpp b/third_party/rive_renderer/source/gradient.cpp new file mode 100644 index 0000000..8d5da79 --- /dev/null +++ b/third_party/rive_renderer/source/gradient.cpp @@ -0,0 +1,193 @@ +/* + * Copyright 2022 Rive + */ + +#include "gradient.hpp" + +#include "rive/renderer/rive_render_image.hpp" + +namespace rive::gpu +{ +// Ensure the given gradient stops are in a format expected by PLS. +static bool validate_gradient_stops(const ColorInt colors[], // [count] + const float stops[], // [count] + size_t count) +{ + // Stops cannot be empty. + if (count == 0) + { + return false; + } + for (size_t i = 0; i < count; ++i) + { + // Stops must be finite, real numbers in the range [0, 1]. + if (!(0 <= stops[i] && stops[i] <= 1)) + { + return false; + } + } + for (size_t i = 1; i < count; ++i) + { + // Stops must be ordered. + if (!(stops[i - 1] <= stops[i])) + { + return false; + } + } + return true; +} + +rcp Gradient::MakeLinear(float sx, + float sy, + float ex, + float ey, + const ColorInt colors[], // [count] + const float stops[], // [count] + size_t count) +{ + if (!validate_gradient_stops(colors, stops, count)) + { + return nullptr; + } + + float2 start = {sx, sy}; + float2 end = {ex, ey}; + GradDataArray newColors(colors, count); + GradDataArray newStops(stops, count); + + // If the stops don't begin and end on 0 and 1, transform the gradient so + // they do. This allows us to take full advantage of the gradient's range of + // pixels in the texture. + float firstStop = stops[0]; + float lastStop = stops[count - 1]; + if ((firstStop != 0 || lastStop != 1) && + lastStop - firstStop > math::EPSILON) + { + // Tighten the endpoints to align with the mininum and maximum gradient + // stops. + float4 newEndpoints = + simd::precise_mix(start.xyxy, + end.xyxy, + float4{firstStop, firstStop, lastStop, lastStop}); + start = newEndpoints.xy; + end = newEndpoints.zw; + newStops[0] = 0; + newStops[count - 1] = 1; + if (count > 2) + { + // Transform the stops into the range defined by the new endpoints. + float m = 1.f / (lastStop - firstStop); + float a = -firstStop * m; + for (size_t i = 1; i < count - 1; ++i) + { + newStops[i] = stops[i] * m + a; + } + + // Clamp the interior stops so they remain monotonically increasing. + // newStops[0] and newStops[count - 1] are already 0 and 1, so this + // also ensures they stay within 0..1. + for (size_t i = 1; i < count - 1; ++i) + { + newStops[i] = fmaxf(newStops[i - 1], newStops[i]); + } + for (size_t i = count - 2; i != 0; --i) + { + newStops[i] = fminf(newStops[i], newStops[i + 1]); + } + } + assert(validate_gradient_stops(newColors.get(), newStops.get(), count)); + } + + float2 v = end - start; + v *= 1.f / simd::dot(v, v); // dot(v, end - start) == 1 + return rcp(new Gradient(gpu::PaintType::linearGradient, + std::move(newColors), + std::move(newStops), + count, + v.x, + v.y, + -simd::dot(v, start))); +} + +rcp Gradient::MakeRadial(float cx, + float cy, + float radius, + const ColorInt colors[], // [count] + const float stops[], // [count] + size_t count) +{ + if (!validate_gradient_stops(colors, stops, count)) + { + return nullptr; + } + + GradDataArray newColors(colors, count); + GradDataArray newStops(stops, count); + + // If the stops don't end on 1, scale the gradient so they do. This allows + // us to take better advantage of the gradient's full range of pixels in the + // texture. + // + // TODO: If we want to take full advantage of the gradient texture pixels, + // we could add an inner radius that specifies where t=0 begins (instead of + // assuming it begins at the center). + float lastStop = stops[count - 1]; + if (lastStop != 1 && lastStop > math::EPSILON) + { + // Update the gradient to finish on 1. + newStops[count - 1] = 1; + + // Scale the radius to align with the final stop. + radius *= lastStop; + + // Scale the stops into the range defined by the new radius. + float inverseLastStop = 1.f / lastStop; + for (size_t i = 0; i < count - 1; ++i) + { + newStops[i] = stops[i] * inverseLastStop; + } + + if (count > 1) + { + // Clamp the stops so they remain monotonically increasing. + // newStops[count - 1] is already 1, so this also ensures they stay + // within 0..1. + newStops[0] = fmaxf(0, newStops[0]); + for (size_t i = 1; i < count - 1; ++i) + { + newStops[i] = fmaxf(newStops[i - 1], newStops[i]); + } + for (size_t i = count - 2; i != -1; --i) + { + newStops[i] = fminf(newStops[i], newStops[i + 1]); + } + } + + assert(validate_gradient_stops(newColors.get(), newStops.get(), count)); + } + + return rcp(new Gradient(gpu::PaintType::radialGradient, + std::move(newColors), + std::move(newStops), + count, + cx, + cy, + radius)); +} + +bool Gradient::isOpaque() const +{ + if (m_isOpaque == gpu::TriState::unknown) + { + ColorInt allColors = ~0; + for (int i = 0; i < m_count; ++i) + { + allColors &= m_colors[i]; + } + m_isOpaque = colorAlpha(allColors) == 0xff ? gpu::TriState::yes + : gpu::TriState::no; + } + return m_isOpaque == gpu::TriState::yes; +} + +} // namespace rive::gpu diff --git a/third_party/rive_renderer/source/gradient.hpp b/third_party/rive_renderer/source/gradient.hpp new file mode 100644 index 0000000..099f12b --- /dev/null +++ b/third_party/rive_renderer/source/gradient.hpp @@ -0,0 +1,112 @@ +/* + * Copyright 2022 Rive + */ + +#pragma once + +#include "rive/renderer/gpu.hpp" +#include "rive/renderer.hpp" +#include + +namespace rive::gpu +{ +// Copies an array of colors or stops for a gradient. +// Stores the data locally if there are 4 values or fewer. +// Spills onto the heap if there are >4 values. +template class GradDataArray +{ +public: + static_assert(std::is_pod_v); + + GradDataArray(const T data[], size_t count) + { + m_data = + count <= m_localData.size() ? m_localData.data() : new T[count]; + memcpy(m_data, data, count * sizeof(T)); + } + + GradDataArray(GradDataArray&& other) + { + if (other.m_data == other.m_localData.data()) + { + m_localData = other.m_localData; + m_data = m_localData.data(); + } + else + { + m_data = other.m_data; + other.m_data = + other.m_localData.data(); // Don't delete[] other.m_data. + } + } + + ~GradDataArray() + { + if (m_data != m_localData.data()) + { + delete[] m_data; + } + } + + const T* get() const { return m_data; } + const T operator[](size_t i) const { return m_data[i]; } + T& operator[](size_t i) { return m_data[i]; } + +private: + std::array m_localData; + T* m_data; +}; + +// RenderShader implementation for Rive's pixel local storage renderer. +class Gradient : public LITE_RTTI_OVERRIDE(RenderShader, Gradient) +{ +public: + static rcp MakeLinear(float sx, + float sy, + float ex, + float ey, + const ColorInt colors[], // [count] + const float stops[], // [count] + size_t count); + + static rcp MakeRadial(float cx, + float cy, + float radius, + const ColorInt colors[], // [count] + const float stops[], // [count] + size_t count); + + PaintType paintType() const { return m_paintType; } + const float* coeffs() const { return m_coeffs.data(); } + const ColorInt* colors() const { return m_colors.get(); } + const float* stops() const { return m_stops.get(); } + size_t count() const { return m_count; } + bool isOpaque() const; + +private: + Gradient(PaintType paintType, + GradDataArray&& colors, // [count] + GradDataArray&& stops, // [count] + size_t count, + float coeffX, + float coeffY, + float coeffZ) : + m_paintType(paintType), + m_colors(std::move(colors)), + m_stops(std::move(stops)), + m_count(count), + m_coeffs{coeffX, coeffY, coeffZ} + { + assert(paintType == gpu::PaintType::linearGradient || + paintType == gpu::PaintType::radialGradient); + } + + PaintType m_paintType; // Specifically, linearGradient or radialGradient. + GradDataArray m_colors; + GradDataArray m_stops; + size_t m_count; + std::array m_coeffs; + mutable gpu::TriState m_isOpaque = gpu::TriState::unknown; +}; + +} // namespace rive::gpu diff --git a/third_party/rive_renderer/source/intersection_board.cpp b/third_party/rive_renderer/source/intersection_board.cpp new file mode 100644 index 0000000..827823d --- /dev/null +++ b/third_party/rive_renderer/source/intersection_board.cpp @@ -0,0 +1,287 @@ +/* + * Copyright 2024 Rive + */ + +#include "intersection_board.hpp" + +#include "rive/math/math_types.hpp" + +#if !SIMD_NATIVE_GVEC && \ + (defined(__SSE2__) || defined(_M_AMD64) || defined(_M_X64)) +// MSVC doesn't get codegen for the inner loop. Provide direct SSE intrinsics. +#include +#define FALLBACK_ON_SSE2_INTRINSICS +#else +#endif + +namespace rive::gpu +{ +void IntersectionTile::reset(int left, int top, int16_t baselineGroupIndex) +{ + // Since we mask non-intersecting groupIndices to zero, the "mask and max" + // algorithm is only correct for positive values. (baselineGroupIndex is + // only signed because SSE doesn't have an unsigned max instruction.) + assert(baselineGroupIndex >= 0); + m_topLeft = {left, top, left, top}; + m_baselineGroupIndex = baselineGroupIndex; + m_maxGroupIndex = baselineGroupIndex; + m_edges.clear(); + m_groupIndices.clear(); + m_rectangleCount = 0; +} + +void IntersectionTile::addRectangle(int4 ltrb, int16_t groupIndex) +{ + assert(simd::all(ltrb.xy < ltrb.zw)); // Ensure ltrb isn't zero or negative. + // Ensure this rectangle preserves the integrity of our list. + assert(groupIndex > + simd::reduce_max(findMaxIntersectingGroupIndex(ltrb, 0))); + assert(groupIndex > m_baselineGroupIndex); + assert(groupIndex >= 0); + + // Translate ltrb to our tile and negate the right and bottom sides. + ltrb -= m_topLeft; + ltrb.zw = 255 - ltrb.zw; // right = 255 - right, bottom = 255 - bottom + assert(simd::all(ltrb < + 255)); // Ensure ltrb isn't completely outside the tile. + ltrb = simd::max(ltrb, int4(0)); // Clamp ltrb to our tile. + + if (simd::all(ltrb == 0)) + { + // ltrb covers the entire tile -- reset to a new baseline. + assert(groupIndex > m_maxGroupIndex); + reset(m_topLeft.x, m_topLeft.y, groupIndex); + return; + } + + // Append a chunk if needed, to make room for this new rectangle. + uint32_t subIdx = m_rectangleCount % kChunkSize; + if (subIdx == 0) + { + // Push back maximally negative rectangles so they always fail + // intersection tests. + assert(m_edges.size() * kChunkSize == m_rectangleCount); + m_edges.push_back(int8x32(std::numeric_limits::max())); + + // Uninitialized since the corresponding rectangles never pass an + // intersection test. + assert(m_groupIndices.size() * kChunkSize == m_rectangleCount); + m_groupIndices.emplace_back(); + } + + // m_edges is a list of 8 rectangles encoded as [L, T, 255 - R, 255 - B], + // relative to m_topLeft. The data is also transposed: [L0..L7, T0..T7, + // -R0..R7, -B0..B7]. Bias ltrb by -128 so we can use int8_t. SSE doesn't + // have an unsigned byte compare. + int4 biased = ltrb + std::numeric_limits::min(); + m_edges.back()[subIdx] = biased.x; + m_edges.back()[subIdx + 8] = biased.y; + m_edges.back()[subIdx + 16] = + biased.z; // Already converted to "255 - right" above. + m_edges.back()[subIdx + 24] = + biased.w; // Already converted to "255 - bottom" above. + + m_groupIndices.back()[subIdx] = groupIndex; + + m_maxGroupIndex = std::max(groupIndex, m_maxGroupIndex); + ++m_rectangleCount; +} + +int16x8 IntersectionTile::findMaxIntersectingGroupIndex( + int4 ltrb, + int16x8 runningMaxGroupIndices) const +{ + assert(simd::all(ltrb.xy < ltrb.zw)); // Ensure ltrb isn't zero or negative. + + // Since we mask non-intersecting groupIndices to zero, the "mask and max" + // algorithm is only correct for positive values. (runningMaxGroupIndices is + // only signed because SSE doesn't have an unsigned max instruction.) + assert(simd::all(runningMaxGroupIndices >= 0)); + assert(m_baselineGroupIndex >= 0); + assert(m_maxGroupIndex >= m_baselineGroupIndex); + + // Translate ltrb to our tile and negate the left and top sides. + ltrb -= m_topLeft; + ltrb.xy = 255 - ltrb.xy; // left = 255 - left, top = 255 - top + assert( + simd::all(ltrb > 0)); // Ensure ltrb isn't completely outside the tile. + ltrb = simd::min(ltrb, int4(255)); // Clamp ltrb to our tile. + + if (simd::all(ltrb == 255)) + { + // ltrb covers the entire -- we know it intersects with every rectangle. + runningMaxGroupIndices[0] = + std::max(runningMaxGroupIndices[0], m_maxGroupIndex); + return runningMaxGroupIndices; + } + + // Intersection test: l0 < r1 && + // t0 < b1 && + // r0 > l1 && + // b0 > t1 + // + // Or, to make them all use the same operator: +l0 < +r1 && + // +t0 < +b1 && + // -r0 < -l1 && + // -b0 < -t1 + // + // m_edges are already encoded like the left column, so encode "ltrb" like + // the right. + // + // Bias ltrb by -128 so we can use int8_t. SSE doesn't have an unsigned byte + // compare. + int4 biased = ltrb + std::numeric_limits::min(); + int8x8 r = biased.z; + int8x8 b = biased.w; + int8x8 _l = biased.x; // Already converted to "255 - left" above. + int8x8 _t = biased.y; // Already converted to "255 - top" above. + +#if !defined(FALLBACK_ON_SSE2_INTRINSICS) + auto edges = m_edges.begin(); + auto groupIndices = m_groupIndices.begin(); + assert(m_edges.size() == m_groupIndices.size()); + int8x32 complement = simd::join(r, b, _l, _t); + for (; edges != m_edges.end(); ++edges, ++groupIndices) + { + // Test 32 edges! + auto edgeMasks = *edges < complement; + // Since the transposed L,T,R,B rows are a each 64-bit vectors, + // "and-reducing" them returns the intersection test (l0 < r1 && t0 < b1 + // && r0 > l1 && b0 > t1) in each byte. + int64_t isectMask = + simd::reduce_and(math::bit_cast(edgeMasks)); + // Each element of isectMasks8 is 0xff if we intersect with the + // corresponding rectangle, otherwise 0. + int8x8 isectMasks8 = math::bit_cast(isectMask); + // Widen isectMasks8 to 16 bits per mask, where each element of + // isectMasks16 is 0xffff if we intersect with the rectangle, otherwise + // 0. + int16x8 isectMasks16 = + math::bit_cast(simd::zip(isectMasks8, isectMasks8)); + // Mask out any groupIndices we don't intersect with so they don't + // participate in the test for maximum groupIndex. + int16x8 maskedGroupIndices = isectMasks16 & *groupIndices; + runningMaxGroupIndices = + simd::max(maskedGroupIndices, runningMaxGroupIndices); + } +#else + // MSVC doesn't get good codegen for the above loop. Provide direct SSE + // intrinsics. + const __m128i* edgeData = reinterpret_cast(m_edges.data()); + const __m128i* groupIndices = + reinterpret_cast(m_groupIndices.data()); + __m128i complementLO = math::bit_cast<__m128i>(simd::join(r, b)); + __m128i complementHI = math::bit_cast<__m128i>(simd::join(_l, _t)); + __m128i localMaxGroupIndices = + math::bit_cast<__m128i>(runningMaxGroupIndices); + for (size_t i = 0; i < m_groupIndices.size(); ++i) + { + __m128i edgesLO = edgeData[i * 2]; + __m128i edgesHI = edgeData[i * 2 + 1]; + // Test 32 edges! + __m128i edgeMasksLO = _mm_cmpgt_epi8(complementLO, edgesLO); + __m128i edgeMasksHI = _mm_cmpgt_epi8(complementHI, edgesHI); + // AND L & R masks (bits 0:63) and T & B masks (bits 63:127). + __m128i partialIsectMasks = _mm_and_si128(edgeMasksLO, edgeMasksHI); + // Widen partial edge masks from 8 bits to 16. + __m128i partialIsectMasksTB16 = + _mm_unpackhi_epi8(partialIsectMasks, partialIsectMasks); + __m128i partialIsectMasksLR16 = + _mm_unpacklo_epi8(partialIsectMasks, partialIsectMasks); + // AND LR masks with TB masks for a full LTRB intersection mask. + __m128i isectMasks16 = + _mm_and_si128(partialIsectMasksLR16, partialIsectMasksTB16); + // Mask out the groupIndices that don't intersect. + __m128i intersectingGroupIndices = + _mm_and_si128(isectMasks16, groupIndices[i]); + // Accumulate max intersecting groupIndices. + localMaxGroupIndices = + _mm_max_epi16(intersectingGroupIndices, localMaxGroupIndices); + } + runningMaxGroupIndices = math::bit_cast(localMaxGroupIndices); +#endif // !FALLBACK_ON_SSE2_INTRINSICS + + // Ensure we never drop below our baseline index. + runningMaxGroupIndices[0] = + std::max(runningMaxGroupIndices[0], m_baselineGroupIndex); + return runningMaxGroupIndices; +} + +void IntersectionBoard::resizeAndReset(uint32_t viewportWidth, + uint32_t viewportHeight) +{ + m_viewportSize = + int2{static_cast(viewportWidth), static_cast(viewportHeight)}; + + // Divide the board into 255x255 tiles. + int2 dims = (m_viewportSize + 254) / 255; + m_cols = dims.x; + m_rows = dims.y; + if (m_tiles.size() < m_cols * m_rows) + { + m_tiles.resize(m_cols * m_rows); + } + auto tileIter = m_tiles.begin(); + for (int y = 0; y < m_rows; ++y) + { + for (int x = 0; x < m_cols; ++x) + { + tileIter->reset(x * 255, y * 255); + ++tileIter; + } + } +} + +int16_t IntersectionBoard::addRectangle(int4 ltrb, int16_t layerCount) +{ + // Discard empty, negative, or offscreen rectangles. + if (simd::any(ltrb.xy >= m_viewportSize || ltrb.zw <= 0 || + ltrb.xy >= ltrb.zw)) + { + return 0; + } + + // Clamp ltrb to the viewport to avoid integer overflows. + ltrb.xy = simd::max(ltrb.xy, int2(0)); + ltrb.zw = simd::min(ltrb.zw, m_viewportSize); + + // Find the tiled row and column that each corner of the rectangle falls on. + int4 span = (ltrb - int4{0, 0, 1, 1}) / 255; + span = simd::clamp(span, int4(0), int4{m_cols, m_rows, m_cols, m_rows} - 1); + assert(simd::all(span.xy <= span.zw)); + + // Accumulate the max groupIndex from each tile the rectangle touches. + int16x8 maxGroupIndices = 0; + for (int y = span.y; y <= span.w; ++y) + { + auto tileIter = m_tiles.begin() + y * m_cols + span.x; + for (int x = span.x; x <= span.z; ++x) + { + maxGroupIndices = + tileIter->findMaxIntersectingGroupIndex(ltrb, maxGroupIndices); + ++tileIter; + } + } + + // Find the absolute max group index this rectangle intersects with. + int16_t maxIntersectingGroupIndex = simd::reduce_max(maxGroupIndices); + // It is the caller's responsibility to not insert more rectangles than can + // fit in a signed 16-bit integer. + assert(maxIntersectingGroupIndex <= + std::numeric_limits::max() - layerCount); + + // Add the rectangle and its newly-found groupIndex to each tile it touches. + int16_t finalLayerGroupIndex = maxIntersectingGroupIndex + layerCount; + for (int y = span.y; y <= span.w; ++y) + { + auto tileIter = m_tiles.begin() + y * m_cols + span.x; + for (int x = span.x; x <= span.z; ++x) + { + tileIter->addRectangle(ltrb, finalLayerGroupIndex); + ++tileIter; + } + } + + return maxIntersectingGroupIndex + 1; +} +} // namespace rive::gpu diff --git a/third_party/rive_renderer/source/intersection_board.hpp b/third_party/rive_renderer/source/intersection_board.hpp new file mode 100644 index 0000000..9cce93b --- /dev/null +++ b/third_party/rive_renderer/source/intersection_board.hpp @@ -0,0 +1,79 @@ +/* + * Copyright 2024 Rive + */ + +#pragma once + +#include "rive/math/simd.hpp" +#include + +namespace rive::gpu +{ +// 255 x 255 tile that manages a set of rectangles and their groupIndex. +// From a given rectangle, finds the max groupIndex in the set of internal +// rectangles it intersects. The size is 255 so we can store bounding box +// coordinates in 8 bits. +class IntersectionTile +{ +public: + void reset(int left, int top, int16_t baselineGroupIndex = 0); + + void addRectangle(int4 ltrb, int16_t groupIndex); + + // Accumulate local maximum intersecting group indices for the given + // rectangle in each channel of a int16x8. "runningMaxGroupIndices" is a + // running set of local maximums if the IntersectionBoard also ran this same + // test on other tile(s) that the rectangle touched. The absolute maximum + // group index that this rectangle intersects with will be + // simd::reduce_max(returnValue). + int16x8 findMaxIntersectingGroupIndex(int4 ltrb, + int16x8 runningMaxGroupIndices) const; + +private: + int4 m_topLeft; + int16_t m_baselineGroupIndex; + int16_t m_maxGroupIndex; + size_t m_rectangleCount = 0; + + // How many rectangles/groupIndices are in each chunk of data? + constexpr static size_t kChunkSize = 8; + + // Chunk of 8 rectangles encoded as [L, T, 255 - R, 255 - B], relative to + // m_left and m_top. The data is also transposed: [L0..L7, T0..T7, -R0..R7, + // -B0..B7]. + std::vector m_edges; + static_assert(sizeof(m_edges[0]) == kChunkSize * 4); + + // Chunk of 8 groupIndices corresponding to the above edges. + std::vector m_groupIndices; + static_assert(sizeof(m_groupIndices[0]) == kChunkSize * 2); +}; + +// Manages a set of rectangles and their groupIndex across a variable-sized +// viewport. Each time a rectangle is added, assigns and returns a groupIndex +// that is one larger than the max groupIndex in the set of existing rectangles +// it intersects. +class IntersectionBoard +{ +public: + void resizeAndReset(uint32_t viewportWidth, uint32_t viewportHeight); + + // Adds a rectangle to the internal set and assigns it "layerCount" + // contiguous group indices, beginning one larger than the max groupIndex in + // the set of existing rectangles it intersects. + // + // Returns the first newly assigned groupIndex for the added rectangle. + // If it does not intersect with any other rectangles, this groupIndex is 1. + // + // It is the caller's responsibility to not insert more rectangles than can + // fit in a signed 16-bit integer. (The result is signed because SSE doesn't + // have an unsigned max instruction.) + int16_t addRectangle(int4 ltrb, int16_t layerCount = 1); + +private: + int2 m_viewportSize; + int32_t m_cols; + int32_t m_rows; + std::vector m_tiles; +}; +} // namespace rive::gpu diff --git a/third_party/rive_renderer/source/metal/background_shader_compiler.h b/third_party/rive_renderer/source/metal/background_shader_compiler.h new file mode 100644 index 0000000..00aa24e --- /dev/null +++ b/third_party/rive_renderer/source/metal/background_shader_compiler.h @@ -0,0 +1,62 @@ +/* + * Copyright 2023 Rive + */ + +#pragma once + +#include "rive/renderer/gpu.hpp" +#include "rive/renderer/metal/render_context_metal_impl.h" + +#include +#include + +#import + +namespace rive::gpu +{ +// Defines a job to compile a "draw" shader -- either draw_path.glsl or +// draw_image_mesh.glsl, with a specific set of features enabled. +struct BackgroundCompileJob +{ + gpu::DrawType drawType; + gpu::ShaderFeatures shaderFeatures; + gpu::InterlockMode interlockMode; + gpu::ShaderMiscFlags shaderMiscFlags; + id compiledLibrary = nil; +#ifdef WITH_RIVE_TOOLS + bool synthesizeCompilationFailure = false; +#endif +}; + +// Compiles "draw" shaders in a background thread. A "draw" shaders is either +// draw_path.glsl or draw_image_mesh.glsl, with a specific set of features +// enabled. +class BackgroundShaderCompiler +{ +public: + using AtomicBarrierType = RenderContextMetalImpl::AtomicBarrierType; + using MetalFeatures = RenderContextMetalImpl::MetalFeatures; + + BackgroundShaderCompiler(id gpu, MetalFeatures metalFeatures) : + m_gpu(gpu), m_metalFeatures(metalFeatures) + {} + + ~BackgroundShaderCompiler(); + + void pushJob(const BackgroundCompileJob&); + bool popFinishedJob(BackgroundCompileJob* job, bool wait); + +private: + void threadMain(); + + const id m_gpu; + const MetalFeatures m_metalFeatures; + std::queue m_pendingJobs; + std::vector m_finishedJobs; + std::mutex m_mutex; + std::condition_variable m_workAddedCondition; + std::condition_variable m_workFinishedCondition; + bool m_shouldQuit = false; + std::thread m_compilerThread; +}; +} // namespace rive::gpu diff --git a/third_party/rive_renderer/source/metal/background_shader_compiler.mm b/third_party/rive_renderer/source/metal/background_shader_compiler.mm new file mode 100644 index 0000000..9e7e478 --- /dev/null +++ b/third_party/rive_renderer/source/metal/background_shader_compiler.mm @@ -0,0 +1,311 @@ +/* + * Copyright 2023 Rive + */ + +#include "background_shader_compiler.h" + +#include "generated/shaders/metal.glsl.hpp" +#include "generated/shaders/constants.glsl.hpp" +#include "generated/shaders/common.glsl.hpp" +#include "generated/shaders/advanced_blend.glsl.hpp" +#include "generated/shaders/draw_path_common.glsl.hpp" +#include "generated/shaders/draw_path.glsl.hpp" +#include "generated/shaders/draw_image_mesh.glsl.hpp" + +#ifndef RIVE_IOS +// iOS doesn't need the atomic shaders; every non-simulated iOS device supports +// framebuffer reads. +#include "generated/shaders/atomic_draw.glsl.hpp" +#endif + +#include + +namespace rive::gpu +{ +BackgroundShaderCompiler::~BackgroundShaderCompiler() +{ + if (m_compilerThread.joinable()) + { + m_shouldQuit = true; + m_workAddedCondition.notify_all(); + m_compilerThread.join(); + } +} + +void BackgroundShaderCompiler::pushJob(const BackgroundCompileJob& job) +{ + { + std::lock_guard lock(m_mutex); + if (!m_compilerThread.joinable()) + { + m_compilerThread = + std::thread(&BackgroundShaderCompiler::threadMain, this); + } + m_pendingJobs.push(std::move(job)); + } + m_workAddedCondition.notify_all(); +} + +bool BackgroundShaderCompiler::popFinishedJob(BackgroundCompileJob* job, + bool wait) +{ + std::unique_lock lock(m_mutex); + while (m_finishedJobs.empty()) + { + if (!wait) + { + return false; + } + m_workFinishedCondition.wait(lock); + } + *job = std::move(m_finishedJobs.back()); + m_finishedJobs.pop_back(); + return true; +} + +void BackgroundShaderCompiler::threadMain() +{ + BackgroundCompileJob job; + std::unique_lock lock(m_mutex); + for (;;) + { + while (m_pendingJobs.empty() && !m_shouldQuit) + { + m_workAddedCondition.wait(lock); + } + + if (m_shouldQuit) + { + return; + } + + job = std::move(m_pendingJobs.front()); + m_pendingJobs.pop(); + + lock.unlock(); + + gpu::DrawType drawType = job.drawType; + gpu::ShaderFeatures shaderFeatures = job.shaderFeatures; + gpu::InterlockMode interlockMode = job.interlockMode; + gpu::ShaderMiscFlags shaderMiscFlags = job.shaderMiscFlags; + + auto defines = [[NSMutableDictionary alloc] init]; + defines[@GLSL_VERTEX] = @""; + defines[@GLSL_FRAGMENT] = @""; + for (size_t i = 0; i < gpu::kShaderFeatureCount; ++i) + { + ShaderFeatures feature = static_cast(1 << i); + if (shaderFeatures & feature) + { + const char* macro = gpu::GetShaderFeatureGLSLName(feature); + defines[[NSString stringWithUTF8String:macro]] = @"1"; + } + } + if (interlockMode == gpu::InterlockMode::atomics) + { + // Atomic mode uses device buffers instead of framebuffer fetches. + defines[@GLSL_PLS_IMPL_DEVICE_BUFFER] = @""; + if (m_metalFeatures.atomicBarrierType == + AtomicBarrierType::rasterOrderGroup) + { + defines[@GLSL_PLS_IMPL_DEVICE_BUFFER_RASTER_ORDERED] = @""; + } + if (shaderMiscFlags & + gpu::ShaderMiscFlags::fixedFunctionColorOutput) + { + defines[@GLSL_FIXED_FUNCTION_COLOR_OUTPUT] = @""; + } + } + if (shaderMiscFlags & gpu::ShaderMiscFlags::clockwiseFill) + { + defines[@GLSL_CLOCKWISE_FILL] = @"1"; + } + + auto source = + [[NSMutableString alloc] initWithCString:gpu::glsl::metal + encoding:NSUTF8StringEncoding]; + [source + appendFormat:@"%s\n%s\n", gpu::glsl::constants, gpu::glsl::common]; + if (shaderFeatures & ShaderFeatures::ENABLE_ADVANCED_BLEND) + { + [source appendFormat:@"%s\n", gpu::glsl::advanced_blend]; + } + + switch (drawType) + { + case DrawType::midpointFanPatches: + case DrawType::midpointFanCenterAAPatches: + case DrawType::outerCurvePatches: + // Add baseInstance to the instanceID for path draws. + defines[@GLSL_ENABLE_INSTANCE_INDEX] = @""; + defines[@GLSL_DRAW_PATH] = @""; + [source appendFormat:@"%s\n", gpu::glsl::draw_path_common]; +#ifdef RIVE_IOS + [source appendFormat:@"%s\n", gpu::glsl::draw_path]; +#else + [source appendFormat:@"%s\n", + interlockMode == + gpu::InterlockMode::rasterOrdering + ? gpu::glsl::draw_path + : gpu::glsl::atomic_draw]; +#endif + break; + case DrawType::atlasBlit: + defines[@GLSL_ATLAS_BLIT] = @"1"; + [[fallthrough]]; + case DrawType::interiorTriangulation: + defines[@GLSL_DRAW_INTERIOR_TRIANGLES] = @""; + [source appendFormat:@"%s\n", gpu::glsl::draw_path_common]; +#ifdef RIVE_IOS + [source appendFormat:@"%s\n", gpu::glsl::draw_path]; +#else + [source appendFormat:@"%s\n", + interlockMode == + gpu::InterlockMode::rasterOrdering + ? gpu::glsl::draw_path + : gpu::glsl::atomic_draw]; +#endif + break; + case DrawType::imageRect: +#ifdef RIVE_IOS + RIVE_UNREACHABLE(); +#else + assert(interlockMode == InterlockMode::atomics); + defines[@GLSL_DRAW_IMAGE] = @""; + defines[@GLSL_DRAW_IMAGE_RECT] = @""; + [source appendFormat:@"%s\n", gpu::glsl::draw_path_common]; + [source appendFormat:@"%s\n", gpu::glsl::atomic_draw]; +#endif + break; + case DrawType::imageMesh: + defines[@GLSL_DRAW_IMAGE] = @""; + defines[@GLSL_DRAW_IMAGE_MESH] = @""; +#ifdef RIVE_IOS + [source appendFormat:@"%s\n", gpu::glsl::draw_image_mesh]; +#else + if (interlockMode == gpu::InterlockMode::rasterOrdering) + { + [source appendFormat:@"%s\n", gpu::glsl::draw_image_mesh]; + } + else + { + [source appendFormat:@"%s\n", gpu::glsl::draw_path_common]; + [source appendFormat:@"%s\n", gpu::glsl::atomic_draw]; + } +#endif + break; + case DrawType::atomicInitialize: +#ifdef RIVE_IOS + RIVE_UNREACHABLE(); +#else + assert(interlockMode == InterlockMode::atomics); + defines[@GLSL_DRAW_RENDER_TARGET_UPDATE_BOUNDS] = @""; + defines[@GLSL_INITIALIZE_PLS] = @""; + if (shaderMiscFlags & gpu::ShaderMiscFlags::storeColorClear) + { + defines[@GLSL_STORE_COLOR_CLEAR] = @""; + } + if (shaderMiscFlags & + gpu::ShaderMiscFlags::swizzleColorBGRAToRGBA) + { + defines[@GLSL_SWIZZLE_COLOR_BGRA_TO_RGBA] = @""; + } + [source appendFormat:@"%s\n", gpu::glsl::draw_path_common]; + [source appendFormat:@"%s\n", gpu::glsl::atomic_draw]; +#endif + break; + case DrawType::atomicResolve: +#ifdef RIVE_IOS + RIVE_UNREACHABLE(); +#else + assert(interlockMode == InterlockMode::atomics); + defines[@GLSL_DRAW_RENDER_TARGET_UPDATE_BOUNDS] = @""; + defines[@GLSL_RESOLVE_PLS] = @""; + if (shaderMiscFlags & + gpu::ShaderMiscFlags::coalescedResolveAndTransfer) + { + defines[@GLSL_COALESCED_PLS_RESOLVE_AND_TRANSFER] = @""; + } + [source appendFormat:@"%s\n", gpu::glsl::draw_path_common]; + [source appendFormat:@"%s\n", gpu::glsl::atomic_draw]; +#endif + break; + case DrawType::msaaStrokes: + case DrawType::msaaMidpointFanBorrowedCoverage: + case DrawType::msaaMidpointFans: + case DrawType::msaaMidpointFanStencilReset: + case DrawType::msaaMidpointFanPathsStencil: + case DrawType::msaaMidpointFanPathsCover: + case DrawType::msaaOuterCubics: + case DrawType::msaaStencilClipReset: + RIVE_UNREACHABLE(); + } + + NSError* err = [NSError errorWithDomain:@"compile" + code:200 + userInfo:nil]; + MTLCompileOptions* compileOptions = [MTLCompileOptions new]; +#if defined(RIVE_IOS) || defined(RIVE_IOS_SIMULATOR) + compileOptions.languageVersion = + MTLLanguageVersion2_2; // On ios, we need version 2.2+ +#else + compileOptions.languageVersion = + MTLLanguageVersion2_3; // On mac, we need version 2.3+ +#endif + compileOptions.fastMathEnabled = YES; + if (@available(iOS 14, *)) + { + compileOptions.preserveInvariance = YES; + } + compileOptions.preprocessorMacros = defines; +#ifdef WITH_RIVE_TOOLS + if (job.synthesizeCompilationFailure) + { + assert(job.compiledLibrary == nil); + } + else +#endif + { + job.compiledLibrary = [m_gpu newLibraryWithSource:source + options:compileOptions + error:&err]; + } + + lock.lock(); + + if (job.compiledLibrary == nil) + { +#ifdef WITH_RIVE_TOOLS + if (job.synthesizeCompilationFailure) + { + fprintf(stderr, "Synthesizing shader compilation failure...\n"); + } + else +#endif + { + // The compile job failed, most likely to external environmental + // factors. Give up on this shader and let the render context + // fall back on an uber shader instead. + int lineNumber = 1; + std::stringstream stream(source.UTF8String); + std::string lineStr; + while (std::getline(stream, lineStr, '\n')) + { + fprintf(stderr, "%4i| %s\n", lineNumber++, lineStr.c_str()); + } + fprintf(stderr, "%s\n", err.localizedDescription.UTF8String); + } + + fprintf(stderr, "Failed to compile shader.\n"); + assert(false +#ifdef WITH_RIVE_TOOLS + || job.synthesizeCompilationFailure +#endif + ); + } + + m_finishedJobs.push_back(std::move(job)); + m_workFinishedCondition.notify_all(); + } +} +} // namespace rive::gpu diff --git a/third_party/rive_renderer/source/metal/render_context_metal_impl.mm b/third_party/rive_renderer/source/metal/render_context_metal_impl.mm new file mode 100644 index 0000000..3d53e04 --- /dev/null +++ b/third_party/rive_renderer/source/metal/render_context_metal_impl.mm @@ -0,0 +1,1740 @@ +/* + * Copyright 2023 Rive + */ + +#include "rive/renderer/metal/render_context_metal_impl.h" + +#include "background_shader_compiler.h" +#include "rive/renderer/buffer_ring.hpp" +#include "rive/renderer/texture.hpp" +#include "rive/renderer/rive_render_buffer.hpp" +#include "shaders/constants.glsl" +#include + +#include "generated/shaders/color_ramp.exports.h" +#include "generated/shaders/tessellate.exports.h" + +#if defined(RIVE_IOS_SIMULATOR) +#import +#endif + +namespace rive::gpu +{ +#if defined(RIVE_IOS) +#include "generated/shaders/rive_pls_ios.metallib.c" +#elif defined(RIVE_IOS_SIMULATOR) +#include "generated/shaders/rive_pls_ios_simulator.metallib.c" +#elif defined(RIVE_XROS) +#include "generated/shaders/rive_renderer_xros.metallib.c" +#elif defined(RIVE_XROS_SIMULATOR) +#include "generated/shaders/rive_renderer_xros_simulator.metallib.c" +#elif defined(RIVE_APPLETVOS) +#include "generated/shaders/rive_renderer_appletvos.metallib.c" +#elif defined(RIVE_APPLETVOS_SIMULATOR) +#include "generated/shaders/rive_renderer_appletvsimulator.metallib.c" +#else +#include "generated/shaders/rive_pls_macosx.metallib.c" +#endif + +static id make_pipeline_state( + id gpu, MTLRenderPipelineDescriptor* desc) +{ + NSError* err = [NSError errorWithDomain:@"pipeline_create" + code:201 + userInfo:nil]; + id state = + [gpu newRenderPipelineStateWithDescriptor:desc error:&err]; + if (!state) + { + fprintf(stderr, "%s\n", err.localizedDescription.UTF8String); + abort(); + } + return state; +} + +static MTLSamplerAddressMode address_mode_for_image_wrap(ImageWrap wrap) +{ + switch (wrap) + { + case ImageWrap::clamp: + return MTLSamplerAddressModeClampToEdge; + case ImageWrap::repeat: + return MTLSamplerAddressModeRepeat; + case ImageWrap::mirror: + return MTLSamplerAddressModeMirrorRepeat; + } + + RIVE_UNREACHABLE(); +} + +static MTLSamplerMinMagFilter min_mag_filter_for_image_filter( + ImageFilter option) +{ + switch (option) + { + case ImageFilter::trilinear: + return MTLSamplerMinMagFilterLinear; + case ImageFilter::nearest: + return MTLSamplerMinMagFilterNearest; + } + + RIVE_UNREACHABLE(); +} + +static MTLSamplerMipFilter mip_filter_for_image_filter(ImageFilter option) +{ + switch (option) + { + case ImageFilter::trilinear: + return MTLSamplerMipFilterLinear; + case ImageFilter::nearest: + return MTLSamplerMipFilterNearest; + } + + RIVE_UNREACHABLE(); +} + +// Renders color ramps to the gradient texture. +class RenderContextMetalImpl::ColorRampPipeline +{ +public: + ColorRampPipeline(id gpu, id plsLibrary) + { + MTLRenderPipelineDescriptor* desc = + [[MTLRenderPipelineDescriptor alloc] init]; + desc.vertexFunction = + [plsLibrary newFunctionWithName:@GLSL_colorRampVertexMain]; + desc.fragmentFunction = + [plsLibrary newFunctionWithName:@GLSL_colorRampFragmentMain]; + desc.colorAttachments[0].pixelFormat = MTLPixelFormatRGBA8Unorm; + m_pipelineState = make_pipeline_state(gpu, desc); + } + + id pipelineState() const { return m_pipelineState; } + +private: + id m_pipelineState; +}; + +// Renders tessellated vertices to the tessellation texture. +class RenderContextMetalImpl::TessellatePipeline +{ +public: + TessellatePipeline(id gpu, id plsLibrary) + { + MTLRenderPipelineDescriptor* desc = + [[MTLRenderPipelineDescriptor alloc] init]; + desc.vertexFunction = + [plsLibrary newFunctionWithName:@GLSL_tessellateVertexMain]; + desc.fragmentFunction = + [plsLibrary newFunctionWithName:@GLSL_tessellateFragmentMain]; + desc.colorAttachments[0].pixelFormat = MTLPixelFormatRGBA32Uint; + m_pipelineState = make_pipeline_state(gpu, desc); + } + + id pipelineState() const { return m_pipelineState; } + +private: + id m_pipelineState; +}; + +// Renders feathered fills and strokes to the atlas. +class RenderContextMetalImpl::AtlasPipeline +{ +public: + AtlasPipeline(id gpu, + id plsLibrary, + NSString* fragmentMain, + MTLBlendOperation blendOperation) + { + MTLRenderPipelineDescriptor* desc = + [[MTLRenderPipelineDescriptor alloc] init]; + desc.vertexFunction = + [plsLibrary newFunctionWithName:@GLSL_atlasVertexMain]; + desc.fragmentFunction = [plsLibrary newFunctionWithName:fragmentMain]; + desc.colorAttachments[0].pixelFormat = MTLPixelFormatR32Float; + desc.colorAttachments[0].blendingEnabled = TRUE; + desc.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorOne; + desc.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactorOne; + desc.colorAttachments[0].rgbBlendOperation = blendOperation; + desc.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactorOne; + desc.colorAttachments[0].destinationAlphaBlendFactor = + MTLBlendFactorOne; + desc.colorAttachments[0].alphaBlendOperation = blendOperation; + desc.colorAttachments[0].writeMask = MTLColorWriteMaskAll; + m_pipelineState = make_pipeline_state(gpu, desc); + } + + id pipelineState() const { return m_pipelineState; } + +private: + id m_pipelineState; +}; + +// Renders paths to the main render target. +class RenderContextMetalImpl::DrawPipeline +{ +public: + // Precompiled functions are embedded in namespaces. Return the fully + // qualified name of the desired function, including its namespace. + static NSString* GetPrecompiledFunctionName( + DrawType drawType, + gpu::ShaderFeatures shaderFeatures, + gpu::ShaderMiscFlags shaderMiscFlags, + id precompiledLibrary, + const char* functionBaseName) + { + // Each feature corresponds to a specific index in the namespaceID. + // These must stay in sync with generate_draw_combinations.py. + char namespaceID[] = "000000000"; + static_assert(sizeof(namespaceID) == + gpu::kShaderFeatureCount + 1 /*DRAW_INTERIOR_TRIANGLES*/ + + 1 /*ATLAS_BLIT*/ + 1 /*null terminator*/); + for (size_t i = 0; i < gpu::kShaderFeatureCount; ++i) + { + ShaderFeatures feature = static_cast(1 << i); + if (shaderFeatures & feature) + { + namespaceID[i] = '1'; + } + static_assert((int)ShaderFeatures::ENABLE_CLIPPING == 1 << 0); + static_assert((int)ShaderFeatures::ENABLE_CLIP_RECT == 1 << 1); + static_assert((int)ShaderFeatures::ENABLE_ADVANCED_BLEND == 1 << 2); + static_assert((int)ShaderFeatures::ENABLE_FEATHER == 1 << 3); + static_assert((int)ShaderFeatures::ENABLE_EVEN_ODD == 1 << 4); + static_assert((int)ShaderFeatures::ENABLE_NESTED_CLIPPING == + 1 << 5); + static_assert((int)ShaderFeatures::ENABLE_HSL_BLEND_MODES == + 1 << 6); + } + if (drawType == DrawType::interiorTriangulation) + { + namespaceID[gpu::kShaderFeatureCount] = '1'; + } + else if (drawType == DrawType::atlasBlit) + { + namespaceID[gpu::kShaderFeatureCount] = '1'; + namespaceID[gpu::kShaderFeatureCount + 1] = '1'; + } + + char namespacePrefix; + switch (drawType) + { + case DrawType::midpointFanPatches: + case DrawType::midpointFanCenterAAPatches: + case DrawType::outerCurvePatches: + case DrawType::interiorTriangulation: + case DrawType::atlasBlit: + namespacePrefix = + (shaderMiscFlags & gpu::ShaderMiscFlags::clockwiseFill) + ? 'c' + : 'p'; + break; + case DrawType::imageRect: + RIVE_UNREACHABLE(); + case DrawType::imageMesh: + namespacePrefix = 'm'; + break; + case DrawType::atomicInitialize: + case DrawType::atomicResolve: + case DrawType::msaaStrokes: + case DrawType::msaaMidpointFanBorrowedCoverage: + case DrawType::msaaMidpointFans: + case DrawType::msaaMidpointFanStencilReset: + case DrawType::msaaMidpointFanPathsStencil: + case DrawType::msaaMidpointFanPathsCover: + case DrawType::msaaOuterCubics: + case DrawType::msaaStencilClipReset: + RIVE_UNREACHABLE(); + } + + return [NSString stringWithFormat:@"%c%s::%s", + namespacePrefix, + namespaceID, + functionBaseName]; + } + + DrawPipeline(id gpu, + id library, + NSString* vertexFunctionName, + NSString* fragmentFunctionName, + gpu::DrawType drawType, + gpu::InterlockMode interlockMode, + gpu::ShaderFeatures shaderFeatures, + gpu::ShaderMiscFlags shaderMiscFlags) + { + if (library == nil) + { + // This pipeline is being built from a shader that failed to + // compile. Leave everything nil and let draws fail. + return; + } + + auto makePipelineState = [=](id vertexMain, + id fragmentMain, + MTLPixelFormat pixelFormat) { + MTLRenderPipelineDescriptor* desc = + [[MTLRenderPipelineDescriptor alloc] init]; + desc.vertexFunction = vertexMain; + desc.fragmentFunction = fragmentMain; + + auto* framebuffer = desc.colorAttachments[COLOR_PLANE_IDX]; + framebuffer.pixelFormat = pixelFormat; + + switch (interlockMode) + { + case gpu::InterlockMode::rasterOrdering: + // In rasterOrdering mode, the PLS planes are accessed as + // color attachments. + desc.colorAttachments[CLIP_PLANE_IDX].pixelFormat = + MTLPixelFormatR32Uint; + desc.colorAttachments[SCRATCH_COLOR_PLANE_IDX].pixelFormat = + pixelFormat; + desc.colorAttachments[COVERAGE_PLANE_IDX].pixelFormat = + MTLPixelFormatR32Uint; + break; + + case gpu::InterlockMode::atomics: + // In atomic mode, the PLS planes are accessed as device + // buffers. We only use the "framebuffer" attachment + // configured above. + if (shaderMiscFlags & + gpu::ShaderMiscFlags::fixedFunctionColorOutput) + { + // The shader expectes a "src-over" blend function in + // order to to implement antialiasing and opacity. + framebuffer.blendingEnabled = TRUE; + framebuffer.sourceRGBBlendFactor = MTLBlendFactorOne; + framebuffer.destinationRGBBlendFactor = + MTLBlendFactorOneMinusSourceAlpha; + framebuffer.rgbBlendOperation = MTLBlendOperationAdd; + framebuffer.sourceAlphaBlendFactor = MTLBlendFactorOne; + framebuffer.destinationAlphaBlendFactor = + MTLBlendFactorOneMinusSourceAlpha; + framebuffer.alphaBlendOperation = MTLBlendOperationAdd; + framebuffer.writeMask = MTLColorWriteMaskAll; + } + else if (drawType == gpu::DrawType::atomicResolve) + { + // We're resolving from the offscreen color buffer to + // the framebuffer attachment. Write out the final color + // directly without any blend modes. + framebuffer.blendingEnabled = FALSE; + framebuffer.writeMask = MTLColorWriteMaskAll; + } + else + { + // This pipeline renders by storing to the offscreen + // color buffer; disable writes to the framebuffer + // attachment. + framebuffer.blendingEnabled = FALSE; + framebuffer.writeMask = MTLColorWriteMaskNone; + } + break; + + case gpu::InterlockMode::clockwiseAtomic: + case gpu::InterlockMode::msaa: + RIVE_UNREACHABLE(); + } + return make_pipeline_state(gpu, desc); + }; + id vertexMain = + [library newFunctionWithName:vertexFunctionName]; + id fragmentMain = + [library newFunctionWithName:fragmentFunctionName]; + m_pipelineStateRGBA8 = makePipelineState( + vertexMain, fragmentMain, MTLPixelFormatRGBA8Unorm); + m_pipelineStateBGRA8 = makePipelineState( + vertexMain, fragmentMain, MTLPixelFormatBGRA8Unorm); + } + + bool valid() const + { + assert((m_pipelineStateRGBA8 != nil) == (m_pipelineStateBGRA8 != nil)); + return m_pipelineStateRGBA8 != nil; + } + + id pipelineState(MTLPixelFormat pixelFormat) const + { + assert(valid()); + assert(pixelFormat == MTLPixelFormatRGBA8Unorm || + pixelFormat == MTLPixelFormatRGBA16Float || + pixelFormat == MTLPixelFormatRGBA8Unorm_sRGB || + pixelFormat == MTLPixelFormatBGRA8Unorm || + pixelFormat == MTLPixelFormatBGRA8Unorm_sRGB); + + switch (pixelFormat) + { + case MTLPixelFormatRGBA8Unorm_sRGB: + case MTLPixelFormatRGBA8Unorm: + case MTLPixelFormatRGBA16Float: + return m_pipelineStateRGBA8; + default: + return m_pipelineStateBGRA8; + } + } + +private: + id m_pipelineStateRGBA8 = nil; + id m_pipelineStateBGRA8 = nil; +}; + +#if defined(RIVE_IOS) || defined(RIVE_XROS) || defined(RIVE_APPLETVOS) +static bool is_apple_silicon(id gpu) +{ + if (@available(iOS 13, tvOS 13, visionOS 1, *)) + { + return [gpu supportsFamily:MTLGPUFamilyApple4]; + } + return false; +} +#endif + +class BufferRingMetalImpl : public BufferRing +{ +public: + static std::unique_ptr Make(id gpu, + size_t capacityInBytes) + { + return capacityInBytes != 0 + ? std::make_unique(gpu, capacityInBytes) + : nullptr; + } + + BufferRingMetalImpl(id gpu, size_t capacityInBytes) : + BufferRing(capacityInBytes) + { + for (int i = 0; i < kBufferRingSize; ++i) + { + m_buffers[i] = + [gpu newBufferWithLength:capacityInBytes + options:MTLResourceStorageModeShared]; + } + } + + id submittedBuffer() const + { + return m_buffers[submittedBufferIdx()]; + } + +protected: + void* onMapBuffer(int bufferIdx, size_t mapSizeInBytes) override + { + return m_buffers[bufferIdx].contents; + } + + void onUnmapAndSubmitBuffer(int bufferIdx, size_t mapSizeInBytes) override + {} + +private: + id m_buffers[kBufferRingSize]; +}; + +std::unique_ptr RenderContextMetalImpl::MakeContext( + id gpu, const ContextOptions& contextOptions) +{ + auto renderContextImpl = std::unique_ptr( + new RenderContextMetalImpl(gpu, contextOptions)); + return std::make_unique(std::move(renderContextImpl)); +} + +RenderContextMetalImpl::RenderContextMetalImpl( + id gpu, const ContextOptions& contextOptions) : + m_contextOptions(contextOptions), m_gpu(gpu) +{ + // It appears, so far, that we don't need to use flat interpolation for path + // IDs on any Apple device, and it's faster not to. + m_platformFeatures.avoidFlatVaryings = true; + m_platformFeatures.clipSpaceBottomUp = true; + m_platformFeatures.framebufferBottomUp = false; + if ([m_gpu supportsFamily:MTLGPUFamilyApple2] || + [m_gpu supportsFamily:MTLGPUFamilyMac2]) + { + m_platformFeatures.maxTextureSize = 16384; + } + else + { + m_platformFeatures.maxTextureSize = 8192; + } +#if defined(RIVE_IOS) || defined(RIVE_XROS) || defined(RIVE_APPLETVOS) + m_platformFeatures.supportsRasterOrdering = true; + m_platformFeatures.supportsFragmentShaderAtomics = false; + if (!is_apple_silicon(m_gpu)) + { + // The PowerVR GPU, at least on A10, has fp16 precision issues. We can't + // use the the bottom 3 bits of the path and clip IDs in order for our + // equality testing to work. + m_platformFeatures.pathIDGranularity = 8; + } +#elif defined(RIVE_IOS_SIMULATOR) || defined(RIVE_XROS_SIMULATOR) || \ + defined(RIVE_APPLETVOS_SIMULATOR) + // The simulator does not support framebuffer reads. Fall back on atomic + // mode. + m_platformFeatures.supportsRasterOrdering = false; + m_platformFeatures.supportsFragmentShaderAtomics = true; +#else + m_platformFeatures.supportsRasterOrdering = + [m_gpu supportsFamily:MTLGPUFamilyApple1] && + !contextOptions.disableFramebufferReads; + m_platformFeatures.supportsFragmentShaderAtomics = true; +#endif + m_platformFeatures.atomicPLSMustBeInitializedAsDraw = true; + +#if defined(RIVE_IOS) || defined(RIVE_XROS) || defined(RIVE_XROS_SIMULATOR) || \ + defined(RIVE_APPLETVOS) || defined(RIVE_APPLETVOS_SIMULATOR) + // Atomic barriers are never used on iOS, but if we ever did need them, we + // would use rasterOrderGroups. + m_metalFeatures.atomicBarrierType = AtomicBarrierType::rasterOrderGroup; +#elif defined(RIVE_IOS_SIMULATOR) + const NXArchInfo* hostArchitecture = NXGetLocalArchInfo(); + if (strncmp(hostArchitecture->name, "arm64", 5) == 0) + { + // The simulator doesn't advertise support for raster order groups, but + // they appear to work anyway on an Apple-Silicon-hosted simulator. Use + // rasterOrderGroup in this case because it's much faster than + // renderPassBreak. (On Intel/AMD this doesn't matter anyway because + // renderPassBreaks are cheap and actually faster than + // rasterOrderGroups.) + m_metalFeatures.atomicBarrierType = AtomicBarrierType::rasterOrderGroup; + } + else + { + m_metalFeatures.atomicBarrierType = AtomicBarrierType::renderPassBreak; + } +#else + // Use real memory barriers for atomic mode if they're availabile. + // "GPU devices in Apple3 through Apple9 families don’t support memory + // barriers that include the MTLRenderStages.fragment or .tile stages in the + // after argument..." + if (([m_gpu supportsFamily:MTLGPUFamilyCommon2] || + [m_gpu supportsFamily:MTLGPUFamilyMac2]) && + ![m_gpu supportsFamily:MTLGPUFamilyApple3]) + { + m_metalFeatures.atomicBarrierType = AtomicBarrierType::memoryBarrier; + } + else if (m_gpu.rasterOrderGroupsSupported) + { + m_metalFeatures.atomicBarrierType = AtomicBarrierType::rasterOrderGroup; + } + else + { + m_metalFeatures.atomicBarrierType = AtomicBarrierType::renderPassBreak; + } +#endif + + for (int i = 0; i < rive::ImageSampler::MAX_SAMPLER_PERMUTATIONS; ++i) + { + auto wrapX = ImageSampler::GetWrapXOptionFromKey(i); + auto wrapY = ImageSampler::GetWrapYOptionFromKey(i); + auto filter = ImageSampler::GetFilterOptionFromKey(i); + + MTLSamplerDescriptor* samplerDescriptor = [MTLSamplerDescriptor new]; + samplerDescriptor.minFilter = min_mag_filter_for_image_filter(filter); + samplerDescriptor.magFilter = min_mag_filter_for_image_filter(filter); + samplerDescriptor.mipFilter = mip_filter_for_image_filter(filter); + samplerDescriptor.sAddressMode = address_mode_for_image_wrap(wrapX); + samplerDescriptor.tAddressMode = address_mode_for_image_wrap(wrapY); + + m_imageSamplers[i] = + [gpu newSamplerStateWithDescriptor:samplerDescriptor]; + } + + m_backgroundShaderCompiler = + std::make_unique(m_gpu, m_metalFeatures); + + // Load the precompiled shaders. + dispatch_data_t metallibData = dispatch_data_create( +#if defined(RIVE_IOS) + rive_pls_ios_metallib, + rive_pls_ios_metallib_len, +#elif defined(RIVE_IOS_SIMULATOR) + rive_pls_ios_simulator_metallib, + rive_pls_ios_simulator_metallib_len, +#elif defined(RIVE_XROS) + rive_renderer_xros_metallib, + rive_renderer_xros_metallib_len, +#elif defined(RIVE_XROS_SIMULATOR) + rive_renderer_xros_simulator_metallib, + rive_renderer_xros_simulator_metallib_len, +#elif defined(RIVE_APPLETVOS) + rive_renderer_appletvos_metallib, + rive_renderer_appletvos_metallib_len, +#elif defined(RIVE_APPLETVOS_SIMULATOR) + rive_renderer_appletvsimulator_metallib, + rive_renderer_appletvsimulator_metallib_len, +#else + rive_pls_macosx_metallib, + rive_pls_macosx_metallib_len, +#endif + nil, + nil); + NSError* err = [NSError errorWithDomain:@"metallib_load" + code:200 + userInfo:nil]; + m_plsPrecompiledLibrary = [m_gpu newLibraryWithData:metallibData + error:&err]; + if (m_plsPrecompiledLibrary == nil) + { + fprintf(stderr, "Failed to load pls metallib.\n"); + fprintf(stderr, "%s\n", err.localizedDescription.UTF8String); + abort(); + } + + m_colorRampPipeline = + std::make_unique(m_gpu, m_plsPrecompiledLibrary); + + MTLTextureDescriptor* desc = [[MTLTextureDescriptor alloc] init]; + desc.pixelFormat = MTLPixelFormatR16Float; + desc.textureType = MTLTextureType1DArray; + desc.width = gpu::GAUSSIAN_TABLE_SIZE; + desc.mipmapLevelCount = 1; + desc.arrayLength = FEATHER_TEXTURE_1D_ARRAY_LENGTH; + desc.usage = MTLTextureUsageShaderRead; + m_featherTexture = [m_gpu newTextureWithDescriptor:desc]; + [m_featherTexture + replaceRegion:MTLRegionMake2D(0, 0, gpu::GAUSSIAN_TABLE_SIZE, 1) + mipmapLevel:0 + slice:FEATHER_FUNCTION_ARRAY_INDEX + withBytes:gpu::g_gaussianIntegralTableF16 + bytesPerRow:sizeof(gpu::g_gaussianIntegralTableF16) + bytesPerImage:sizeof(gpu::g_gaussianIntegralTableF16)]; + [m_featherTexture + replaceRegion:MTLRegionMake2D(0, 0, gpu::GAUSSIAN_TABLE_SIZE, 1) + mipmapLevel:0 + slice:FEATHER_INVERSE_FUNCTION_ARRAY_INDEX + withBytes:gpu::g_inverseGaussianIntegralTableF16 + bytesPerRow:sizeof(gpu::g_gaussianIntegralTableF16) + bytesPerImage:sizeof(gpu::g_gaussianIntegralTableF16)]; + + m_tessPipeline = + std::make_unique(m_gpu, m_plsPrecompiledLibrary); + m_tessSpanIndexBuffer = + [m_gpu newBufferWithBytes:gpu::kTessSpanIndices + length:sizeof(gpu::kTessSpanIndices) + options:MTLResourceStorageModeShared]; + + // The precompiled static library has a fully-featured shader for each + // drawType in "rasterOrdering" mode. We load these at initialization and + // use them while waiting for the background compiler to generate more + // specialized, higher performance shaders. + if (m_platformFeatures.supportsRasterOrdering) + { + for (auto drawType : {DrawType::midpointFanPatches, + DrawType::interiorTriangulation, + DrawType::atlasBlit, + DrawType::imageMesh}) + { + for (auto shaderMiscFlags : {gpu::ShaderMiscFlags::none, + gpu::ShaderMiscFlags::clockwiseFill}) + { + if (drawType == gpu::DrawType::atlasBlit && + shaderMiscFlags != gpu::ShaderMiscFlags::none) + { + continue; + } + gpu::ShaderFeatures allShaderFeatures = + gpu::ShaderFeaturesMaskFor( + drawType, gpu::InterlockMode::rasterOrdering); + uint32_t pipelineKey = + ShaderUniqueKey(drawType, + allShaderFeatures, + gpu::InterlockMode::rasterOrdering, + shaderMiscFlags); + m_drawPipelines[pipelineKey] = std::make_unique( + m_gpu, + m_plsPrecompiledLibrary, + DrawPipeline::GetPrecompiledFunctionName( + drawType, + allShaderFeatures & gpu::kVertexShaderFeaturesMask, + gpu::ShaderMiscFlags::none, + m_plsPrecompiledLibrary, + GLSL_drawVertexMain), + DrawPipeline::GetPrecompiledFunctionName( + drawType, + allShaderFeatures, + shaderMiscFlags, + m_plsPrecompiledLibrary, + GLSL_drawFragmentMain), + drawType, + gpu::InterlockMode::rasterOrdering, + allShaderFeatures, + shaderMiscFlags); + } + } + } + + // Create vertex and index buffers for the different PLS patches. + m_pathPatchVertexBuffer = + [m_gpu newBufferWithLength:kPatchVertexBufferCount * sizeof(PatchVertex) + options:MTLResourceStorageModeShared]; + m_pathPatchIndexBuffer = + [m_gpu newBufferWithLength:kPatchIndexBufferCount * sizeof(uint16_t) + options:MTLResourceStorageModeShared]; + GeneratePatchBufferData( + reinterpret_cast(m_pathPatchVertexBuffer.contents), + reinterpret_cast(m_pathPatchIndexBuffer.contents)); + + // Set up the imageRect rendering buffers. (gpu::InterlockMode::atomics + // only.) + m_imageRectVertexBuffer = + [m_gpu newBufferWithBytes:gpu::kImageRectVertices + length:sizeof(gpu::kImageRectVertices) + options:MTLResourceStorageModeShared]; + m_imageRectIndexBuffer = + [m_gpu newBufferWithBytes:gpu::kImageRectIndices + length:sizeof(gpu::kImageRectIndices) + options:MTLResourceStorageModeShared]; +} + +RenderContextMetalImpl::~RenderContextMetalImpl() {} + +// If the GPU supports framebuffer reads (called "programmable blending" in the +// feature tables), PLS planes besides the main framebuffer can exist in +// ephemeral "memoryless" storage. This means their contents are never actually +// written to main memory, and they only exist in fast tiled memory. +static id make_pls_memoryless_texture(id gpu, + MTLPixelFormat pixelFormat, + uint32_t width, + uint32_t height) +{ + MTLTextureDescriptor* desc = [[MTLTextureDescriptor alloc] init]; + desc.pixelFormat = pixelFormat; + desc.width = width; + desc.height = height; + desc.usage = MTLTextureUsageRenderTarget; + desc.textureType = MTLTextureType2D; + desc.mipmapLevelCount = 1; + desc.storageMode = MTLStorageModeMemoryless; + return [gpu newTextureWithDescriptor:desc]; +} + +RenderTargetMetal::RenderTargetMetal(id gpu, + MTLPixelFormat pixelFormat, + uint32_t width, + uint32_t height, + const PlatformFeatures& platformFeatures) : + RenderTarget(width, height), m_gpu(gpu), m_pixelFormat(pixelFormat) +{ + m_targetTexture = nil; // Will be configured later by setTargetTexture(). + if (platformFeatures.supportsRasterOrdering) + { + m_coverageMemorylessTexture = make_pls_memoryless_texture( + gpu, MTLPixelFormatR32Uint, width, height); + m_clipMemorylessTexture = make_pls_memoryless_texture( + gpu, MTLPixelFormatR32Uint, width, height); + m_scratchColorMemorylessTexture = + make_pls_memoryless_texture(gpu, m_pixelFormat, width, height); + } +} + +void RenderTargetMetal::setTargetTexture(id texture) +{ + assert(!texture || compatibleWith(texture)); + m_targetTexture = texture; +} + +rcp RenderContextMetalImpl::makeRenderTarget( + MTLPixelFormat pixelFormat, uint32_t width, uint32_t height) +{ + return rcp(new RenderTargetMetal( + m_gpu, pixelFormat, width, height, m_platformFeatures)); +} + +class RenderBufferMetalImpl + : public LITE_RTTI_OVERRIDE(RiveRenderBuffer, RenderBufferMetalImpl) +{ +public: + RenderBufferMetalImpl(RenderBufferType renderBufferType, + RenderBufferFlags renderBufferFlags, + size_t sizeInBytes, + id gpu) : + lite_rtti_override(renderBufferType, renderBufferFlags, sizeInBytes), + m_gpu(gpu) + { + int bufferCount = + flags() & RenderBufferFlags::mappedOnceAtInitialization + ? 1 + : gpu::kBufferRingSize; + for (int i = 0; i < bufferCount; ++i) + { + m_buffers[i] = + [gpu newBufferWithLength:sizeInBytes + options:MTLResourceStorageModeShared]; + } + } + + id submittedBuffer() { return m_buffers[frontBufferIdx()]; } + +protected: + void* onMap() override + { + assert(m_buffers[backBufferIdx()] != nil); + return m_buffers[backBufferIdx()].contents; + } + + void onUnmap() override {} + +private: + id m_gpu; + id m_buffers[gpu::kBufferRingSize]; + int m_submittedBufferIdx = -1; +}; + +rcp RenderContextMetalImpl::makeRenderBuffer( + RenderBufferType type, RenderBufferFlags flags, size_t sizeInBytes) +{ + return make_rcp(type, flags, sizeInBytes, m_gpu); +} + +class TextureMetalImpl : public Texture +{ +public: + TextureMetalImpl(id gpu, + uint32_t width, + uint32_t height, + uint32_t mipLevelCount, + const uint8_t imageDataRGBAPremul[]) : + Texture(width, height) + { + // Create the texture. + MTLTextureDescriptor* desc = [[MTLTextureDescriptor alloc] init]; + desc.pixelFormat = MTLPixelFormatRGBA8Unorm; + desc.width = width; + desc.height = height; + desc.mipmapLevelCount = mipLevelCount; + desc.usage = MTLTextureUsageShaderRead; + desc.textureType = MTLTextureType2D; + m_texture = [gpu newTextureWithDescriptor:desc]; + + // Specify the top-level image in the mipmap chain. + MTLRegion region = MTLRegionMake2D(0, 0, width, height); + [m_texture replaceRegion:region + mipmapLevel:0 + withBytes:imageDataRGBAPremul + bytesPerRow:width * 4]; + } + + void ensureMipmaps(id commandBuffer) const + { + if (m_mipsDirty) + { + // Generate mipmaps. + id mipEncoder = + [commandBuffer blitCommandEncoder]; + [mipEncoder generateMipmapsForTexture:m_texture]; + [mipEncoder endEncoding]; + m_mipsDirty = false; + } + } + + id texture() const { return m_texture; } + +private: + id m_texture; + mutable bool m_mipsDirty = true; +}; + +rcp RenderContextMetalImpl::makeImageTexture( + uint32_t width, + uint32_t height, + uint32_t mipLevelCount, + const uint8_t imageDataRGBAPremul[]) +{ + return make_rcp( + m_gpu, width, height, mipLevelCount, imageDataRGBAPremul); +} + +std::unique_ptr RenderContextMetalImpl::makeUniformBufferRing( + size_t capacityInBytes) +{ + return BufferRingMetalImpl::Make(m_gpu, capacityInBytes); +} + +std::unique_ptr RenderContextMetalImpl::makeStorageBufferRing( + size_t capacityInBytes, gpu::StorageBufferStructure) +{ + return BufferRingMetalImpl::Make(m_gpu, capacityInBytes); +} + +std::unique_ptr RenderContextMetalImpl::makeVertexBufferRing( + size_t capacityInBytes) +{ + return BufferRingMetalImpl::Make(m_gpu, capacityInBytes); +} + +void RenderContextMetalImpl::resizeGradientTexture(uint32_t width, + uint32_t height) +{ + if (width == 0 || height == 0) + { + m_gradientTexture = nil; + return; + } + MTLTextureDescriptor* desc = [[MTLTextureDescriptor alloc] init]; + desc.pixelFormat = MTLPixelFormatRGBA8Unorm; + desc.width = width; + desc.height = height; + desc.usage = MTLTextureUsageRenderTarget | MTLTextureUsageShaderRead; + desc.textureType = MTLTextureType2D; + desc.mipmapLevelCount = 1; + desc.storageMode = MTLStorageModePrivate; + m_gradientTexture = [m_gpu newTextureWithDescriptor:desc]; +} + +void RenderContextMetalImpl::resizeTessellationTexture(uint32_t width, + uint32_t height) +{ + if (width == 0 || height == 0) + { + m_tessVertexTexture = nil; + return; + } + MTLTextureDescriptor* desc = [[MTLTextureDescriptor alloc] init]; + desc.pixelFormat = MTLPixelFormatRGBA32Uint; + desc.width = width; + desc.height = height; + desc.usage = MTLTextureUsageRenderTarget | MTLTextureUsageShaderRead; + desc.textureType = MTLTextureType2D; + desc.mipmapLevelCount = 1; + desc.storageMode = MTLStorageModePrivate; + m_tessVertexTexture = [m_gpu newTextureWithDescriptor:desc]; +} + +void RenderContextMetalImpl::resizeAtlasTexture(uint32_t width, uint32_t height) +{ + if (width == 0 || height == 0) + { + m_atlasTexture = nil; + return; + } + + MTLTextureDescriptor* desc = [[MTLTextureDescriptor alloc] init]; + desc.pixelFormat = MTLPixelFormatR32Float; + desc.width = width; + desc.height = height; + desc.usage = MTLTextureUsageRenderTarget | MTLTextureUsageShaderRead; + desc.textureType = MTLTextureType2D; + desc.mipmapLevelCount = 1; + desc.storageMode = MTLStorageModePrivate; + m_atlasTexture = [m_gpu newTextureWithDescriptor:desc]; + + // Don't build atlas pipelines until we get an indication that they will be + // used. + assert((m_atlasFillPipeline == nil) == (m_atlasStrokePipeline == nil)); + if (m_atlasFillPipeline == nil) + { + m_atlasFillPipeline = + std::make_unique(m_gpu, + m_plsPrecompiledLibrary, + @GLSL_atlasFillFragmentMain, + MTLBlendOperationAdd); + m_atlasStrokePipeline = + std::make_unique(m_gpu, + m_plsPrecompiledLibrary, + @GLSL_atlasStrokeFragmentMain, + MTLBlendOperationMax); + } +} + +const RenderContextMetalImpl::DrawPipeline* RenderContextMetalImpl:: + findCompatibleDrawPipeline(gpu::DrawType drawType, + gpu::ShaderFeatures shaderFeatures, + const gpu::FlushDescriptor& desc, + gpu::ShaderMiscFlags shaderMiscFlags) +{ + // Find a fully-featured superset of features whose pipeline we can fall + // back on while waiting for it to compile. + ShaderFeatures fullyFeaturedPipelineFeatures = + gpu::ShaderFeaturesMaskFor(drawType, desc.interlockMode); + if (desc.interlockMode == gpu::InterlockMode::atomics) + { + // Never add ENABLE_ADVANCED_BLEND to an atomic pipeline that doesn't + // use advanced blend, since in atomic mode, the shaders behave + // differently depending on whether advanced blend is enabled. + fullyFeaturedPipelineFeatures &= + shaderFeatures | ~ShaderFeatures::ENABLE_ADVANCED_BLEND; + // Never add ENABLE_CLIPPING to an atomic pipeline that doesn't use + // clipping; it will cause a "missing buffer binding" validation error + // because the shader will define an (unused) clipBuffer, but we won't + // bind anything to it. + fullyFeaturedPipelineFeatures &= + shaderFeatures | ~ShaderFeatures::ENABLE_CLIPPING; + } + shaderFeatures &= fullyFeaturedPipelineFeatures; + + uint32_t pipelineKey = gpu::ShaderUniqueKey( + drawType, shaderFeatures, desc.interlockMode, shaderMiscFlags); + auto pipelineIter = m_drawPipelines.find(pipelineKey); + if (pipelineIter == m_drawPipelines.end()) + { + // The shader for this pipeline hasn't been scheduled for compiling yet. + // Schedule it to compile in the background. + m_backgroundShaderCompiler->pushJob({ + .drawType = drawType, + .shaderFeatures = shaderFeatures, + .interlockMode = desc.interlockMode, + .shaderMiscFlags = shaderMiscFlags, +#ifdef WITH_RIVE_TOOLS + .synthesizeCompilationFailure = desc.synthesizeCompilationFailures, +#endif + }); + pipelineIter = m_drawPipelines.insert({pipelineKey, nullptr}).first; + } + + if (pipelineIter->second == nullptr) + { + // The shader for this pipeline hasn't finished compiling yet. + // Fully-featured "rasterOrdering" pipelines should have already been + // pre-loaded from the static library. + assert(shaderFeatures != fullyFeaturedPipelineFeatures || + desc.interlockMode != gpu::InterlockMode::rasterOrdering); + + // Poll to see if the shader is actually done compiling, but only wait + // if it's a fully-feature pipeline. Otherwise, we can fall back on the + // fully-featured pipeline while we wait for compilation. + BackgroundCompileJob job; + bool shouldWaitForBackgroundCompilation = + shaderFeatures == fullyFeaturedPipelineFeatures || + m_contextOptions.synchronousShaderCompilations; + while (m_backgroundShaderCompiler->popFinishedJob( + &job, shouldWaitForBackgroundCompilation)) + { + uint32_t jobKey = gpu::ShaderUniqueKey(job.drawType, + job.shaderFeatures, + job.interlockMode, + job.shaderMiscFlags); + m_drawPipelines[jobKey] = + std::make_unique(m_gpu, + job.compiledLibrary, + @GLSL_drawVertexMain, + @GLSL_drawFragmentMain, + job.drawType, + job.interlockMode, + job.shaderFeatures, + job.shaderMiscFlags); + if (jobKey == pipelineKey) + { + // The shader we wanted was actually done compiling and pending + // being built into a pipeline. + break; + } + } + } + + if ((pipelineIter->second == nullptr || !pipelineIter->second->valid()) && + shaderFeatures != fullyFeaturedPipelineFeatures) + { + // The shader for this feature set hasn't finished compiling (or it + // failed to compile). Use the uber-shader pipeline that has all + // features enabled while we wait for it to finish. + return findCompatibleDrawPipeline( + drawType, fullyFeaturedPipelineFeatures, desc, shaderMiscFlags); + } + + return pipelineIter->second.get(); +} + +void RenderContextMetalImpl::prepareToFlush(uint64_t nextFrameNumber, + uint64_t safeFrameNumber) +{ + // Wait until the GPU finishes rendering flush "N + 1 - kBufferRingSize". + // This ensures it is safe for the CPU to begin modifying the next buffers + // in our rings. + m_bufferRingIdx = (m_bufferRingIdx + 1) % kBufferRingSize; + m_bufferRingLocks[m_bufferRingIdx].lock(); +} + +static id mtl_buffer(const BufferRing* bufferRing) +{ + assert(bufferRing != nullptr); + return static_cast(bufferRing) + ->submittedBuffer(); +} + +static MTLViewport make_viewport(uint32_t x, + uint32_t y, + uint32_t width, + uint32_t height) +{ + return { + static_cast(x), + static_cast(y), + static_cast(width), + static_cast(height), + 0, + 1, + }; +} + +static MTLScissorRect make_scissor(const TAABB& scissor) +{ + return { + static_cast(scissor.left), + static_cast(scissor.top), + static_cast(scissor.width()), + static_cast(scissor.height()), + }; +} + +id RenderContextMetalImpl::makeRenderPassForDraws( + const gpu::FlushDescriptor& flushDesc, + MTLRenderPassDescriptor* passDesc, + id commandBuffer, + gpu::ShaderMiscFlags baselineShaderMiscFlags) +{ + auto* renderTarget = + static_cast(flushDesc.renderTarget); + + id encoder = + [commandBuffer renderCommandEncoderWithDescriptor:passDesc]; + + [encoder + setViewport:make_viewport( + 0, 0, renderTarget->width(), renderTarget->height())]; + [encoder setVertexBuffer:mtl_buffer(flushUniformBufferRing()) + offset:flushDesc.flushUniformDataOffsetInBytes + atIndex:METAL_BUFFER_IDX(FLUSH_UNIFORM_BUFFER_IDX)]; + [encoder setFragmentBuffer:mtl_buffer(flushUniformBufferRing()) + offset:flushDesc.flushUniformDataOffsetInBytes + atIndex:METAL_BUFFER_IDX(FLUSH_UNIFORM_BUFFER_IDX)]; + [encoder setVertexTexture:m_tessVertexTexture + atIndex:TESS_VERTEX_TEXTURE_IDX]; + [encoder setVertexTexture:m_featherTexture atIndex:FEATHER_TEXTURE_IDX]; + [encoder setFragmentTexture:m_gradientTexture atIndex:GRAD_TEXTURE_IDX]; + [encoder setFragmentTexture:m_featherTexture atIndex:FEATHER_TEXTURE_IDX]; + [encoder setFragmentTexture:m_atlasTexture atIndex:ATLAS_TEXTURE_IDX]; + if (flushDesc.pathCount > 0) + { + [encoder setVertexBuffer:mtl_buffer(pathBufferRing()) + offset:flushDesc.firstPath * sizeof(gpu::PathData) + atIndex:METAL_BUFFER_IDX(PATH_BUFFER_IDX)]; + if (flushDesc.interlockMode == gpu::InterlockMode::atomics) + { + [encoder + setFragmentBuffer:mtl_buffer(paintBufferRing()) + offset:flushDesc.firstPaint * sizeof(gpu::PaintData) + atIndex:METAL_BUFFER_IDX(PAINT_BUFFER_IDX)]; + [encoder setFragmentBuffer:mtl_buffer(paintAuxBufferRing()) + offset:flushDesc.firstPaintAux * + sizeof(gpu::PaintAuxData) + atIndex:METAL_BUFFER_IDX(PAINT_AUX_BUFFER_IDX)]; + } + else + { + [encoder + setVertexBuffer:mtl_buffer(paintBufferRing()) + offset:flushDesc.firstPaint * sizeof(gpu::PaintData) + atIndex:METAL_BUFFER_IDX(PAINT_BUFFER_IDX)]; + [encoder setVertexBuffer:mtl_buffer(paintAuxBufferRing()) + offset:flushDesc.firstPaintAux * + sizeof(gpu::PaintAuxData) + atIndex:METAL_BUFFER_IDX(PAINT_AUX_BUFFER_IDX)]; + } + } + if (flushDesc.contourCount > 0) + { + [encoder + setVertexBuffer:mtl_buffer(contourBufferRing()) + offset:flushDesc.firstContour * sizeof(gpu::ContourData) + atIndex:METAL_BUFFER_IDX(CONTOUR_BUFFER_IDX)]; + } + if (flushDesc.interlockMode == gpu::InterlockMode::atomics) + { + // In atomic mode, the PLS planes are buffers that we need to bind + // separately. Since the PLS plane indices collide with other buffer + // bindings, offset the binding indices of these buffers by + // DEFAULT_BINDINGS_SET_SIZE. + if (!(baselineShaderMiscFlags & + gpu::ShaderMiscFlags::fixedFunctionColorOutput)) + { + [encoder + setFragmentBuffer:renderTarget->colorAtomicBuffer() + offset:0 + atIndex:METAL_BUFFER_IDX(COLOR_PLANE_IDX + + DEFAULT_BINDINGS_SET_SIZE)]; + } + if (flushDesc.combinedShaderFeatures & + gpu::ShaderFeatures::ENABLE_CLIPPING) + { + [encoder + setFragmentBuffer:renderTarget->clipAtomicBuffer() + offset:0 + atIndex:METAL_BUFFER_IDX(CLIP_PLANE_IDX + + DEFAULT_BINDINGS_SET_SIZE)]; + } + [encoder setFragmentBuffer:renderTarget->coverageAtomicBuffer() + offset:0 + atIndex:METAL_BUFFER_IDX(COVERAGE_PLANE_IDX + + DEFAULT_BINDINGS_SET_SIZE)]; + } + if (flushDesc.wireframe) + { + [encoder setTriangleFillMode:MTLTriangleFillModeLines]; + } + return encoder; +} + +void RenderContextMetalImpl::flush(const FlushDescriptor& desc) +{ + assert(desc.interlockMode != gpu::InterlockMode::clockwiseAtomic); + assert(desc.interlockMode != gpu::InterlockMode::msaa); // TODO: msaa. + + auto* renderTarget = static_cast(desc.renderTarget); + id commandBuffer = + (__bridge id)desc.externalCommandBuffer; + + // Render the color ramps to the gradient texture. + if (desc.gradSpanCount > 0) + { + MTLRenderPassDescriptor* gradPass = + [MTLRenderPassDescriptor renderPassDescriptor]; + gradPass.renderTargetWidth = kGradTextureWidth; + gradPass.renderTargetHeight = desc.gradDataHeight; + gradPass.colorAttachments[0].loadAction = MTLLoadActionDontCare; + gradPass.colorAttachments[0].storeAction = MTLStoreActionStore; + gradPass.colorAttachments[0].texture = m_gradientTexture; + + id gradEncoder = + [commandBuffer renderCommandEncoderWithDescriptor:gradPass]; + [gradEncoder + setViewport:make_viewport(0, + 0, + kGradTextureWidth, + static_cast(desc.gradDataHeight))]; + [gradEncoder + setRenderPipelineState:m_colorRampPipeline->pipelineState()]; + [gradEncoder + setVertexBuffer:mtl_buffer(flushUniformBufferRing()) + offset:desc.flushUniformDataOffsetInBytes + atIndex:METAL_BUFFER_IDX(FLUSH_UNIFORM_BUFFER_IDX)]; + [gradEncoder + setVertexBuffer:mtl_buffer(gradSpanBufferRing()) + offset:desc.firstGradSpan * sizeof(gpu::GradientSpan) + atIndex:0]; + [gradEncoder setCullMode:MTLCullModeBack]; + [gradEncoder drawPrimitives:MTLPrimitiveTypeTriangleStrip + vertexStart:0 + vertexCount:gpu::GRAD_SPAN_TRI_STRIP_VERTEX_COUNT + instanceCount:desc.gradSpanCount]; + [gradEncoder endEncoding]; + } + + // Tessellate all curves into vertices in the tessellation texture. + if (desc.tessVertexSpanCount > 0) + { + MTLRenderPassDescriptor* tessPass = + [MTLRenderPassDescriptor renderPassDescriptor]; + tessPass.renderTargetWidth = kTessTextureWidth; + tessPass.renderTargetHeight = desc.tessDataHeight; + tessPass.colorAttachments[0].loadAction = MTLLoadActionDontCare; + tessPass.colorAttachments[0].storeAction = MTLStoreActionStore; + tessPass.colorAttachments[0].texture = m_tessVertexTexture; + + id tessEncoder = + [commandBuffer renderCommandEncoderWithDescriptor:tessPass]; + [tessEncoder + setViewport:make_viewport( + 0, 0, kTessTextureWidth, desc.tessDataHeight)]; + [tessEncoder setRenderPipelineState:m_tessPipeline->pipelineState()]; + [tessEncoder setVertexTexture:m_featherTexture + atIndex:FEATHER_TEXTURE_IDX]; + [tessEncoder + setVertexBuffer:mtl_buffer(flushUniformBufferRing()) + offset:desc.flushUniformDataOffsetInBytes + atIndex:METAL_BUFFER_IDX(FLUSH_UNIFORM_BUFFER_IDX)]; + [tessEncoder setVertexBuffer:mtl_buffer(tessSpanBufferRing()) + offset:desc.firstTessVertexSpan * + sizeof(gpu::TessVertexSpan) + atIndex:0]; + assert(desc.pathCount > 0); + [tessEncoder setVertexBuffer:mtl_buffer(pathBufferRing()) + offset:desc.firstPath * sizeof(gpu::PathData) + atIndex:METAL_BUFFER_IDX(PATH_BUFFER_IDX)]; + assert(desc.contourCount > 0); + [tessEncoder + setVertexBuffer:mtl_buffer(contourBufferRing()) + offset:desc.firstContour * sizeof(gpu::ContourData) + atIndex:METAL_BUFFER_IDX(CONTOUR_BUFFER_IDX)]; + [tessEncoder setCullMode:MTLCullModeBack]; + [tessEncoder drawIndexedPrimitives:MTLPrimitiveTypeTriangle + indexCount:std::size(gpu::kTessSpanIndices) + indexType:MTLIndexTypeUInt16 + indexBuffer:m_tessSpanIndexBuffer + indexBufferOffset:0 + instanceCount:desc.tessVertexSpanCount]; + [tessEncoder endEncoding]; + } + + // Render the atlas if we have any offscreen feathers. + if ((desc.atlasFillBatchCount | desc.atlasStrokeBatchCount) != 0) + { + MTLRenderPassDescriptor* atlasPass = + [MTLRenderPassDescriptor renderPassDescriptor]; + atlasPass.renderTargetWidth = desc.atlasContentWidth; + atlasPass.renderTargetHeight = desc.atlasContentHeight; + atlasPass.colorAttachments[0].loadAction = MTLLoadActionClear; + atlasPass.colorAttachments[0].storeAction = MTLStoreActionStore; + atlasPass.colorAttachments[0].texture = m_atlasTexture; + atlasPass.colorAttachments[0].clearColor = + MTLClearColorMake(0, 0, 0, 0); + + id atlasEncoder = + [commandBuffer renderCommandEncoderWithDescriptor:atlasPass]; + [atlasEncoder setViewport:make_viewport(0, + 0, + desc.atlasContentWidth, + desc.atlasContentHeight)]; + [atlasEncoder + setVertexBuffer:mtl_buffer(flushUniformBufferRing()) + offset:desc.flushUniformDataOffsetInBytes + atIndex:METAL_BUFFER_IDX(FLUSH_UNIFORM_BUFFER_IDX)]; + [atlasEncoder + setFragmentBuffer:mtl_buffer(flushUniformBufferRing()) + offset:desc.flushUniformDataOffsetInBytes + atIndex:METAL_BUFFER_IDX(FLUSH_UNIFORM_BUFFER_IDX)]; + [atlasEncoder setVertexTexture:m_tessVertexTexture + atIndex:TESS_VERTEX_TEXTURE_IDX]; + [atlasEncoder setVertexTexture:m_featherTexture + atIndex:FEATHER_TEXTURE_IDX]; + [atlasEncoder setFragmentTexture:m_gradientTexture + atIndex:GRAD_TEXTURE_IDX]; + [atlasEncoder setFragmentTexture:m_featherTexture + atIndex:FEATHER_TEXTURE_IDX]; + if (desc.pathCount > 0) + { + [atlasEncoder setVertexBuffer:mtl_buffer(pathBufferRing()) + offset:desc.firstPath * sizeof(gpu::PathData) + atIndex:METAL_BUFFER_IDX(PATH_BUFFER_IDX)]; + [atlasEncoder + setVertexBuffer:mtl_buffer(paintBufferRing()) + offset:desc.firstPaint * sizeof(gpu::PaintData) + atIndex:METAL_BUFFER_IDX(PAINT_BUFFER_IDX)]; + [atlasEncoder + setVertexBuffer:mtl_buffer(paintAuxBufferRing()) + offset:desc.firstPaintAux * sizeof(gpu::PaintAuxData) + atIndex:METAL_BUFFER_IDX(PAINT_AUX_BUFFER_IDX)]; + } + if (desc.contourCount > 0) + { + [atlasEncoder + setVertexBuffer:mtl_buffer(contourBufferRing()) + offset:desc.firstContour * sizeof(gpu::ContourData) + atIndex:METAL_BUFFER_IDX(CONTOUR_BUFFER_IDX)]; + } + [atlasEncoder setVertexBuffer:m_pathPatchVertexBuffer + offset:0 + atIndex:0]; + [atlasEncoder setCullMode:MTLCullModeBack]; + + if (desc.atlasFillBatchCount != 0) + { + [atlasEncoder + setRenderPipelineState:m_atlasFillPipeline->pipelineState()]; + for (size_t i = 0; i < desc.atlasFillBatchCount; ++i) + { + const gpu::AtlasDrawBatch& fillBatch = desc.atlasFillBatches[i]; + [atlasEncoder setScissorRect:make_scissor(fillBatch.scissor)]; + [atlasEncoder + setVertexBytes:&fillBatch.basePatch + length:sizeof(uint32_t) + atIndex:METAL_BUFFER_IDX( + PATH_BASE_INSTANCE_UNIFORM_BUFFER_IDX)]; + [atlasEncoder + drawIndexedPrimitives:MTLPrimitiveTypeTriangle + indexCount: + gpu::kMidpointFanCenterAAPatchIndexCount + indexType:MTLIndexTypeUInt16 + indexBuffer:m_pathPatchIndexBuffer + indexBufferOffset: + gpu::kMidpointFanCenterAAPatchBaseIndex * + sizeof(uint16_t) + instanceCount:fillBatch.patchCount]; + } + } + + if (desc.atlasStrokeBatchCount != 0) + { + [atlasEncoder + setRenderPipelineState:m_atlasStrokePipeline->pipelineState()]; + for (size_t i = 0; i < desc.atlasStrokeBatchCount; ++i) + { + const gpu::AtlasDrawBatch& strokeBatch = + desc.atlasStrokeBatches[i]; + [atlasEncoder setScissorRect:make_scissor(strokeBatch.scissor)]; + [atlasEncoder + setVertexBytes:&strokeBatch.basePatch + length:sizeof(uint32_t) + atIndex:METAL_BUFFER_IDX( + PATH_BASE_INSTANCE_UNIFORM_BUFFER_IDX)]; + [atlasEncoder + drawIndexedPrimitives:MTLPrimitiveTypeTriangle + indexCount:gpu::kMidpointFanPatchBorderIndexCount + indexType:MTLIndexTypeUInt16 + indexBuffer:m_pathPatchIndexBuffer + indexBufferOffset:gpu::kMidpointFanPatchBaseIndex * + sizeof(uint16_t) + instanceCount:strokeBatch.patchCount]; + } + } + + [atlasEncoder endEncoding]; + } + + // Generate mipmaps if needed. + for (const DrawBatch& batch : *desc.drawList) + { + if (auto imageTextureMetal = + static_cast(batch.imageTexture)) + { + imageTextureMetal->ensureMipmaps(commandBuffer); + } + } + + // Set up a render pass to do the final rendering using (some form of) pixel + // local storage. + MTLRenderPassDescriptor* pass = + [MTLRenderPassDescriptor renderPassDescriptor]; + pass.renderTargetWidth = desc.renderTargetUpdateBounds.right; + pass.renderTargetHeight = desc.renderTargetUpdateBounds.bottom; + pass.colorAttachments[COLOR_PLANE_IDX].texture = + renderTarget->targetTexture(); + switch (desc.colorLoadAction) + { + case gpu::LoadAction::clear: + { + float cc[4]; + UnpackColorToRGBA32FPremul(desc.colorClearValue, cc); + pass.colorAttachments[COLOR_PLANE_IDX].loadAction = + MTLLoadActionClear; + pass.colorAttachments[COLOR_PLANE_IDX].clearColor = + MTLClearColorMake(cc[0], cc[1], cc[2], cc[3]); + break; + } + case gpu::LoadAction::preserveRenderTarget: + pass.colorAttachments[COLOR_PLANE_IDX].loadAction = + MTLLoadActionLoad; + break; + case gpu::LoadAction::dontCare: + pass.colorAttachments[COLOR_PLANE_IDX].loadAction = + MTLLoadActionDontCare; + break; + } + pass.colorAttachments[COLOR_PLANE_IDX].storeAction = MTLStoreActionStore; + + auto baselineShaderMiscFlags = gpu::ShaderMiscFlags::none; + if (desc.interlockMode == gpu::InterlockMode::rasterOrdering) + { + // In rasterOrdering mode, the PLS planes are accessed as color + // attachments. + pass.colorAttachments[CLIP_PLANE_IDX].texture = + renderTarget->m_clipMemorylessTexture; + pass.colorAttachments[CLIP_PLANE_IDX].loadAction = MTLLoadActionClear; + pass.colorAttachments[CLIP_PLANE_IDX].clearColor = + MTLClearColorMake(0, 0, 0, 0); + pass.colorAttachments[CLIP_PLANE_IDX].storeAction = + MTLStoreActionDontCare; + + pass.colorAttachments[SCRATCH_COLOR_PLANE_IDX].texture = + renderTarget->m_scratchColorMemorylessTexture; + pass.colorAttachments[SCRATCH_COLOR_PLANE_IDX].loadAction = + MTLLoadActionDontCare; + pass.colorAttachments[SCRATCH_COLOR_PLANE_IDX].storeAction = + MTLStoreActionDontCare; + + pass.colorAttachments[COVERAGE_PLANE_IDX].texture = + renderTarget->m_coverageMemorylessTexture; + pass.colorAttachments[COVERAGE_PLANE_IDX].loadAction = + MTLLoadActionClear; + pass.colorAttachments[COVERAGE_PLANE_IDX].clearColor = + MTLClearColorMake(desc.coverageClearValue, 0, 0, 0); + pass.colorAttachments[COVERAGE_PLANE_IDX].storeAction = + MTLStoreActionDontCare; + } + else if (desc.atomicFixedFunctionColorOutput) + { + assert(desc.interlockMode == gpu::InterlockMode::atomics); + baselineShaderMiscFlags |= + gpu::ShaderMiscFlags::fixedFunctionColorOutput; + } + else if (desc.colorLoadAction == gpu::LoadAction::preserveRenderTarget) + { + // Since we need to preserve the renderTarget during load, and since + // we're rendering to an offscreen color buffer, we have to literally + // copy the renderTarget into the color buffer. + assert(desc.interlockMode == gpu::InterlockMode::atomics); + id copyEncoder = + [commandBuffer blitCommandEncoder]; + auto updateOrigin = MTLOriginMake(desc.renderTargetUpdateBounds.left, + desc.renderTargetUpdateBounds.top, + 0); + auto updateSize = MTLSizeMake(desc.renderTargetUpdateBounds.width(), + desc.renderTargetUpdateBounds.height(), + 1); + [copyEncoder copyFromTexture:renderTarget->targetTexture() + sourceSlice:0 + sourceLevel:0 + sourceOrigin:updateOrigin + sourceSize:updateSize + toBuffer:renderTarget->colorAtomicBuffer() + destinationOffset:(updateOrigin.y * renderTarget->width() + + updateOrigin.x) * + sizeof(uint32_t) + destinationBytesPerRow:renderTarget->width() * sizeof(uint32_t) + destinationBytesPerImage:renderTarget->height() * + renderTarget->width() * sizeof(uint32_t)]; + [copyEncoder endEncoding]; + } + + // Execute the DrawList. + id encoder = makeRenderPassForDraws( + desc, pass, commandBuffer, baselineShaderMiscFlags); + for (const DrawBatch& batch : *desc.drawList) + { + // Setup the pipeline for this specific drawType and shaderFeatures. + gpu::ShaderFeatures shaderFeatures = + desc.interlockMode == gpu::InterlockMode::atomics + ? desc.combinedShaderFeatures + : batch.shaderFeatures; + gpu::ShaderMiscFlags batchMiscFlags = + baselineShaderMiscFlags | batch.shaderMiscFlags; + if (desc.interlockMode == gpu::InterlockMode::rasterOrdering && + (batch.drawContents & gpu::DrawContents::clockwiseFill)) + { + batchMiscFlags |= gpu::ShaderMiscFlags::clockwiseFill; + } + if (!(batchMiscFlags & gpu::ShaderMiscFlags::fixedFunctionColorOutput)) + { + if (batch.drawType == gpu::DrawType::atomicResolve) + { + // Atomic mode can always do a coalesced resolve when rendering + // to an offscreen color buffer. + batchMiscFlags |= + gpu::ShaderMiscFlags::coalescedResolveAndTransfer; + } + else if (batch.drawType == gpu::DrawType::atomicInitialize) + { + if (desc.colorLoadAction == gpu::LoadAction::clear) + { + batchMiscFlags |= gpu::ShaderMiscFlags::storeColorClear; + } + else if (desc.colorLoadAction == + gpu::LoadAction::preserveRenderTarget && + renderTarget->pixelFormat() == + MTLPixelFormatBGRA8Unorm) + { + // We already copied the renderTarget to our color buffer, + // but since the target is BGRA, we also need to swizzle it + // to RGBA before it's ready for PLS. + batchMiscFlags |= + gpu::ShaderMiscFlags::swizzleColorBGRAToRGBA; + } + } + } + const DrawPipeline* drawPipeline = findCompatibleDrawPipeline( + batch.drawType, shaderFeatures, desc, batchMiscFlags); + if (drawPipeline == nullptr || !drawPipeline->valid()) + { + // The shader for this draw AND the uber-shader both failed to + // compile. This should virtually never happen, and can only happen + // on non-Apple Silicon, where we don't use precompiled shaders. + // Skip the draw. + continue; + } + id drawPipelineState = + drawPipeline->pipelineState(renderTarget->pixelFormat()); + + // Bind the appropriate image texture, if any. + if (auto imageTextureMetal = + static_cast(batch.imageTexture)) + { + [encoder setFragmentTexture:imageTextureMetal->texture() + atIndex:IMAGE_TEXTURE_IDX]; + + [encoder setFragmentSamplerState:m_imageSamplers[batch.imageSampler + .asKey()] + atIndex:IMAGE_SAMPLER_IDX]; + } + else + { + [encoder setFragmentSamplerState: + m_imageSamplers[ImageSampler::LINEAR_CLAMP_SAMPLER_KEY] + atIndex:IMAGE_SAMPLER_IDX]; + } + + // Issue any barriers if needed. + if (batch.barriers & + (BarrierFlags::plsAtomic | BarrierFlags::plsAtomicPostInit | + BarrierFlags::plsAtomicPreResolve)) + { + assert(desc.interlockMode == gpu::InterlockMode::atomics); + switch (m_metalFeatures.atomicBarrierType) + { + case AtomicBarrierType::memoryBarrier: +#if defined(RIVE_MACOSX) + if (@available(macOS 10.14, *)) + { + [encoder + memoryBarrierWithScope:MTLBarrierScopeBuffers | + MTLBarrierScopeRenderTargets + afterStages:MTLRenderStageFragment + beforeStages:MTLRenderStageFragment]; + break; + } +#endif + // atomicBarrierType shouldn't be "memoryBarrier" in this + // case. + RIVE_UNREACHABLE(); + + case AtomicBarrierType::rasterOrderGroup: + break; + + case AtomicBarrierType::renderPassBreak: + // On very old hardware that can't support barriers, we just + // take a sledge hammer and break the entire render pass + // between overlapping draws. + // TODO: Is there a lighter way to achieve this? + [encoder endEncoding]; + pass.colorAttachments[COLOR_PLANE_IDX].loadAction = + MTLLoadActionLoad; + encoder = makeRenderPassForDraws( + desc, pass, commandBuffer, baselineShaderMiscFlags); + break; + } + } + + DrawType drawType = batch.drawType; + switch (drawType) + { + case DrawType::midpointFanPatches: + case DrawType::midpointFanCenterAAPatches: + case DrawType::outerCurvePatches: + { + // Draw PLS patches that connect the tessellation vertices. + [encoder setRenderPipelineState:drawPipelineState]; + [encoder setVertexBuffer:m_pathPatchVertexBuffer + offset:0 + atIndex:0]; + [encoder setCullMode:MTLCullModeBack]; + // Don't use baseInstance in order to run on Apple GPU Family 2. + // TODO: Use baseInstance instead once we deprecate Apple2. + [encoder + setVertexBytes:&batch.baseElement + length:sizeof(uint32_t) + atIndex:METAL_BUFFER_IDX( + PATH_BASE_INSTANCE_UNIFORM_BUFFER_IDX)]; + [encoder drawIndexedPrimitives:MTLPrimitiveTypeTriangle + indexCount:gpu::PatchIndexCount(drawType) + indexType:MTLIndexTypeUInt16 + indexBuffer:m_pathPatchIndexBuffer + indexBufferOffset:gpu::PatchBaseIndex(drawType) * + sizeof(uint16_t) + instanceCount:batch.elementCount]; + break; + } + case DrawType::interiorTriangulation: + case DrawType::atlasBlit: + { + [encoder setRenderPipelineState:drawPipelineState]; + [encoder setVertexBuffer:mtl_buffer(triangleBufferRing()) + offset:0 + atIndex:0]; + [encoder setCullMode:MTLCullModeBack]; + [encoder drawPrimitives:MTLPrimitiveTypeTriangle + vertexStart:batch.baseElement + vertexCount:batch.elementCount]; + break; + } + case DrawType::imageRect: + case DrawType::imageMesh: + { + [encoder setRenderPipelineState:drawPipelineState]; + [encoder + setVertexBuffer:mtl_buffer(imageDrawUniformBufferRing()) + offset:batch.imageDrawDataOffset + atIndex:METAL_BUFFER_IDX( + IMAGE_DRAW_UNIFORM_BUFFER_IDX)]; + [encoder + setFragmentBuffer:mtl_buffer(imageDrawUniformBufferRing()) + offset:batch.imageDrawDataOffset + atIndex:METAL_BUFFER_IDX( + IMAGE_DRAW_UNIFORM_BUFFER_IDX)]; + [encoder setCullMode:MTLCullModeNone]; + if (drawType == DrawType::imageRect) + { + assert(desc.interlockMode == gpu::InterlockMode::atomics); + [encoder setVertexBuffer:m_imageRectVertexBuffer + offset:0 + atIndex:0]; + [encoder + drawIndexedPrimitives:MTLPrimitiveTypeTriangle + indexCount:std::size(gpu::kImageRectIndices) + indexType:MTLIndexTypeUInt16 + indexBuffer:m_imageRectIndexBuffer + indexBufferOffset:0]; + } + else + { + LITE_RTTI_CAST_OR_BREAK(vertexBuffer, + RenderBufferMetalImpl*, + batch.vertexBuffer); + LITE_RTTI_CAST_OR_BREAK( + uvBuffer, RenderBufferMetalImpl*, batch.uvBuffer); + LITE_RTTI_CAST_OR_BREAK( + indexBuffer, RenderBufferMetalImpl*, batch.indexBuffer); + [encoder setVertexBuffer:vertexBuffer->submittedBuffer() + offset:0 + atIndex:0]; + [encoder setVertexBuffer:uvBuffer->submittedBuffer() + offset:0 + atIndex:1]; + [encoder + drawIndexedPrimitives:MTLPrimitiveTypeTriangle + indexCount:batch.elementCount + indexType:MTLIndexTypeUInt16 + indexBuffer:indexBuffer->submittedBuffer() + indexBufferOffset:batch.baseElement * + sizeof(uint16_t)]; + } + break; + } + case DrawType::atomicInitialize: + case DrawType::atomicResolve: + { + assert(desc.interlockMode == gpu::InterlockMode::atomics); + [encoder setRenderPipelineState:drawPipelineState]; + [encoder drawPrimitives:MTLPrimitiveTypeTriangleStrip + vertexStart:0 + vertexCount:4]; + break; + } + case DrawType::msaaStrokes: + case DrawType::msaaMidpointFanBorrowedCoverage: + case DrawType::msaaMidpointFans: + case DrawType::msaaMidpointFanStencilReset: + case DrawType::msaaMidpointFanPathsStencil: + case DrawType::msaaMidpointFanPathsCover: + case DrawType::msaaOuterCubics: + case DrawType::msaaStencilClipReset: + { + RIVE_UNREACHABLE(); + } + } + } + [encoder endEncoding]; +} + +void RenderContextMetalImpl::postFlush( + const RenderContext::FlushResources& flushResources) +{ + // Schedule a callback that will unlock the buffers used by this flush, + // after the GPU has finished rendering with them. This unblocks the CPU + // from reusing them in a future flush. + id commandBuffer = + (__bridge id)flushResources.externalCommandBuffer; + std::mutex& thisFlushLock = m_bufferRingLocks[m_bufferRingIdx]; + [commandBuffer addCompletedHandler:^(id) { + assert(!thisFlushLock.try_lock()); // The mutex should already be locked. + thisFlushLock.unlock(); + }]; +} +} // namespace rive::gpu diff --git a/third_party/rive_renderer/source/render_context.cpp b/third_party/rive_renderer/source/render_context.cpp new file mode 100644 index 0000000..ba675ad --- /dev/null +++ b/third_party/rive_renderer/source/render_context.cpp @@ -0,0 +1,2852 @@ +/* + * Copyright 2022 Rive + */ + +#include "rive/renderer/render_context.hpp" + +#include "gr_inner_fan_triangulator.hpp" +#include "intersection_board.hpp" +#include "gradient.hpp" +#include "rive_render_paint.hpp" +#include "rive/renderer/draw.hpp" +#include "rive/renderer/rive_render_image.hpp" +#include "rive/renderer/render_context_impl.hpp" +#include "shaders/constants.glsl" + +#include + +#ifdef RIVE_DECODERS +#include "rive/decoders/bitmap_decoder.hpp" +#endif + +namespace rive::gpu +{ +constexpr size_t kDefaultSimpleGradientCapacity = 512; +constexpr size_t kDefaultComplexGradientCapacity = 1024; +constexpr size_t kDefaultDrawCapacity = 2048; + +// TODO: Move this variable to PlatformFeatures. +constexpr uint32_t kMaxTextureHeight = 2048; +constexpr size_t kMaxTessellationVertexCount = + kMaxTextureHeight * kTessTextureWidth; +constexpr size_t kMaxTessellationPaddingVertexCount = + gpu::kMidpointFanPatchSegmentSpan + // Padding at the beginning of the tess + // texture + (gpu::kOuterCurvePatchSegmentSpan - + 1) + // Max padding between patch types in the tess texture + 1; // Padding at the end of the tessellation texture +constexpr size_t kMaxTessellationVertexCountBeforePadding = + kMaxTessellationVertexCount - kMaxTessellationPaddingVertexCount; + +// Metal requires vertex buffers to be 256-byte aligned. +constexpr size_t kMaxTessellationAlignmentVertices = + gpu::kTessVertexBufferAlignmentInElements - 1; + +// We can only reorder 32767 draws at a time since the one-based groupIndex +// returned by IntersectionBoard is a signed 16-bit integer. +constexpr size_t kMaxReorderedDrawPassCount = + std::numeric_limits::max(); + +// How tall to make a resource texture in order to support the given number of +// items. +template +constexpr static size_t resource_texture_height(size_t itemCount) +{ + return (itemCount + WidthInItems - 1) / WidthInItems; +} + +constexpr static size_t gradient_data_height(size_t simpleRampCount, + size_t complexRampCount) +{ + return resource_texture_height( + simpleRampCount) + + complexRampCount; +} + +inline GradientContentKey::GradientContentKey(rcp gradient) : + m_gradient(std::move(gradient)) +{} + +inline GradientContentKey::GradientContentKey(GradientContentKey&& other) : + m_gradient(std::move(other.m_gradient)) +{} + +bool GradientContentKey::operator==(const GradientContentKey& other) const +{ + if (m_gradient.get() == other.m_gradient.get()) + { + return true; + } + else + { + return m_gradient->count() == other.m_gradient->count() && + !memcmp(m_gradient->stops(), + other.m_gradient->stops(), + m_gradient->count() * sizeof(float)) && + !memcmp(m_gradient->colors(), + other.m_gradient->colors(), + m_gradient->count() * sizeof(ColorInt)); + } +} + +size_t DeepHashGradient::operator()(const GradientContentKey& key) const +{ + const Gradient* grad = key.gradient(); + std::hash hash; + size_t x = + hash(std::string_view(reinterpret_cast(grad->stops()), + grad->count() * sizeof(float))); + size_t y = + hash(std::string_view(reinterpret_cast(grad->colors()), + grad->count() * sizeof(ColorInt))); + return x ^ y; +} + +RenderContext::RenderContext(std::unique_ptr impl) : + m_impl(std::move(impl)), + // -1 from m_maxPathID so we reserve a path record for the clearColor paint + // (for atomic mode). This also allows us to index the storage buffers + // directly by pathID. + m_maxPathID(MaxPathID(m_impl->platformFeatures().pathIDGranularity) - 1) +{ + setResourceSizes(ResourceAllocationCounts(), /*forceRealloc =*/true); + releaseResources(); +} + +RenderContext::~RenderContext() +{ + // Always call flush() to avoid deadlock. + assert(!m_didBeginFrame); + // Delete the logical flushes before the block allocators let go of their + // allocations. + m_logicalFlushes.clear(); +} + +const gpu::PlatformFeatures& RenderContext::platformFeatures() const +{ + return m_impl->platformFeatures(); +} + +rcp RenderContext::makeRenderBuffer(RenderBufferType type, + RenderBufferFlags flags, + size_t sizeInBytes) +{ + return m_impl->makeRenderBuffer(type, flags, sizeInBytes); +} + +rcp RenderContext::decodeImage(Span encodedBytes) +{ + rcp texture = m_impl->platformDecodeImageTexture(encodedBytes); +#ifdef RIVE_DECODERS + if (texture == nullptr) + { + auto bitmap = Bitmap::decode(encodedBytes.data(), encodedBytes.size()); + if (bitmap) + { + // For now, RenderContextImpl::makeImageTexture() only accepts RGBA. + if (bitmap->pixelFormat() != Bitmap::PixelFormat::RGBAPremul) + { + bitmap->pixelFormat(Bitmap::PixelFormat::RGBAPremul); + } + uint32_t width = bitmap->width(); + uint32_t height = bitmap->height(); + uint32_t mipLevelCount = math::msb(height | width); + texture = m_impl->makeImageTexture(width, + height, + mipLevelCount, + bitmap->bytes()); + } + } +#endif + return texture != nullptr ? make_rcp(std::move(texture)) + : nullptr; +} + +void RenderContext::releaseResources() +{ + assert(!m_didBeginFrame); + resetContainers(); + setResourceSizes(ResourceAllocationCounts()); + m_maxRecentResourceRequirements = ResourceAllocationCounts(); + m_lastResourceTrimTimeInSeconds = m_impl->secondsNow(); +} + +void RenderContext::resetContainers() +{ + assert(!m_didBeginFrame); + + if (!m_logicalFlushes.empty()) + { + // Should get reset to 1 after flush(). + assert(m_logicalFlushes.size() == 1); + m_logicalFlushes.resize(1); + m_logicalFlushes.front()->resetContainers(); + } + + m_indirectDrawList.clear(); + m_indirectDrawList.shrink_to_fit(); + + m_intersectionBoard = nullptr; +} + +RenderContext::LogicalFlush::LogicalFlush(RenderContext* parent) : m_ctx(parent) +{ + rewind(); +} + +void RenderContext::LogicalFlush::rewind() +{ + m_resourceCounts = Draw::ResourceCounters(); + m_drawPassCount = 0; + m_simpleGradients.clear(); + m_pendingSimpleGradDraws.clear(); + m_complexGradients.clear(); + m_pendingComplexGradDraws.clear(); + m_pendingGradSpanCount = 0; + m_clips.clear(); + m_draws.clear(); + m_combinedDrawBounds = {std::numeric_limits::max(), + std::numeric_limits::max(), + std::numeric_limits::min(), + std::numeric_limits::min()}; + + m_pathPaddingCount = 0; + m_paintPaddingCount = 0; + m_paintAuxPaddingCount = 0; + m_contourPaddingCount = 0; + m_gradSpanPaddingCount = 0; + m_midpointFanTessEndLocation = 0; + m_outerCubicTessEndLocation = 0; + m_outerCubicTessVertexIdx = 0; + m_midpointFanTessVertexIdx = 0; + + m_flushDesc = FlushDescriptor(); + + m_drawList.reset(); + m_combinedShaderFeatures = gpu::ShaderFeatures::NONE; + + m_currentPathID = 0; + m_currentContourID = 0; + + if (m_atlasRectanizer != nullptr) + { + m_atlasRectanizer->reset(); + } + m_atlasMaxX = 0; + m_atlasMaxY = 0; + m_pendingAtlasDraws.clear(); + + m_coverageBufferLength = 0; + + m_pendingBarriers = BarrierFlags::none; + + m_currentZIndex = 0; + + RIVE_DEBUG_CODE(m_hasDoneLayout = false;) +} + +void RenderContext::LogicalFlush::resetContainers() +{ + m_clips.clear(); + m_clips.shrink_to_fit(); + m_draws.clear(); + m_draws.shrink_to_fit(); + m_draws.reserve(kDefaultDrawCapacity); + + m_simpleGradients.rehash(0); + m_simpleGradients.reserve(kDefaultSimpleGradientCapacity); + + m_pendingSimpleGradDraws.clear(); + m_pendingSimpleGradDraws.shrink_to_fit(); + m_pendingSimpleGradDraws.reserve(kDefaultSimpleGradientCapacity); + + m_complexGradients.rehash(0); + m_complexGradients.reserve(kDefaultComplexGradientCapacity); + + m_pendingComplexGradDraws.clear(); + m_pendingComplexGradDraws.shrink_to_fit(); + m_pendingComplexGradDraws.reserve(kDefaultComplexGradientCapacity); + + m_pendingAtlasDraws.clear(); + m_pendingAtlasDraws.shrink_to_fit(); + // Don't reserve any space in m_pendingAtlasDraws since there are many + // usecases where it isn't used at all. +} + +void RenderContext::beginFrame(const FrameDescriptor& frameDescriptor) +{ + assert(!m_didBeginFrame); + assert(frameDescriptor.renderTargetWidth > 0); + assert(frameDescriptor.renderTargetHeight > 0); + m_frameDescriptor = frameDescriptor; + if (!platformFeatures().supportsRasterOrdering && + !platformFeatures().supportsFragmentShaderAtomics) + { + // We don't have pixel local storage in any form. Use 4x MSAA if + // msaaSampleCount wasn't already specified. + m_frameDescriptor.msaaSampleCount = + m_frameDescriptor.msaaSampleCount > 0 + ? m_frameDescriptor.msaaSampleCount + : 4; + } + if (m_frameDescriptor.msaaSampleCount > 0) + { + m_frameInterlockMode = gpu::InterlockMode::msaa; + } + else if (platformFeatures().supportsRasterOrdering && + (!m_frameDescriptor.disableRasterOrdering || + !platformFeatures().supportsFragmentShaderAtomics)) + { + m_frameInterlockMode = gpu::InterlockMode::rasterOrdering; + } + else if (frameDescriptor.clockwiseFillOverride && + platformFeatures().supportsClockwiseAtomicRendering) + { + assert(platformFeatures().supportsFragmentShaderAtomics); + m_frameInterlockMode = gpu::InterlockMode::clockwiseAtomic; + } + else + { + assert(platformFeatures().supportsFragmentShaderAtomics); + m_frameInterlockMode = gpu::InterlockMode::atomics; + } + m_frameShaderFeaturesMask = + gpu::ShaderFeaturesMaskFor(m_frameInterlockMode); + if (m_logicalFlushes.empty()) + { + m_logicalFlushes.emplace_back(new LogicalFlush(this)); + } + RIVE_DEBUG_CODE(m_didBeginFrame = true); +} + +bool RenderContext::isOutsideCurrentFrame(const IAABB& pixelBounds) +{ + assert(m_didBeginFrame); + int4 bounds = simd::load4i(&pixelBounds); + auto renderTargetSize = + simd::cast(uint2{m_frameDescriptor.renderTargetWidth, + m_frameDescriptor.renderTargetHeight}); + return simd::any(bounds.xy >= renderTargetSize || bounds.zw <= 0 || + bounds.xy >= bounds.zw); +} + +bool RenderContext::frameSupportsClipRects() const +{ + assert(m_didBeginFrame); + return m_frameInterlockMode != gpu::InterlockMode::msaa || + platformFeatures().supportsClipPlanes; +} + +bool RenderContext::frameSupportsImagePaintForPaths() const +{ + assert(m_didBeginFrame); + return m_frameInterlockMode != gpu::InterlockMode::atomics; +} + +uint32_t RenderContext::generateClipID(const IAABB& contentBounds) +{ + assert(m_didBeginFrame); + assert(!m_logicalFlushes.empty()); + return m_logicalFlushes.back()->generateClipID(contentBounds); +} + +uint32_t RenderContext::LogicalFlush::generateClipID(const IAABB& contentBounds) +{ + if (m_clips.size() < m_ctx->m_maxPathID) // maxClipID == maxPathID. + { + m_clips.emplace_back(contentBounds); + assert(m_ctx->m_clipContentID != m_clips.size()); + return math::lossless_numeric_cast(m_clips.size()); + } + return 0; // There are no available clip IDs. The caller should flush and + // try again. +} + +RenderContext::LogicalFlush::ClipInfo& RenderContext::LogicalFlush:: + getWritableClipInfo(uint32_t clipID) +{ + assert(clipID > 0); + assert(clipID <= m_clips.size()); + return m_clips[clipID - 1]; +} + +void RenderContext::LogicalFlush::addClipReadBounds(uint32_t clipID, + const IAABB& bounds) +{ + assert(clipID > 0); + assert(clipID <= m_clips.size()); + ClipInfo& clipInfo = getWritableClipInfo(clipID); + clipInfo.readBounds = clipInfo.readBounds.join(bounds); +} + +bool RenderContext::pushDraws(DrawUniquePtr draws[], size_t drawCount) +{ + assert(m_didBeginFrame); + assert(!m_logicalFlushes.empty()); + return m_logicalFlushes.back()->pushDraws(draws, drawCount); +} + +bool RenderContext::LogicalFlush::pushDraws(DrawUniquePtr draws[], + size_t drawCount) +{ + assert(!m_hasDoneLayout); + + auto countsVector = m_resourceCounts.toVec(); + for (size_t i = 0; i < drawCount; ++i) + { + assert(!draws[i]->pixelBounds().empty()); + assert(m_ctx->frameSupportsClipRects() || + draws[i]->clipRectInverseMatrix() == nullptr); + countsVector += draws[i]->resourceCounts().toVec(); + } + Draw::ResourceCounters countsWithNewBatch = countsVector; + + // Textures and buffers have hard size limits. If the new batch doesn't fit + // within our constraints, the caller needs to flush and try again. + if (countsWithNewBatch.pathCount > m_ctx->m_maxPathID || + countsWithNewBatch.contourCount > kMaxContourID || + countsWithNewBatch.midpointFanTessVertexCount + + countsWithNewBatch.outerCubicTessVertexCount > + kMaxTessellationVertexCountBeforePadding) + { + return false; + } + + // Allocate subpasses. + int passCountInBatch = 0; + for (size_t i = 0; i < drawCount; ++i) + { + draws[i]->countSubpasses(); + assert(draws[i]->prepassCount() >= 0); + assert(draws[i]->subpassCount() >= 0); + assert(draws[i]->prepassCount() + draws[i]->subpassCount() >= 1); + passCountInBatch += draws[i]->prepassCount() + draws[i]->subpassCount(); + } + + // We can only reorder 32k draws at a time in atomic and msaa modes since + // the sort key addresses them with a signed 16-bit index. Make sure we + // don't exceed that limit. + if (m_ctx->frameInterlockMode() != gpu::InterlockMode::rasterOrdering && + m_drawPassCount + passCountInBatch > kMaxReorderedDrawPassCount) + { + return false; + } + + // Allocate final resources. + for (size_t i = 0; i < drawCount; ++i) + { + if (!draws[i]->allocateResources(this)) + { + // The draw failed to allocate resources. Give up and let the caller + // flush and try again. + // + // FIXME: This works today, but the surrounding code could be + // modified to inadvertently leave a stale dangling reference to one + // of these draws in m_pendingAtlasDraws. This needs to be + // revisited. + return false; + } + } + + for (size_t i = 0; i < drawCount; ++i) + { + m_draws.push_back(std::move(draws[i])); + m_combinedDrawBounds = + m_combinedDrawBounds.join(m_draws.back()->pixelBounds()); + } + + m_resourceCounts = countsWithNewBatch; + m_drawPassCount += passCountInBatch; + return true; +} + +bool RenderContext::LogicalFlush::allocateGradient( + const Gradient* gradient, + gpu::ColorRampLocation* colorRampLocation) +{ + assert(!m_hasDoneLayout); + + const float* stops = gradient->stops(); + size_t stopCount = gradient->count(); + assert(stopCount > 0); // RiveRenderFactory guarantees this. + + if (stopCount == 1 || (stopCount == 2 && stops[0] == 0 && stops[1] == 1)) + { + // This is a simple gradient that can be implemented by a two-texel + // color ramp. + const ColorInt* colors = gradient->colors(); + TwoTexelRamp colorRamp = {colors[0], + // Handle ramps with a single stop. + colors[std::min(1, stopCount - 1)]}; + uint64_t simpleKey; + static_assert(sizeof(simpleKey) == sizeof(ColorInt) * 2); + RIVE_INLINE_MEMCPY(&simpleKey, &colorRamp, sizeof(ColorInt) * 2); + uint32_t rampTexelsIdx; + auto iter = m_simpleGradients.find(simpleKey); + if (iter != m_simpleGradients.end()) + { + // This gradient is already in the texture. + rampTexelsIdx = iter->second; + } + else + { + if (gradient_data_height(m_simpleGradients.size() + 1, + m_complexGradients.size()) > + kMaxTextureHeight) + { + // We ran out of rows in the gradient texture. Caller has to + // flush and try again. + return false; + } + rampTexelsIdx = math::lossless_numeric_cast( + m_simpleGradients.size() * 2); + m_simpleGradients.insert({simpleKey, rampTexelsIdx}); + m_pendingSimpleGradDraws.push_back(colorRamp); + // Simple gradients get uploaded to the GPU as a single GradientSpan + // instance. + ++m_pendingGradSpanCount; + } + colorRampLocation->row = rampTexelsIdx / kGradTextureWidth; + colorRampLocation->col = rampTexelsIdx % kGradTextureWidth; + } + else + { + // This is a complex gradient. Render it to an entire row of the + // gradient texture. + GradientContentKey key(ref_rcp(gradient)); + auto iter = m_complexGradients.find(key); + uint16_t row; + if (iter != m_complexGradients.end()) + { + row = iter->second; // This gradient is already in the texture. + } + else + { + if (gradient_data_height(m_simpleGradients.size(), + m_complexGradients.size() + 1) > + kMaxTextureHeight) + { + // We ran out of rows in the gradient texture. Caller has to + // flush and try again. + return false; + } + + row = static_cast(m_complexGradients.size()); + m_complexGradients.emplace(std::move(key), row); + m_pendingComplexGradDraws.push_back(gradient); + + size_t spanCount = stopCount - 1; + m_pendingGradSpanCount += spanCount; + } + // Store the row relative to the first complex gradient for now. + // PaintData::set() will offset this value by the number of simple + // gradient rows once its final value is known. + colorRampLocation->row = row; + colorRampLocation->col = ColorRampLocation::kComplexGradientMarker; + } + return true; +} + +bool RenderContext::LogicalFlush::allocateAtlasDraw( + PathDraw* pathDraw, + uint16_t drawWidth, + uint16_t drawHeight, + uint16_t desiredPadding, + uint16_t* x, + uint16_t* y, + TAABB* paddedRegion) +{ + if (m_atlasRectanizer == nullptr) + { + uint16_t atlasMaxSize = m_ctx->atlasMaxSize(); + // Use an atlas larger than atlasMaxSize if it's too small for the + // request (meaning the render target is larger than atlasMaxSize). + m_atlasRectanizer = std::make_unique( + std::max(atlasMaxSize, drawWidth), + std::max(atlasMaxSize, drawHeight)); + } + + const uint16_t atlasMaxWidth = m_atlasRectanizer->width(); + const uint16_t atlasMaxHeight = m_atlasRectanizer->height(); + uint16_t paddedWidth = + std::min(drawWidth + desiredPadding * 2, atlasMaxWidth); + uint16_t paddedHeight = + std::min(drawHeight + desiredPadding * 2, atlasMaxHeight); + int16_t ix, iy; + if (!m_atlasRectanizer->addRect(paddedWidth, paddedHeight, &ix, &iy)) + { + // Delete the rectanizer of it wasn't big enough for this path. It will + // be reallocated to a large enough size on the next call. + if (drawWidth > atlasMaxWidth || drawHeight > atlasMaxHeight) + { + m_atlasRectanizer = nullptr; + } + m_atlasRectanizer = nullptr; + return false; + } + + assert(ix >= 0); + assert(iy >= 0); + assert(ix + paddedWidth <= atlasMaxWidth); + assert(iy + paddedHeight <= atlasMaxHeight); + + *x = ix + (paddedWidth - drawWidth) / 2; + *y = iy + (paddedHeight - drawHeight) / 2; + *paddedRegion = {ix, iy, ix + paddedWidth, iy + paddedHeight}; + assert((TAABB{0, 0, atlasMaxWidth, atlasMaxHeight}) + .contains(*paddedRegion)); + + m_atlasMaxX = std::max(m_atlasMaxX, paddedRegion->right); + m_atlasMaxY = std::max(m_atlasMaxY, paddedRegion->bottom); + assert(m_atlasMaxX <= atlasMaxWidth); + assert(m_atlasMaxY <= atlasMaxHeight); + + m_pendingAtlasDraws.push_back(pathDraw); + return true; +} + +size_t RenderContext::LogicalFlush::allocateCoverageBufferRange(size_t length) +{ + assert(m_ctx->frameInterlockMode() == gpu::InterlockMode::clockwiseAtomic); + assert(length % (32 * 32) == 0u); // Allocations must support 32x32 tiles. + uint32_t offset = m_coverageBufferLength; + if (offset + length > m_ctx->platformFeatures().maxCoverageBufferLength) + { + return -1; + } + m_coverageBufferLength += length; + return offset; +} + +void RenderContext::logicalFlush() +{ + assert(m_didBeginFrame); + + // Reset clipping state after every logical flush because the clip buffer is + // not preserved between render passes. + m_clipContentID = 0; + + // Don't issue any GPU commands between logical flushes. Instead, build up a + // list of flushes that we will submit all at once at the end of the frame. + m_logicalFlushes.emplace_back(new LogicalFlush(this)); +} + +void RenderContext::flush(const FlushResources& flushResources) +{ + assert(m_didBeginFrame); + assert(flushResources.renderTarget->width() == + m_frameDescriptor.renderTargetWidth); + assert(flushResources.renderTarget->height() == + m_frameDescriptor.renderTargetHeight); + + m_clipContentID = 0; + + // Layout this frame's resource buffers and textures. + LogicalFlush::ResourceCounters totalFrameResourceCounts; + LogicalFlush::LayoutCounters layoutCounts; + for (size_t i = 0; i < m_logicalFlushes.size(); ++i) + { + m_logicalFlushes[i]->layoutResources(flushResources, + i, + &totalFrameResourceCounts, + &layoutCounts); + } + + // Determine the minimum required resource allocation sizes to service this + // flush. + ResourceAllocationCounts resourceRequirements; + resourceRequirements.flushUniformBufferCount = m_logicalFlushes.size(); + resourceRequirements.imageDrawUniformBufferCount = + totalFrameResourceCounts.imageDrawCount; + resourceRequirements.pathBufferCount = + totalFrameResourceCounts.pathCount + layoutCounts.pathPaddingCount; + resourceRequirements.paintBufferCount = + totalFrameResourceCounts.pathCount + layoutCounts.paintPaddingCount; + resourceRequirements.paintAuxBufferCount = + totalFrameResourceCounts.pathCount + layoutCounts.paintAuxPaddingCount; + resourceRequirements.contourBufferCount = + totalFrameResourceCounts.contourCount + + layoutCounts.contourPaddingCount; + resourceRequirements.gradSpanBufferCount = + layoutCounts.gradSpanCount + layoutCounts.gradSpanPaddingCount; + resourceRequirements.tessSpanBufferCount = + totalFrameResourceCounts.maxTessellatedSegmentCount; + resourceRequirements.triangleVertexBufferCount = + totalFrameResourceCounts.maxTriangleVertexCount; + resourceRequirements.gradTextureHeight = layoutCounts.maxGradTextureHeight; + resourceRequirements.tessTextureHeight = layoutCounts.maxTessTextureHeight; + resourceRequirements.atlasTextureWidth = layoutCounts.maxAtlasWidth; + resourceRequirements.atlasTextureHeight = layoutCounts.maxAtlasHeight; + resourceRequirements.coverageBufferLength = + layoutCounts.maxCoverageBufferLength; + + // Ensure we're within hardware limits. + assert(resourceRequirements.gradTextureHeight <= kMaxTextureHeight); + assert(resourceRequirements.tessTextureHeight <= kMaxTextureHeight); + assert(resourceRequirements.atlasTextureWidth <= atlasMaxSize() || + resourceRequirements.atlasTextureWidth <= + frameDescriptor().renderTargetWidth); + assert(resourceRequirements.atlasTextureHeight <= atlasMaxSize() || + resourceRequirements.atlasTextureHeight <= + frameDescriptor().renderTargetHeight); + assert(resourceRequirements.coverageBufferLength <= + platformFeatures().maxCoverageBufferLength); + + // Track m_maxRecentResourceRequirements so we can trim GPU allocations when + // steady-state usage goes down. + m_maxRecentResourceRequirements = + simd::max(resourceRequirements.toVec(), + m_maxRecentResourceRequirements.toVec()); + + // Grow resources enough to handle this flush. + // If "allocs" already fits in our current allocations, then don't change + // them. If they don't fit, overallocate by 25% in order to create some + // slack for growth. + ResourceAllocationCounts allocs = simd::if_then_else( + resourceRequirements.toVec() <= m_currentResourceAllocations.toVec(), + m_currentResourceAllocations.toVec(), + resourceRequirements.toVec() * size_t(5) / size_t(4)); + + // In case the 25% growth pushed us above limits. + allocs.gradTextureHeight = + std::min(allocs.gradTextureHeight, kMaxTextureHeight); + allocs.tessTextureHeight = + std::min(allocs.tessTextureHeight, kMaxTextureHeight); + allocs.atlasTextureWidth = std::min( + allocs.atlasTextureWidth, + std::max(atlasMaxSize(), frameDescriptor().renderTargetWidth)); + allocs.atlasTextureHeight = std::min( + allocs.atlasTextureHeight, + std::max(atlasMaxSize(), frameDescriptor().renderTargetHeight)); + allocs.coverageBufferLength = + std::min(allocs.coverageBufferLength, + platformFeatures().maxCoverageBufferLength); + + // Additionally, every 5 seconds, trim resources down to the most recent + // steady-state usage. + double flushTime = m_impl->secondsNow(); + bool needsResourceTrim = flushTime - m_lastResourceTrimTimeInSeconds >= 5; + if (needsResourceTrim) + { + // Trim GPU resource allocations to 125% of their maximum recent usage, + // and only if the recent usage is 2/3 or less of the current + // allocation. + allocs = simd::if_then_else(m_maxRecentResourceRequirements.toVec() <= + allocs.toVec() * size_t(2) / size_t(3), + m_maxRecentResourceRequirements.toVec() * + size_t(5) / size_t(4), + allocs.toVec()); + + // Ensure we stayed within limits. + assert(allocs.gradTextureHeight <= kMaxTextureHeight); + assert(allocs.tessTextureHeight <= kMaxTextureHeight); + assert(allocs.atlasTextureWidth <= atlasMaxSize() || + allocs.atlasTextureWidth <= frameDescriptor().renderTargetWidth); + assert(allocs.atlasTextureHeight <= atlasMaxSize() || + allocs.atlasTextureHeight <= + frameDescriptor().renderTargetHeight); + assert(allocs.coverageBufferLength <= + platformFeatures().maxCoverageBufferLength); + + // Zero out m_maxRecentResourceRequirements for the next interval. + m_maxRecentResourceRequirements = ResourceAllocationCounts(); + m_lastResourceTrimTimeInSeconds = flushTime; + } + + setResourceSizes(allocs); + + m_impl->prepareToFlush(flushResources.currentFrameNumber, + flushResources.safeFrameNumber); + + mapResourceBuffers(resourceRequirements); + + for (const auto& flush : m_logicalFlushes) + { + flush->writeResources(); + } + + assert(m_flushUniformData.elementsWritten() == m_logicalFlushes.size()); + assert(m_imageDrawUniformData.elementsWritten() == + totalFrameResourceCounts.imageDrawCount); + assert(m_pathData.elementsWritten() == + totalFrameResourceCounts.pathCount + layoutCounts.pathPaddingCount); + assert(m_paintData.elementsWritten() == + totalFrameResourceCounts.pathCount + layoutCounts.paintPaddingCount); + assert(m_paintAuxData.elementsWritten() == + totalFrameResourceCounts.pathCount + + layoutCounts.paintAuxPaddingCount); + assert(m_contourData.elementsWritten() == + totalFrameResourceCounts.contourCount + + layoutCounts.contourPaddingCount); + assert(m_gradSpanData.elementsWritten() == + layoutCounts.gradSpanCount + layoutCounts.gradSpanPaddingCount); + assert(m_tessSpanData.elementsWritten() <= + totalFrameResourceCounts.maxTessellatedSegmentCount); + assert(m_triangleVertexData.elementsWritten() <= + totalFrameResourceCounts.maxTriangleVertexCount); + + unmapResourceBuffers(resourceRequirements); + + // Issue logical flushes to the backend. + for (const auto& flush : m_logicalFlushes) + { + m_impl->flush(flush->desc()); + } + + m_impl->postFlush(flushResources); + + if (!m_logicalFlushes.empty()) + { + m_logicalFlushes.resize(1); + m_logicalFlushes.front()->rewind(); + } + + // Drop all memory that was allocated for this frame using + // TrivialBlockAllocator. + m_perFrameAllocator.reset(); + m_numChopsAllocator.reset(); + m_chopVerticesAllocator.reset(); + m_tangentPairsAllocator.reset(); + m_polarSegmentCountsAllocator.reset(); + m_parametricSegmentCountsAllocator.reset(); + + m_frameDescriptor = FrameDescriptor(); + + RIVE_DEBUG_CODE(m_didBeginFrame = false;) + + // Wait to reset CPU-side containers until after the flush has finished. + if (needsResourceTrim) + { + resetContainers(); + } +} + +void RenderContext::LogicalFlush::layoutResources( + const FlushResources& flushResources, + size_t logicalFlushIdx, + ResourceCounters* runningFrameResourceCounts, + LayoutCounters* runningFrameLayoutCounts) +{ + assert(!m_hasDoneLayout); + + const FrameDescriptor& frameDescriptor = m_ctx->frameDescriptor(); + + // Reserve a path record for the clearColor paint (used by atomic mode). + // This also allows us to index the storage buffers directly by pathID. + ++m_resourceCounts.pathCount; + + // Storage buffer offsets are required to be aligned on multiples of 256. + m_pathPaddingCount = + math::padding_to_align_up( + m_resourceCounts.pathCount); + m_paintPaddingCount = + math::padding_to_align_up( + m_resourceCounts.pathCount); + m_paintAuxPaddingCount = + math::padding_to_align_up( + m_resourceCounts.pathCount); + m_contourPaddingCount = + math::padding_to_align_up( + m_resourceCounts.contourCount); + + // Metal requires vertex buffers to be 256-byte aligned. + m_gradSpanPaddingCount = + math::padding_to_align_up( + m_pendingGradSpanCount); + + size_t totalTessVertexCountWithPadding = 0; + if ((m_resourceCounts.midpointFanTessVertexCount | + m_resourceCounts.outerCubicTessVertexCount) != 0) + { + // midpointFan tessellation vertices reside at the beginning of the + // tessellation texture, after 1 patch of padding vertices. + constexpr uint32_t kPrePadding = gpu::kMidpointFanPatchSegmentSpan; + m_midpointFanTessVertexIdx = kPrePadding; + m_midpointFanTessEndLocation = + m_midpointFanTessVertexIdx + + math::lossless_numeric_cast( + m_resourceCounts.midpointFanTessVertexCount); + + // outerCubic tessellation vertices reside after the midpointFan + // vertices, aligned on a multiple of the outerCubic patch size. + uint32_t interiorPadding = + math::padding_to_align_up( + m_midpointFanTessEndLocation); + m_outerCubicTessVertexIdx = + m_midpointFanTessEndLocation + interiorPadding; + m_outerCubicTessEndLocation = + m_outerCubicTessVertexIdx + + math::lossless_numeric_cast( + m_resourceCounts.outerCubicTessVertexCount); + + // We need one more padding vertex after all the tessellation vertices. + constexpr uint32_t kPostPadding = 1; + totalTessVertexCountWithPadding = + m_outerCubicTessEndLocation + kPostPadding; + + assert(kPrePadding + interiorPadding + kPostPadding <= + kMaxTessellationPaddingVertexCount); + assert(totalTessVertexCountWithPadding <= kMaxTessellationVertexCount); + } + + uint32_t tessDataHeight = math::lossless_numeric_cast( + resource_texture_height( + totalTessVertexCountWithPadding)); + if (m_resourceCounts.maxTessellatedSegmentCount != 0) + { + // Conservatively account for line breaks and padding in the + // tessellation span count. Line breaks potentially introduce a new + // span. Count the maximum number of line breaks we might encounter, + // which is at most TWO for every line in the tessellation texture (one + // for a forward span, and one for its reflection.) + size_t maxSpanBreakCount = tessDataHeight * 2; + // The tessellation texture requires 3 separate spans of padding + // vertices (see above and below). + constexpr size_t kPaddingSpanCount = 3; + m_resourceCounts.maxTessellatedSegmentCount += + maxSpanBreakCount + kPaddingSpanCount + + kMaxTessellationAlignmentVertices; + } + + // Complex gradients begin on the first row immediately after the simple + // gradients. + m_gradTextureLayout.complexOffsetY = math::lossless_numeric_cast( + resource_texture_height( + m_simpleGradients.size())); + + m_flushDesc.renderTarget = flushResources.renderTarget; + m_flushDesc.interlockMode = m_ctx->frameInterlockMode(); + m_flushDesc.msaaSampleCount = frameDescriptor.msaaSampleCount; + + // In atomic mode, we may be able to skip the explicit clear of the color + // buffer and fold it into the atomic "resolve" operation instead. + bool doClearDuringAtomicResolve = false; + + if (logicalFlushIdx != 0) + { + // We always have to preserve the renderTarget between logical flushes. + m_flushDesc.colorLoadAction = gpu::LoadAction::preserveRenderTarget; + } + else if (frameDescriptor.loadAction == gpu::LoadAction::clear) + { + // In atomic mode, we can clear during the resolve operation if the + // clearColor is opaque (because we don't want or have a "source only" + // blend mode). + doClearDuringAtomicResolve = + m_ctx->frameInterlockMode() == gpu::InterlockMode::atomics && + colorAlpha(frameDescriptor.clearColor) == 255; + m_flushDesc.colorLoadAction = doClearDuringAtomicResolve + ? gpu::LoadAction::dontCare + : gpu::LoadAction::clear; + } + else + { + m_flushDesc.colorLoadAction = frameDescriptor.loadAction; + } + m_flushDesc.colorClearValue = frameDescriptor.clearColor; + + if (doClearDuringAtomicResolve) + { + // In atomic mode we can accomplish a clear of the color buffer while + // the shader resolves coverage, instead of actually clearing. + // writeResources() will configure the fill for pathID=0 to be a solid + // fill matching the clearColor, so if we just initialize coverage + // buffer to solid coverage with pathID=0, the resolve step will write + // out the correct clear color. + assert(m_flushDesc.interlockMode == gpu::InterlockMode::atomics); + m_flushDesc.coverageClearValue = + static_cast(FIXED_COVERAGE_ONE); + } + else if (m_flushDesc.interlockMode == gpu::InterlockMode::atomics) + { + // When we don't skip the initial clear in atomic mode, clear the + // coverage buffer to pathID=0 and a transparent coverage value. + // pathID=0 meets the requirement that pathID is always monotonically + // increasing. Transparent coverage makes sure the clearColor doesn't + // get written out while resolving. + m_flushDesc.coverageClearValue = + static_cast(FIXED_COVERAGE_ZERO); + } + else + { + // In non-atomic mode, the coverage buffer just needs to be initialized + // with "pathID=0" to avoid collisions with any pathIDs being rendered. + m_flushDesc.coverageClearValue = 0; + } + + if (doClearDuringAtomicResolve || + m_flushDesc.colorLoadAction == gpu::LoadAction::clear) + { + // If we're clearing then we always update the entire render target. + m_flushDesc.renderTargetUpdateBounds = + m_flushDesc.renderTarget->bounds(); + } + else + { + // When we don't clear, we only update the draw bounds. + m_flushDesc.renderTargetUpdateBounds = + m_flushDesc.renderTarget->bounds().intersect(m_combinedDrawBounds); + } + if (m_flushDesc.renderTargetUpdateBounds.empty()) + { + // If this is empty it means there are no draws and no clear. + m_flushDesc.renderTargetUpdateBounds = {0, 0, 0, 0}; + } + + m_flushDesc.atlasContentWidth = m_atlasMaxX; + m_flushDesc.atlasContentHeight = m_atlasMaxY; + + m_flushDesc.flushUniformDataOffsetInBytes = + logicalFlushIdx * sizeof(gpu::FlushUniforms); + m_flushDesc.pathCount = + math::lossless_numeric_cast(m_resourceCounts.pathCount); + m_flushDesc.firstPath = runningFrameResourceCounts->pathCount + + runningFrameLayoutCounts->pathPaddingCount; + m_flushDesc.firstPaint = runningFrameResourceCounts->pathCount + + runningFrameLayoutCounts->paintPaddingCount; + m_flushDesc.firstPaintAux = runningFrameResourceCounts->pathCount + + runningFrameLayoutCounts->paintAuxPaddingCount; + m_flushDesc.contourCount = + math::lossless_numeric_cast(m_resourceCounts.contourCount); + m_flushDesc.firstContour = runningFrameResourceCounts->contourCount + + runningFrameLayoutCounts->contourPaddingCount; + m_flushDesc.gradSpanCount = + math::lossless_numeric_cast(m_pendingGradSpanCount); + m_flushDesc.firstGradSpan = runningFrameLayoutCounts->gradSpanCount + + runningFrameLayoutCounts->gradSpanPaddingCount; + m_flushDesc.gradDataHeight = math::lossless_numeric_cast( + m_gradTextureLayout.complexOffsetY + m_complexGradients.size()); + m_flushDesc.tessDataHeight = tessDataHeight; + m_flushDesc.clockwiseFillOverride = frameDescriptor.clockwiseFillOverride; + m_flushDesc.wireframe = frameDescriptor.wireframe; +#ifdef WITH_RIVE_TOOLS + m_flushDesc.synthesizeCompilationFailures = + frameDescriptor.synthesizeCompilationFailures; +#endif + + m_flushDesc.externalCommandBuffer = flushResources.externalCommandBuffer; + + *runningFrameResourceCounts = + runningFrameResourceCounts->toVec() + m_resourceCounts.toVec(); + runningFrameLayoutCounts->pathPaddingCount += m_pathPaddingCount; + runningFrameLayoutCounts->paintPaddingCount += m_paintPaddingCount; + runningFrameLayoutCounts->paintAuxPaddingCount += m_paintAuxPaddingCount; + runningFrameLayoutCounts->contourPaddingCount += m_contourPaddingCount; + runningFrameLayoutCounts->gradSpanCount += m_pendingGradSpanCount; + runningFrameLayoutCounts->gradSpanPaddingCount += m_gradSpanPaddingCount; + runningFrameLayoutCounts->maxGradTextureHeight = + std::max(m_flushDesc.gradDataHeight, + runningFrameLayoutCounts->maxGradTextureHeight); + runningFrameLayoutCounts->maxTessTextureHeight = + std::max(m_flushDesc.tessDataHeight, + runningFrameLayoutCounts->maxTessTextureHeight); + runningFrameLayoutCounts->maxAtlasWidth = + std::max(m_atlasMaxX, runningFrameLayoutCounts->maxAtlasWidth); + runningFrameLayoutCounts->maxAtlasHeight = + std::max(m_atlasMaxY, runningFrameLayoutCounts->maxAtlasHeight); + runningFrameLayoutCounts->maxCoverageBufferLength = + std::max(m_coverageBufferLength, + runningFrameLayoutCounts->maxCoverageBufferLength); + + assert(m_flushDesc.firstPath % gpu::kPathBufferAlignmentInElements == 0); + assert(m_flushDesc.firstPaint % gpu::kPaintBufferAlignmentInElements == 0); + assert(m_flushDesc.firstPaintAux % + gpu::kPaintAuxBufferAlignmentInElements == + 0); + assert(m_flushDesc.firstContour % gpu::kContourBufferAlignmentInElements == + 0); + assert(m_flushDesc.firstGradSpan % + gpu::kGradSpanBufferAlignmentInElements == + 0); + RIVE_DEBUG_CODE(m_hasDoneLayout = true;) +} + +void RenderContext::LogicalFlush::writeResources() +{ + const gpu::PlatformFeatures& platformFeatures = m_ctx->platformFeatures(); + assert(m_hasDoneLayout); + assert(m_flushDesc.firstPath == m_ctx->m_pathData.elementsWritten()); + assert(m_flushDesc.firstPaint == m_ctx->m_paintData.elementsWritten()); + assert(m_flushDesc.firstPaintAux == + m_ctx->m_paintAuxData.elementsWritten()); + + // Wait until here before we record these texture sizes; they aren't decided + // until after all LogicalFlushes have run layoutResources(). + m_flushDesc.atlasTextureWidth = math::lossless_numeric_cast( + m_ctx->m_currentResourceAllocations.atlasTextureWidth); + m_flushDesc.atlasTextureHeight = math::lossless_numeric_cast( + m_ctx->m_currentResourceAllocations.atlasTextureHeight); + m_gradTextureLayout.inverseHeight = + 1.f / m_ctx->m_currentResourceAllocations.gradTextureHeight; + + // Exact tessSpan/triangleVertex counts aren't known until after their data + // is written out. + size_t firstTessVertexSpan = m_ctx->m_tessSpanData.elementsWritten(); + size_t initialTriangleVertexDataSize = + m_ctx->m_triangleVertexData.bytesWritten(); + + // Metal requires vertex buffers to be 256-byte aligned. + size_t tessAlignmentPadding = + math::padding_to_align_up( + firstTessVertexSpan); + assert(tessAlignmentPadding <= kMaxTessellationAlignmentVertices); + m_ctx->m_tessSpanData.push_back_n(nullptr, tessAlignmentPadding); + m_flushDesc.firstTessVertexSpan = + firstTessVertexSpan + tessAlignmentPadding; + assert(m_flushDesc.firstTessVertexSpan == + m_ctx->m_tessSpanData.elementsWritten()); + + // Write out the simple gradient data. + constexpr static uint32_t ONE_TEXEL_FIXED = 65536 / gpu::kGradTextureWidth; + assert(m_simpleGradients.size() == m_pendingSimpleGradDraws.size()); + if (!m_pendingSimpleGradDraws.empty()) + { + for (size_t i = 0; i < m_pendingSimpleGradDraws.size(); ++i) + { + // Render each simple gradient as a single, empty GradientSpan with + // 1px borders to the left and right. + auto [color0, color1] = m_pendingSimpleGradDraws[i]; + uint32_t y = math::lossless_numeric_cast( + i / gpu::kGradTextureWidthInSimpleRamps); + size_t centerX = (i % gpu::kGradTextureWidthInSimpleRamps) * 2 + 1; + uint32_t centerXFixed = math::lossless_numeric_cast( + centerX * ONE_TEXEL_FIXED); + m_ctx->m_gradSpanData.set_back(centerXFixed, + centerXFixed, + y, + GRAD_SPAN_FLAG_LEFT_BORDER | + GRAD_SPAN_FLAG_RIGHT_BORDER, + color0, + color1); + } + } + + // Write out the vertex data for rendering complex gradients. + assert(m_complexGradients.size() == m_pendingComplexGradDraws.size()); + if (!m_pendingComplexGradDraws.empty()) + { + // The viewport will start at simpleGradDataHeight when rendering color + // ramps. + for (uint32_t i = 0; i < m_pendingComplexGradDraws.size(); ++i) + { + // Push "GradientSpan" instances that will render each section of + // this color ramp's gradient. + const Gradient* gradient = m_pendingComplexGradDraws[i]; + const float* stops = gradient->stops(); + const ColorInt* colors = gradient->colors(); + size_t stopCount = gradient->count(); + uint32_t y = i + m_gradTextureLayout.complexOffsetY; + + // "stop * m + a" converts a stop position to a fixed-point x + // coordinate in the gradient texture. (In an ideal world, stops + // would all be aligned on pixel centers for the texture sampling to + // be identical to the gradient, but here we just stretch it across + // kGradTextureWidth pixels and hope everything looks ok.) + float m = (kGradTextureWidth - 1.f) * ONE_TEXEL_FIXED; + float a = .5f * ONE_TEXEL_FIXED; + uint32_t lastXFixed = static_cast(stops[0] * m + a); + ColorInt lastColor = colors[0]; + assert(stopCount >= 2); + for (size_t i = 1; i < stopCount; ++i) + { + uint32_t xFixed = static_cast(stops[i] * m + a); + // stops[] must be ordered. + assert(lastXFixed <= xFixed && xFixed < 65536); + uint32_t flags = GRAD_SPAN_FLAG_COMPLEX_BORDER; + if (i == 1) + flags |= GRAD_SPAN_FLAG_LEFT_BORDER; + if (i == stopCount - 1) + flags |= GRAD_SPAN_FLAG_RIGHT_BORDER; + m_ctx->m_gradSpanData.set_back(lastXFixed, + xFixed, + y, + flags, + lastColor, + colors[i]); + lastColor = colors[i]; + lastXFixed = xFixed; + } + } + } + + // Write a path record for the clearColor paint (used by atomic mode). + // This also allows us to index the storage buffers directly by pathID. + gpu::SimplePaintValue clearColorValue; + clearColorValue.color = m_ctx->frameDescriptor().clearColor; + m_ctx->m_pathData.skip_back(); + m_ctx->m_paintData.set_back(gpu::DrawContents::none, + PaintType::solidColor, + clearColorValue, + GradTextureLayout(), + /*clipID =*/0, + /*hasClipRect =*/false, + BlendMode::srcOver); + m_ctx->m_paintAuxData.skip_back(); + + // Render padding vertices in the tessellation texture. + if (m_flushDesc.tessDataHeight > 0) + { + // Padding at the beginning of the tessellation texture. + pushPaddingVertices(gpu::kMidpointFanPatchSegmentSpan, 0); + // Padding between patch types in the tessellation texture. + if (m_outerCubicTessVertexIdx > m_midpointFanTessEndLocation) + { + pushPaddingVertices(m_outerCubicTessVertexIdx - + m_midpointFanTessEndLocation, + m_midpointFanTessEndLocation); + } + // The final vertex of the final patch of each contour crosses over into + // the next contour. (This is how we wrap around back to the beginning.) + // Therefore, the final contour of the flush needs an out-of-contour + // vertex to cross into as well, so we emit a padding vertex here at the + // end. + pushPaddingVertices(1, m_outerCubicTessEndLocation); + } + + // Write out all the data for our high level draws, and build up a low-level + // draw list. + if (m_ctx->frameInterlockMode() == gpu::InterlockMode::rasterOrdering) + { + for (const DrawUniquePtr& draw : m_draws) + { + // TODO: We don't currently support a front-to-back prepass in + // rasterOrdering mode. If we decide to support this, we will either + // need to walk the draws backwards here, or, more likely, start + // sorting and re-ordering in rasterOrdering mode as well. + assert(draw->prepassCount() == 0); + assert(draw->subpassCount() > 0); + for (int i = 0; i < draw->subpassCount(); ++i) + { + draw->pushToRenderContext(this, i); + } + } + } + else + { + assert(m_drawPassCount <= kMaxReorderedDrawPassCount); + + // Sort the draw list to optimize batching, since we can only batch + // non-overlapping draws. + std::vector& indirectDrawList = m_ctx->m_indirectDrawList; + indirectDrawList.clear(); + indirectDrawList.reserve(m_drawPassCount); + + if (m_ctx->m_intersectionBoard == nullptr) + { + m_ctx->m_intersectionBoard = std::make_unique(); + } + IntersectionBoard* intersectionBoard = m_ctx->m_intersectionBoard.get(); + intersectionBoard->resizeAndReset(m_flushDesc.renderTarget->width(), + m_flushDesc.renderTarget->height()); + + // Build a list of sort keys that determine the final draw order. + constexpr static int kDrawGroupShift = + 48; // Where in the key does the draw group begin? + constexpr static int64_t kDrawGroupMask = 0x7fffllu << kDrawGroupShift; + constexpr static int kDrawTypeShift = 45; + constexpr static int64_t kDrawTypeMask RIVE_MAYBE_UNUSED = + 7llu << kDrawTypeShift; + constexpr static int kTextureHashShift = 31; + constexpr static int64_t kTextureHashMask = 0x3fffllu + << kTextureHashShift; + constexpr static int kBlendModeShift = 27; + constexpr static int kBlendModeMask = 0xf << kBlendModeShift; + constexpr static int kDrawContentsShift = 18; + constexpr static int64_t kDrawContentsMask = 0x1ffllu + << kDrawContentsShift; + constexpr static int kDrawIndexShift = 2; + constexpr static int64_t kDrawIndexMask = 0x7fff << kDrawIndexShift; + constexpr static int64_t kSubpassIndexMask = 0x3; + + for (size_t i = 0; i < m_draws.size(); ++i) + { + Draw* draw = m_draws[i].get(); + int4 drawBounds = simd::load4i(&m_draws[i]->pixelBounds()); + + // Add one extra pixel of padding to the draw bounds to make + // absolutely certain we get no overlapping pixels, which destroy + // the atomic shader. + constexpr int32_t kMax32i = std::numeric_limits::max(); + constexpr int32_t kMin32i = std::numeric_limits::min(); + drawBounds = simd::if_then_else( + drawBounds != int4{kMin32i, kMin32i, kMax32i, kMax32i}, + drawBounds + int4{-1, -1, 1, 1}, + drawBounds); + + // Our top priority in re-ordering is to group non-overlapping draws + // together, in order to maximize batching while preserving + // correctness. + int maxPasses = + std::max(draw->prepassCount(), draw->subpassCount()); + int16_t drawGroupIdx = + intersectionBoard->addRectangle(drawBounds, maxPasses); + assert(drawGroupIdx > 0); + int64_t key = static_cast(drawGroupIdx) << kDrawGroupShift; + + // Within sub-groups of non-overlapping draws, sort similar draw + // types together. + int64_t drawType = static_cast(draw->type()); + assert(drawType <= kDrawTypeMask >> kDrawTypeShift); + key |= drawType << kDrawTypeShift; + + // Within sub-groups of matching draw type, sort by texture binding. + int64_t textureHash = + draw->imageTexture() != nullptr + ? draw->imageTexture()->textureResourceHash() & + (kTextureHashMask >> kTextureHashShift) + : 0; + key |= textureHash << kTextureHashShift; + + // If using KHR_blend_equation_advanced, we need a batching barrier + // between draws with different blend modes. If not using + // KHR_blend_equation_advanced, sorting by blend mode may still give + // us better branching on the GPU. + int64_t blendMode = + gpu::ConvertBlendModeToPLSBlendMode(draw->blendMode()); + assert(blendMode <= kBlendModeMask >> kBlendModeShift); + key |= blendMode << kBlendModeShift; + + // msaa mode draws strokes, fills, and even/odd with different + // stencil settings. + int64_t drawContents = static_cast(draw->drawContents()); + assert(drawContents <= kDrawContentsMask >> kDrawContentsShift); + key |= drawContents << kDrawContentsShift; + + // Draw and subpass indices go at the bottom of the key so we can + // reference them again after sorting without affecting the order. + assert(i <= kDrawIndexMask >> kDrawIndexShift); + key |= i << kDrawIndexShift; + + assert((key & kDrawGroupMask) >> kDrawGroupShift == drawGroupIdx); + assert((key & kDrawTypeMask) >> kDrawTypeShift == drawType); + assert((key & kTextureHashMask) >> kTextureHashShift == + textureHash); + assert((key & kBlendModeMask) >> kBlendModeShift == blendMode); + assert((key & kDrawContentsMask) >> kDrawContentsShift == + drawContents); + assert((key & kDrawIndexMask) >> kDrawIndexShift == i); + + // Add the first prepass and subpass, if any. + if (draw->prepassCount() > 0) + { + // Negating the key is an easy way to sort the prepasses + // front-to-back, and before the subpasses. + indirectDrawList.push_back(-key); + } + if (draw->subpassCount() > 0) + { + indirectDrawList.push_back(key); + } + + // Add any additional passes. + for (int i = 1; i < maxPasses; ++i) + { + // Increment the drawGroupIdx and i both at once. (The + // intersectionBoard already reserved "maxPasses" layers of + // drawGroupIndices for us.) + key += (1ll << kDrawGroupShift) + 1; + assert((key & kDrawGroupMask) >> kDrawGroupShift == + drawGroupIdx + i); + assert((key & kSubpassIndexMask) == i); + + if (i < draw->prepassCount()) + { + // Negating the key is an easy way to sort the prepasses + // front-to-back, and before the subpasses. + indirectDrawList.push_back(-key); + } + if (i < draw->subpassCount()) + { + indirectDrawList.push_back(key); + } + } + } + assert(indirectDrawList.size() == m_drawPassCount); + + // Re-order the draws!! + std::sort(indirectDrawList.begin(), indirectDrawList.end()); + + // Atomic mode sometimes needs to initialize PLS with a draw when the + // backend can't do it with typical clear/load APIs. + if (m_ctx->frameInterlockMode() == gpu::InterlockMode::atomics) + { + assert(m_pendingBarriers == BarrierFlags::none); + if (platformFeatures.atomicPLSMustBeInitializedAsDraw) + { + m_drawList.emplace_back(m_ctx->perFrameAllocator(), + DrawType::atomicInitialize, + gpu::ShaderMiscFlags::none, + 1, + 0, + BlendMode::srcOver, + ImageSampler::LinearClamp(), + BarrierFlags::none); + } + m_pendingBarriers |= BarrierFlags::plsAtomicPostInit; + } + + // Find a mask that tells us when to insert barriers, and which barriers + // are needed. When the keys of two adjacent draws differ within this + // bitmask, we insert a barrier between them. + int64_t needsBarrierMask = 0; + BarrierFlags neededBarriers = BarrierFlags::none; + switch (m_flushDesc.interlockMode) + { + case gpu::InterlockMode::rasterOrdering: + // rasterOrdering mode doesn't reorder draws. + RIVE_UNREACHABLE(); + + case gpu::InterlockMode::atomics: + // In atomic mode, we need barriers any time draws overlap. + // Insert a barrier every time the drawGroupIdx changes. + needsBarrierMask = kDrawGroupMask; + neededBarriers = BarrierFlags::plsAtomic; + break; + + case gpu::InterlockMode::clockwiseAtomic: + // In clockwiseAtomic mode, we only need a barrier between the + // borrowedCoverage prepasses and the main rendering. Prepasses + // have a negative key, so just insert a barrier when the sign + // changes. + needsBarrierMask = 1ll << 63; + neededBarriers = BarrierFlags::clockwiseBorrowedCoverage; + break; + + case gpu::InterlockMode::msaa: + // MSAA mode can't batch draws that overlap because they both + // rely on the stencil buffer across subpasses. Stop batching + // every time the drawGroupIdx changes. + needsBarrierMask = kDrawGroupMask; + // MSAA mode draws clips, strokes, fills, and even/odd with + // different stencil settings, so these can't be batched. + needsBarrierMask |= kDrawContentsMask; + if (platformFeatures.supportsKHRBlendEquations) + { + // If using KHR_blend_equation_advanced, we also need to + // stop batching between blend modes in order to change the + // blend equation. + needsBarrierMask |= kBlendModeMask; + } + // MSAA barriers only need to prevent batching of draws for now. + // If we also need a dstColorTexture barrier, that will be + // decided later. + neededBarriers = BarrierFlags::drawBatchBreak; + break; + } + + // Write out the draw data from the sorted draw list, and build up a + // condensed/batched list of low-level draws. + int64_t priorSignedKey = + !indirectDrawList.empty() ? indirectDrawList[0] : 0; + for (const int64_t signedKey : indirectDrawList) + { + assert(signedKey >= priorSignedKey); + if ((priorSignedKey & needsBarrierMask) != + (signedKey & needsBarrierMask)) + { + m_pendingBarriers |= neededBarriers; + } + int64_t key = abs(signedKey); + uint32_t drawIndex = (key & kDrawIndexMask) >> kDrawIndexShift; + int subpassIndex = key & kSubpassIndexMask; + if (signedKey < 0) + { + // Negative keys are a prepass. Update the subpassIndex to be + // negative. + subpassIndex = -1 - subpassIndex; + } + // FIXME: m_currentZIndex shouldn't be a stateful variable; it + // should be passed to pushToRenderContext() instead. + m_currentZIndex = math::lossless_numeric_cast( + abs(key >> static_cast(kDrawGroupShift))); + m_draws[drawIndex]->pushToRenderContext(this, subpassIndex); + priorSignedKey = signedKey; + } + + // Atomic mode needs one more draw to resolve all the pixels. + if (m_ctx->frameInterlockMode() == gpu::InterlockMode::atomics) + { + // We can ignore any pending "plsAtomic" barriers; the + // plsAtomicPreResolve can replace them. + assert((m_pendingBarriers & ~(BarrierFlags::plsAtomic | + BarrierFlags::plsAtomicPostInit)) == + BarrierFlags::none); + m_drawList + .emplace_back(m_ctx->perFrameAllocator(), + DrawType::atomicResolve, + gpu::ShaderMiscFlags::none, + 1, + 0, + BlendMode::srcOver, + ImageSampler::LinearClamp(), + BarrierFlags::plsAtomicPreResolve) + .shaderFeatures = m_combinedShaderFeatures; + } + } + + // Write out the draws to the feather atlas. Do this after the main draws + // (even though the atlas ones execute first) so that our path info and Z + // index are decided and available to pushAtlasTessellation(). + if (!m_pendingAtlasDraws.empty()) + { + TAABB fullAtlasViewport = {0, + 0, + m_flushDesc.atlasContentWidth, + m_flushDesc.atlasContentHeight}; + gpu::AtlasDrawBatch* currentBatch = + m_ctx->m_perFrameAllocator.makePODArray( + m_pendingAtlasDraws.size()); + // Iterate the atlas draws 4 times so we can sort by fill / stroke / + // scissored / not, and batch together the draws that don't have + // scissor. + for (bool stroked : {false, true}) + { + if (stroked) + { + m_flushDesc.atlasStrokeBatches = currentBatch; + } + else + { + m_flushDesc.atlasFillBatches = currentBatch; + } + for (bool scissored : {false, true}) + { + gpu::AtlasDrawBatch* lastBatch = nullptr; + for (PathDraw* draw : m_pendingAtlasDraws) + { + if (draw->isStroke() != stroked || + draw->atlasScissorEnabled() != scissored) + { + continue; + } + uint32_t tessVertexCount, tessBaseVertex; + draw->pushAtlasTessellation(this, + &tessVertexCount, + &tessBaseVertex); + if (tessVertexCount == 0) + { + continue; + } + uint32_t patchCount = + tessVertexCount / gpu::kMidpointFanPatchSegmentSpan; + uint32_t basePatch = + tessBaseVertex / gpu::kMidpointFanPatchSegmentSpan; + assert(patchCount * gpu::kMidpointFanPatchSegmentSpan == + tessVertexCount); + assert(basePatch * gpu::kMidpointFanPatchSegmentSpan == + tessBaseVertex); + if (lastBatch == nullptr || scissored) + { + lastBatch = currentBatch++; + *lastBatch = { + lastBatch->scissor = scissored + ? draw->atlasScissor() + : fullAtlasViewport, + lastBatch->patchCount = patchCount, + lastBatch->basePatch = basePatch, + }; + } + else + { + assert(lastBatch->basePatch + lastBatch->patchCount == + basePatch); + lastBatch->patchCount += patchCount; + } + } + } + if (stroked) + { + m_flushDesc.atlasStrokeBatchCount = + currentBatch - m_flushDesc.atlasStrokeBatches; + } + else + { + m_flushDesc.atlasFillBatchCount = + currentBatch - m_flushDesc.atlasFillBatches; + } + } + assert(m_flushDesc.atlasFillBatchCount + + m_flushDesc.atlasStrokeBatchCount == + currentBatch - m_flushDesc.atlasFillBatches); + assert(m_flushDesc.atlasFillBatchCount + + m_flushDesc.atlasStrokeBatchCount <= + m_pendingAtlasDraws.size()); + } + + // Pad our buffers to 256-byte alignment. + m_ctx->m_pathData.push_back_n(nullptr, m_pathPaddingCount); + m_ctx->m_paintData.push_back_n(nullptr, m_paintPaddingCount); + m_ctx->m_paintAuxData.push_back_n(nullptr, m_paintAuxPaddingCount); + m_ctx->m_contourData.push_back_n(nullptr, m_contourPaddingCount); + m_ctx->m_gradSpanData.push_back_n(nullptr, m_gradSpanPaddingCount); + + assert(m_ctx->m_pathData.elementsWritten() == + m_flushDesc.firstPath + m_resourceCounts.pathCount + + m_pathPaddingCount); + assert(m_ctx->m_paintData.elementsWritten() == + m_flushDesc.firstPaint + m_resourceCounts.pathCount + + m_paintPaddingCount); + assert(m_ctx->m_paintAuxData.elementsWritten() == + m_flushDesc.firstPaintAux + m_resourceCounts.pathCount + + m_paintAuxPaddingCount); + assert(m_ctx->m_contourData.elementsWritten() == + m_flushDesc.firstContour + m_resourceCounts.contourCount + + m_contourPaddingCount); + assert(m_ctx->m_gradSpanData.elementsWritten() == + m_flushDesc.firstGradSpan + m_pendingGradSpanCount + + m_gradSpanPaddingCount); + assert(m_midpointFanTessVertexIdx == m_midpointFanTessEndLocation); + assert(m_outerCubicTessVertexIdx == m_outerCubicTessEndLocation); + + // Some of the flushDescriptor's data isn't known until after + // writeResources(). Update it now that it's known. + m_flushDesc.combinedShaderFeatures = m_combinedShaderFeatures; + m_flushDesc.atomicFixedFunctionColorOutput = + m_ctx->frameInterlockMode() == InterlockMode::atomics && + !(m_combinedShaderFeatures & ShaderFeatures::ENABLE_ADVANCED_BLEND); + + if (m_coverageBufferLength > 0) + { + assert(m_flushDesc.interlockMode == + gpu::InterlockMode::clockwiseAtomic); + // The coverage buffer prefix gets reset to zero when the buffer is + // reallocated, so wait until here to get the prefix. + m_flushDesc.coverageBufferPrefix = m_ctx->incrementCoverageBufferPrefix( + &m_flushDesc.needsCoverageBufferClear); + } + + m_flushDesc.tessVertexSpanCount = math::lossless_numeric_cast( + m_ctx->m_tessSpanData.elementsWritten() - + m_flushDesc.firstTessVertexSpan); + + m_flushDesc.hasTriangleVertices = + m_ctx->m_triangleVertexData.bytesWritten() != + initialTriangleVertexDataSize; + + m_flushDesc.drawList = &m_drawList; + + // Write out the uniforms for this flush now that the flushDescriptor is + // complete. + m_ctx->m_flushUniformData.emplace_back(m_flushDesc, platformFeatures); +} + +void RenderContext::setResourceSizes(ResourceAllocationCounts allocs, + bool forceRealloc) +{ +#if 0 + class Logger + { + public: + void logSize(const char* name, + size_t oldSize, + size_t newSize, + size_t newSizeInBytes) + { + m_totalSizeInBytes += newSizeInBytes; + if (oldSize == newSize) + { + return; + } + if (!m_hasChanged) + { + printf("RenderContext::setResourceSizes():\n"); + m_hasChanged = true; + } + printf(" resize %s: %zu -> %zu (%zu KiB)\n", + name, + oldSize, + newSize, + newSizeInBytes >> 10); + } + + void logTextureSize(const char* widthName, + const char* heightName, + size_t oldWidth, + size_t oldHeight, + size_t newWidth, + size_t newHeight, + size_t bytesPerPixel) + { + m_totalSizeInBytes += newHeight * newWidth * bytesPerPixel; + if (oldWidth == newWidth && oldHeight == newHeight) + { + return; + } + if (!m_hasChanged) + { + printf("RenderContext::setResourceSizes():\n"); + m_hasChanged = true; + } + printf(" resize %s x %s: %zu x %zu -> %zu x %zu (%zu KiB)\n", + widthName, + heightName, + oldWidth, + oldHeight, + newWidth, + newHeight, + (newHeight * newWidth * bytesPerPixel) >> 10); + } + + ~Logger() + { + if (!m_hasChanged) + { + return; + } + printf(" TOTAL GPU resource usage: %zu KiB\n", + m_totalSizeInBytes >> 10); + } + + private: + size_t m_totalSizeInBytes = 0; + bool m_hasChanged = false; + } logger; +#define LOG_BUFFER_RING_SIZE(NAME, ITEM_SIZE_IN_BYTES) \ + logger.logSize(#NAME, \ + m_currentResourceAllocations.NAME, \ + allocs.NAME, \ + allocs.NAME* ITEM_SIZE_IN_BYTES* gpu::kBufferRingSize) +#define LOG_TEXTURE_HEIGHT(NAME, BYTES_PER_ROW) \ + logger.logSize(#NAME, \ + m_currentResourceAllocations.NAME, \ + allocs.NAME, \ + allocs.NAME* BYTES_PER_ROW) +#define LOG_TEXTURE_SIZE(WIDTH_NAME, HEIGHT_NAME, BYTES_PER_PIXEL) \ + logger.logTextureSize(#WIDTH_NAME, \ + #HEIGHT_NAME, \ + m_currentResourceAllocations.WIDTH_NAME, \ + m_currentResourceAllocations.HEIGHT_NAME, \ + allocs.WIDTH_NAME, \ + allocs.HEIGHT_NAME, \ + BYTES_PER_PIXEL) +#define LOG_BUFFER_SIZE(NAME, BYTES_PER_ELEMENT) \ + logger.logSize(#NAME, \ + m_currentResourceAllocations.NAME, \ + allocs.NAME, \ + allocs.NAME* BYTES_PER_ELEMENT) +#else +#define LOG_BUFFER_RING_SIZE(NAME, ITEM_SIZE_IN_BYTES) +#define LOG_TEXTURE_HEIGHT(NAME, BYTES_PER_ROW) +#define LOG_TEXTURE_SIZE(WIDTH_NAME, HEIGHT_NAME, BYTES_PER_PIXEL) +#define LOG_BUFFER_SIZE(NAME, BYTES_PER_ELEMENT) +#endif + + LOG_BUFFER_RING_SIZE(flushUniformBufferCount, sizeof(gpu::FlushUniforms)); + if (allocs.flushUniformBufferCount != + m_currentResourceAllocations.flushUniformBufferCount || + forceRealloc) + { + m_impl->resizeFlushUniformBuffer(allocs.flushUniformBufferCount * + sizeof(gpu::FlushUniforms)); + } + + LOG_BUFFER_RING_SIZE(imageDrawUniformBufferCount, + sizeof(gpu::ImageDrawUniforms)); + if (allocs.imageDrawUniformBufferCount != + m_currentResourceAllocations.imageDrawUniformBufferCount || + forceRealloc) + { + m_impl->resizeImageDrawUniformBuffer( + allocs.imageDrawUniformBufferCount * + sizeof(gpu::ImageDrawUniforms)); + } + + LOG_BUFFER_RING_SIZE(pathBufferCount, sizeof(gpu::PathData)); + if (allocs.pathBufferCount != + m_currentResourceAllocations.pathBufferCount || + forceRealloc) + { + m_impl->resizePathBuffer(allocs.pathBufferCount * sizeof(gpu::PathData), + gpu::PathData::kBufferStructure); + } + + LOG_BUFFER_RING_SIZE(paintBufferCount, sizeof(gpu::PaintData)); + if (allocs.paintBufferCount != + m_currentResourceAllocations.paintBufferCount || + forceRealloc) + { + m_impl->resizePaintBuffer(allocs.paintBufferCount * + sizeof(gpu::PaintData), + gpu::PaintData::kBufferStructure); + } + + LOG_BUFFER_RING_SIZE(paintAuxBufferCount, sizeof(gpu::PaintAuxData)); + if (allocs.paintAuxBufferCount != + m_currentResourceAllocations.paintAuxBufferCount || + forceRealloc) + { + m_impl->resizePaintAuxBuffer(allocs.paintAuxBufferCount * + sizeof(gpu::PaintAuxData), + gpu::PaintAuxData::kBufferStructure); + } + + LOG_BUFFER_RING_SIZE(contourBufferCount, sizeof(gpu::ContourData)); + if (allocs.contourBufferCount != + m_currentResourceAllocations.contourBufferCount || + forceRealloc) + { + m_impl->resizeContourBuffer(allocs.contourBufferCount * + sizeof(gpu::ContourData), + gpu::ContourData::kBufferStructure); + } + + LOG_BUFFER_RING_SIZE(gradSpanBufferCount, sizeof(gpu::GradientSpan)); + if (allocs.gradSpanBufferCount != + m_currentResourceAllocations.gradSpanBufferCount || + forceRealloc) + { + m_impl->resizeGradSpanBuffer(allocs.gradSpanBufferCount * + sizeof(gpu::GradientSpan)); + } + + LOG_BUFFER_RING_SIZE(tessSpanBufferCount, sizeof(gpu::TessVertexSpan)); + if (allocs.tessSpanBufferCount != + m_currentResourceAllocations.tessSpanBufferCount || + forceRealloc) + { + m_impl->resizeTessVertexSpanBuffer(allocs.tessSpanBufferCount * + sizeof(gpu::TessVertexSpan)); + } + + LOG_BUFFER_RING_SIZE(triangleVertexBufferCount, + sizeof(gpu::TriangleVertex)); + if (allocs.triangleVertexBufferCount != + m_currentResourceAllocations.triangleVertexBufferCount || + forceRealloc) + { + m_impl->resizeTriangleVertexBuffer(allocs.triangleVertexBufferCount * + sizeof(gpu::TriangleVertex)); + } + + assert(allocs.gradTextureHeight <= kMaxTextureHeight); + LOG_TEXTURE_HEIGHT(gradTextureHeight, gpu::kGradTextureWidth * 4); + if (allocs.gradTextureHeight != + m_currentResourceAllocations.gradTextureHeight || + forceRealloc) + { + m_impl->resizeGradientTexture( + gpu::kGradTextureWidth, + math::lossless_numeric_cast(allocs.gradTextureHeight)); + } + + assert(allocs.tessTextureHeight <= kMaxTextureHeight); + LOG_TEXTURE_HEIGHT(tessTextureHeight, gpu::kTessTextureWidth * 4 * 4); + if (allocs.tessTextureHeight != + m_currentResourceAllocations.tessTextureHeight || + forceRealloc) + { + m_impl->resizeTessellationTexture( + gpu::kTessTextureWidth, + math::lossless_numeric_cast(allocs.tessTextureHeight)); + } + + assert(allocs.atlasTextureWidth <= atlasMaxSize() || + allocs.atlasTextureWidth <= frameDescriptor().renderTargetWidth); + assert(allocs.atlasTextureHeight <= atlasMaxSize() || + allocs.atlasTextureHeight <= frameDescriptor().renderTargetHeight); + LOG_TEXTURE_SIZE(atlasTextureWidth, atlasTextureHeight, sizeof(uint16_t)); + if (allocs.atlasTextureWidth != + m_currentResourceAllocations.atlasTextureWidth || + allocs.atlasTextureHeight != + m_currentResourceAllocations.atlasTextureHeight || + forceRealloc) + { + m_impl->resizeAtlasTexture( + math::lossless_numeric_cast(allocs.atlasTextureWidth), + math::lossless_numeric_cast(allocs.atlasTextureHeight)); + } + + assert(allocs.coverageBufferLength <= + platformFeatures().maxCoverageBufferLength); + LOG_BUFFER_SIZE(coverageBufferLength, sizeof(uint32_t)); + if (allocs.coverageBufferLength != + m_currentResourceAllocations.coverageBufferLength || + forceRealloc) + { + m_impl->resizeCoverageBuffer(allocs.coverageBufferLength * + sizeof(uint32_t)); + // Start the coverageBufferPrefix over at zero. This ensure the new + // buffer gets cleared because the only criteria for clearing it is when + // the prefix wraps around to 0. + m_coverageBufferPrefix = 0; + } + + m_currentResourceAllocations = allocs; +} + +void RenderContext::mapResourceBuffers( + const ResourceAllocationCounts& mapCounts) +{ + if (mapCounts.flushUniformBufferCount > 0) + { + m_flushUniformData.mapElements( + m_impl.get(), + &RenderContextImpl::mapFlushUniformBuffer, + mapCounts.flushUniformBufferCount); + } + assert(m_flushUniformData.hasRoomFor(mapCounts.flushUniformBufferCount)); + + if (mapCounts.imageDrawUniformBufferCount > 0) + { + m_imageDrawUniformData.mapElements( + m_impl.get(), + &RenderContextImpl::mapImageDrawUniformBuffer, + mapCounts.imageDrawUniformBufferCount); + } + assert(m_imageDrawUniformData.hasRoomFor( + mapCounts.imageDrawUniformBufferCount > 0)); + + if (mapCounts.pathBufferCount > 0) + { + m_pathData.mapElements(m_impl.get(), + &RenderContextImpl::mapPathBuffer, + mapCounts.pathBufferCount); + } + assert(m_pathData.hasRoomFor(mapCounts.pathBufferCount)); + + if (mapCounts.paintBufferCount > 0) + { + m_paintData.mapElements(m_impl.get(), + &RenderContextImpl::mapPaintBuffer, + mapCounts.paintBufferCount); + } + assert(m_paintData.hasRoomFor(mapCounts.paintBufferCount)); + + if (mapCounts.paintAuxBufferCount > 0) + { + m_paintAuxData.mapElements(m_impl.get(), + &RenderContextImpl::mapPaintAuxBuffer, + mapCounts.paintAuxBufferCount); + } + assert(m_paintAuxData.hasRoomFor(mapCounts.paintAuxBufferCount)); + + if (mapCounts.contourBufferCount > 0) + { + m_contourData.mapElements(m_impl.get(), + &RenderContextImpl::mapContourBuffer, + mapCounts.contourBufferCount); + } + assert(m_contourData.hasRoomFor(mapCounts.contourBufferCount)); + + if (mapCounts.gradSpanBufferCount > 0) + { + m_gradSpanData.mapElements(m_impl.get(), + &RenderContextImpl::mapGradSpanBuffer, + mapCounts.gradSpanBufferCount); + } + assert(m_gradSpanData.hasRoomFor(mapCounts.gradSpanBufferCount)); + + if (mapCounts.tessSpanBufferCount > 0) + { + m_tessSpanData.mapElements(m_impl.get(), + &RenderContextImpl::mapTessVertexSpanBuffer, + mapCounts.tessSpanBufferCount); + } + assert(m_tessSpanData.hasRoomFor(mapCounts.tessSpanBufferCount)); + + if (mapCounts.triangleVertexBufferCount > 0) + { + m_triangleVertexData.mapElements( + m_impl.get(), + &RenderContextImpl::mapTriangleVertexBuffer, + mapCounts.triangleVertexBufferCount); + } + assert( + m_triangleVertexData.hasRoomFor(mapCounts.triangleVertexBufferCount)); +} + +void RenderContext::unmapResourceBuffers( + const ResourceAllocationCounts& mapCounts) +{ + if (m_flushUniformData) + { + m_flushUniformData.unmapElements( + m_impl.get(), + &RenderContextImpl::unmapFlushUniformBuffer, + mapCounts.flushUniformBufferCount); + } + if (m_imageDrawUniformData) + { + m_imageDrawUniformData.unmapElements( + m_impl.get(), + &RenderContextImpl::unmapImageDrawUniformBuffer, + mapCounts.imageDrawUniformBufferCount); + } + if (m_pathData) + { + m_pathData.unmapElements(m_impl.get(), + &RenderContextImpl::unmapPathBuffer, + mapCounts.pathBufferCount); + } + if (m_paintData) + { + m_paintData.unmapElements(m_impl.get(), + &RenderContextImpl::unmapPaintBuffer, + mapCounts.paintBufferCount); + } + if (m_paintAuxData) + { + m_paintAuxData.unmapElements(m_impl.get(), + &RenderContextImpl::unmapPaintAuxBuffer, + mapCounts.paintAuxBufferCount); + } + if (m_contourData) + { + m_contourData.unmapElements(m_impl.get(), + &RenderContextImpl::unmapContourBuffer, + mapCounts.contourBufferCount); + } + if (m_gradSpanData) + { + m_gradSpanData.unmapElements(m_impl.get(), + &RenderContextImpl::unmapGradSpanBuffer, + mapCounts.gradSpanBufferCount); + } + if (m_tessSpanData) + { + m_tessSpanData.unmapElements( + m_impl.get(), + &RenderContextImpl::unmapTessVertexSpanBuffer, + mapCounts.tessSpanBufferCount); + } + if (m_triangleVertexData) + { + m_triangleVertexData.unmapElements( + m_impl.get(), + &RenderContextImpl::unmapTriangleVertexBuffer, + mapCounts.triangleVertexBufferCount); + } +} + +uint32_t RenderContext::incrementCoverageBufferPrefix( + bool* needsCoverageBufferClear) +{ + assert(m_didBeginFrame); + assert(frameInterlockMode() == gpu::InterlockMode::clockwiseAtomic); + do + { + if (m_coverageBufferPrefix == 0) + { + // When the prefix wraps around to 0, we need to clear the coverage + // buffer because our shaders require coverageBufferPrefix to be + // monotonically increasing. + *needsCoverageBufferClear = true; + } + m_coverageBufferPrefix += 1 << CLOCKWISE_COVERAGE_BIT_COUNT; + } while (m_coverageBufferPrefix == 0); + + return m_coverageBufferPrefix; +} + +uint32_t RenderContext::LogicalFlush::allocateMidpointFanTessVertices( + uint32_t count) +{ + uint32_t location = m_midpointFanTessVertexIdx; + m_midpointFanTessVertexIdx += count; + assert(m_midpointFanTessVertexIdx <= m_midpointFanTessEndLocation); + return location; +} + +uint32_t RenderContext::LogicalFlush::allocateOuterCubicTessVertices( + uint32_t count) +{ + uint32_t location = m_outerCubicTessVertexIdx; + m_outerCubicTessVertexIdx += count; + assert(m_outerCubicTessVertexIdx <= m_outerCubicTessEndLocation); + return location; +} + +uint32_t RenderContext::LogicalFlush::pushPath(const PathDraw* draw) +{ + assert(m_hasDoneLayout); + + ++m_currentPathID; + assert(0 < m_currentPathID && m_currentPathID <= m_ctx->m_maxPathID); + + m_ctx->m_pathData.set_back(draw->matrix(), + draw->strokeRadius(), + draw->featherRadius(), + m_currentZIndex, + draw->atlasTransform(), + draw->coverageBufferRange()); + m_ctx->m_paintData.set_back(draw->drawContents(), + draw->paintType(), + draw->simplePaintValue(), + m_gradTextureLayout, + draw->clipID(), + draw->hasClipRect(), + draw->blendMode()); + m_ctx->m_paintAuxData.set_back(draw->matrix(), + draw->paintType(), + draw->simplePaintValue(), + draw->gradient(), + draw->imageTexture(), + draw->clipRectInverseMatrix(), + m_flushDesc.renderTarget, + m_ctx->platformFeatures()); + + assert(m_flushDesc.firstPath + m_currentPathID + 1 == + m_ctx->m_pathData.elementsWritten()); + assert(m_flushDesc.firstPaint + m_currentPathID + 1 == + m_ctx->m_paintData.elementsWritten()); + assert(m_flushDesc.firstPaintAux + m_currentPathID + 1 == + m_ctx->m_paintAuxData.elementsWritten()); + + return m_currentPathID; +} + +RenderContext::TessellationWriter::TessellationWriter( + LogicalFlush* flush, + uint32_t pathID, + gpu::ContourDirections contourDirections, + uint32_t forwardTessVertexCount, + uint32_t forwardTessLocation, + uint32_t mirroredTessVertexCount, + uint32_t mirroredTessLocation) : + m_flush(flush), + m_tessSpanData(m_flush->m_ctx->m_tessSpanData), + m_pathID(pathID), + m_contourDirections(contourDirections), + m_pathTessLocation(forwardTessLocation), + m_pathMirroredTessLocation(mirroredTessLocation) +{ + RIVE_DEBUG_CODE(m_expectedPathTessEndLocation = + m_pathTessLocation + forwardTessVertexCount;) + RIVE_DEBUG_CODE(m_expectedPathMirroredTessEndLocation = + m_pathMirroredTessLocation - mirroredTessVertexCount;) + assert(m_flush->m_hasDoneLayout); + assert(m_flush->m_ctx->m_pathData.elementsWritten() > 0); + assert(forwardTessVertexCount == 0 || mirroredTessVertexCount == 0 || + forwardTessVertexCount == mirroredTessVertexCount); + assert(!gpu::ContourDirectionsAreDoubleSided(m_contourDirections) || + forwardTessVertexCount == mirroredTessVertexCount); + assert(m_pathTessLocation >= 0); + assert(m_pathMirroredTessLocation <= kMaxTessellationVertexCount); + assert(m_expectedPathTessEndLocation <= kMaxTessellationVertexCount); + assert(m_expectedPathMirroredTessEndLocation >= 0); +} + +RenderContext::TessellationWriter::~TessellationWriter() +{ + assert(m_pathTessLocation == m_expectedPathTessEndLocation); + assert(m_pathMirroredTessLocation == m_expectedPathMirroredTessEndLocation); +} + +uint32_t RenderContext::LogicalFlush::pushContour(uint32_t pathID, + Vec2D midpoint, + bool isStroke, + bool closed, + uint32_t vertexIndex0) +{ + assert(pathID != 0); + assert(isStroke || closed); + + if (isStroke) + { + midpoint.x = closed ? 1 : 0; + } + m_ctx->m_contourData.emplace_back(midpoint, pathID, vertexIndex0); + + ++m_currentContourID; + assert(0 < m_currentContourID && m_currentContourID <= gpu::kMaxContourID); + assert(m_flushDesc.firstContour + m_currentContourID == + m_ctx->m_contourData.elementsWritten()); + return m_currentContourID; +} + +uint32_t RenderContext::TessellationWriter::pushContour( + Vec2D midpoint, + bool isStroke, + bool closed, + uint32_t paddingVertexCount) +{ + // The first curve of the contour will be pre-padded with + // 'paddingVertexCount' tessellation vertices, colocated at T=0. The caller + // must use this argument align the end of the contour on a boundary of the + // patch size. (See math::padding_to_align_up().) + m_nextCubicPaddingVertexCount = paddingVertexCount; + + return m_flush->pushContour(m_pathID, + midpoint, + isStroke, + closed, + nextVertexIndex()); +} + +void RenderContext::TessellationWriter::pushCubic( + const Vec2D pts[4], + gpu::ContourDirections contourDirections, + Vec2D joinTangent, + uint32_t parametricSegmentCount, + uint32_t polarSegmentCount, + uint32_t joinSegmentCount, + uint32_t contourIDWithFlags) +{ + assert(0 <= parametricSegmentCount && + parametricSegmentCount <= kMaxParametricSegments); + assert(0 <= polarSegmentCount && polarSegmentCount <= kMaxPolarSegments); + assert(joinSegmentCount > 0); + assert((contourIDWithFlags & 0xffff) == + (m_flush->m_currentContourID & 0xffff)); + assert((contourIDWithFlags & 0xffff) != 0); // contourID can't be zero. + + // Polar and parametric segments share the same beginning and ending + // vertices, so the merged *vertex* count is equal to the sum of polar and + // parametric *segment* counts. + uint32_t curveMergedVertexCount = + parametricSegmentCount + polarSegmentCount; + // -1 because the curve and join share an ending/beginning vertex. + uint32_t totalVertexCount = m_nextCubicPaddingVertexCount + + curveMergedVertexCount + joinSegmentCount - 1; + + // Only the first curve of a contour gets padding vertices. + m_nextCubicPaddingVertexCount = 0; + + switch (contourDirections) + { + case gpu::ContourDirections::forward: + pushTessellationSpans(pts, + joinTangent, + totalVertexCount, + parametricSegmentCount, + polarSegmentCount, + joinSegmentCount, + contourIDWithFlags); + break; + case gpu::ContourDirections::reverse: + pushMirroredTessellationSpans(pts, + joinTangent, + totalVertexCount, + parametricSegmentCount, + polarSegmentCount, + joinSegmentCount, + contourIDWithFlags); + break; + case gpu::ContourDirections::reverseThenForward: + case gpu::ContourDirections::forwardThenReverse: + // m_pathTessLocation and m_pathMirroredTessLocation are already + // configured, so at ths point we don't need to handle + // reverseThenForward or forwardThenReverse differently. + pushDoubleSidedTessellationSpans(pts, + joinTangent, + totalVertexCount, + parametricSegmentCount, + polarSegmentCount, + joinSegmentCount, + contourIDWithFlags); + break; + } +} + +RIVE_ALWAYS_INLINE void RenderContext::TessellationWriter:: + pushTessellationSpans(const Vec2D pts[4], + Vec2D joinTangent, + uint32_t totalVertexCount, + uint32_t parametricSegmentCount, + uint32_t polarSegmentCount, + uint32_t joinSegmentCount, + uint32_t contourIDWithFlags) +{ + assert(totalVertexCount > 0); + + uint32_t y = m_pathTessLocation / kTessTextureWidth; + int32_t x0 = m_pathTessLocation % kTessTextureWidth; + int32_t x1 = x0 + totalVertexCount; + for (;;) + { + m_tessSpanData.set_back(pts, + joinTangent, + static_cast(y), + x0, + x1, + parametricSegmentCount, + polarSegmentCount, + joinSegmentCount, + contourIDWithFlags); + if (x1 > static_cast(kTessTextureWidth)) + { + // The span was too long to fit on the current line. Wrap and draw + // it again, this time behind the left edge of the texture so we + // capture what got clipped off last time. + ++y; + x0 -= kTessTextureWidth; + x1 -= kTessTextureWidth; + continue; + } + break; + } + assert(y == + (m_pathTessLocation + totalVertexCount - 1) / kTessTextureWidth); + + m_pathTessLocation += totalVertexCount; + assert(m_pathTessLocation <= m_expectedPathTessEndLocation); +} + +RIVE_ALWAYS_INLINE void RenderContext::TessellationWriter:: + pushMirroredTessellationSpans(const Vec2D pts[4], + Vec2D joinTangent, + uint32_t totalVertexCount, + uint32_t parametricSegmentCount, + uint32_t polarSegmentCount, + uint32_t joinSegmentCount, + uint32_t contourIDWithFlags) +{ + assert(totalVertexCount > 0); + + uint32_t reflectionY = (m_pathMirroredTessLocation - 1) / kTessTextureWidth; + int32_t reflectionX0 = + (m_pathMirroredTessLocation - 1) % kTessTextureWidth + 1; + int32_t reflectionX1 = reflectionX0 - totalVertexCount; + + for (;;) + { + m_tessSpanData.set_back(pts, + joinTangent, + static_cast(reflectionY), + reflectionX0, + reflectionX1, + parametricSegmentCount, + polarSegmentCount, + joinSegmentCount, + contourIDWithFlags); + if (reflectionX1 < 0) + { + --reflectionY; + reflectionX0 += kTessTextureWidth; + reflectionX1 += kTessTextureWidth; + continue; + } + break; + } + + m_pathMirroredTessLocation -= totalVertexCount; + assert(m_pathMirroredTessLocation >= m_expectedPathMirroredTessEndLocation); +} + +RIVE_ALWAYS_INLINE void RenderContext::TessellationWriter:: + pushDoubleSidedTessellationSpans(const Vec2D pts[4], + Vec2D joinTangent, + uint32_t totalVertexCount, + uint32_t parametricSegmentCount, + uint32_t polarSegmentCount, + uint32_t joinSegmentCount, + uint32_t contourIDWithFlags) +{ + assert(totalVertexCount > 0); + + int32_t y = m_pathTessLocation / kTessTextureWidth; + int32_t x0 = m_pathTessLocation % kTessTextureWidth; + int32_t x1 = x0 + totalVertexCount; + + uint32_t reflectionY = (m_pathMirroredTessLocation - 1) / kTessTextureWidth; + int32_t reflectionX0 = + (m_pathMirroredTessLocation - 1) % kTessTextureWidth + 1; + int32_t reflectionX1 = reflectionX0 - totalVertexCount; + + for (;;) + { + m_tessSpanData.set_back(pts, + joinTangent, + static_cast(y), + x0, + x1, + static_cast(reflectionY), + reflectionX0, + reflectionX1, + parametricSegmentCount, + polarSegmentCount, + joinSegmentCount, + contourIDWithFlags); + if (x1 > static_cast(kTessTextureWidth) || reflectionX1 < 0) + { + // Either the span or its reflection was too long to fit on the + // current line. Wrap and draw both of them again, this time beyond + // the opposite edge of the texture so we capture what got clipped + // off last time. + ++y; + x0 -= kTessTextureWidth; + x1 -= kTessTextureWidth; + + --reflectionY; + reflectionX0 += kTessTextureWidth; + reflectionX1 += kTessTextureWidth; + continue; + } + break; + } + + m_pathTessLocation += totalVertexCount; + assert(m_pathTessLocation <= m_expectedPathTessEndLocation); + + m_pathMirroredTessLocation -= totalVertexCount; + assert(m_pathMirroredTessLocation >= m_expectedPathMirroredTessEndLocation); +} + +void RenderContext::LogicalFlush::pushPaddingVertices(uint32_t count, + uint32_t tessLocation) +{ + assert(m_hasDoneLayout); + assert(count > 0); + + constexpr static Vec2D kEmptyCubic[4]{}; + TessellationWriter(this, + /*pathID=*/0, + gpu::ContourDirections::forward, + count, + tessLocation) + .pushTessellationSpans(kEmptyCubic, + {0, 0}, + count, + 0, + 0, + 1, + INVALID_CONTOUR_ID_WITH_FLAGS); +} + +void RenderContext::LogicalFlush::pushMidpointFanDraw( + const PathDraw* draw, + gpu::DrawType drawType, + uint32_t tessVertexCount, + uint32_t tessLocation, + gpu::ShaderMiscFlags shaderMiscFlags) +{ + assert(m_hasDoneLayout); + + uint32_t baseInstance = math::lossless_numeric_cast( + tessLocation / kMidpointFanPatchSegmentSpan); + // flush() is responsible for alignment. + assert(baseInstance * kMidpointFanPatchSegmentSpan == tessLocation); + + uint32_t instanceCount = tessVertexCount / kMidpointFanPatchSegmentSpan; + // flush() is responsible for alignment. + assert(instanceCount * kMidpointFanPatchSegmentSpan == tessVertexCount); + + pushPathDraw(draw, drawType, shaderMiscFlags, instanceCount, baseInstance); +} + +void RenderContext::LogicalFlush::pushOuterCubicsDraw( + const PathDraw* draw, + gpu::DrawType drawType, + uint32_t tessVertexCount, + uint32_t tessLocation, + gpu::ShaderMiscFlags shaderMiscFlags) +{ + assert(m_hasDoneLayout); + + uint32_t baseInstance = math::lossless_numeric_cast( + tessLocation / kOuterCurvePatchSegmentSpan); + // flush() is responsible for alignment. + assert(baseInstance * kOuterCurvePatchSegmentSpan == tessLocation); + + uint32_t instanceCount = tessVertexCount / kOuterCurvePatchSegmentSpan; + // flush() is responsible for alignment. + assert(instanceCount * kOuterCurvePatchSegmentSpan == tessVertexCount); + + pushPathDraw(draw, drawType, shaderMiscFlags, instanceCount, baseInstance); +} + +size_t RenderContext::LogicalFlush::pushInteriorTriangulationDraw( + const PathDraw* draw, + uint32_t pathID, + gpu::WindingFaces windingFaces, + gpu::ShaderMiscFlags shaderMiscFlags) +{ + assert(m_hasDoneLayout); + assert(pathID != 0); + + uint32_t baseVertex = math::lossless_numeric_cast( + m_ctx->m_triangleVertexData.elementsWritten()); + size_t actualVertexCount = + draw->triangulator()->polysToTriangles(pathID, + windingFaces, + &m_ctx->m_triangleVertexData); + assert(baseVertex + actualVertexCount == + m_ctx->m_triangleVertexData.elementsWritten()); + if (actualVertexCount > 0) + { + pushPathDraw(draw, + DrawType::interiorTriangulation, + shaderMiscFlags, + math::lossless_numeric_cast(actualVertexCount), + baseVertex); + } + return actualVertexCount; +} + +void RenderContext::LogicalFlush::pushAtlasBlit(PathDraw* draw, uint32_t pathID) +{ + auto baseVertex = math::lossless_numeric_cast( + m_ctx->m_triangleVertexData.elementsWritten()); + auto [l, t, r, b] = AABB(draw->pixelBounds()); + m_ctx->m_triangleVertexData.emplace_back(Vec2D{l, b}, 1, pathID); + m_ctx->m_triangleVertexData.emplace_back(Vec2D{l, t}, 1, pathID); + m_ctx->m_triangleVertexData.emplace_back(Vec2D{r, b}, 1, pathID); + m_ctx->m_triangleVertexData.emplace_back(Vec2D{r, b}, 1, pathID); + m_ctx->m_triangleVertexData.emplace_back(Vec2D{l, t}, 1, pathID); + m_ctx->m_triangleVertexData.emplace_back(Vec2D{r, t}, 1, pathID); + pushPathDraw(draw, + DrawType::atlasBlit, + gpu::ShaderMiscFlags::none, + 6, + baseVertex); +} + +void RenderContext::LogicalFlush::pushImageRectDraw(ImageRectDraw* draw) +{ + assert(m_hasDoneLayout); + + // If we support image paints for paths, the client should use pushPath() + // with an image paint instead of calling this method. + assert(!m_ctx->frameSupportsImagePaintForPaths()); + + size_t imageDrawDataOffset = m_ctx->m_imageDrawUniformData.bytesWritten(); + m_ctx->m_imageDrawUniformData.emplace_back(draw->matrix(), + draw->opacity(), + draw->clipRectInverseMatrix(), + draw->clipID(), + draw->blendMode(), + m_currentZIndex); + + DrawBatch& batch = pushDraw(draw, + DrawType::imageRect, + gpu::ShaderMiscFlags::none, + PaintType::image, + 1, + 0); + batch.imageDrawDataOffset = + math::lossless_numeric_cast(imageDrawDataOffset); +} + +void RenderContext::LogicalFlush::pushImageMeshDraw(ImageMeshDraw* draw) +{ + + assert(m_hasDoneLayout); + + size_t imageDrawDataOffset = m_ctx->m_imageDrawUniformData.bytesWritten(); + m_ctx->m_imageDrawUniformData.emplace_back(draw->matrix(), + draw->opacity(), + draw->clipRectInverseMatrix(), + draw->clipID(), + draw->blendMode(), + m_currentZIndex); + + DrawBatch& batch = pushDraw(draw, + DrawType::imageMesh, + gpu::ShaderMiscFlags::none, + PaintType::image, + draw->indexCount(), + 0); + batch.vertexBuffer = draw->vertexBuffer(); + batch.uvBuffer = draw->uvBuffer(); + batch.indexBuffer = draw->indexBuffer(); + batch.imageDrawDataOffset = + math::lossless_numeric_cast(imageDrawDataOffset); +} + +void RenderContext::LogicalFlush::pushStencilClipResetDraw( + StencilClipReset* draw) +{ + assert(m_hasDoneLayout); + + uint32_t baseVertex = math::lossless_numeric_cast( + m_ctx->m_triangleVertexData.elementsWritten()); + auto [l, t, r, b] = AABB(getClipInfo(draw->previousClipID()).contentBounds); + uint32_t z = m_currentZIndex; + assert(AABB(l, t, r, b).round() == draw->pixelBounds()); + assert(draw->resourceCounts().maxTriangleVertexCount == 6); + assert(m_ctx->m_triangleVertexData.hasRoomFor(6)); + m_ctx->m_triangleVertexData.emplace_back(Vec2D{l, b}, 0, z); + m_ctx->m_triangleVertexData.emplace_back(Vec2D{l, t}, 0, z); + m_ctx->m_triangleVertexData.emplace_back(Vec2D{r, b}, 0, z); + m_ctx->m_triangleVertexData.emplace_back(Vec2D{r, b}, 0, z); + m_ctx->m_triangleVertexData.emplace_back(Vec2D{l, t}, 0, z); + m_ctx->m_triangleVertexData.emplace_back(Vec2D{r, t}, 0, z); + pushDraw(draw, + DrawType::msaaStencilClipReset, + gpu::ShaderMiscFlags::none, + PaintType::clipUpdate, + 6, + baseVertex); +} + +gpu::DrawBatch& RenderContext::LogicalFlush::pushPathDraw( + const PathDraw* draw, + DrawType drawType, + gpu::ShaderMiscFlags shaderMiscFlags, + uint32_t vertexCount, + uint32_t baseVertex) +{ + assert(m_hasDoneLayout); + + DrawBatch& batch = pushDraw(draw, + drawType, + shaderMiscFlags, + draw->paintType(), + vertexCount, + baseVertex); + + auto pathShaderFeatures = gpu::ShaderFeatures::NONE; + if (draw->featherRadius() != 0 && + drawType != gpu::DrawType::interiorTriangulation && + drawType != gpu::DrawType::atlasBlit) + { + pathShaderFeatures |= ShaderFeatures::ENABLE_FEATHER; + } + if (draw->drawContents() & gpu::DrawContents::evenOddFill) + { + assert(!(shaderMiscFlags & gpu::ShaderMiscFlags::clockwiseFill)); + pathShaderFeatures |= ShaderFeatures::ENABLE_EVEN_ODD; + } + constexpr static gpu::DrawContents NESTED_CLIP_FLAGS = + gpu::DrawContents::clipUpdate | gpu::DrawContents::activeClip; + if ((draw->drawContents() & NESTED_CLIP_FLAGS) == NESTED_CLIP_FLAGS) + { + pathShaderFeatures |= ShaderFeatures::ENABLE_NESTED_CLIPPING; + } + batch.shaderFeatures |= + pathShaderFeatures & m_ctx->m_frameShaderFeaturesMask; + m_combinedShaderFeatures |= batch.shaderFeatures; + assert( + (batch.shaderFeatures & + gpu::ShaderFeaturesMaskFor(drawType, m_ctx->frameInterlockMode())) == + batch.shaderFeatures); + return batch; +} + +RIVE_ALWAYS_INLINE static bool can_combine_draw_contents( + gpu::InterlockMode interlockMode, + gpu::DrawContents batchContents, + const Draw* draw) +{ + // Feathered fills should never attempt to combine with fills, strokes, or + // feathered strokes because they use a different DrawType. + assert((batchContents & gpu::DrawContents::featheredFill).bits() == + (draw->drawContents() & gpu::DrawContents::featheredFill).bits()); + + constexpr static auto ANY_FILL = gpu::DrawContents::clockwiseFill | + gpu::DrawContents::evenOddFill | + gpu::DrawContents::nonZeroFill; + // Raster ordering uses a different shader for clockwise fills, so we + // can't combine both legacy and clockwise fills into the same draw. + if (interlockMode == gpu::InterlockMode::rasterOrdering && + // Anything can be combined if either the existing batch or the new draw + // don't have fills yet. + (batchContents & ANY_FILL) && (draw->drawContents() & ANY_FILL)) + { + assert(!(draw->drawContents() & gpu::DrawContents::stroke)); + return (batchContents & gpu::DrawContents::clockwiseFill).bits() == + (draw->drawContents() & gpu::DrawContents::clockwiseFill).bits(); + } + return true; +} + +RIVE_ALWAYS_INLINE static bool can_combine_draw_images( + const Texture* currentDrawTexture, + const Texture* nextDrawTexture, + const ImageSampler currentImageSamplerKey, + const ImageSampler nextImageSamplerKey) +{ + if (currentDrawTexture == nullptr || nextDrawTexture == nullptr) + { + // We can always combine two draws if one or both do not use an image + // paint. + return true; + } + // Since the image paint's texture must be bound to a specific slot, we + // can't combine draws that use different textures. + return (currentDrawTexture == nextDrawTexture) && + (currentImageSamplerKey == nextImageSamplerKey); +} + +gpu::DrawBatch& RenderContext::LogicalFlush::pushDraw( + const Draw* draw, + DrawType drawType, + gpu::ShaderMiscFlags shaderMiscFlags, + gpu::PaintType paintType, + uint32_t elementCount, + uint32_t baseElement) +{ + assert(m_hasDoneLayout); + assert(elementCount > 0); + + bool canMergeWithPreviousBatch; + switch (drawType) + { + case DrawType::midpointFanPatches: + case DrawType::midpointFanCenterAAPatches: + case DrawType::outerCurvePatches: + case DrawType::interiorTriangulation: + case DrawType::atlasBlit: + case DrawType::msaaStrokes: + case DrawType::msaaMidpointFanBorrowedCoverage: + case DrawType::msaaMidpointFans: + case DrawType::msaaMidpointFanStencilReset: + case DrawType::msaaMidpointFanPathsStencil: + case DrawType::msaaMidpointFanPathsCover: + case DrawType::msaaOuterCubics: + case DrawType::msaaStencilClipReset: + if (!m_drawList.empty() && m_pendingBarriers == BarrierFlags::none) + { + const DrawBatch& currentBatch = m_drawList.tail(); + canMergeWithPreviousBatch = + currentBatch.drawType == drawType && + currentBatch.shaderMiscFlags == shaderMiscFlags && + can_combine_draw_contents(m_ctx->frameInterlockMode(), + currentBatch.drawContents, + draw) && + can_combine_draw_images(currentBatch.imageTexture, + draw->imageTexture(), + currentBatch.imageSampler, + draw->imageSampler()); + if (canMergeWithPreviousBatch && + currentBatch.baseElement + currentBatch.elementCount != + baseElement) + { + // In MSAA mode, multiple subpasses reference the same + // tessellation data. Although rare, this breaks the + // guarantee we have in other modes that mergeable batches + // will always have contiguous patches. + assert(m_ctx->frameInterlockMode() == + gpu::InterlockMode::msaa); + canMergeWithPreviousBatch = false; + } + break; + } + [[fallthrough]]; + + // Image draws can't be combined for now because they each have their + // own unique uniforms. + case DrawType::imageRect: + case DrawType::imageMesh: + case DrawType::atomicInitialize: + case DrawType::atomicResolve: + canMergeWithPreviousBatch = false; + break; + } + + DrawBatch* batch; + if (canMergeWithPreviousBatch) + { + batch = &m_drawList.tail(); + assert(m_pendingBarriers == BarrierFlags::none); + assert(batch->drawType == drawType); + assert(batch->shaderMiscFlags == shaderMiscFlags); + assert(batch->baseElement + batch->elementCount == baseElement); + batch->elementCount += elementCount; + } + else + { + batch = &m_drawList.emplace_back( + m_ctx->perFrameAllocator(), + drawType, + shaderMiscFlags, + elementCount, + baseElement, + draw->blendMode(), + draw->imageSampler(), + std::exchange(m_pendingBarriers, BarrierFlags::none)); + } + + // If the batch was merged into a previous one, this ensures it was a valid + // merge. + assert(batch->drawType == drawType); + assert(can_combine_draw_images(batch->imageTexture, + draw->imageTexture(), + batch->imageSampler, + draw->imageSampler())); + assert(m_pendingBarriers == BarrierFlags::none); + + auto shaderFeatures = ShaderFeatures::NONE; + if (draw->clipID() != 0) + { + shaderFeatures |= ShaderFeatures::ENABLE_CLIPPING; + } + if (draw->hasClipRect() && paintType != PaintType::clipUpdate) + { + shaderFeatures |= ShaderFeatures::ENABLE_CLIP_RECT; + } + if (paintType != PaintType::clipUpdate && + !(shaderMiscFlags & gpu::ShaderMiscFlags::borrowedCoveragePrepass)) + { + switch (draw->blendMode()) + { + case BlendMode::hue: + case BlendMode::saturation: + case BlendMode::color: + case BlendMode::luminosity: + shaderFeatures |= ShaderFeatures::ENABLE_HSL_BLEND_MODES; + [[fallthrough]]; + case BlendMode::screen: + case BlendMode::overlay: + case BlendMode::darken: + case BlendMode::lighten: + case BlendMode::colorDodge: + case BlendMode::colorBurn: + case BlendMode::hardLight: + case BlendMode::softLight: + case BlendMode::difference: + case BlendMode::exclusion: + case BlendMode::multiply: + shaderFeatures |= ShaderFeatures::ENABLE_ADVANCED_BLEND; + break; + case BlendMode::srcOver: + break; + } + } + batch->shaderFeatures |= shaderFeatures & m_ctx->m_frameShaderFeaturesMask; + m_combinedShaderFeatures |= batch->shaderFeatures; + assert( + (batch->shaderFeatures & + gpu::ShaderFeaturesMaskFor(drawType, m_ctx->frameInterlockMode())) == + batch->shaderFeatures); + + batch->drawContents |= draw->drawContents(); + + if (paintType == PaintType::image) + { + assert(draw->imageTexture() != nullptr); + if (batch->imageTexture == nullptr) + { + batch->imageTexture = draw->imageTexture(); + } + assert(batch->imageTexture == draw->imageTexture()); + } + + if (m_ctx->frameInterlockMode() == gpu::InterlockMode::msaa) + { + // msaa can't mix drawContents in a batch. + assert(batch->drawContents == draw->drawContents()); + // msaa does't mix src-over draws with advanced blend draws. + assert((batch->shaderFeatures & + gpu::ShaderFeatures::ENABLE_ADVANCED_BLEND) == + (draw->blendMode() != BlendMode::srcOver)); + // If using KHR_blend_equation_advanced, we can't mix blend modes in a + // batch. + assert(!m_ctx->platformFeatures().supportsKHRBlendEquations || + batch->firstBlendMode == draw->blendMode()); + if (draw->blendMode() != BlendMode::srcOver && + !m_ctx->platformFeatures().supportsKHRBlendEquations) + { + // The MSAA shader needs to do a manual blend mode. Add a + // "dstColorTexture" barrier and build up a list of "dstReads" for + // the batch. In MSAA mode, we don't always have a mechanism for + // shaders to read the framebuffer, so the backend may have to blit + // their bounding boxes to a separate texture that mirrors the + // framebuffer. + // + // (But if the draw already has a "nextDstRead" neighbor, do + // nothing. It means an earlier subpass will already issue the + // barrier and sync this region of the framebuffer. Since nothing + // that overlaps will be ordered between that first subpass and us, + // that barrier for the first subpass is all we need.) + if (draw->nextDstRead() == nullptr) + { + batch->barriers |= BarrierFlags::dstColorTexture; + batch->dstReadList = draw->addToDstReadList(batch->dstReadList); + } + } + } + + return *batch; +} +} // namespace rive::gpu diff --git a/third_party/rive_renderer/source/render_context_helper_impl.cpp b/third_party/rive_renderer/source/render_context_helper_impl.cpp new file mode 100644 index 0000000..cc4c150 --- /dev/null +++ b/third_party/rive_renderer/source/render_context_helper_impl.cpp @@ -0,0 +1,168 @@ +/* + * Copyright 2022 Rive + */ + +#include "rive/renderer/render_context_helper_impl.hpp" + +#include "rive/renderer/rive_render_image.hpp" +#include "shaders/constants.glsl" + +#ifdef RIVE_DECODERS +#include "rive/decoders/bitmap_decoder.hpp" +#endif + +namespace rive::gpu +{ + +void RenderContextHelperImpl::resizeFlushUniformBuffer(size_t sizeInBytes) +{ + m_flushUniformBuffer = makeUniformBufferRing(sizeInBytes); +} + +void RenderContextHelperImpl::resizeImageDrawUniformBuffer(size_t sizeInBytes) +{ + m_imageDrawUniformBuffer = makeUniformBufferRing(sizeInBytes); +} + +void RenderContextHelperImpl::resizePathBuffer( + size_t sizeInBytes, + gpu::StorageBufferStructure bufferStructure) +{ + m_pathBuffer = makeStorageBufferRing(sizeInBytes, bufferStructure); +} + +void RenderContextHelperImpl::resizePaintBuffer( + size_t sizeInBytes, + gpu::StorageBufferStructure bufferStructure) +{ + m_paintBuffer = makeStorageBufferRing(sizeInBytes, bufferStructure); +} + +void RenderContextHelperImpl::resizePaintAuxBuffer( + size_t sizeInBytes, + gpu::StorageBufferStructure bufferStructure) +{ + m_paintAuxBuffer = makeStorageBufferRing(sizeInBytes, bufferStructure); +} + +void RenderContextHelperImpl::resizeContourBuffer( + size_t sizeInBytes, + gpu::StorageBufferStructure bufferStructure) +{ + m_contourBuffer = makeStorageBufferRing(sizeInBytes, bufferStructure); +} + +void RenderContextHelperImpl::resizeGradSpanBuffer(size_t sizeInBytes) +{ + m_gradSpanBuffer = makeVertexBufferRing(sizeInBytes); +} + +void RenderContextHelperImpl::resizeTessVertexSpanBuffer(size_t sizeInBytes) +{ + m_tessSpanBuffer = makeVertexBufferRing(sizeInBytes); +} + +void RenderContextHelperImpl::resizeTriangleVertexBuffer(size_t sizeInBytes) +{ + m_triangleBuffer = makeVertexBufferRing(sizeInBytes); +} + +void* RenderContextHelperImpl::mapFlushUniformBuffer(size_t mapSizeInBytes) +{ + return m_flushUniformBuffer->mapBuffer(mapSizeInBytes); +} + +void* RenderContextHelperImpl::mapImageDrawUniformBuffer(size_t mapSizeInBytes) +{ + return m_imageDrawUniformBuffer->mapBuffer(mapSizeInBytes); +} + +void* RenderContextHelperImpl::mapPathBuffer(size_t mapSizeInBytes) +{ + return m_pathBuffer->mapBuffer(mapSizeInBytes); +} + +void* RenderContextHelperImpl::mapPaintBuffer(size_t mapSizeInBytes) +{ + return m_paintBuffer->mapBuffer(mapSizeInBytes); +} + +void* RenderContextHelperImpl::mapPaintAuxBuffer(size_t mapSizeInBytes) +{ + return m_paintAuxBuffer->mapBuffer(mapSizeInBytes); +} + +void* RenderContextHelperImpl::mapContourBuffer(size_t mapSizeInBytes) +{ + return m_contourBuffer->mapBuffer(mapSizeInBytes); +} + +void* RenderContextHelperImpl::mapGradSpanBuffer(size_t mapSizeInBytes) +{ + return m_gradSpanBuffer->mapBuffer(mapSizeInBytes); +} + +void* RenderContextHelperImpl::mapTessVertexSpanBuffer(size_t mapSizeInBytes) +{ + return m_tessSpanBuffer->mapBuffer(mapSizeInBytes); +} + +void* RenderContextHelperImpl::mapTriangleVertexBuffer(size_t mapSizeInBytes) +{ + return m_triangleBuffer->mapBuffer(mapSizeInBytes); +} + +void RenderContextHelperImpl::unmapFlushUniformBuffer(size_t mapSizeInBytes) +{ + assert(m_flushUniformBuffer->mapSizeInBytes() == mapSizeInBytes); + m_flushUniformBuffer->unmapAndSubmitBuffer(); +} + +void RenderContextHelperImpl::unmapImageDrawUniformBuffer(size_t mapSizeInBytes) +{ + assert(m_imageDrawUniformBuffer->mapSizeInBytes() == mapSizeInBytes); + m_imageDrawUniformBuffer->unmapAndSubmitBuffer(); +} + +void RenderContextHelperImpl::unmapPathBuffer(size_t mapSizeInBytes) +{ + assert(m_pathBuffer->mapSizeInBytes() == mapSizeInBytes); + m_pathBuffer->unmapAndSubmitBuffer(); +} + +void RenderContextHelperImpl::unmapPaintBuffer(size_t mapSizeInBytes) +{ + assert(m_paintBuffer->mapSizeInBytes() == mapSizeInBytes); + m_paintBuffer->unmapAndSubmitBuffer(); +} + +void RenderContextHelperImpl::unmapPaintAuxBuffer(size_t mapSizeInBytes) +{ + assert(m_paintAuxBuffer->mapSizeInBytes() == mapSizeInBytes); + m_paintAuxBuffer->unmapAndSubmitBuffer(); +} + +void RenderContextHelperImpl::unmapContourBuffer(size_t mapSizeInBytes) +{ + assert(m_contourBuffer->mapSizeInBytes() == mapSizeInBytes); + m_contourBuffer->unmapAndSubmitBuffer(); +} + +void RenderContextHelperImpl::unmapGradSpanBuffer(size_t mapSizeInBytes) +{ + assert(m_gradSpanBuffer->mapSizeInBytes() == mapSizeInBytes); + m_gradSpanBuffer->unmapAndSubmitBuffer(); +} + +void RenderContextHelperImpl::unmapTessVertexSpanBuffer(size_t mapSizeInBytes) +{ + assert(m_tessSpanBuffer->mapSizeInBytes() == mapSizeInBytes); + m_tessSpanBuffer->unmapAndSubmitBuffer(); +} + +void RenderContextHelperImpl::unmapTriangleVertexBuffer(size_t mapSizeInBytes) +{ + assert(m_triangleBuffer->mapSizeInBytes() == mapSizeInBytes); + m_triangleBuffer->unmapAndSubmitBuffer(); +} +} // namespace rive::gpu diff --git a/third_party/rive_renderer/source/rive_render_factory.cpp b/third_party/rive_renderer/source/rive_render_factory.cpp new file mode 100644 index 0000000..c887e61 --- /dev/null +++ b/third_party/rive_renderer/source/rive_render_factory.cpp @@ -0,0 +1,51 @@ +/* + * Copyright 2022 Rive + */ + +#include "rive/renderer/rive_render_factory.hpp" +#include "gradient.hpp" +#include "rive_render_paint.hpp" +#include "rive_render_path.hpp" +#include "rive/renderer/rive_renderer.hpp" + +namespace rive +{ +rcp RiveRenderFactory::makeLinearGradient( + float sx, + float sy, + float ex, + float ey, + const ColorInt colors[], // [count] + const float stops[], // [count] + size_t count) +{ + return gpu::Gradient::MakeLinear(sx, sy, ex, ey, colors, stops, count); +} + +rcp RiveRenderFactory::makeRadialGradient( + float cx, + float cy, + float radius, + const ColorInt colors[], // [count] + const float stops[], // [count] + size_t count) +{ + return gpu::Gradient::MakeRadial(cx, cy, radius, colors, stops, count); +} + +rcp RiveRenderFactory::makeRenderPath(RawPath& rawPath, + FillRule fillRule) +{ + return make_rcp(fillRule, rawPath); +} + +rcp RiveRenderFactory::makeEmptyRenderPath() +{ + return make_rcp(); +} + +rcp RiveRenderFactory::makeRenderPaint() +{ + return make_rcp(); +} +} // namespace rive diff --git a/third_party/rive_renderer/source/rive_render_image.cpp b/third_party/rive_renderer/source/rive_render_image.cpp new file mode 100644 index 0000000..36076a8 --- /dev/null +++ b/third_party/rive_renderer/source/rive_render_image.cpp @@ -0,0 +1,15 @@ +/* + * Copyright 2022 Rive + */ + +#include "rive/renderer/rive_render_image.hpp" + +namespace rive::gpu +{ +Texture::Texture(uint32_t width, uint32_t height) : + m_width(width), m_height(height) +{ + static std::atomic_uint32_t textureResourceHashCounter = 0; + m_textureResourceHash = ++textureResourceHashCounter; +} +} // namespace rive::gpu diff --git a/third_party/rive_renderer/source/rive_render_paint.cpp b/third_party/rive_renderer/source/rive_render_paint.cpp new file mode 100644 index 0000000..3833519 --- /dev/null +++ b/third_party/rive_renderer/source/rive_render_paint.cpp @@ -0,0 +1,73 @@ +/* + * Copyright 2022 Rive + */ + +#include "rive_render_paint.hpp" +#include "gradient.hpp" + +namespace rive +{ +RiveRenderPaint::RiveRenderPaint() {} + +RiveRenderPaint::~RiveRenderPaint() {} + +void RiveRenderPaint::color(ColorInt color) +{ + m_paintType = gpu::PaintType::solidColor; + m_simpleValue.color = color; + m_gradient.reset(); + m_imageTexture.reset(); +} + +void RiveRenderPaint::shader(rcp shader) +{ + m_gradient = static_rcp_cast(std::move(shader)); + m_paintType = + m_gradient ? m_gradient->paintType() : gpu::PaintType::solidColor; + // m_simpleValue.colorRampLocation is unused at this level. A new location + // for a this gradient's color ramp will decided by the render context every + // frame. + m_simpleValue.color = 0xff000000; + m_imageTexture.reset(); +} + +void RiveRenderPaint::image(rcp imageTexture, float opacity) +{ + m_paintType = gpu::PaintType::image; + m_simpleValue.imageOpacity = opacity; + m_gradient.reset(); + m_imageTexture = std::move(imageTexture); +} + +void RiveRenderPaint::clipUpdate(uint32_t outerClipID) +{ + m_paintType = gpu::PaintType::clipUpdate; + m_simpleValue.outerClipID = outerClipID; + m_gradient.reset(); + m_imageTexture.reset(); +} + +bool RiveRenderPaint::getIsOpaque() const +{ + if (m_feather != 0) + { + return false; + } + if (m_blendMode != BlendMode::srcOver) + { + return false; + } + switch (m_paintType) + { + case gpu::PaintType::solidColor: + return colorAlpha(m_simpleValue.color) == 0xff; + case gpu::PaintType::linearGradient: + case gpu::PaintType::radialGradient: + return m_gradient->isOpaque(); + case gpu::PaintType::image: + case gpu::PaintType::clipUpdate: + return false; + } + RIVE_UNREACHABLE(); +} +} // namespace rive diff --git a/third_party/rive_renderer/source/rive_render_paint.hpp b/third_party/rive_renderer/source/rive_render_paint.hpp new file mode 100644 index 0000000..54baf38 --- /dev/null +++ b/third_party/rive_renderer/source/rive_render_paint.hpp @@ -0,0 +1,81 @@ +/* + * Copyright 2022 Rive + */ + +#pragma once + +#include "rive/renderer.hpp" +#include "rive/renderer/gpu.hpp" +#include "rive/renderer/texture.hpp" + +namespace rive::gpu +{ +class Gradient; +} + +namespace rive +{ +// RenderPaint implementation for Rive's pixel local storage renderer. +class RiveRenderPaint : public LITE_RTTI_OVERRIDE(RenderPaint, RiveRenderPaint) +{ +public: + RiveRenderPaint(); + ~RiveRenderPaint(); + + void style(RenderPaintStyle style) override + { + m_stroked = style == RenderPaintStyle::stroke; + } + void color(ColorInt color) override; + void thickness(float thickness) override { m_thickness = fabsf(thickness); } + void join(StrokeJoin join) override { m_join = join; } + void cap(StrokeCap cap) override { m_cap = cap; } + void feather(float feather) override { m_feather = fabsf(feather); } + void blendMode(BlendMode mode) override { m_blendMode = mode; } + void shader(rcp shader) override; + void image(rcp, float opacity); + void imageSampler(ImageSampler imageSampler) + { + m_imageSampler = imageSampler; + } + void clipUpdate(uint32_t outerClipID); + void invalidateStroke() override {} + + gpu::PaintType getType() const { return m_paintType; } + bool getIsStroked() const { return m_stroked; } + ColorInt getColor() const { return m_simpleValue.color; } + const gpu::Gradient* getGradient() const { return m_gradient.get(); } + gpu::Texture* getImageTexture() const { return m_imageTexture.get(); } + ImageSampler getImageSampler() const { return m_imageSampler; } + float getImageOpacity() const { return m_simpleValue.imageOpacity; } + float getOuterClipID() const { return m_simpleValue.outerClipID; } + float getThickness() const { return m_thickness; } + StrokeJoin getJoin() const + { + // Feathers ignore the join and always use round. + return m_feather != 0 ? StrokeJoin::round : m_join; + } + StrokeCap getCap() const + { + // Feathers ignore the cap and always use round. + return m_feather != .0 ? StrokeCap::round : m_cap; + } + float getFeather() const { return m_feather; } + BlendMode getBlendMode() const { return m_blendMode; } + gpu::SimplePaintValue getSimpleValue() const { return m_simpleValue; } + bool getIsOpaque() const; + +private: + gpu::PaintType m_paintType = gpu::PaintType::solidColor; + gpu::SimplePaintValue m_simpleValue; + rcp m_gradient; + rcp m_imageTexture; + ImageSampler m_imageSampler = ImageSampler::LinearClamp(); + float m_thickness = 1; + StrokeJoin m_join = StrokeJoin::miter; + StrokeCap m_cap = StrokeCap::butt; + float m_feather = 0; + BlendMode m_blendMode = BlendMode::srcOver; + bool m_stroked = false; +}; +} // namespace rive diff --git a/third_party/rive_renderer/source/rive_render_path.cpp b/third_party/rive_renderer/source/rive_render_path.cpp new file mode 100644 index 0000000..8e90d45 --- /dev/null +++ b/third_party/rive_renderer/source/rive_render_path.cpp @@ -0,0 +1,369 @@ +/* + * Copyright 2022 Rive + */ + +#include "rive_render_path.hpp" + +#include "rive/math/bezier_utils.hpp" +#include "rive/math/simd.hpp" +#include "rive/renderer/gpu.hpp" +#include "shaders/constants.glsl" + +namespace rive +{ +RiveRenderPath::RiveRenderPath(FillRule fillRule, RawPath& rawPath) +{ + m_fillRule = fillRule; + m_rawPath.swap(rawPath); + m_rawPath.pruneEmptySegments(); +} + +void RiveRenderPath::rewind() +{ + assert(m_rawPathMutationLockCount == 0); + m_rawPath.rewind(); + m_dirt = kAllDirt; +} + +void RiveRenderPath::moveTo(float x, float y) +{ + assert(m_rawPathMutationLockCount == 0); + m_rawPath.moveTo(x, y); + m_dirt = kAllDirt; +} + +void RiveRenderPath::lineTo(float x, float y) +{ + assert(m_rawPathMutationLockCount == 0); + + // Make sure to start a new contour, even if this line is empty. + m_rawPath.injectImplicitMoveIfNeeded(); + + Vec2D p1 = {x, y}; + if (m_rawPath.points().back() != p1) + { + m_rawPath.line(p1); + } + + m_dirt = kAllDirt; +} + +void RiveRenderPath::cubicTo(float ox, + float oy, + float ix, + float iy, + float x, + float y) +{ + assert(m_rawPathMutationLockCount == 0); + + // Make sure to start a new contour, even if this cubic is empty. + m_rawPath.injectImplicitMoveIfNeeded(); + + Vec2D p1 = {ox, oy}; + Vec2D p2 = {ix, iy}; + Vec2D p3 = {x, y}; + if (m_rawPath.points().back() != p1 || p1 != p2 || p2 != p3) + { + m_rawPath.cubic(p1, p2, p3); + } + + m_dirt = kAllDirt; +} + +void RiveRenderPath::close() +{ + assert(m_rawPathMutationLockCount == 0); + m_rawPath.close(); + m_dirt = kAllDirt; +} + +void RiveRenderPath::addRenderPath(RenderPath* path, const Mat2D& matrix) +{ + assert(m_rawPathMutationLockCount == 0); + RiveRenderPath* riveRenderPath = static_cast(path); + + bool isIdentity = matrix == Mat2D(); + RawPath::Iter transformedPathIter = + m_rawPath.addPath(riveRenderPath->m_rawPath, + isIdentity ? nullptr : &matrix); + if (!isIdentity) + { + // Prune any segments that became empty after the transform. + m_rawPath.pruneEmptySegments(transformedPathIter); + } + m_dirt = kAllDirt; +} + +void RiveRenderPath::addRenderPathBackwards(RenderPath* path, + const Mat2D& transform) +{ + RiveRenderPath* riveRenderPath = static_cast(path); + RawPath::Iter transformedPathIter = + m_rawPath.addPathBackwards(riveRenderPath->m_rawPath, &transform); + if (transform != Mat2D()) + { + // Prune any segments that became empty after the transform. + m_rawPath.pruneEmptySegments(transformedPathIter); + } + m_dirt = kAllDirt; +} + +void RiveRenderPath::addRawPath(const RawPath& path) +{ + m_rawPath.addPath(path, nullptr); +} + +const AABB& RiveRenderPath::getBounds() const +{ + if (m_dirt & kPathBoundsDirt) + { + m_bounds = m_rawPath.bounds(); + m_dirt &= ~kPathBoundsDirt; + } + return m_bounds; +} + +float RiveRenderPath::getCoarseArea() const +{ + if (m_dirt & kPathCoarseAreaDirt) + { + m_coarseArea = m_rawPath.computeCoarseArea(); + m_dirt &= ~kPathCoarseAreaDirt; + } + return m_coarseArea; +} + +bool RiveRenderPath::isClockwiseDominant(const Mat2D& viewMatrix) const +{ + float matrixDeterminant = + viewMatrix[0] * viewMatrix[3] - viewMatrix[2] * viewMatrix[1]; + return getCoarseArea() * matrixDeterminant >= 0; +} + +uint64_t RiveRenderPath::getRawPathMutationID() const +{ + static std::atomic uniqueIDCounter = 0; + if (m_dirt & kRawPathMutationIDDirt) + { + m_rawPathMutationID = ++uniqueIDCounter; + m_dirt &= ~kRawPathMutationIDDirt; + } + return m_rawPathMutationID; +} + +// Chops the cubic definfed by p[4] at 'numChops' locations, each defined by +// the next position where the tangent rotates by 'rotationMatrix'. Adds each +// segment to 'path'. +static void chop_cubic_at_uniform_rotation(RawPath* path, + const Vec2D p[4], + const Vec2D tangents[2], + int numChops, + const Mat2D& rotationMatrix) +{ + math::CubicCoeffs coeffs(p); + float2 tangent = simd::load2f(&tangents[0]); + float4 rotation = simd::load4f(rotationMatrix.values()); + const Vec2D* remainingCubic = p; + float remainingT = 0; + Vec2D chops[10]; + for (int i = 0; i < numChops; i += 4) + { + // Load up to 4 quadratic equations to solve. + int numChopsRemaining = std::min(numChops - i, 4); + float4 tangentsX, tangentsY; + for (int j = 0; j < numChopsRemaining; ++j) + { + float4 m = rotation * tangent.xxyy; + tangent = m.xy + m.zw; + tangentsX[j & 3] = tangent.x; + tangentsY[j & 3] = tangent.y; + } + + // Solve for the T values where the tangent of the curve is equal to + // each tangent. + float4 a = coeffs.A.x * tangentsY - coeffs.A.y * tangentsX; + float4 b_over_2 = coeffs.B.x * tangentsY - coeffs.B.y * tangentsX; + float4 c = coeffs.C.x * tangentsY - coeffs.C.y * tangentsX; + float4 discr_over_4 = b_over_2 * b_over_2 - a * c; + float4 q = simd::sqrt(discr_over_4); + q = -b_over_2 - simd::copysign(q, b_over_2); + // Since C == tan0: + // * c/q == 0 when tangent == tan0 + // * c/q is the root where tangent == tan0 + // * c/q is the root we need at each subsequent step + float4 roots = c / q; + + // Filter out any roots that fell out of order due to fp32 precision + // issues, or are too close together for fp32 precision. + float t[4]; + int numT = 0; + float maxT = remainingT; + for (int j = 0; j < numChopsRemaining; ++j) + { + constexpr float MIN_SPACING = 1e-4f; + if (roots[j] > maxT + MIN_SPACING && roots[j] < 1 - MIN_SPACING) + { + t[numT++] = maxT = roots[j]; + } + } + + // Chop the curve at the t values we just found. Add all but the final + // chop to the path. Update remainingCubic[4] & remainingT to the final + // chop. + for (int j = 0; j < numT; j += 2) + { + // Localize the t values from p[4] to remainingCubic[4]. + float2 localT = simd::clamp((simd::load2f(t + j) - remainingT) / + (1 - remainingT), + float2(0), + float2(1)); + if (j + 1 < numT) + { + // Two chops. + math::chop_cubic_at(remainingCubic, + chops, + localT[0], + localT[1]); + path->cubic(chops[1], chops[2], chops[3]); + path->cubic(chops[4], chops[5], chops[6]); + remainingCubic = chops + 6; + remainingT = t[j + 1]; + } + else + { + // Only one chop is left. + math::chop_cubic_at(remainingCubic, chops, localT[0]); + path->cubic(chops[1], chops[2], chops[3]); + remainingCubic = chops + 3; + remainingT = t[j]; + } + } + } + + // Finally, add whatever is left over after chopping. + path->cubic(remainingCubic[1], remainingCubic[2], remainingCubic[3]); +} + +rcp RiveRenderPath::makeSoftenedCopyForFeathering( + float feather, + float matrixMaxScale) +{ + // Since curvature is what breaks 1-dimensional feathering along the normal + // vector, chop into segments that rotate no more than a certain threshold. + constexpr static int POLAR_JOIN_PRECISION = 2; + float r_ = feather * (FEATHER_TEXTURE_STDDEVS / 2) * matrixMaxScale * .25f; + float polarSegmentsPerRadian = + math::calc_polar_segments_per_radian(r_); + float rotationBetweenJoins = 1 / polarSegmentsPerRadian; + if (rotationBetweenJoins < gpu::FEATHER_POLAR_SEGMENT_MIN_ANGLE) + { + // Once we cross the FEATHER_POLAR_SEGMENT_MIN_ANGLE threshold, we start + // needing fewer polar joins again. Mirror at this point and begin + // adding back space between the joins. + // TODO: This formula is founded entirely in what feels good visually. + // It has almost no mathematical method. We can probably improve it. + rotationBetweenJoins = + gpu::FEATHER_POLAR_SEGMENT_MIN_ANGLE + + math::pow3( + (gpu::FEATHER_POLAR_SEGMENT_MIN_ANGLE - rotationBetweenJoins) * + 5.f); + } + // Our math that flattens feathered curves relies on curves not rotating + // more than 90 degrees. + rotationBetweenJoins = std::min(rotationBetweenJoins, math::PI / 2); + Mat2D rotationMatrix = Mat2D::fromRotation(rotationBetweenJoins); + Mat2D reverseRotationMatrix = Mat2D::fromRotation(-rotationBetweenJoins); + + RawPath featheredPath; + // Reserve a generous amount of space upfront so we hopefully don't have to + // reallocate -- enough for each verb to be chopped 4 times. + featheredPath.reserve(m_rawPath.verbs().size() * 4, + m_rawPath.points().size() * 4); + for (auto [verb, pts] : m_rawPath) + { + switch (verb) + { + case PathVerb::move: + featheredPath.move(pts[0]); + break; + case PathVerb::line: + featheredPath.line(pts[1]); + break; + case PathVerb::cubic: + { + // Start by chopping all cubics so they are convex and rotate no + // more than 180 degrees. chop_cubic_at_uniform_rotation() + // requires them to not have inflections or rotate more than 180 + // degrees. + float T[4]; + Vec2D chops[(std::size(T) + 1) * 3 + 1]; // 4 chops will produce + // 16 cubic vertices. + bool areCusps; + int n = math::find_cubic_convex_180_chops(pts, T, &areCusps); + assert(n <= 2); + if (areCusps) + { + // Cross through cusps with short lines to avoid unstable + // math. Large cusp padding empirically gets better results. + constexpr static float CUSP_PADDING = 1e-2f; + for (int i = 0; i < n; ++i) + { + // If the cusps are extremely close together, don't + // allow the straddle points to cross. + float minT = i == 0 ? 0.f : (T[i - 1] + T[i]) * .5f; + float maxT = i + 1 == n ? 1.f : (T[i + 1] + T[i]) * .5f; + T[i * 2 + 0] = fmaxf(T[i] - CUSP_PADDING, minT); + T[i * 2 + 1] = fminf(T[i] + CUSP_PADDING, maxT); + } + n *= 2; + } + math::chop_cubic_at(pts, chops, T, n); + Vec2D* p = chops; + for (int i = 0; i <= n; ++i, p += 3) + { + if (areCusps && (i & 1) == 1) + { + // This cubic contains an actual cusp. Cross through it + // with a line. + featheredPath.line(p[3]); + continue; + } + Vec2D tangents[2]; + math::find_cubic_tangents(p, tangents); + float rotation = + math::measure_angle_between_vectors(tangents[0], + tangents[1]); + int numChops = + static_cast(rotation / rotationBetweenJoins); + // Determine which the direction the curve turns. + // NOTE: Since the curve does not inflect, we can just + // check F'(.5) x F''(.5). + // NOTE: F'(.5) x F''(.5) has the same sign as + // (p2 - p0) x (p3 - p1). + float turn = Vec2D::cross(p[2] - p[0], p[3] - p[1]); + if (turn == 0) + { + // This is the case for joins and cusps where points + // are co-located. + turn = Vec2D::cross(tangents[0], tangents[1]); + } + chop_cubic_at_uniform_rotation( + &featheredPath, + p, + tangents, + numChops, + turn >= 0 ? rotationMatrix : reverseRotationMatrix); + } + break; + } + case PathVerb::close: + featheredPath.close(); + break; + case PathVerb::quad: + RIVE_UNREACHABLE(); + } + } + return make_rcp(m_fillRule, featheredPath); +} +} // namespace rive diff --git a/third_party/rive_renderer/source/rive_render_path.hpp b/third_party/rive_renderer/source/rive_render_path.hpp new file mode 100644 index 0000000..84d4124 --- /dev/null +++ b/third_party/rive_renderer/source/rive_render_path.hpp @@ -0,0 +1,86 @@ +/* + * Copyright 2022 Rive + */ + +#pragma once + +#include "rive/math/raw_path.hpp" +#include "rive/renderer.hpp" + +namespace rive +{ +// RenderPath implementation for Rive's pixel local storage renderer. +class RiveRenderPath : public LITE_RTTI_OVERRIDE(RenderPath, RiveRenderPath) +{ +public: + RiveRenderPath() = default; + RiveRenderPath(FillRule fillRule, RawPath& rawPath); + + void rewind() override; + void fillRule(FillRule rule) override { m_fillRule = rule; } + + void moveTo(float x, float y) override; + void lineTo(float x, float y) override; + void cubicTo(float ox, float oy, float ix, float iy, float x, float y) + override; + void close() override; + + void addPath(CommandPath* p, const Mat2D& m) override + { + addRenderPath(p->renderPath(), m); + } + void addRenderPath(RenderPath* path, const Mat2D& matrix) override; + void addRenderPathBackwards(RenderPath* path, + const Mat2D& transform) override; + void addRawPath(const RawPath& path) override; + const RawPath& getRawPath() const { return m_rawPath; } + FillRule getFillRule() const { return m_fillRule; } + + const AABB& getBounds() const; + // Approximates the area of the path by linearizing it with a coarse + // tolerance of 8px in artboard space. + constexpr static float kCoarseAreaTolerance = 8; + float getCoarseArea() const; + // Determine if the path's signed, post-transform area is positive. + bool isClockwiseDominant(const Mat2D& viewMatrix) const; + uint64_t getRawPathMutationID() const; + + // 1-dimensional feathering along the normal vector quits looking like a + // blur when there is strong curvature. This method returns a copy of the + // path with shorter, flatter curves that will more accurately depict a + // gaussian blur when drawn with the given feather. + // + // TODO: Move this work to the GPU. + rcp makeSoftenedCopyForFeathering(float feather, + float matrixMaxScale); + +#ifdef DEBUG + // Allows ref holders to guarantee the rawPath doesn't mutate during a + // specific time. + void lockRawPathMutations() const { ++m_rawPathMutationLockCount; } + void unlockRawPathMutations() const + { + assert(m_rawPathMutationLockCount > 0); + --m_rawPathMutationLockCount; + } +#endif + +private: + FillRule m_fillRule = FillRule::nonZero; + RawPath m_rawPath; + mutable AABB m_bounds; + mutable float m_coarseArea; + mutable uint64_t m_rawPathMutationID; + + enum Dirt + { + kPathBoundsDirt = 1 << 0, + kRawPathMutationIDDirt = 1 << 1, + kPathCoarseAreaDirt = 1 << 2, + kAllDirt = ~0, + }; + + mutable uint32_t m_dirt = kAllDirt; + RIVE_DEBUG_CODE(mutable int m_rawPathMutationLockCount = 0;) +}; +} // namespace rive diff --git a/third_party/rive_renderer/source/rive_renderer.cpp b/third_party/rive_renderer/source/rive_renderer.cpp new file mode 100644 index 0000000..a5a9654 --- /dev/null +++ b/third_party/rive_renderer/source/rive_renderer.cpp @@ -0,0 +1,631 @@ +/* + * Copyright 2022 Rive + */ + +#include "rive/renderer/rive_renderer.hpp" + +#include "rive_render_paint.hpp" +#include "rive_render_path.hpp" +#include "rive/math/math_types.hpp" +#include "rive/math/simd.hpp" +#include "rive/renderer/rive_render_image.hpp" + +namespace rive +{ +bool RiveRenderer::IsAABB(const RawPath& path, AABB* result) +{ + // Any quadrilateral begins with a move plus 3 lines. + constexpr static size_t kAABBVerbCount = 4; + constexpr static PathVerb aabbVerbs[kAABBVerbCount] = {PathVerb::move, + PathVerb::line, + PathVerb::line, + PathVerb::line}; + Span verbs = path.verbs(); + if (verbs.count() < kAABBVerbCount || + memcmp(verbs.data(), aabbVerbs, sizeof(aabbVerbs)) != 0) + { + return false; + } + + // Only accept extra verbs and points if every point after the quadrilateral + // is equal to p0. + Span pts = path.points(); + for (size_t i = 4; i < pts.count(); ++i) + { + if (pts[i] != pts[0]) + { + return false; + } + } + + // We have a quadrilateral! Now check if it is an axis-aligned rectangle. + float4 corners = {pts[0].x, pts[0].y, pts[2].x, pts[2].y}; + float4 oppositeCorners = {pts[1].x, pts[1].y, pts[3].x, pts[3].y}; + if (simd::all(corners == oppositeCorners.zyxw) || + simd::all(corners == oppositeCorners.xwzy)) + { + float4 r = simd::join(simd::min(corners.xy, corners.zw), + simd::max(corners.xy, corners.zw)); + simd::store(result, r); + return true; + } + return false; +} + +RiveRenderer::ClipElement::ClipElement(const Mat2D& matrix_, + const RiveRenderPath* path_, + FillRule fillRule_) +{ + reset(matrix_, path_, fillRule_); +} + +RiveRenderer::ClipElement::~ClipElement() {} + +void RiveRenderer::ClipElement::reset(const Mat2D& matrix_, + const RiveRenderPath* path_, + FillRule fillRule_) +{ + matrix = matrix_; + rawPathMutationID = path_->getRawPathMutationID(); + pathBounds = path_->getBounds(); + path = ref_rcp(path_); + fillRule = fillRule_; + clipID = 0; // This gets initialized lazily. +} + +bool RiveRenderer::ClipElement::isEquivalent(const Mat2D& matrix_, + const RiveRenderPath* path_) const +{ + return matrix_ == matrix && + path_->getRawPathMutationID() == rawPathMutationID && + path_->getFillRule() == fillRule; +} + +RiveRenderer::RiveRenderer(gpu::RenderContext* context) : m_context(context) {} + +RiveRenderer::~RiveRenderer() {} + +void RiveRenderer::save() +{ + // Copy the back of the stack before pushing, in case the vector grows and + // invalidates the reference. + RenderState copy = m_stack.back(); + m_stack.push_back(copy); +} + +void RiveRenderer::restore() +{ + assert(m_stack.size() > 1); + assert(m_stack.back().clipStackHeight >= + m_stack[m_stack.size() - 2].clipStackHeight); + m_stack.pop_back(); +} + +void RiveRenderer::transform(const Mat2D& matrix) +{ + m_stack.back().matrix = m_stack.back().matrix * matrix; +} + +void RiveRenderer::drawPath(RenderPath* renderPath, RenderPaint* renderPaint) +{ + LITE_RTTI_CAST_OR_RETURN(path, RiveRenderPath*, renderPath); + LITE_RTTI_CAST_OR_RETURN(paint, RiveRenderPaint*, renderPaint); + + if (path->getRawPath().empty()) + { + return; + } + + if (paint->getIsStroked() && m_context->frameDescriptor().strokesDisabled) + { + return; + } + if (!paint->getIsStroked() && m_context->frameDescriptor().fillsDisabled) + { + return; + } + if (paint->getIsStroked() && + // Use inverse logic to ensure we abort when stroke thickness is NaN. + !(paint->getThickness() > 0)) + { + return; + } + // Use inverse logic to ensure we abort when stroke thickness is NaN. + if (!(paint->getFeather() >= 0)) + { + return; + } + if (m_stack.back().clipIsEmpty) + { + return; + } + + if (paint->getFeather() != 0 && !paint->getIsStroked()) + { + if (path->getFillRule() != FillRule::clockwise && + !m_context->frameDescriptor().clockwiseFillOverride) + { + // Don't draw feathered fills that aren't clockwise. + return; + } + float matrixMaxScale = m_stack.back().matrix.findMaxScale(); + if (paint->getFeather() * matrixMaxScale > 1) + { + clipAndPushDraw(gpu::PathDraw::Make( + m_context, + m_stack.back().matrix, + path->makeSoftenedCopyForFeathering(paint->getFeather(), + matrixMaxScale), + path->getFillRule(), + paint, + &m_scratchPath)); + return; + } + } + + clipAndPushDraw(gpu::PathDraw::Make(m_context, + m_stack.back().matrix, + ref_rcp(path), + path->getFillRule(), + paint, + &m_scratchPath)); +} + +void RiveRenderer::clipPath(RenderPath* renderPath) +{ + LITE_RTTI_CAST_OR_RETURN(path, RiveRenderPath*, renderPath); + + if (m_context->frameInterlockMode() == gpu::InterlockMode::clockwiseAtomic) + { + // Just discard clips in clockwiseAtomic mode for now. + // TODO: Implement clipping in clockwiseAtomic mode. + return; + } + + if (m_stack.back().clipIsEmpty) + { + return; + } + + if (path->getRawPath().empty()) + { + m_stack.back().clipIsEmpty = true; + return; + } + + // First try to handle axis-aligned rectangles using the "ENABLE_CLIP_RECT" + // shader feature. Multiple axis-aligned rectangles can be intersected into + // a single rectangle if their matrices are compatible. + AABB clipRectCandidate; + if (m_context->frameSupportsClipRects() && + IsAABB(path->getRawPath(), &clipRectCandidate)) + { + clipRectImpl(clipRectCandidate, path); + } + else + { + clipPathImpl(path); + } +} + +// Finds a new rect, if such a rect exists, such that: +// +// currentMatrix * rect == newMatrix * newRect +// +// Returns true if *rect was replaced with newRect. +static bool transform_rect_to_new_space(AABB* rect, + const Mat2D& currentMatrix, + const Mat2D& newMatrix) +{ + if (currentMatrix == newMatrix) + { + return true; + } + Mat2D currentToNew; + if (!newMatrix.invert(¤tToNew)) + { + return false; + } + currentToNew = currentToNew * currentMatrix; + float maxSkew = fmaxf(fabsf(currentToNew.xy()), fabsf(currentToNew.yx())); + float maxScale = fmaxf(fabsf(currentToNew.xx()), fabsf(currentToNew.yy())); + if (maxSkew > math::EPSILON && maxScale > math::EPSILON) + { + // Transforming this rect to the new view matrix would turn it into + // something that isn't a rect. + return false; + } + Vec2D pts[2] = {{rect->left(), rect->top()}, + {rect->right(), rect->bottom()}}; + currentToNew.mapPoints(pts, pts, 2); + float4 p = simd::load4f(pts); + float2 topLeft = simd::min(p.xy, p.zw); + float2 botRight = simd::max(p.xy, p.zw); + *rect = {topLeft.x, topLeft.y, botRight.x, botRight.y}; + return true; +} + +void RiveRenderer::clipRectImpl(AABB rect, const RiveRenderPath* originalPath) +{ + bool hasClipRect = m_stack.back().clipRectInverseMatrix != nullptr; + if (rect.isEmptyOrNaN()) + { + m_stack.back().clipIsEmpty = true; + return; + } + + // If there already is a clipRect, we can only accept another one by + // intersecting it with the existing one. This means the new rect must be + // axis-aligned with the existing clipRect. + if (hasClipRect && + !transform_rect_to_new_space(&rect, + m_stack.back().matrix, + m_stack.back().clipRectMatrix)) + { + // 'rect' is not axis-aligned with the existing clipRect. Fall back to + // clipPath. + clipPathImpl(originalPath); + return; + } + + if (!hasClipRect) + { + // There wasn't an existing clipRect. This is the one! + m_stack.back().clipRect = rect; + m_stack.back().clipRectMatrix = m_stack.back().matrix; + } + else + { + // Both rects are in the same space now. Intersect the two + // geometrically. + float4 a = simd::load4f(&m_stack.back().clipRect); + float4 b = simd::load4f(&rect); + float4 intersection = + simd::join(simd::max(a.xy, b.xy), simd::min(a.zw, b.zw)); + simd::store(&m_stack.back().clipRect, intersection); + } + + m_stack.back().clipRectInverseMatrix = + m_context->make( + m_stack.back().clipRectMatrix, + m_stack.back().clipRect); +} + +void RiveRenderer::clipPathImpl(const RiveRenderPath* path) +{ + if (path->getBounds().isEmptyOrNaN()) + { + m_stack.back().clipIsEmpty = true; + return; + } + // Only write a new clip element if this path isn't already on the stack + // from before. e.g.: + // + // clipPath(samePath); + // restore(); + // save(); + // clipPath(samePath); // <-- reuse the ClipElement (and clipID!) + // already in m_clipStack. + // + const size_t clipStackHeight = m_stack.back().clipStackHeight; + assert(m_clipStack.size() >= clipStackHeight); + if (m_clipStack.size() == clipStackHeight || + !m_clipStack[clipStackHeight].isEquivalent(m_stack.back().matrix, path)) + { + m_clipStack.resize(clipStackHeight); + m_clipStack.emplace_back(m_stack.back().matrix, + path, + path->getFillRule()); + } + m_stack.back().clipStackHeight = clipStackHeight + 1; +} + +void RiveRenderer::drawImage(const RenderImage* renderImage, + ImageSampler imageSampler, + BlendMode blendMode, + float opacity) +{ + LITE_RTTI_CAST_OR_RETURN(image, const RiveRenderImage*, renderImage); + + rcp imageTexture = image->refTexture(); + if (imageTexture == nullptr) + { + // imageTexture may be null if the backend uses a custom factory and/or + // updates out-of-band assets asynchronously. If there's no texture yet, + // just don't draw anything. + return; + } + + // Scale the view matrix so we can draw this image as the rect [0, 0, 1, 1]. + save(); + scale(image->width(), image->height()); + + if (!m_context->frameSupportsImagePaintForPaths()) + { + // Fall back on ImageRectDraw if the current frame doesn't support + // drawing paths with image paints. + if (!m_stack.back().clipIsEmpty) + { + const Mat2D& m = m_stack.back().matrix; + clipAndPushDraw( + gpu::DrawUniquePtr(m_context->make( + m_context, + m.mapBoundingBox(AABB{0, 0, 1, 1}).roundOut(), + m, + blendMode, + std::move(imageTexture), + imageSampler, + opacity))); + } + } + else + { + // Implement drawImage() as drawPath() with a rectangular path and an + // image paint. + if (m_unitRectPath == nullptr) + { + m_unitRectPath = make_rcp(); + m_unitRectPath->line({1, 0}); + m_unitRectPath->line({1, 1}); + m_unitRectPath->line({0, 1}); + } + + RiveRenderPaint paint; + paint.image(std::move(imageTexture), opacity); + paint.blendMode(blendMode); + paint.imageSampler(imageSampler); + drawPath(m_unitRectPath.get(), &paint); + } + + restore(); +} + +void RiveRenderer::drawImageMesh(const RenderImage* renderImage, + ImageSampler imageSampler, + rcp vertices_f32, + rcp uvCoords_f32, + rcp indices_u16, + uint32_t vertexCount, + uint32_t indexCount, + BlendMode blendMode, + float opacity) +{ + LITE_RTTI_CAST_OR_RETURN(image, const RiveRenderImage*, renderImage); + + rcp imageTexture = image->refTexture(); + if (imageTexture == nullptr) + { + // imageTexture may be null if the backend uses a custom factory and/or + // updates out-of-band assets asynchronously. If there's no texture yet, + // just don't draw anything. + return; + } + + assert(vertices_f32); + assert(uvCoords_f32); + assert(indices_u16); + + if (m_stack.back().clipIsEmpty) + { + return; + } + + clipAndPushDraw(gpu::DrawUniquePtr( + m_context->make(gpu::Draw::FULLSCREEN_PIXEL_BOUNDS, + m_stack.back().matrix, + blendMode, + std::move(imageTexture), + imageSampler, + std::move(vertices_f32), + std::move(uvCoords_f32), + std::move(indices_u16), + indexCount, + opacity))); +} + +void RiveRenderer::clipAndPushDraw(gpu::DrawUniquePtr draw) +{ + assert(!m_stack.back().clipIsEmpty); + if (draw.get() == nullptr) + { + return; + } + if (m_context->isOutsideCurrentFrame(draw->pixelBounds())) + { + return; + } + + // Make two attempts to issue the draw: once on the context as-is and once + // with a clean flush. + for (int i = 0; i < 2; ++i) + { + // Always make sure we begin this loop with the internal draw batch + // empty, and clear it when we're done. + struct AutoResetInternalDrawBatch + { + public: + AutoResetInternalDrawBatch(RiveRenderer* renderer) : + m_renderer(renderer) + { + assert(m_renderer->m_internalDrawBatch.empty()); + } + ~AutoResetInternalDrawBatch() + { + m_renderer->m_internalDrawBatch.clear(); + } + + private: + RiveRenderer* m_renderer; + }; + + AutoResetInternalDrawBatch aridb(this); + + auto applyClipResult = applyClip(draw.get()); + if (applyClipResult == ApplyClipResult::failure) + { + // There wasn't room in the GPU buffers for this path draw. Flush + // and try again. + m_context->logicalFlush(); + continue; + } + else if (applyClipResult == ApplyClipResult::clipEmpty) + { + return; + } + + m_internalDrawBatch.push_back(std::move(draw)); + if (!m_context->pushDraws(m_internalDrawBatch.data(), + m_internalDrawBatch.size())) + { + // There wasn't room in the GPU buffers for this path draw. Flush + // and try again. + m_context->logicalFlush(); + // Reclaim "draw" because we will use it again on the next + // iteration. + draw = std::move(m_internalDrawBatch.back()); + assert(draw != nullptr); + m_internalDrawBatch.pop_back(); + continue; + } + + // Success! + return; + } + + // We failed to process the draw. Release its refs. + fprintf(stderr, + "RiveRenderer::clipAndPushDraw failed. The draw and/or clip stack " + "are too complex.\n"); +} + +RiveRenderer::ApplyClipResult RiveRenderer::applyClip(gpu::Draw* draw) +{ + if (m_stack.back().clipIsEmpty) + { + return ApplyClipResult::clipEmpty; + } + draw->setClipRect(m_stack.back().clipRectInverseMatrix); + + const size_t clipStackHeight = m_stack.back().clipStackHeight; + if (clipStackHeight == 0) + { + assert(draw->clipID() == 0); + return ApplyClipResult::success; + } + + // Find which clip element in the stack (if any) is currently rendered to + // the clip buffer. + size_t clipIdxCurrentlyInClipBuffer = -1; // i.e., "none". + if (m_context->getClipContentID() != 0) + { + for (size_t i = clipStackHeight - 1; i != -1; --i) + { + if (m_clipStack[i].clipID == m_context->getClipContentID()) + { + clipIdxCurrentlyInClipBuffer = i; + break; + } + } + } + + // Draw the necessary updates to the clip buffer (i.e., draw every clip + // element after clipIdxCurrentlyInClipBuffer). + uint32_t lastClipID = + clipIdxCurrentlyInClipBuffer == -1 + ? 0 // The next clip to be drawn is not nested. + : m_clipStack[clipIdxCurrentlyInClipBuffer].clipID; + if (m_context->frameInterlockMode() == gpu::InterlockMode::msaa) + { + if (lastClipID == 0 && m_context->getClipContentID() != 0) + { + // Time for a new stencil clip! Erase the clip currently in the + // stencil buffer before we draw the new one. + auto stencilClipClear = + gpu::DrawUniquePtr(m_context->make( + m_context, + m_context->getClipContentID(), + gpu::DrawContents::none, + gpu::StencilClipReset::ResetAction::clearPreviousClip)); + if (!m_context->isOutsideCurrentFrame( + stencilClipClear->pixelBounds())) + { + m_internalDrawBatch.push_back(std::move(stencilClipClear)); + } + } + } + + for (size_t i = clipIdxCurrentlyInClipBuffer + 1; i < clipStackHeight; ++i) + { + ClipElement& clip = m_clipStack[i]; + assert(clip.pathBounds == clip.path->getBounds()); + + IAABB clipDrawBounds; + RiveRenderPaint clipUpdatePaint; + clipUpdatePaint.clipUpdate(/*clip THIS clipDraw against:*/ lastClipID); + + gpu::DrawUniquePtr clipDraw = gpu::PathDraw::Make(m_context, + clip.matrix, + clip.path, + clip.fillRule, + &clipUpdatePaint, + &m_scratchPath); + + if (clipDraw == nullptr) + { + return ApplyClipResult::clipEmpty; + } + clipDrawBounds = clipDraw->pixelBounds(); + + // Generate a new clipID every time we (re-)render an element to the + // clip buffer. (Each embodiment of the element needs its own + // separate readBounds.) + clip.clipID = m_context->generateClipID(clipDrawBounds); + assert(clip.clipID != m_context->getClipContentID()); + if (clip.clipID == 0) + { + return ApplyClipResult::failure; // The context is out of + // clipIDs. We will flush and + // try again. + } + clipDraw->setClipID(clip.clipID); + + gpu::DrawContents clipDrawContents = clipDraw->drawContents(); + if (!m_context->isOutsideCurrentFrame(clipDrawBounds)) + { + m_internalDrawBatch.push_back(std::move(clipDraw)); + } + + if (lastClipID != 0) + { + m_context->addClipReadBounds(lastClipID, clipDrawBounds); + if (m_context->frameInterlockMode() == gpu::InterlockMode::msaa) + { + // When drawing nested stencil clips, we need to intersect them, + // which involves erasing the region of the current clip in the + // stencil buffer that is outside the the one we just drew. + auto stencilClipIntersect = + gpu::DrawUniquePtr(m_context->make( + m_context, + lastClipID, + clipDrawContents, + gpu::StencilClipReset::ResetAction:: + intersectPreviousClip)); + if (!m_context->isOutsideCurrentFrame( + stencilClipIntersect->pixelBounds())) + { + m_internalDrawBatch.push_back( + std::move(stencilClipIntersect)); + } + } + } + + lastClipID = clip.clipID; // Nest the next clip (if any) inside the one + // we just rendered. + } + assert(lastClipID == m_clipStack[clipStackHeight - 1].clipID); + draw->setClipID(lastClipID); + m_context->addClipReadBounds(lastClipID, draw->pixelBounds()); + m_context->setClipContentID(lastClipID); + return ApplyClipResult::success; +} +} // namespace rive diff --git a/third_party/rive_renderer/source/shaders/advanced_blend.glsl b/third_party/rive_renderer/source/shaders/advanced_blend.glsl new file mode 100644 index 0000000..bde63e6 --- /dev/null +++ b/third_party/rive_renderer/source/shaders/advanced_blend.glsl @@ -0,0 +1,307 @@ +/* + * Copyright 2022 Rive + */ + +// From the KHR_blend_equation_advanced spec: +// +// The advanced blend equations are those listed in tables X.1 and X.2. When +// using one of these equations, blending is performed according to the +// following equations: +// +// R = f(Rs',Rd')*p0(As,Ad) + Y*Rs'*p1(As,Ad) + Z*Rd'*p2(As,Ad) +// G = f(Gs',Gd')*p0(As,Ad) + Y*Gs'*p1(As,Ad) + Z*Gd'*p2(As,Ad) +// B = f(Bs',Bd')*p0(As,Ad) + Y*Bs'*p1(As,Ad) + Z*Bd'*p2(As,Ad) +// A = X*p0(As,Ad) + Y*p1(As,Ad) + Z*p2(As,Ad) +// +// where the function f and terms X, Y, and Z are specified in the table. +// The R, G, and B components of the source color used for blending are +// considered to have been premultiplied by the A component prior to +// blending. The base source color (Rs',Gs',Bs') is obtained by dividing +// through by the A component: +// +// (Rs', Gs', Bs') = +// (0, 0, 0), if As == 0 +// (Rs/As, Gs/As, Bs/As), otherwise +// +// The destination color components are always considered to have been +// premultiplied by the destination A component and the base destination +// color (Rd', Gd', Bd') is obtained by dividing through by the A component: +// +// (Rd', Gd', Bd') = +// (0, 0, 0), if Ad == 0 +// (Rd/Ad, Gd/Ad, Bd/Ad), otherwise +// +// When blending using advanced blend equations, we expect that the R, G, and +// B components of premultiplied source and destination color inputs be +// stored as the product of non-premultiplied R, G, and B components and the +// A component of the color. If any R, G, or B component of a premultiplied +// input color is non-zero and the A component is zero, the color is +// considered ill-formed, and the corresponding component of the blend result +// will be undefined. +// +// The weighting functions p0, p1, and p2 are defined as follows: +// +// p0(As,Ad) = As*Ad +// p1(As,Ad) = As*(1 - Ad) +// p2(As,Ad) = Ad*(1 - As) +// +// In these functions, the A components of the source and destination colors +// are taken to indicate the portion of the pixel covered by the fragment +// (source) and the fragments previously accumulated in the pixel +// (destination). The functions p0, p1, and p2 approximate the relative +// portion of the pixel covered by the intersection of the source and +// destination, covered only by the source, and covered only by the +// destination, respectively. The equations defined here assume that there +// is no correlation between the source and destination coverage. +// + +#ifdef @FRAGMENT + +#ifdef @ENABLE_KHR_BLEND +layout( +#ifdef @ENABLE_HSL_BLEND_MODES + blend_support_all_equations +#else + blend_support_multiply, + blend_support_screen, + blend_support_overlay, + blend_support_darken, + blend_support_lighten, + blend_support_colordodge, + blend_support_colorburn, + blend_support_hardlight, + blend_support_softlight, + blend_support_difference, + blend_support_exclusion +#endif + ) out; +#endif // ENABLE_KHR_BLEND + +#ifdef @ENABLE_ADVANCED_BLEND +#ifdef @ENABLE_HSL_BLEND_MODES +// When using one of the HSL blend equations in table X.2 as the blend equation, +// the blend coefficients are effectively obtained by converting both the +// non-premultiplied source and destination colors to the HSL (hue, saturation, +// luminosity) color space, generating a new HSL color by selecting H, S, and L +// components from the source or destination according to the blend equation, +// and then converting the result back to RGB. The HSL blend equations are only +// well defined when the values of the input color components are in the range +// [0..1]. +half minv3(half3 c) { return min(min(c.r, c.g), c.b); } +half maxv3(half3 c) { return max(max(c.r, c.g), c.b); } +half lumv3(half3 c) { return dot(c, make_half3(.30, .59, .11)); } +half satv3(half3 c) { return maxv3(c) - minv3(c); } + +// If any color components are outside [0,1], adjust the color to get the +// components in range. +half3 clip_color(half3 color) +{ + half lum = lumv3(color); + half mincol = minv3(color); + half maxcol = maxv3(color); + if (mincol < .0) + color = lum + ((color - lum) * lum) / (lum - mincol); + if (maxcol > 1.) + color = lum + ((color - lum) * (1. - lum)) / (maxcol - lum); + return color; +} + +// Take the base RGB color and override its luminosity with that of the +// RGB color . +half3 set_lum(half3 cbase, half3 clum) +{ + half lbase = lumv3(cbase); + half llum = lumv3(clum); + half ldiff = llum - lbase; + half3 color = cbase + make_half3(ldiff); + return clip_color(color); +} + +// Take the base RGB color and override its saturation with that of the +// RGB color . The override the luminosity of the result with that of the +// RGB color . +half3 set_lum_sat(half3 cbase, half3 csat, half3 clum) +{ + half minbase = minv3(cbase); + half sbase = satv3(cbase); + half ssat = satv3(csat); + half3 color; + if (sbase > .0) + { + // Equivalent (modulo rounding errors) to setting the smallest (R,G,B) + // component to 0, the largest to , and interpolating the "middle" + // component based on its original value relative to the + // smallest/largest. + color = (cbase - minbase) * ssat / sbase; + } + else + { + color = make_half3(.0); + } + return set_lum(color, clum); +} +#endif // ENABLE_HSL_BLEND_MODES + +// The advanced blend coefficients are generated from un-multiplied RGB values, +// and control the look of each blend mode. +half3 advanced_blend_coeffs(half3 src, half4 dstPremul, ushort mode) +{ + half3 dst = unmultiply_rgb(dstPremul); + half3 coeffs; + switch (mode) + { + case BLEND_MODE_MULTIPLY: + coeffs = src.rgb * dst.rgb; + break; + case BLEND_MODE_SCREEN: + coeffs = src.rgb + dst.rgb - src.rgb * dst.rgb; + break; + case BLEND_MODE_OVERLAY: + { + for (int i = 0; i < 3; ++i) + { + if (dst[i] <= .5) + coeffs[i] = 2. * src[i] * dst[i]; + else + coeffs[i] = 1. - 2. * (1. - src[i]) * (1. - dst[i]); + } + break; + } + case BLEND_MODE_DARKEN: + coeffs = min(src.rgb, dst.rgb); + break; + case BLEND_MODE_LIGHTEN: + coeffs = max(src.rgb, dst.rgb); + break; + case BLEND_MODE_COLORDODGE: + { + dstPremul.rgb = clamp(dstPremul.rgb, make_half3(.0), dstPremul.aaa); + half3 denom = + clamp(1. - src, make_half3(.0), make_half3(1.)) * dstPremul.a; + coeffs = mix(min(make_half3(1.), dstPremul.rgb / denom), + sign(dstPremul.rgb), + equal(denom, make_half3(.0))); + break; + } + case BLEND_MODE_COLORBURN: + { + src = clamp(src, make_half3(.0), make_half3(1.)); + dstPremul.rgb = clamp(dstPremul.rgb, make_half3(.0), dstPremul.aaa); + if (dstPremul.a == .0) + dstPremul.a = 1.; + half3 numer = dstPremul.a - dstPremul.rgb; + coeffs = 1. - mix(min(make_half3(1.), numer / (src * dstPremul.a)), + sign(numer), + equal(src, make_half3(.0))); + break; + } + case BLEND_MODE_HARDLIGHT: + { + for (int i = 0; i < 3; ++i) + { + if (src[i] <= .5) + coeffs[i] = 2. * src[i] * dst[i]; + else + coeffs[i] = 1. - 2. * (1. - src[i]) * (1. - dst[i]); + } + break; + } + case BLEND_MODE_SOFTLIGHT: + { + for (int i = 0; i < 3; ++i) + { + if (src[i] <= 0.5) + coeffs[i] = + dst[i] - (1. - 2. * src[i]) * dst[i] * (1. - dst[i]); + else if (dst[i] <= .25) + coeffs[i] = + dst[i] + (2. * src[i] - 1.) * dst[i] * + ((16. * dst[i] - 12.) * dst[i] + 3.); + else + coeffs[i] = + dst[i] + (2. * src[i] - 1.) * (sqrt(dst[i]) - dst[i]); + } + break; + } + case BLEND_MODE_DIFFERENCE: + coeffs = abs(dst.rgb - src.rgb); + break; + case BLEND_MODE_EXCLUSION: + coeffs = src.rgb + dst.rgb - 2. * src.rgb * dst.rgb; + break; +#ifdef @ENABLE_HSL_BLEND_MODES + // The HSL blend equations are only well defined when the values of the + // input color components are in the range [0..1]. + case BLEND_MODE_HUE: + if (@ENABLE_HSL_BLEND_MODES) + { + src.rgb = clamp(src.rgb, make_half3(.0), make_half3(1.)); + coeffs = set_lum_sat(src.rgb, dst.rgb, dst.rgb); + } + break; + case BLEND_MODE_SATURATION: + if (@ENABLE_HSL_BLEND_MODES) + { + src.rgb = clamp(src.rgb, make_half3(.0), make_half3(1.)); + coeffs = set_lum_sat(dst.rgb, src.rgb, dst.rgb); + } + break; + case BLEND_MODE_COLOR: + if (@ENABLE_HSL_BLEND_MODES) + { + src.rgb = clamp(src.rgb, make_half3(.0), make_half3(1.)); + coeffs = set_lum(src.rgb, dst.rgb); + } + break; + case BLEND_MODE_LUMINOSITY: + if (@ENABLE_HSL_BLEND_MODES) + { + src.rgb = clamp(src.rgb, make_half3(.0), make_half3(1.)); + coeffs = set_lum(dst.rgb, src.rgb); + } + break; +#endif + } + return coeffs; +} + +// Performs the given advanced blend operation with a solid RGB src color (no +// srcAlpha). +// +// NOTE: This method is sufficient for all blending because alpha in the src +// can be accounted for afterward using a standard src-over blend operation. +// +// e.g., dst = blend_src_over( +// premultiply(advanced_color_blend(src.rgb, dstPremul)), +// dstPremul) +INLINE half3 advanced_color_blend(half3 src, half4 dstPremul, ushort mode) +{ + // The weighting functions p0, p1, and p2 are defined as follows: + // + // p0(As,Ad) = As*Ad + // p1(As,Ad) = As*(1 - Ad) + // p2(As,Ad) = Ad*(1 - As) + // + // Since srcAlpha (As) == 1, this simplifies to: + // + // p0(As,Ad) = Ad + // p1(As,Ad) = (1 - Ad) + // p2(As,Ad) = 0 + // + // Blending is performed according to the following equations: + // + // R = coeffs(Rs',Rd')*p0 + Y*Rs'*p1 + Z*Rd'*p2 + // G = coeffs(Gs',Gd')*p0 + Y*Gs'*p1 + Z*Gd'*p2 + // B = coeffs(Bs',Bd')*p0 + Y*Bs'*p1 + Z*Bd'*p2 + // A = X*p0 + Y*p1 + Z*p2 + // + // NOTE: (X,Y,Z) always == 1, so it is ignored in this implementation. + // Also, since (X,Y,Z) == 1, alpha simplifies to standard src-over + // rules: A = Ad * (1 - As) + As + half3 coeffs = advanced_blend_coeffs(src, dstPremul, mode); + half2 p = make_half2(dstPremul.a, 1. - dstPremul.a); // p2 cancelled to 0. + return MUL(make_half2x3(coeffs, src), p); +} +#endif // ENABLE_ADVANCED_BLEND + +#endif // FRAGMENT diff --git a/third_party/rive_renderer/source/shaders/atomic_draw.glsl b/third_party/rive_renderer/source/shaders/atomic_draw.glsl new file mode 100644 index 0000000..e8c5c67 --- /dev/null +++ b/third_party/rive_renderer/source/shaders/atomic_draw.glsl @@ -0,0 +1,904 @@ +/* + * Copyright 2023 Rive + */ + +#ifdef @DRAW_PATH +#ifdef @VERTEX +ATTR_BLOCK_BEGIN(Attrs) +ATTR(0, + float4, + @a_patchVertexData); // [localVertexID, outset, fillCoverage, vertexType] +ATTR(1, float4, @a_mirroredVertexData); +ATTR_BLOCK_END +#endif + +VARYING_BLOCK_BEGIN +#ifdef @ENABLE_FEATHER +NO_PERSPECTIVE VARYING(0, float4, v_coverages); +#else +NO_PERSPECTIVE VARYING(0, half2, v_coverages); +#endif +FLAT VARYING(1, ushort, v_pathID); +VARYING_BLOCK_END + +#ifdef @VERTEX +VERTEX_MAIN(@drawVertexMain, Attrs, attrs, _vertexID, _instanceID) +{ + ATTR_UNPACK(_vertexID, attrs, @a_patchVertexData, float4); + ATTR_UNPACK(_vertexID, attrs, @a_mirroredVertexData, float4); + +#ifdef @ENABLE_FEATHER + VARYING_INIT(v_coverages, float4); +#else + VARYING_INIT(v_coverages, half2); +#endif + VARYING_INIT(v_pathID, ushort); + + float4 pos; + uint pathID; + float2 vertexPosition; + float4 coverages; + if (unpack_tessellated_path_vertex(@a_patchVertexData, + @a_mirroredVertexData, + _instanceID, + pathID, + vertexPosition, + coverages VERTEX_CONTEXT_UNPACK)) + { +#ifdef @ENABLE_FEATHER + v_coverages = coverages; +#else + v_coverages.xy = cast_float2_to_half2(coverages.xy); +#endif + v_pathID = cast_uint_to_ushort(pathID); + pos = RENDER_TARGET_COORD_TO_CLIP_COORD(vertexPosition); + } + else + { + pos = float4(uniforms.vertexDiscardValue, + uniforms.vertexDiscardValue, + uniforms.vertexDiscardValue, + uniforms.vertexDiscardValue); + } + + VARYING_PACK(v_coverages); + VARYING_PACK(v_pathID); + EMIT_VERTEX(pos); +} +#endif // VERTEX +#endif // DRAW_PATH + +#ifdef @DRAW_INTERIOR_TRIANGLES +#ifdef @VERTEX +ATTR_BLOCK_BEGIN(Attrs) +ATTR(0, packed_float3, @a_triangleVertex); +ATTR_BLOCK_END +#endif + +VARYING_BLOCK_BEGIN +#ifdef @ATLAS_BLIT +NO_PERSPECTIVE VARYING(0, float2, v_atlasCoord); +#else +@OPTIONALLY_FLAT VARYING(0, half, v_windingWeight); +#endif +FLAT VARYING(1, ushort, v_pathID); +VARYING_BLOCK_END + +#ifdef @VERTEX +VERTEX_MAIN(@drawVertexMain, Attrs, attrs, _vertexID, _instanceID) +{ + ATTR_UNPACK(_vertexID, attrs, @a_triangleVertex, float3); + +#ifdef @ATLAS_BLIT + VARYING_INIT(v_atlasCoord, float2); +#else + VARYING_INIT(v_windingWeight, half); +#endif + VARYING_INIT(v_pathID, ushort); + + uint pathID; + float2 vertexPosition; +#ifdef @ATLAS_BLIT + vertexPosition = + unpack_atlas_coverage_vertex(@a_triangleVertex, + pathID, + v_atlasCoord VERTEX_CONTEXT_UNPACK); +#else + vertexPosition = + unpack_interior_triangle_vertex(@a_triangleVertex, + pathID, + v_windingWeight VERTEX_CONTEXT_UNPACK); +#endif + v_pathID = cast_uint_to_ushort(pathID); + float4 pos = RENDER_TARGET_COORD_TO_CLIP_COORD(vertexPosition); + +#ifdef @ATLAS_BLIT + VARYING_PACK(v_atlasCoord); +#else + VARYING_PACK(v_windingWeight); +#endif + VARYING_PACK(v_pathID); + EMIT_VERTEX(pos); +} +#endif // VERTEX +#endif // DRAW_INTERIOR_TRIANGLES + +#ifdef @DRAW_IMAGE_RECT +#ifdef @VERTEX +ATTR_BLOCK_BEGIN(Attrs) +ATTR(0, float4, @a_imageRectVertex); +ATTR_BLOCK_END +#endif + +VARYING_BLOCK_BEGIN +NO_PERSPECTIVE VARYING(0, float2, v_texCoord); +NO_PERSPECTIVE VARYING(1, half, v_edgeCoverage); +#ifdef @ENABLE_CLIP_RECT +NO_PERSPECTIVE VARYING(2, float4, v_clipRect); +#endif +VARYING_BLOCK_END + +#ifdef @VERTEX +IMAGE_RECT_VERTEX_MAIN(@drawVertexMain, Attrs, attrs, _vertexID, _instanceID) +{ + ATTR_UNPACK(_vertexID, attrs, @a_imageRectVertex, float4); + + VARYING_INIT(v_texCoord, float2); + VARYING_INIT(v_edgeCoverage, half); +#ifdef @ENABLE_CLIP_RECT + VARYING_INIT(v_clipRect, float4); +#endif + + bool isOuterVertex = + @a_imageRectVertex.z == .0 || @a_imageRectVertex.w == .0; + v_edgeCoverage = isOuterVertex ? .0 : 1.; + + float2 vertexPosition = @a_imageRectVertex.xy; + float2x2 M = make_float2x2(imageDrawUniforms.viewMatrix); + float2x2 MIT = transpose(inverse(M)); + if (!isOuterVertex) + { + // Inset the inner vertices to the point where coverage == 1. + // NOTE: if width/height ever change from 1, these equations need to be + // updated. + float aaRadiusX = + AA_RADIUS * manhattan_width(MIT[1]) / dot(M[1], MIT[1]); + if (aaRadiusX >= .5) + { + vertexPosition.x = .5; + v_edgeCoverage *= cast_float_to_half(.5 / aaRadiusX); + } + else + { + vertexPosition.x += aaRadiusX * @a_imageRectVertex.z; + } + float aaRadiusY = + AA_RADIUS * manhattan_width(MIT[0]) / dot(M[0], MIT[0]); + if (aaRadiusY >= .5) + { + vertexPosition.y = .5; + v_edgeCoverage *= cast_float_to_half(.5 / aaRadiusY); + } + else + { + vertexPosition.y += aaRadiusY * @a_imageRectVertex.w; + } + } + + v_texCoord = vertexPosition; + vertexPosition = MUL(M, vertexPosition) + imageDrawUniforms.translate; + + if (isOuterVertex) + { + // Outset the outer vertices to the point where coverage == 0. + float2 n = MUL(MIT, @a_imageRectVertex.zw); + n *= manhattan_width(n) / dot(n, n); + vertexPosition += AA_RADIUS * n; + } + +#ifdef @ENABLE_CLIP_RECT + if (@ENABLE_CLIP_RECT) + { + v_clipRect = find_clip_rect_coverage_distances( + make_float2x2(imageDrawUniforms.clipRectInverseMatrix), + imageDrawUniforms.clipRectInverseTranslate, + vertexPosition); + } +#endif + + float4 pos = RENDER_TARGET_COORD_TO_CLIP_COORD(vertexPosition); + + VARYING_PACK(v_texCoord); + VARYING_PACK(v_edgeCoverage); +#ifdef @ENABLE_CLIP_RECT + VARYING_PACK(v_clipRect); +#endif + EMIT_VERTEX(pos); +} +#endif // VERTEX + +#elif defined(@DRAW_IMAGE_MESH) +#ifdef @VERTEX +ATTR_BLOCK_BEGIN(PositionAttr) +ATTR(0, float2, @a_position); +ATTR_BLOCK_END + +ATTR_BLOCK_BEGIN(UVAttr) +ATTR(1, float2, @a_texCoord); +ATTR_BLOCK_END +#endif + +VARYING_BLOCK_BEGIN +NO_PERSPECTIVE VARYING(0, float2, v_texCoord); +#ifdef @ENABLE_CLIP_RECT +NO_PERSPECTIVE VARYING(1, float4, v_clipRect); +#endif +VARYING_BLOCK_END + +#ifdef @VERTEX +IMAGE_MESH_VERTEX_MAIN(@drawVertexMain, + PositionAttr, + position, + UVAttr, + uv, + _vertexID) +{ + ATTR_UNPACK(_vertexID, position, @a_position, float2); + ATTR_UNPACK(_vertexID, uv, @a_texCoord, float2); + + VARYING_INIT(v_texCoord, float2); +#ifdef @ENABLE_CLIP_RECT + VARYING_INIT(v_clipRect, float4); +#endif + + float2x2 M = make_float2x2(imageDrawUniforms.viewMatrix); + float2 vertexPosition = MUL(M, @a_position) + imageDrawUniforms.translate; + v_texCoord = @a_texCoord; + +#ifdef @ENABLE_CLIP_RECT + if (@ENABLE_CLIP_RECT) + { + v_clipRect = find_clip_rect_coverage_distances( + make_float2x2(imageDrawUniforms.clipRectInverseMatrix), + imageDrawUniforms.clipRectInverseTranslate, + vertexPosition); + } +#endif + + float4 pos = RENDER_TARGET_COORD_TO_CLIP_COORD(vertexPosition); + + VARYING_PACK(v_texCoord); +#ifdef @ENABLE_CLIP_RECT + VARYING_PACK(v_clipRect); +#endif + EMIT_VERTEX(pos); +} +#endif // VERTEX +#endif // DRAW_IMAGE_MESH + +#ifdef @DRAW_RENDER_TARGET_UPDATE_BOUNDS +#ifdef @VERTEX +ATTR_BLOCK_BEGIN(Attrs) +ATTR_BLOCK_END +#endif // VERTEX + +VARYING_BLOCK_BEGIN +VARYING_BLOCK_END + +#ifdef @VERTEX +VERTEX_MAIN(@drawVertexMain, Attrs, attrs, _vertexID, _instanceID) +{ + int2 coord; + coord.x = (_vertexID & 1) == 0 ? uniforms.renderTargetUpdateBounds.x + : uniforms.renderTargetUpdateBounds.z; + coord.y = (_vertexID & 2) == 0 ? uniforms.renderTargetUpdateBounds.y + : uniforms.renderTargetUpdateBounds.w; + float4 pos = RENDER_TARGET_COORD_TO_CLIP_COORD(float2(coord)); + EMIT_VERTEX(pos); +} +#endif // VERTEX +#endif // DRAW_RENDER_TARGET_UPDATE_BOUNDS + +#ifdef @DRAW_IMAGE +#define NEEDS_IMAGE_TEXTURE +#endif + +#ifdef @FRAGMENT +PLS_BLOCK_BEGIN +// We only bind the framebuffer as PLS when there are blend modes. Otherwise, we +// render to it as a normal color attachment. +#ifndef @FIXED_FUNCTION_COLOR_OUTPUT +#ifdef @COLOR_PLANE_IDX_OVERRIDE +// D3D11 doesn't let us bind the framebuffer UAV to slot 0 when there is a color +// output. +#define LOCAL_COLOR_PLANE_IDX @COLOR_PLANE_IDX_OVERRIDE +#else +#define LOCAL_COLOR_PLANE_IDX COLOR_PLANE_IDX +#endif +#ifdef @COALESCED_PLS_RESOLVE_AND_TRANSFER +PLS_DECL4F_READONLY(LOCAL_COLOR_PLANE_IDX, colorBuffer); +#else +PLS_DECL4F(LOCAL_COLOR_PLANE_IDX, colorBuffer); +#endif +#endif // !FIXED_FUNCTION_COLOR_OUTPUT +#ifdef @PLS_BLEND_SRC_OVER +// When PLS has src-over blending enabled, the clip buffer is RGBA8 so we can +// preserve clip contents by emitting a=0 instead of loading the current value. +// This is also is a hint to the hardware that it doesn't need to write anything +// to the clip attachment. +#define CLIP_VALUE_TYPE half4 +#define PLS_LOAD_CLIP_TYPE PLS_LOAD4F +#define MAKE_NON_UPDATING_CLIP_VALUE make_half4(.0) +#define HAS_UPDATED_CLIP_VALUE(X) ((X).a != .0) +#ifdef @ENABLE_CLIPPING +#ifndef @RESOLVE_PLS +PLS_DECL4F(CLIP_PLANE_IDX, clipBuffer); +#else +PLS_DECL4F_READONLY(CLIP_PLANE_IDX, clipBuffer); +#endif +#endif // ENABLE_CLIPPING +#else +// When PLS does not have src-over blending, the clip buffer the usual packed +// R32UI. +#define CLIP_VALUE_TYPE uint +#define MAKE_NON_UPDATING_CLIP_VALUE 0u +#define PLS_LOAD_CLIP_TYPE PLS_LOADUI +#define HAS_UPDATED_CLIP_VALUE(X) ((X) != 0u) +#ifdef @ENABLE_CLIPPING +PLS_DECLUI(CLIP_PLANE_IDX, clipBuffer); +#endif // ENABLE_CLIPPING +#endif // !PLS_BLEND_SRC_OVER +PLS_DECLUI_ATOMIC(COVERAGE_PLANE_IDX, coverageAtomicBuffer); +PLS_BLOCK_END + +FRAG_STORAGE_BUFFER_BLOCK_BEGIN +STORAGE_BUFFER_U32x2(PAINT_BUFFER_IDX, PaintBuffer, @paintBuffer); +STORAGE_BUFFER_F32x4(PAINT_AUX_BUFFER_IDX, PaintAuxBuffer, @paintAuxBuffer); +FRAG_STORAGE_BUFFER_BLOCK_END + +INLINE uint to_fixed(float x) +{ + return uint(round(x * FIXED_COVERAGE_PRECISION + FIXED_COVERAGE_ZERO)); +} + +INLINE half from_fixed(uint x) +{ + return cast_float_to_half( + float(x) * FIXED_COVERAGE_INVERSE_PRECISION + + (-FIXED_COVERAGE_ZERO * FIXED_COVERAGE_INVERSE_PRECISION)); +} + +#ifdef @ENABLE_CLIPPING +INLINE void apply_clip(uint clipID, + CLIP_VALUE_TYPE clipData, + INOUT(half) coverage) +{ +#ifdef @PLS_BLEND_SRC_OVER + // The clipID is packed into r & g of clipData. Use a fuzzy equality test + // since we lose precision when the clip value gets stored to and from the + // attachment. + if (all(lessThan(abs(clipData.rg - unpackUnorm4x8(clipID).rg), + make_half2(.25 / 255.)))) + coverage = min(coverage, clipData.b); + else + coverage = .0; +#else + // The clipID is the top 16 bits of clipData. + if (clipID == clipData >> 16) + coverage = min(coverage, unpackHalf2x16(clipData).r); + else + coverage = .0; +#endif +} +#endif + +INLINE void resolve_paint(uint pathID, + half coverageCount, + OUT(half4) fragColorOut +#if defined(@ENABLE_CLIPPING) && !defined(@RESOLVE_PLS) + , + INOUT(CLIP_VALUE_TYPE) fragClipOut +#endif + FRAGMENT_CONTEXT_DECL PLS_CONTEXT_DECL) +{ + uint2 paintData = STORAGE_BUFFER_LOAD2(@paintBuffer, pathID); + half coverage = coverageCount; + if ((paintData.x & (PAINT_FLAG_NON_ZERO_FILL | PAINT_FLAG_EVEN_ODD_FILL)) != + 0u) + { + // This path has a legacy (non-clockwise) fill. + coverage = abs(coverage); +#ifdef @ENABLE_EVEN_ODD + if (@ENABLE_EVEN_ODD && (paintData.x & PAINT_FLAG_EVEN_ODD_FILL) != 0u) + { + coverage = 1. - abs(fract(coverage * .5) * 2. + -1.); + } +#endif + } + // This also caps stroke coverage, which can be >1. + coverage = clamp(coverage, make_half(.0), make_half(1.)); +#ifdef @ENABLE_CLIPPING + if (@ENABLE_CLIPPING) + { + uint clipID = paintData.x >> 16u; + if (clipID != 0u) + { + apply_clip(clipID, PLS_LOAD_CLIP_TYPE(clipBuffer), coverage); + } + } +#endif // ENABLE_CLIPPING +#ifdef @ENABLE_CLIP_RECT + if (@ENABLE_CLIP_RECT && (paintData.x & PAINT_FLAG_HAS_CLIP_RECT) != 0u) + { + float2x2 M = make_float2x2( + STORAGE_BUFFER_LOAD4(@paintAuxBuffer, pathID * 4u + 2u)); + float4 translate = + STORAGE_BUFFER_LOAD4(@paintAuxBuffer, pathID * 4u + 3u); + float2 clipCoord = MUL(M, _fragCoord) + translate.xy; + // translate.zw contains -1 / fwidth(clipCoord), which we use to + // calculate antialiasing. + half2 distXY = + cast_float2_to_half2(abs(clipCoord) * translate.zw - translate.zw); + half clipRectCoverage = clamp(min(distXY.x, distXY.y) + .5, .0, 1.); + coverage = min(coverage, clipRectCoverage); + } +#endif // ENABLE_CLIP_RECT + uint paintType = paintData.x & 0xfu; + if (paintType <= SOLID_COLOR_PAINT_TYPE) // CLIP_UPDATE_PAINT_TYPE or + // SOLID_COLOR_PAINT_TYPE + { + fragColorOut = unpackUnorm4x8(paintData.y); +#ifdef @ENABLE_CLIPPING + if (@ENABLE_CLIPPING && paintType == CLIP_UPDATE_PAINT_TYPE) + { +#ifndef @RESOLVE_PLS +#ifdef @PLS_BLEND_SRC_OVER + // This was actually a clip update. fragColorOut contains the packed + // clipID. + fragClipOut.rg = fragColorOut.ba; // Pack the clipID into r & g. + fragClipOut.b = coverage; // Put the clipCoverage in b. + fragClipOut.a = + 1.; // a=1 so we replace the value in the clipBuffer. +#else + fragClipOut = paintData.y | packHalf2x16(make_half2(coverage, .0)); +#endif +#endif + // Don't update the colorBuffer when this is a clip update. + fragColorOut = make_half4(.0); + } +#endif + } + else // LINEAR_GRADIENT_PAINT_TYPE or RADIAL_GRADIENT_PAINT_TYPE + { + float2x2 M = + make_float2x2(STORAGE_BUFFER_LOAD4(@paintAuxBuffer, pathID * 4u)); + float4 translate = + STORAGE_BUFFER_LOAD4(@paintAuxBuffer, pathID * 4u + 1u); + float2 paintCoord = MUL(M, _fragCoord) + translate.xy; + float t = paintType == LINEAR_GRADIENT_PAINT_TYPE + ? /*linear*/ paintCoord.x + : /*radial*/ length(paintCoord); + t = clamp(t, .0, 1.); + float x = t * translate.z + translate.w; + float y = uintBitsToFloat(paintData.y); + fragColorOut = + TEXTURE_SAMPLE_LOD(@gradTexture, gradSampler, float2(x, y), .0); + } + fragColorOut.a *= coverage; + +#if !defined(@FIXED_FUNCTION_COLOR_OUTPUT) && defined(@ENABLE_ADVANCED_BLEND) + // Apply the advanced blend mode, if applicable. + ushort blendMode; + if (@ENABLE_ADVANCED_BLEND && fragColorOut.a != .0 && + (blendMode = cast_uint_to_ushort((paintData.x >> 4) & 0xfu)) != 0u) + { + half4 dstColorPremul = PLS_LOAD4F(colorBuffer); + fragColorOut.rgb = + advanced_color_blend(fragColorOut.rgb, dstColorPremul, blendMode); + } +#endif // !FIXED_FUNCTION_COLOR_OUTPUT && ENABLE_ADVANCED_BLEND + + // When PLS_BLEND_SRC_OVER is defined, the caller and/or blend state + // multiply alpha into fragColorOut for us. Otherwise, we have to + // premultiply it. +#ifndef @PLS_BLEND_SRC_OVER + fragColorOut.rgb *= fragColorOut.a; +#endif +} + +#if !defined(@FIXED_FUNCTION_COLOR_OUTPUT) && \ + !defined(@COALESCED_PLS_RESOLVE_AND_TRANSFER) +INLINE void blend_pls_color_src_over(half4 fragColorOut PLS_CONTEXT_DECL) +{ +#ifndef @PLS_BLEND_SRC_OVER + if (fragColorOut.a == .0) + return; + float oneMinusSrcAlpha = 1. - fragColorOut.a; + if (oneMinusSrcAlpha != .0) + fragColorOut += PLS_LOAD4F(colorBuffer) * oneMinusSrcAlpha; +#endif + PLS_STORE4F(colorBuffer, fragColorOut); +} +#endif // !@FIXED_FUNCTION_COLOR_OUTPUT && !@COALESCED_PLS_RESOLVE_AND_TRANSFER + +#if defined(@ENABLE_CLIPPING) && !defined(@RESOLVE_PLS) +INLINE void emit_pls_clip(CLIP_VALUE_TYPE fragClipOut PLS_CONTEXT_DECL) +{ +#ifdef @PLS_BLEND_SRC_OVER + PLS_STORE4F(clipBuffer, fragClipOut); +#else + if (fragClipOut != 0u) + PLS_STOREUI(clipBuffer, fragClipOut); +#endif +} +#endif // ENABLE_CLIPPING && !RESOLVE_PLS + +#ifdef @FIXED_FUNCTION_COLOR_OUTPUT +#define ATOMIC_PLS_MAIN PLS_FRAG_COLOR_MAIN +#define ATOMIC_PLS_MAIN_WITH_IMAGE_UNIFORMS \ + PLS_FRAG_COLOR_MAIN_WITH_IMAGE_UNIFORMS +#define EMIT_ATOMIC_PLS EMIT_PLS_AND_FRAG_COLOR +#else // !FIXED_FUNCTION_COLOR_OUTPUT +#define ATOMIC_PLS_MAIN PLS_MAIN +#define ATOMIC_PLS_MAIN_WITH_IMAGE_UNIFORMS PLS_MAIN_WITH_IMAGE_UNIFORMS +#define EMIT_ATOMIC_PLS EMIT_PLS +#endif + +#ifdef @DRAW_PATH +ATOMIC_PLS_MAIN(@drawFragmentMain) +{ +#ifdef @ENABLE_FEATHER + VARYING_UNPACK(v_coverages, float4); +#else + VARYING_UNPACK(v_coverages, half2); +#endif + VARYING_UNPACK(v_pathID, ushort); + + half fragmentCoverage; +#ifdef @ENABLE_FEATHER + if (@ENABLE_FEATHER && is_feathered_stroke(v_coverages)) + { + fragmentCoverage = + eval_feathered_stroke(v_coverages TEXTURE_CONTEXT_FORWARD); + } + else if (@ENABLE_FEATHER && is_feathered_fill(v_coverages)) + { + fragmentCoverage = + eval_feathered_fill(v_coverages TEXTURE_CONTEXT_FORWARD); + } + else +#endif + { + // Cover stroke and fill both in a branchless expression. + fragmentCoverage = + min(min(make_half(v_coverages.x), abs(make_half(v_coverages.y))), + make_half(1.)); + } + + half4 fragColorOut = make_half4(.0); +#ifdef @ENABLE_CLIPPING + CLIP_VALUE_TYPE fragClipOut = MAKE_NON_UPDATING_CLIP_VALUE; +#endif + + // Since v_pathID increases monotonically with every draw, and since it + // lives in the most significant bits of the coverage data, an atomic max() + // function will serve 3 purposes: + // + // * The invocation that changes the pathID is the single first fragment + // invocation to hit the new path, and the one that should resolve the + // previous path in the framebuffer. + // * Properly resets coverage to zero when we do cross over into + // processing a new path. + // * Accumulates coverage for strokes. + // + uint fixedCoverage = to_fixed(fragmentCoverage); + uint minCoverageData = + (make_uint(v_pathID) << FIXED_COVERAGE_BIT_COUNT) | fixedCoverage; + uint lastCoverageData = + PLS_ATOMIC_MAX(coverageAtomicBuffer, minCoverageData); + ushort lastPathID = + cast_uint_to_ushort(lastCoverageData >> FIXED_COVERAGE_BIT_COUNT); + if (lastPathID == v_pathID) + { + // This is not the first fragment of the current path to touch this + // pixel. We already resolved the previous path, so just update coverage + // (if we're a fill) and move on. + if (!is_stroke(v_coverages)) + { + // Only apply the effect of the min() the first time we cross into a + // path. + fixedCoverage += + lastCoverageData - max(minCoverageData, lastCoverageData); + fixedCoverage -= + FIXED_COVERAGE_ZERO_UINT; // Only apply the zero bias once. + PLS_ATOMIC_ADD(coverageAtomicBuffer, + fixedCoverage); // Count coverage. + } + } + else + { + // We crossed into a new path! Resolve the previous path now that we + // know its exact coverage. + half coverageCount = from_fixed(lastCoverageData & FIXED_COVERAGE_MASK); + resolve_paint(lastPathID, + coverageCount, + fragColorOut +#ifdef @ENABLE_CLIPPING + , + fragClipOut +#endif + FRAGMENT_CONTEXT_UNPACK PLS_CONTEXT_UNPACK); + } + +#ifdef @FIXED_FUNCTION_COLOR_OUTPUT + _fragColor = fragColorOut; +#else + blend_pls_color_src_over(fragColorOut PLS_CONTEXT_UNPACK); +#endif +#ifdef @ENABLE_CLIPPING + emit_pls_clip(fragClipOut PLS_CONTEXT_UNPACK); +#endif + + EMIT_ATOMIC_PLS +} +#endif // DRAW_PATH + +#ifdef @DRAW_INTERIOR_TRIANGLES +ATOMIC_PLS_MAIN(@drawFragmentMain) +{ +#ifdef @ATLAS_BLIT + VARYING_UNPACK(v_atlasCoord, float2); +#else + VARYING_UNPACK(v_windingWeight, half); +#endif + VARYING_UNPACK(v_pathID, ushort); + + uint lastCoverageData = PLS_LOADUI_ATOMIC(coverageAtomicBuffer); + ushort lastPathID = + cast_uint_to_ushort(lastCoverageData >> FIXED_COVERAGE_BIT_COUNT); + + // Update coverageAtomicBuffer with the coverage weight of the current + // triangle. This does not need to be atomic since interior triangles don't + // overlap. + uint currPathCoverageData; +#ifndef @ATLAS_BLIT + if (lastPathID == v_pathID) + { + currPathCoverageData = lastCoverageData; + } + else +#endif + { + currPathCoverageData = + (make_uint(v_pathID) << FIXED_COVERAGE_BIT_COUNT) + + FIXED_COVERAGE_ZERO_UINT; + } + + half coverage; +#ifdef @ATLAS_BLIT + coverage = filter_feather_atlas( + v_atlasCoord, + uniforms.atlasTextureInverseSize TEXTURE_CONTEXT_FORWARD); +#else + coverage = v_windingWeight; +#endif + + int coverageDeltaFixed = int(round(coverage * FIXED_COVERAGE_PRECISION)); + PLS_STOREUI_ATOMIC(coverageAtomicBuffer, + currPathCoverageData + uint(coverageDeltaFixed)); + + half4 fragColorOut = make_half4(.0); +#ifdef @ENABLE_CLIPPING + CLIP_VALUE_TYPE fragClipOut = MAKE_NON_UPDATING_CLIP_VALUE; +#endif + +#ifndef @ATLAS_BLIT + // If this is not the first fragment of the current path to touch this + // pixel, then we've already resolved the previous path and can move on. + if (lastPathID != v_pathID) +#endif + { + // We crossed into a new path! Resolve the previous path now that we + // know its exact coverage. + half lastCoverageCount = + from_fixed(lastCoverageData & FIXED_COVERAGE_MASK); + resolve_paint(lastPathID, + lastCoverageCount, + fragColorOut +#ifdef @ENABLE_CLIPPING + , + fragClipOut +#endif + FRAGMENT_CONTEXT_UNPACK PLS_CONTEXT_UNPACK); + } + +#ifdef @FIXED_FUNCTION_COLOR_OUTPUT + _fragColor = fragColorOut; +#else + blend_pls_color_src_over(fragColorOut PLS_CONTEXT_UNPACK); +#endif +#ifdef @ENABLE_CLIPPING + emit_pls_clip(fragClipOut PLS_CONTEXT_UNPACK); +#endif + + EMIT_ATOMIC_PLS +} +#endif // DRAW_INTERIOR_TRIANGLES + +#ifdef @DRAW_IMAGE +ATOMIC_PLS_MAIN_WITH_IMAGE_UNIFORMS(@drawFragmentMain) +{ + VARYING_UNPACK(v_texCoord, float2); +#ifdef @DRAW_IMAGE_RECT + VARYING_UNPACK(v_edgeCoverage, half); +#endif +#ifdef @ENABLE_CLIP_RECT + VARYING_UNPACK(v_clipRect, float4); +#endif + + // Start by finding the image color. We have to do this immediately instead + // of allowing it to get resolved later like other draws because the + // @imageTexture binding is liable to change, and furthermore in the case of + // imageMeshes, we can't calculate UV coordinates based on fragment + // position. + half4 imageColor = + TEXTURE_SAMPLE_DYNAMIC(@imageTexture, imageSampler, v_texCoord); + half imageCoverage = 1.; +#ifdef @DRAW_IMAGE_RECT + imageCoverage = min(v_edgeCoverage, imageCoverage); +#endif +#ifdef @ENABLE_CLIP_RECT + if (@ENABLE_CLIP_RECT) + { + half clipRectCoverage = min_value(cast_float4_to_half4(v_clipRect)); + imageCoverage = clamp(clipRectCoverage, make_half(.0), imageCoverage); + } +#endif + + // Resolve the previous path. + uint lastCoverageData = PLS_LOADUI_ATOMIC(coverageAtomicBuffer); + ushort lastPathID = + cast_uint_to_ushort(lastCoverageData >> FIXED_COVERAGE_BIT_COUNT); + half lastCoverageCount = from_fixed(lastCoverageData & FIXED_COVERAGE_MASK); + half4 fragColorOut; +#ifdef @ENABLE_CLIPPING + CLIP_VALUE_TYPE fragClipOut = MAKE_NON_UPDATING_CLIP_VALUE; +#endif + // TODO: consider not resolving the prior paint if we're solid and the prior + // paint is not a clip update: (imageColor.a == 1. && + // imageDrawUniforms.blendMode == + // BLEND_SRC_OVER && priorPaintType != + // CLIP_UPDATE_PAINT_TYPE) + resolve_paint(lastPathID, + lastCoverageCount, + fragColorOut +#ifdef @ENABLE_CLIPPING + , + fragClipOut +#endif + FRAGMENT_CONTEXT_UNPACK PLS_CONTEXT_UNPACK); + +#ifdef @PLS_BLEND_SRC_OVER + // Image draws use a premultiplied blend state, but resolve_paint() did not + // premultiply fragColorOut. Multiply fragColorOut by alpha now. + fragColorOut.rgb *= fragColorOut.a; +#endif + + // Clip the image after resolving the previous path, since that can affect + // the clip buffer. +#ifdef @ENABLE_CLIPPING // TODO! ENABLE_IMAGE_CLIPPING in addition to + // ENABLE_CLIPPING? + if (@ENABLE_CLIPPING && imageDrawUniforms.clipID != 0u) + { + CLIP_VALUE_TYPE clipData = HAS_UPDATED_CLIP_VALUE(fragClipOut) + ? fragClipOut + : PLS_LOAD_CLIP_TYPE(clipBuffer); + apply_clip(imageDrawUniforms.clipID, clipData, imageCoverage); + } +#endif // ENABLE_CLIPPING + + // Prepare imageColor for premultiplied src-over blending. +#if !defined(@FIXED_FUNCTION_COLOR_OUTPUT) && defined(@ENABLE_ADVANCED_BLEND) + if (@ENABLE_ADVANCED_BLEND && imageDrawUniforms.blendMode != BLEND_SRC_OVER) + { + // Calculate what dstColorPremul will be after applying fragColorOut. + half4 dstColorPremul = + PLS_LOAD4F(colorBuffer) * (1. - fragColorOut.a) + fragColorOut; + // Calculate the imageColor to emit *BEFORE* src-over blending, such + // that the post-src-over-blend result is equivalent to the blendMode. + imageColor.rgb = advanced_color_blend( + unmultiply_rgb(imageColor), + dstColorPremul, + cast_uint_to_ushort(imageDrawUniforms.blendMode)) * + imageColor.a; + } +#endif // !FIXED_FUNCTION_COLOR_OUTPUT && ENABLE_ADVANCED_BLEND + imageColor *= imageCoverage * cast_float_to_half(imageDrawUniforms.opacity); + + // Leverage the property that premultiplied src-over blending is associative + // and blend the imageColor and fragColorOut before passing them on to the + // blending pipeline. + fragColorOut = fragColorOut * (1. - imageColor.a) + imageColor; + +#ifdef @FIXED_FUNCTION_COLOR_OUTPUT + _fragColor = fragColorOut; +#else + blend_pls_color_src_over(fragColorOut PLS_CONTEXT_UNPACK); +#endif +#ifdef @ENABLE_CLIPPING + emit_pls_clip(fragClipOut PLS_CONTEXT_UNPACK); +#endif + + // Write out a coverage value of "zero at pathID=0" so a future resolve + // attempt doesn't affect this pixel. + PLS_STOREUI_ATOMIC(coverageAtomicBuffer, FIXED_COVERAGE_ZERO_UINT); + + EMIT_ATOMIC_PLS +} +#endif // DRAW_IMAGE + +#ifdef @INITIALIZE_PLS + +ATOMIC_PLS_MAIN(@drawFragmentMain) +{ +#ifdef @STORE_COLOR_CLEAR + PLS_STORE4F(colorBuffer, unpackUnorm4x8(uniforms.colorClearValue)); +#endif +#ifdef @SWIZZLE_COLOR_BGRA_TO_RGBA + half4 color = PLS_LOAD4F(colorBuffer); + PLS_STORE4F(colorBuffer, color.bgra); +#endif + PLS_STOREUI_ATOMIC(coverageAtomicBuffer, uniforms.coverageClearValue); +#ifdef @ENABLE_CLIPPING + if (@ENABLE_CLIPPING) + { + PLS_STOREUI(clipBuffer, 0u); + } +#endif +#ifdef @FIXED_FUNCTION_COLOR_OUTPUT + discard; +#endif + EMIT_ATOMIC_PLS +} + +#endif // INITIALIZE_PLS + +#ifdef @RESOLVE_PLS + +#ifdef @COALESCED_PLS_RESOLVE_AND_TRANSFER +PLS_FRAG_COLOR_MAIN(@drawFragmentMain) +#else +ATOMIC_PLS_MAIN(@drawFragmentMain) +#endif +{ + uint lastCoverageData = PLS_LOADUI_ATOMIC(coverageAtomicBuffer); + half coverageCount = from_fixed(lastCoverageData & FIXED_COVERAGE_MASK); + ushort lastPathID = + cast_uint_to_ushort(lastCoverageData >> FIXED_COVERAGE_BIT_COUNT); + half4 fragColorOut; + resolve_paint(lastPathID, + coverageCount, + fragColorOut FRAGMENT_CONTEXT_UNPACK PLS_CONTEXT_UNPACK); +#ifdef @COALESCED_PLS_RESOLVE_AND_TRANSFER +#ifdef @PLS_BLEND_SRC_OVER + // When PLS_BLEND_SRC_OVER is defined, the blend state usually multiplies + // alpha into fragColorOut for us. But since the coalesced resolve does not + // use blend, premultiply it now. + fragColorOut.rgb *= fragColorOut.a; +#endif + float oneMinusSrcAlpha = 1. - fragColorOut.a; + if (oneMinusSrcAlpha != .0) + fragColorOut += PLS_LOAD4F(colorBuffer) * oneMinusSrcAlpha; + _fragColor = fragColorOut; + EMIT_PLS_AND_FRAG_COLOR +#else +#ifdef @FIXED_FUNCTION_COLOR_OUTPUT + _fragColor = fragColorOut; +#else + blend_pls_color_src_over(fragColorOut PLS_CONTEXT_UNPACK); +#endif + EMIT_ATOMIC_PLS +#endif // COALESCED_PLS_RESOLVE_AND_TRANSFER +} +#endif // RESOLVE_PLS +#endif // FRAGMENT diff --git a/third_party/rive_renderer/source/shaders/bezier_utils.glsl b/third_party/rive_renderer/source/shaders/bezier_utils.glsl new file mode 100644 index 0000000..4d798c8 --- /dev/null +++ b/third_party/rive_renderer/source/shaders/bezier_utils.glsl @@ -0,0 +1,245 @@ +/* + * Copyright 2020 Google LLC. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Some initial imports from + * skia:src/gpu/ganesh/tessellate/GrStrokeTessellationShader.cpp + * + * Copyright 2025 Rive + */ + +// Common definitions and math functions for working with bezier curves. + +// make_float4 and make_float2 are defined for compatibility with C++, so we can +// compile this file as C++ and unit test it. +#ifndef make_float4 +#define make_float4 float4 +#endif +#ifndef make_float2 +#define make_float2 float2 +#endif + +INLINE float cosine_between_vectors(float2 a, float2 b) +{ + float ab_cosTheta = dot(a, b); + float ab_pow2 = dot(a, a) * dot(b, b); + return (ab_pow2 == .0) ? 1. + : clamp(ab_cosTheta * inversesqrt(ab_pow2), -1., 1.); + // FIXME(crbug.com/800804,skbug.com/11268): This can overflow if we don't + // normalize exponents. +} + +// Finds the cubic bezier's power basis coefficients. These define the bezier +// curve as: +// +// |T^3| +// Cubic(T) = x,y = |A 3B 3C| * |T^2| + P0 +// |. . .| |T | +// +// And the tangent: +// +// |T^2| +// Tangent(T) = dx,dy = |3A 6B 3C| * |T | +// | . . .| |1 | +// +INLINE void find_cubic_coeffs(float2 p0, + float2 p1, + float2 p2, + float2 p3, + OUT(float2) A, + OUT(float2) B, + OUT(float2) C) +{ + C = p1 - p0; + float2 D = p2 - p1; + float2 E = p3 - p0; + B = D - C; + A = -3. * D + E; + // FIXME(crbug.com/800804,skbug.com/11268): Consider normalizing the + // exponents in A,B,C at this point in order to prevent fp32 overflow. +} + +// Tangent of the curve at T=0 and T=1. +INLINE float2x2 find_cubic_tangents(float2 p0, float2 p1, float2 p2, float2 p3) +{ + float2x2 t; + t[0] = (any(notEqual(p0, p1)) ? p1 : any(notEqual(p1, p2)) ? p2 : p3) - p0; + t[1] = p3 - (any(notEqual(p3, p2)) ? p2 : any(notEqual(p2, p1)) ? p1 : p0); + return t; +} + +// Measure the amount of curvature, in radians centered at location T, and +// covering a spread of width "desiredSpread" in local coordinates. If +// "desiredSpread" would reach outside the range T=0..1, the spread is clipped +// to stay within range. +INLINE float measure_cubic_local_curvature(float2 p0, + float2 p1, + float2 p2, + float2 p3, + float T, + float desiredSpread) +{ + float2 A, B, C; + find_cubic_coeffs(p0, p1, p2, p3, A, B, C); + float2 tangent = 3. * (((A * T) + 2. * B) * T + C); + float lengthTan = length(tangent); + if (lengthTan == .0) + { + return .0; + } + + // Define the function: + // + // Spread(dt) = A_*dt^3 + C_*dt + // + // Which calculates the spread of the curve in local coordinates, parallel + // to tangent, over the range "T - dt .. T + dt". + tangent *= 1. / lengthTan; + float A_ = 2. * dot(A, tangent); + float C_ = 3. * (A_ * T + 4. * dot(B, tangent)) * T + 6. * dot(C, tangent); + + // Decide the "targetSpread" across which we will measure curvature. Ideally + // this is "desiredSpread", but use less than that if that would reach + // outside T=0..1. + float maxDT = min(T, 1. - T); + float maxSpread = (A_ * maxDT * maxDT + C_) * maxDT; + // Pad the maxSpread to guarantee we won't step outside T=0..1. + float targetSpread = min(desiredSpread, maxSpread * .9999); + + // Solve for dt, where Spread(dt) == targetSpread. + float dt; + if (A_ == .0) + { + // Degenerate case: Spread(dt) == C_*dt. + dt = targetSpread / C_; + } + else + { + // Solve the normalized cubic x^3 + ax^2 + bx + c == 0. + // (Numerical Recipes in C, 5.6 Quadratic and Cubic Equations, + // https://hd.fizyka.umk.pl/~jacek/docs/nrc/c5-6.pdf) + float r = 1. / A_; + float /*a = 0,*/ b = C_ * r, c = -targetSpread * r; + float Q = (-1. / 3.) * b, R = .5 * c; + float discr = R * R - Q * Q * Q; + if (discr < .0) + { + float sqrtQ = sqrt(Q); + float theta = acos(R / (sqrtQ * sqrtQ * sqrtQ)); + // The 3 roots are: (because a == 0) + // -2 * sqrt(Q) * cos(theta/3 + float3{0, 1, -1} * 2*pi/3) + // We want the root closest to zero, which will be the 3rd root + // because its argument for cos() is always closest to +-pi/2. + dt = -2. * sqrtQ * cos(theta * (1. / 3.) + (-PI * 2. / 3.)); + } + else + { + float A = pow(abs(R) + sqrt(discr), 1. / 3.); + if (R < .0) + A = -A; + dt = A != .0 ? A + Q / A : .0; + } + } + dt = abs(dt); + + // Measure curvature over the spread T - dt .. T + dt. + float4 t0011 = T + make_float4(-dt, -dt, dt, dt); + float4 tanDirs = (A.xyxy * t0011 + 2. * B.xyxy) * t0011 + C.xyxy; + // Use more stable tangents at the ends in case we've encountered a cusp. + float2x2 tangents = find_cubic_tangents(p0, p1, p2, p3); + float2 tan0 = t0011.x < 1e-3 ? tangents[0] : tanDirs.xy; + float2 tan1 = t0011.z > 1. - 1e-3 ? tangents[1] : tanDirs.zw; + // NOTE: this will break if there is an inflection point. + return acos(cosine_between_vectors(tan0, tan1)); +} + +// Returns clamp(a/b, 0, 1). +// Returns 1 if a/b == INF. +// Returns 0 if a/b == -INF. +// Returns 0 if a == 0 and b == 0. +// Returns 0 or 1 if a or b are NaN. +// Returns 0 or 1 if a and b are both +/-INF. +INLINE float clamped_divide(float a, float b) +{ + a = b < .0 ? -a : a; + b = abs(b); + return a > .0 ? (a < b ? a / b : 1.) : .0; +} + +// Find the location and value of a cubic's maximum height, relative to the +// baseline p0->p3. +float find_cubic_max_height(float2 p0, + float2 p1, + float2 p2, + float2 p3, + OUT(float) outT) +{ + // Find the cubic height function, which is also a 1D cubic bezier: + // + // height - 3(dht^3 - (h1 + dh)t^2 + h1t) + // + float2 base = p3 - p0; + float lengthBase = length(p3 - p0); + if (lengthBase == .0) + { + outT = .5; + return .0; + } + float2 norm = make_float2(-base.y, base.x) / lengthBase; + float h2 = dot(norm, p2 - p0); + float h1 = dot(norm, p1 - p0); + float dh = h1 - h2; + +#if 0 + // A cubic's height function has two maxima. Find both. + float a = 3. * dh; + float b_over_minus_2 = dh + h1; + float c = h1; + float q = sqrt(max(dh * dh + h2 * h1, .0)); + if (b_over_minus_2 < .0) + q = -q; + q += b_over_minus_2; + float2 tt = make_float2(clamped_divide(q, a), clamped_divide(c, q)); + float2 hh = 3. * (tt * (tt * (tt * dh - (h1 + dh)) + h1)); + + // Go with whichever maximum is larger. + hh = abs(hh); + outT = hh.x > hh.y ? tt.x : tt.y; + return max(hh.x, hh.y); +#else + // Solve for max height iteratively using Newton-Raphson because the above + // solution fails sometimes on ARM Mali. + // + // This works as easily as it does because the curve is pre-chopped to be + // convex, meaning there is only one maxima in 0..1. + // + // First find the power-basis coefficients for the height function: + // + // height = 3(At^3 + Bt^2 + Ct) + // + float _3A = 3. * dh; + float B = -h1 - dh; + float C = h1; + float t = .5; // First guess of max height is t=.5. + // Per the unit test, 3 iters is enough to fall within 1e-3 of max height. + for (int i = 0; i < 3; ++i) + { + // Standard Newton-Rhapson: + // + // h'(t) = 3(3At^2 + 2Bt + C) + // h''(t) = 3(6At + 2B) + // t -= h'(t) / h''(t) + // + // This reduces to: + // + // t = (3At^2 - C) / (6At + 2B) + // + float _3At = _3A * t; + t = clamped_divide(_3At * t - C, 2. * (_3At + B)); + } + outT = t; + return abs(t * (t * (t * _3A + 3. * B) + 3. * C)); +#endif +} diff --git a/third_party/rive_renderer/source/shaders/blit_texture_as_draw.glsl b/third_party/rive_renderer/source/shaders/blit_texture_as_draw.glsl new file mode 100644 index 0000000..14e8e6c --- /dev/null +++ b/third_party/rive_renderer/source/shaders/blit_texture_as_draw.glsl @@ -0,0 +1,58 @@ +/* + * Copyright 2024 Rive + */ + +VARYING_BLOCK_BEGIN +#ifndef @USE_TEXEL_FETCH_WITH_FRAG_COORD +NO_PERSPECTIVE VARYING(0, float2, v_texCoord); +#endif +VARYING_BLOCK_END + +#ifdef @VERTEX +VERTEX_TEXTURE_BLOCK_BEGIN +VERTEX_TEXTURE_BLOCK_END + +VERTEX_STORAGE_BUFFER_BLOCK_BEGIN +VERTEX_STORAGE_BUFFER_BLOCK_END + +VERTEX_MAIN(@blitVertexMain, Attrs, attrs, _vertexID, _instanceID) +{ + // Fill the entire screen. The caller will use a scissor test to control the + // bounds being drawn. + float2 coord; + coord.x = (_vertexID & 1) == 0 ? -1. : 1.; + coord.y = (_vertexID & 2) == 0 ? -1. : 1.; +#ifndef @USE_TEXEL_FETCH_WITH_FRAG_COORD + VARYING_INIT(v_texCoord, float2); + v_texCoord.x = coord.x * .5 + .5; + v_texCoord.y = coord.y * -.5 + .5; + VARYING_PACK(v_texCoord); +#endif + float4 pos = float4(coord, 0, 1); + EMIT_VERTEX(pos); +} +#endif // @VERTEX + +#ifdef @FRAGMENT +FRAG_TEXTURE_BLOCK_BEGIN +TEXTURE_RGBA8(0, 0, @sourceTexture); +FRAG_TEXTURE_BLOCK_END + +#ifndef @USE_TEXEL_FETCH_WITH_FRAG_COORD +DYNAMIC_SAMPLER_BLOCK_BEGIN +SAMPLER_DYNAMIC(0, blitSampler) +DYNAMIC_SAMPLER_BLOCK_END +#endif + +FRAG_DATA_MAIN(half4, @blitFragmentMain) +{ + half4 srcColor; +#ifndef @USE_TEXEL_FETCH_WITH_FRAG_COORD + VARYING_UNPACK(v_texCoord, float2); + srcColor = TEXTURE_SAMPLE_LOD(@sourceTexture, blitSampler, v_texCoord, .0); +#else + srcColor = TEXEL_FETCH(@sourceTexture, int2(floor(_fragCoord.xy))); +#endif + EMIT_FRAG_DATA(srcColor); +} +#endif // @FRAGMENT diff --git a/third_party/rive_renderer/source/shaders/color_ramp.glsl b/third_party/rive_renderer/source/shaders/color_ramp.glsl new file mode 100644 index 0000000..7bae817 --- /dev/null +++ b/third_party/rive_renderer/source/shaders/color_ramp.glsl @@ -0,0 +1,104 @@ +/* + * Copyright 2022 Rive + */ + +// This shader draws horizontal color ramps into a gradient texture, which will +// later be sampled by the renderer for drawing gradients. + +#ifdef @VERTEX +ATTR_BLOCK_BEGIN(Attrs) +#ifdef SPLIT_UINT4_ATTRIBUTES +ATTR(0, uint, @a_spanX); +ATTR(1, uint, @a_yWithFlags); +ATTR(2, uint, @a_color0); +ATTR(3, uint, @a_color1); +#else +ATTR(0, uint4, @a_span); // [spanX, y, color0, color1] +#endif +ATTR_BLOCK_END +#endif + +VARYING_BLOCK_BEGIN +NO_PERSPECTIVE VARYING(0, half4, v_rampColor); +VARYING_BLOCK_END + +#ifdef @VERTEX +VERTEX_TEXTURE_BLOCK_BEGIN +VERTEX_TEXTURE_BLOCK_END + +VERTEX_STORAGE_BUFFER_BLOCK_BEGIN +VERTEX_STORAGE_BUFFER_BLOCK_END + +half4 unpackColorInt(uint color) +{ + return cast_uint4_to_half4( + (uint4(color, color, color, color) >> uint4(16, 8, 0, 24)) & + 0xffu) / + 255.; +} + +VERTEX_MAIN(@colorRampVertexMain, Attrs, attrs, _vertexID, _instanceID) +{ +#ifdef SPLIT_UINT4_ATTRIBUTES + ATTR_UNPACK(_instanceID, attrs, @a_spanX, uint); + ATTR_UNPACK(_instanceID, attrs, @a_yWithFlags, uint); + ATTR_UNPACK(_instanceID, attrs, @a_color0, uint); + ATTR_UNPACK(_instanceID, attrs, @a_color1, uint); + uint4 @a_span = uint4(@a_spanX, @a_yWithFlags, @a_color0, @a_color1); +#else + ATTR_UNPACK(_instanceID, attrs, @a_span, uint4); +#endif + VARYING_INIT(v_rampColor, half4); + + int columnWithinSpan = _vertexID >> 1; + float x = + float(columnWithinSpan <= 1 ? @a_span.x & 0xffffu : @a_span.x >> 16) / + 65536.; + float offsetY = (_vertexID & 1) == 0 ? .0 : 1.; + if (uniforms.gradInverseViewportY < .0) + { + // Swap the top and bottom vertices to make sure we always emit + // clockwise triangles. vertices. + offsetY = 1. - offsetY; + } + uint yWithFlags = @a_span.y; + float y = float(yWithFlags & ~GRAD_SPAN_FLAGS_MASK) + offsetY; + if ((yWithFlags & GRAD_SPAN_FLAG_LEFT_BORDER) != 0u && + columnWithinSpan == 0) + { + if ((yWithFlags & GRAD_SPAN_FLAG_COMPLEX_BORDER) != 0u) + x = .0; // Borders of complex gradients go to the far edge. + else + // Simple gradients are empty with 1px borders on either side. + x -= GRAD_TEXTURE_INVERSE_WIDTH; + } + if ((yWithFlags & GRAD_SPAN_FLAG_RIGHT_BORDER) != 0u && + columnWithinSpan == 3) + { + if ((yWithFlags & GRAD_SPAN_FLAG_COMPLEX_BORDER) != 0u) + x = 1.; // Borders of complex gradients go to the far edge. + else + // Simple gradients are empty with 1px borders on either side. + x += GRAD_TEXTURE_INVERSE_WIDTH; + } + v_rampColor = unpackColorInt(columnWithinSpan <= 1 ? @a_span.z : @a_span.w); + + float4 pos = pixel_coord_to_clip_coord(float2(x, y), + 2., + uniforms.gradInverseViewportY); + + VARYING_PACK(v_rampColor); + EMIT_VERTEX(pos); +} +#endif + +#ifdef @FRAGMENT +FRAG_TEXTURE_BLOCK_BEGIN +FRAG_TEXTURE_BLOCK_END + +FRAG_DATA_MAIN(half4, @colorRampFragmentMain) +{ + VARYING_UNPACK(v_rampColor, half4); + EMIT_FRAG_DATA(v_rampColor); +} +#endif diff --git a/third_party/rive_renderer/source/shaders/common.glsl b/third_party/rive_renderer/source/shaders/common.glsl new file mode 100644 index 0000000..4a6fc78 --- /dev/null +++ b/third_party/rive_renderer/source/shaders/common.glsl @@ -0,0 +1,328 @@ +/* + * Copyright 2022 Rive + */ + +// Common definitions and functions shared by multiple shaders. + +#define PI 3.14159265359 +#define _2PI 6.28318530718 +#define PI_OVER_2 1.57079632679 +#define ONE_OVER_SQRT_2 0.70710678118 // 1/sqrt(2) + +#ifndef @RENDER_MODE_MSAA +#define AA_RADIUS float(.5) +#else +#define AA_RADIUS float(.0) +#endif + +// Defined as a macro because 'uniforms' isn't always available at global scope. +#define RENDER_TARGET_COORD_TO_CLIP_COORD(COORD) \ + pixel_coord_to_clip_coord(COORD, \ + uniforms.renderTargetInverseViewportX, \ + uniforms.renderTargetInverseViewportY) + +#ifdef @TESS_TEXTURE_FLOATING_POINT +#define TEXTURE_TESSDATA4(SET, IDX, NAME) TEXTURE_RGBA32F(SET, IDX, NAME) +#define TESSDATA4 float4 +#define FLOAT_AS_TESSDATA(X) X +#define TESSDATA_AS_FLOAT(X) X +#define UINT_AS_TESSDATA(X) uintBitsToFloat(X) +#define TESSDATA_AS_UINT(X) floatBitsToUint(X) +#else +#define TEXTURE_TESSDATA4(SET, IDX, NAME) TEXTURE_RGBA32UI(SET, IDX, NAME) +#define TESSDATA4 uint4 +#define FLOAT_AS_TESSDATA(X) floatBitsToUint(X) +#define TESSDATA_AS_FLOAT(X) uintBitsToFloat(X) +#define UINT_AS_TESSDATA(X) X +#define TESSDATA_AS_UINT(X) X +#endif + +// This is a macro because we can't (at least for now) forward texture refs to a +// function in a way that works in all the languages we support. +// This is a macro because we can't (at least for now) forward texture refs to a +// function in a way that works in all the languages we support. +#define FEATHER(X) \ + TEXTURE_SAMPLE_LOD_1D_ARRAY(@featherTexture, \ + featherSampler, \ + X, \ + FEATHER_FUNCTION_ARRAY_INDEX, \ + float(FEATHER_FUNCTION_ARRAY_INDEX), \ + .0) \ + .r +#define INVERSE_FEATHER(X) \ + TEXTURE_SAMPLE_LOD_1D_ARRAY(@featherTexture, \ + featherSampler, \ + X, \ + FEATHER_INVERSE_FUNCTION_ARRAY_INDEX, \ + float(FEATHER_INVERSE_FUNCTION_ARRAY_INDEX), \ + .0) \ + .r + +#ifdef GLSL +// GLSL has different semantics around precision. Normalize type conversions +// across languages with "cast_*_to_*()" methods. +INLINE half cast_float_to_half(float x) { return x; } +INLINE half cast_uint_to_half(uint x) { return float(x); } +INLINE half cast_ushort_to_half(ushort x) { return float(x); } +INLINE half cast_int_to_half(int x) { return float(x); } +INLINE half4 cast_float4_to_half4(float4 xyzw) { return xyzw; } +INLINE half2 cast_float2_to_half2(float2 xy) { return xy; } +INLINE half4 cast_uint4_to_half4(uint4 xyzw) { return vec4(xyzw); } +INLINE ushort cast_half_to_ushort(half x) { return uint(x); } +INLINE ushort cast_uint_to_ushort(uint x) { return x; } +#else +INLINE half cast_float_to_half(float x) { return (half)x; } +INLINE half cast_uint_to_half(uint x) { return (half)x; } +INLINE half cast_ushort_to_half(ushort x) { return (half)x; } +INLINE half cast_int_to_half(int x) { return (half)x; } +INLINE half4 cast_float4_to_half4(float4 xyzw) { return (half4)xyzw; } +INLINE half2 cast_float2_to_half2(float2 xy) { return (half2)xy; } +INLINE half4 cast_uint4_to_half4(uint4 xyzw) { return (half4)xyzw; } +INLINE ushort cast_half_to_ushort(half x) { return (ushort)x; } +INLINE ushort cast_uint_to_ushort(uint x) { return (ushort)x; } +#endif + +INLINE half make_half(half x) { return x; } + +INLINE half2 make_half2(half2 xy) { return xy; } + +INLINE half2 make_half2(half x, half y) +{ + half2 ret; + ret.x = x, ret.y = y; + return ret; +} + +INLINE half2 make_half2(half x) +{ + half2 ret; + ret.x = x, ret.y = x; + return ret; +} + +INLINE float2 make_float2(float x) { return float2(x, x); } + +INLINE half3 make_half3(half x, half y, half z) +{ + half3 ret; + ret.x = x, ret.y = y, ret.z = z; + return ret; +} + +INLINE half3 make_half3(half x) +{ + half3 ret; + ret.x = x, ret.y = x, ret.z = x; + return ret; +} + +INLINE half4 make_half4(half x, half y, half z, half w) +{ + half4 ret; + ret.x = x, ret.y = y, ret.z = z, ret.w = w; + return ret; +} + +INLINE half4 make_half4(half3 xyz, half w) +{ + half4 ret; + ret.xyz = xyz; + ret.w = w; + return ret; +} + +INLINE half4 make_half4(half x) +{ + half4 ret; + ret.x = x, ret.y = x, ret.z = x, ret.w = x; + return ret; +} + +INLINE bool2 make_bool2(bool b) { return bool2(b, b); } + +INLINE half3x3 make_half3x3(half3 a, half3 b, half3 c) +{ + half3x3 ret; + ret[0] = a; + ret[1] = b; + ret[2] = c; + return ret; +} + +INLINE half2x3 make_half2x3(half3 a, half3 b) +{ + half2x3 ret; + ret[0] = a; + ret[1] = b; + return ret; +} + +INLINE float2x2 make_float2x2(float4 x) { return float2x2(x.xy, x.zw); } + +INLINE uint make_uint(ushort x) { return x; } + +INLINE uint contour_data_idx(uint contourIDWithFlags) +{ + return (contourIDWithFlags & CONTOUR_ID_MASK) - 1u; +} + +INLINE float2 unchecked_mix(float2 a, float2 b, float t) +{ + return (b - a) * t + a; +} + +INLINE half id_bits_to_f16(uint idBits, uint pathIDGranularity) +{ + return idBits == 0u + ? .0 + : unpackHalf2x16((idBits + MAX_DENORM_F16) * pathIDGranularity) + .r; +} + +INLINE float atan2(float2 v) +{ + v = normalize(v); + float theta = acos(clamp(v.x, -1., 1.)); + return v.y >= .0 ? theta : -theta; +} + +INLINE half4 premultiply(half4 color) +{ + return make_half4(color.rgb * color.a, color.a); +} + +INLINE half3 unmultiply_rgb(half4 premul) +{ + // We *could* return preciesly 1 when premul.rgb == premul.a, but we can + // also be approximate here. The blend modes that depend on this exact level + // of precision (colordodge and colorburn) account for it with dstPremul. + return premul.rgb * (premul.a != .0 ? 1. / premul.a : .0); +} + +INLINE half min_value(half4 min4) +{ + half2 min2 = min(min4.xy, min4.zw); + half min1 = min(min2.x, min2.y); + return min1; +} + +INLINE float manhattan_width(float2 x) { return abs(x.x) + abs(x.y); } + +#ifndef $UNIFORM_DEFINITIONS_AUTO_GENERATED +UNIFORM_BLOCK_BEGIN(FLUSH_UNIFORM_BUFFER_IDX, @FlushUniforms) +float gradInverseViewportY; +float tessInverseViewportY; +float renderTargetInverseViewportX; +float renderTargetInverseViewportY; +uint renderTargetWidth; +uint renderTargetHeight; +uint colorClearValue; // Only used if clears are implemented as draws. +uint coverageClearValue; // Only used if clears are implemented as draws. +int4 renderTargetUpdateBounds; // drawBounds, or renderTargetBounds if there is + // a clear. (LTRB.) +float2 atlasTextureInverseSize; // 1 / [atlasWidth, atlasHeight] +float2 atlasContentInverseViewport; // 2 / atlasContentBounds +uint coverageBufferPrefix; +uint pathIDGranularity; // Spacing between adjacent path IDs (1 if IEEE + // compliant). +float vertexDiscardValue; +// Debugging. +uint wireframeEnabled; +UNIFORM_BLOCK_END(uniforms) +#endif + +#ifdef @VERTEX + +INLINE float4 pixel_coord_to_clip_coord(float2 pixelCoord, + float inverseViewportX, + float inverseViewportY) +{ + return float4(pixelCoord.x * inverseViewportX - 1., + pixelCoord.y * inverseViewportY - sign(inverseViewportY), + 0., + 1.); +} + +#ifndef @RENDER_MODE_MSAA +// Calculates the Manhattan distance in pixels from the given pixelPosition, to +// the point at each edge of the clipRect where coverage = 0. +// +// clipRectInverseMatrix transforms from pixel coordinates to a space where the +// clipRect is the normalized rectangle: [-1, -1, 1, 1]. +INLINE float4 find_clip_rect_coverage_distances(float2x2 clipRectInverseMatrix, + float2 clipRectInverseTranslate, + float2 pixelPosition) +{ + float2 clipRectAAWidth = + abs(clipRectInverseMatrix[0]) + abs(clipRectInverseMatrix[1]); + if (clipRectAAWidth.x != .0 && clipRectAAWidth.y != .0) + { + float2 r = 1. / clipRectAAWidth; + float2 clipRectCoord = MUL(clipRectInverseMatrix, pixelPosition) + + clipRectInverseTranslate; + // When the center of a pixel falls exactly on an edge, coverage should + // be .5. + const float coverageWhenDistanceIsZero = .5; + return float4(clipRectCoord, -clipRectCoord) * r.xyxy + r.xyxy + + coverageWhenDistanceIsZero; + } + else + { + // The caller gave us a singular clipRectInverseMatrix. This is a + // special case where we are expected to use tx and ty as uniform + // coverage. + return clipRectInverseTranslate.xyxy; + } +} + +#else // RENDER_MODE_MSAA + +INLINE float normalize_z_index(uint zIndex) +{ + return 1. - float(zIndex) * (2. / 32768.); +} + +#ifdef @ENABLE_CLIP_RECT +INLINE void set_clip_rect_plane_distances(float2x2 clipRectInverseMatrix, + float2 clipRectInverseTranslate, + float2 pixelPosition) +{ + if (clipRectInverseMatrix != float2x2(0)) + { + float2 clipRectCoord = MUL(clipRectInverseMatrix, pixelPosition) + + clipRectInverseTranslate.xy; + gl_ClipDistance[0] = clipRectCoord.x + 1.; + gl_ClipDistance[1] = clipRectCoord.y + 1.; + gl_ClipDistance[2] = 1. - clipRectCoord.x; + gl_ClipDistance[3] = 1. - clipRectCoord.y; + } + else + { + // "clipRectInverseMatrix == 0" is a special case: + // "clipRectInverseTranslate.x == 1" => all in. + // "clipRectInverseTranslate.x == 0" => all out. + gl_ClipDistance[0] = gl_ClipDistance[1] = gl_ClipDistance[2] = + gl_ClipDistance[3] = clipRectInverseTranslate.x - .5; + } +} +#endif // ENABLE_CLIP_RECT +#endif // RENDER_MODE_MSAA +#endif // VERTEX + +#ifdef @DRAW_IMAGE +#ifndef $UNIFORM_DEFINITIONS_AUTO_GENERATED +UNIFORM_BLOCK_BEGIN(IMAGE_DRAW_UNIFORM_BUFFER_IDX, @ImageDrawUniforms) +float4 viewMatrix; +float2 translate; +float opacity; +float padding; +// clipRectInverseMatrix transforms from pixel coordinates to a space where the +// clipRect is the normalized rectangle: [-1, -1, 1, 1]. +float4 clipRectInverseMatrix; +float2 clipRectInverseTranslate; +uint clipID; +uint blendMode; +uint zIndex; +UNIFORM_BLOCK_END(imageDrawUniforms) +#endif +#endif diff --git a/third_party/rive_renderer/source/shaders/constants.glsl b/third_party/rive_renderer/source/shaders/constants.glsl new file mode 100644 index 0000000..eb5f3c6 --- /dev/null +++ b/third_party/rive_renderer/source/shaders/constants.glsl @@ -0,0 +1,242 @@ +/* + * Copyright 2022 Rive + */ + +#define TESS_TEXTURE_WIDTH float(2048) +#define TESS_TEXTURE_WIDTH_LOG2 11 + +#define GRAD_TEXTURE_WIDTH float(512) +#define GRAD_TEXTURE_INVERSE_WIDTH float(0.001953125) + +// Number of standard deviations on either side of the middle of the feather +// texture. The feather texture integrates the normal distribution from +// -FEATHER_TEXTURE_STDDEVS to +FEATHER_TEXTURE_STDDEVS in the domain x=0..1. +#define FEATHER_TEXTURE_STDDEVS float(3) + +// Indices of function tables in the feather texture1d array. +// NOTE: This will be a texture2d if texture1d isn't supported. +#define FEATHER_FUNCTION_ARRAY_INDEX 0 +#define FEATHER_INVERSE_FUNCTION_ARRAY_INDEX 1 +#define FEATHER_TEXTURE_1D_ARRAY_LENGTH 2 + +// Number of additional tessellation "helper" vertices that need to be allocated +// for a feather join. +#define FEATHER_JOIN_HELPER_VERTEX_COUNT 3u + +// Amount to increase "joinSegmentCount" in a feather join so the number of +// literal vertices allocated increases by FEATHER_JOIN_HELPER_VERTEX_COUNT. +#define FEATHER_JOIN_HELPER_SEGMENT_COUNT \ + (FEATHER_JOIN_HELPER_VERTEX_COUNT + 1u) + +// Feather joins are split into a backward and forward section. Both sections +// need at least one segment, thus a minimum of 2 (plus helper vertices). +#define FEATHER_JOIN_MIN_SEGMENT_COUNT (2u + FEATHER_JOIN_HELPER_SEGMENT_COUNT) + +// Width to use for a texture that emulates a storage buffer. +// +// Minimize width since the texture needs to be updated in entire rows from the +// resource buffer. Since these only serve paths and contours, both of those are +// limited to 16-bit indices, 2048 is the min specified texture size in ES3, and +// no path buffer uses more than 4 texels, we can safely use a width of 128. +#define STORAGE_TEXTURE_WIDTH 128 +#define STORAGE_TEXTURE_SHIFT_Y 7 +#define STORAGE_TEXTURE_MASK_X 0x7fu + +// Flags that state whether/how we need to render solid-color borders to the +// left and/or right side of a GradientSpan. (Borders of complex gradients +// stretch all the way to the left/right edges of the texture, whereas borders +// of simple gradients just need to stretch 1px to the left/right of the +// span.) +#define GRAD_SPAN_FLAG_LEFT_BORDER 0x80000000u +#define GRAD_SPAN_FLAG_RIGHT_BORDER 0x40000000u +#define GRAD_SPAN_FLAG_COMPLEX_BORDER 0x20000000u +#define GRAD_SPAN_FLAGS_MASK \ + (GRAD_SPAN_FLAG_LEFT_BORDER | GRAD_SPAN_FLAG_RIGHT_BORDER | \ + GRAD_SPAN_FLAG_COMPLEX_BORDER) + +// Tells shaders that a cubic should actually be drawn as the single, non-AA +// triangle: [p0, p1, p3]. This is used to squeeze in more rare triangles, like +// "grout" triangles from self intersections on interior triangulation, where it +// wouldn't be worth it to put them in their own dedicated draw call. +#define RETROFITTED_TRIANGLE_CONTOUR_FLAG (1u << 31u) + +// Skip bit 30 in the contour flags so that it's always 0. This ensures we never +// generate special NaN/Inf floating point values in contourIDWithFlags, which +// may confuse the driver. +#define NEVER_USED_CONTOUR_FLAG (1u << 30u) + +// Tells the tessellation shader to re-run Wang's formula on the given curve, +// figure out how many segments it actually needs, and make any excess segments +// degenerate by co-locating their vertices at T=0. (Used on the "outerCurve" +// patches that are drawn with interior triangulations.) +#define CULL_EXCESS_TESSELLATION_SEGMENTS_CONTOUR_FLAG (1u << 29u) + +// Flags for specifying the join type. +#define JOIN_TYPE_MASK (7u << 26u) +#define MITER_CLIP_JOIN_CONTOUR_FLAG (5u << 26u) +#define MITER_REVERT_JOIN_CONTOUR_FLAG (4u << 26u) +#define BEVEL_JOIN_CONTOUR_FLAG (3u << 26u) +#define ROUND_JOIN_CONTOUR_FLAG (2u << 26u) +#define FEATHER_JOIN_CONTOUR_FLAG (1u << 26u) + +// When a join is being used to emulate a stroke cap, the shader emits +// additional vertices at T=0 and T=1 for round joins, and changes the miter +// limit to 1 for miter-clip joins. +#define EMULATED_STROKE_CAP_CONTOUR_FLAG (1u << 25u) + +// Flip the sign on interpolated fragment coverage for fills. Ignored on +// strokes. This is used when reversing the winding direction of a path. +#define NEGATE_PATH_FILL_COVERAGE_FLAG (1u << 24u) + +// Internal contour flags. +#define MIRRORED_CONTOUR_CONTOUR_FLAG (1u << 23u) +#define JOIN_TANGENT_0_CONTOUR_FLAG (1u << 22u) +#define JOIN_TANGENT_INNER_CONTOUR_FLAG (1u << 21u) +#define LEFT_JOIN_CONTOUR_FLAG (1u << 20u) +#define RIGHT_JOIN_CONTOUR_FLAG (1u << 19u) +#define CONTOUR_ID_MASK 0xffffu + +// This is guaranteed to not collide with a neighboring contour ID. +#define INVALID_CONTOUR_ID_WITH_FLAGS 0u + +// Says which part of the patch a vertex belongs to. +#define STROKE_VERTEX 0 +#define FAN_VERTEX 1 +#define FAN_MIDPOINT_VERTEX 2 + +// Says which part of the patch a vertex belongs to. +#define STROKE_VERTEX 0 +#define FAN_VERTEX 1 +#define FAN_MIDPOINT_VERTEX 2 + +// Mirrors pls::PaintType. +#define CLIP_UPDATE_PAINT_TYPE 0u +#define SOLID_COLOR_PAINT_TYPE 1u +#define LINEAR_GRADIENT_PAINT_TYPE 2u +#define RADIAL_GRADIENT_PAINT_TYPE 3u +#define IMAGE_PAINT_TYPE 4u + +// Paint flags, found in the x-component value of @paintBuffer. +#define PAINT_FLAG_NON_ZERO_FILL 0x100u +#define PAINT_FLAG_EVEN_ODD_FILL 0x200u +#define PAINT_FLAG_HAS_CLIP_RECT 0x400u + +// PLS draw resources are either updated per flush or per draw. They go into set +// 0 or set 1, depending on how often they are updated. +#define PER_FLUSH_BINDINGS_SET 0 +#define PER_DRAW_BINDINGS_SET 1 + +// Index at which we access each resource. +// (Enumerate buffers first because GLES allows a hard limit on buffer index +// bindings as low as 7.) +#define FLUSH_UNIFORM_BUFFER_IDX 0 +#define PATH_BASE_INSTANCE_UNIFORM_BUFFER_IDX 1 +#define IMAGE_DRAW_UNIFORM_BUFFER_IDX 2 +#define PATH_BUFFER_IDX 3 +#define PAINT_BUFFER_IDX 4 +#define PAINT_AUX_BUFFER_IDX 5 +#define CONTOUR_BUFFER_IDX 6 +// Coverage buffer used in coverageAtomic mode. +#define COVERAGE_BUFFER_IDX 7 +#define TESS_VERTEX_TEXTURE_IDX 8 +#define GRAD_TEXTURE_IDX 9 +#define FEATHER_TEXTURE_IDX 10 +#define ATLAS_TEXTURE_IDX 11 +#define IMAGE_TEXTURE_IDX 12 +#define IMAGE_SAMPLER_IDX 13 +#define DST_COLOR_TEXTURE_IDX 14 +#define DEFAULT_BINDINGS_SET_SIZE 15 + +// Metal doesn't allow us to bind buffers index 0 or 1. Offset them by 2. +#define METAL_BUFFER_IDX(IDX) (2 + IDX) + +// Samplers are accessed at the same index as their corresponding texture, so we +// put them in a separate binding set. +#define IMMUTABLE_SAMPLER_BINDINGS_SET 2 + +// PLS textures are accessed at the same index as their PLS planes, so we put +// them in a separate binding set. +#define PLS_TEXTURE_BINDINGS_SET 3 + +#define BINDINGS_SET_COUNT 4 + +// Index of each pixel local storage plane. +#define COLOR_PLANE_IDX 0 +#define CLIP_PLANE_IDX 1 +#define SCRATCH_COLOR_PLANE_IDX 2 +#define COVERAGE_PLANE_IDX 3 +#define PLS_PLANE_COUNT 4 +#define DEPTH_STENCIL_IDX PLS_PLANE_COUNT + +// Rive has a hard-coded miter limit of 4 in the editor and all runtimes. +#define RIVE_MITER_LIMIT float(4) +// acos(1/4), because the miter limit is 4. +#define MITER_ANGLE_LIMIT float(1.318116071652817965746) + +// Raw bit representation of the largest denormalized fp16 value. We offset all +// (1-based) path IDs by this value in order to avoid denorms, which have been +// empirically unreliable on Android as ID values. +#define MAX_DENORM_F16 1023u + +// Blend modes. Mirrors rive::BlendMode, but 0-based and contiguous for tighter +// packing. +#define BLEND_SRC_OVER 0u +#define BLEND_MODE_SCREEN 1u +#define BLEND_MODE_OVERLAY 2u +#define BLEND_MODE_DARKEN 3u +#define BLEND_MODE_LIGHTEN 4u +#define BLEND_MODE_COLORDODGE 5u +#define BLEND_MODE_COLORBURN 6u +#define BLEND_MODE_HARDLIGHT 7u +#define BLEND_MODE_SOFTLIGHT 8u +#define BLEND_MODE_DIFFERENCE 9u +#define BLEND_MODE_EXCLUSION 10u +#define BLEND_MODE_MULTIPLY 11u +#define BLEND_MODE_HUE 12u +#define BLEND_MODE_SATURATION 13u +#define BLEND_MODE_COLOR 14u +#define BLEND_MODE_LUMINOSITY 15u + +// Fixed-point coverage values for atomic mode. +// Atomic mode uses 6:11 fixed point, so the winding number breaks if a shape +// has more than 32 levels of self overlap in either winding direction at any +// point. +#define FIXED_COVERAGE_PRECISION float(2048) +#define FIXED_COVERAGE_INVERSE_PRECISION float(0.00048828125) +#define FIXED_COVERAGE_ZERO float(1 << 16) +#define FIXED_COVERAGE_ZERO_UINT (1u << 16) +#define FIXED_COVERAGE_ONE (FIXED_COVERAGE_PRECISION + FIXED_COVERAGE_ZERO) +#define FIXED_COVERAGE_BIT_COUNT 17u +#define FIXED_COVERAGE_MASK 0x1ffffu + +// Fixed-point coverage values for clockwiseAtomic mode. +// clockwiseAtomic mode uses 6:11 fixed point, so the winding number breaks if a +// shape has more than 32 levels of self overlap in either winding direction at +// any point. +#define CLOCKWISE_COVERAGE_BIT_COUNT 17u +#define CLOCKWISE_COVERAGE_MASK 0x1ffffu +#define CLOCKWISE_COVERAGE_PRECISION float(2048) +#define CLOCKWISE_COVERAGE_INVERSE_PRECISION float(0.00048828125) +#define CLOCKWISE_FILL_ZERO_VALUE (1u << 16) + +// Vendor IDs for driver workarounds. +#define VULKAN_VENDOR_AMD 0x1002u +#define VULKAN_VENDOR_IMG_TEC 0x1010u +#define VULKAN_VENDOR_NVIDIA 0x10DEu +#define VULKAN_VENDOR_ARM 0x13B5u +#define VULKAN_VENDOR_QUALCOMM 0x5143u +#define VULKAN_VENDOR_INTEL 0x8086u + +// Indices for SPIRV specialization constants (used in lieu of #defines in +// Vulkan.) +#define CLIPPING_SPECIALIZATION_IDX 0 +#define CLIP_RECT_SPECIALIZATION_IDX 1 +#define ADVANCED_BLEND_SPECIALIZATION_IDX 2 +#define FEATHER_SPECIALIZATION_IDX 3 +#define EVEN_ODD_SPECIALIZATION_IDX 4 +#define NESTED_CLIPPING_SPECIALIZATION_IDX 5 +#define HSL_BLEND_MODES_SPECIALIZATION_IDX 6 +#define CLOCKWISE_FILL_SPECIALIZATION_IDX 7 +#define BORROWED_COVERAGE_PREPASS_SPECIALIZATION_IDX 8 +#define VULKAN_VENDOR_ID_SPECIALIZATION_IDX 9 +#define SPECIALIZATION_COUNT 10 diff --git a/third_party/rive_renderer/source/shaders/d3d/color_ramp.hlsl_ b/third_party/rive_renderer/source/shaders/d3d/color_ramp.hlsl_ new file mode 100644 index 0000000..4a56bef --- /dev/null +++ b/third_party/rive_renderer/source/shaders/d3d/color_ramp.hlsl_ @@ -0,0 +1,4 @@ +#include "hlsl.minified.glsl" +#include "constants.minified.glsl" +#include "common.minified.glsl" +#include "color_ramp.minified.glsl" \ No newline at end of file diff --git a/third_party/rive_renderer/source/shaders/d3d/render_atlas.hlsl_ b/third_party/rive_renderer/source/shaders/d3d/render_atlas.hlsl_ new file mode 100644 index 0000000..669112d --- /dev/null +++ b/third_party/rive_renderer/source/shaders/d3d/render_atlas.hlsl_ @@ -0,0 +1,8 @@ +#define DRAW_PATH +#define ENABLE_FEATHER + +#include "hlsl.minified.glsl" +#include "constants.minified.glsl" +#include "common.minified.glsl" +#include "draw_path_common.minified.glsl" +#include "render_atlas.minified.glsl" \ No newline at end of file diff --git a/third_party/rive_renderer/source/shaders/d3d/root.sig_ b/third_party/rive_renderer/source/shaders/d3d/root.sig_ new file mode 100644 index 0000000..ea04d87 --- /dev/null +++ b/third_party/rive_renderer/source/shaders/d3d/root.sig_ @@ -0,0 +1,93 @@ +// d3d12 has the concept of descriptor heaps. +// This means we define the "slot" in our root +// signature and then offset our heap to represent positions in that signature. +// These are the offsets needed for each shader resource +// note: rtv's are not considered shader resource but they are a heap + +// all srv and uav are one heap. +// srv +// these are dynamic +#define PATH_BUFFER_HEAP_OFFSET 0 +#define PAINT_BUFFER_HEAP_OFFSET 1 +#define PAINT_AUX_BUFFER_HEAP_OFFSET 2 +#define CONTOUR_BUFFER_HEAP_OFFSET 3 +// these are static +#define TESS_IMAGE_HEAP_OFFSET 4 +#define GRAD_IMAGE_HEAP_OFFSET 5 +#define FEATHER_IMAGE_HEAP_OFFSET 6 +#define ATLAS_IMAGE_HEAP_OFFSET 7 +// uavs +#define ATOMIC_COLOR_HEAP_OFFSET 8 +#define ATOMIC_CLIP_HEAP_OFFSET 9 +#define ATOMIC_SCRATCH_COLOR_HEAP_OFFSET 10 +#define ATOMIC_COVERAGE_HEAP_OFFSET 11 +// images +#define IMAGE_HEAP_OFFSET_START 12 + +#define STATIC_SRV_UAV_HEAP_DESCRIPTOPR_START TESS_IMAGE_HEAP_OFFSET +#define DYNAMIC_SRV_UAV_HEAP_DESCRIPTOPR_START PATH_BUFFER_HEAP_OFFSET + +// this is for copies that happen every logical flush +#define NUM_DYNAMIC_SRV_HEAP_DESCRIPTORS CONTOUR_BUFFER_HEAP_OFFSET + 1 +#define NUM_SRV_HEAP_DESCRIPTORS ATLAS_IMAGE_HEAP_OFFSET + 1 +// this is for the first flush where we copy everything the things that don't +// change only once +#define NUM_STATIC_SRV_UAV_HEAP_DESCRIPTORS \ + ATOMIC_COVERAGE_HEAP_OFFSET - NUM_DYNAMIC_SRV_HEAP_DESCRIPTORS + +#define NUM_SRV_UAV_HEAP_DESCRIPTORS IMAGE_HEAP_OFFSET_START + 1 + +// all samplers are another heap +#define TESS_SAMPLER_HEAP_OFFSET 0 +#define GRAD_SAMPLER_HEAP_OFFSET 1 +#define FEATHER_SAMPLER_HEAP_OFFSET 2 +#define ATLAS_SAMPLER_HEAP_OFFSET 3 +#define IMAGE_SAMPLER_HEAP_OFFSET 4 + +#define NUM_SAMPLER_HEAP_DESCRIPTORS IMAGE_SAMPLER_HEAP_OFFSET + 1 +// constant buffers are bound directly to the sig so we can change it out as we +// go, to change a heap we would have to create a new one and use SetHeaps which +// is very slow +#define FLUSH_UNIFORM_BUFFFER_SIG_INDEX 0 +#define IMAGE_UNIFORM_BUFFFER_SIG_INDEX 1 +#define VERTEX_DRAW_UNIFORM_SIG_INDEX 2 +#define DYNAMIC_SRV_SIG_INDEX 3 +#define STATIC_SRV_SIG_INDEX 4 +#define IMAGE_SIG_INDEX 5 +#define UAV_SIG_INDEX 6 +#define SAMPLER_SIG_INDEX 7 +#define DYNAMIC_SAMPLER_SIG_INDEX 8 + +#define SRV_START_HEAP_INDEX PATH_BUFFER_HEAP_OFFSET +#define UAV_START_HEAP_INDEX ATOMIC_COLOR_HEAP_OFFSET +// samplers just start at 0 + +// rtv offsets +#define GRAD_RTV_HEAP_OFFSET 0 +#define TESS_RTV_HEAP_OFFSET 1 +#define ATLAS_RTV_HEAP_OFFSET 2 +#define TARGET_RTV_HEAP_OFFSET 3 + +// The root signature macro doesn't seem to support string splicing. We need to manually ensure the numbers here stay in sync with the above definitions. +#define ROOT_SIG "RootFlags(ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT), " \ + "CBV(b0, flags=DATA_VOLATILE, visibility=SHADER_VISIBILITY_ALL), "\ + "CBV(b2, flags=DATA_VOLATILE, visibility=SHADER_VISIBILITY_ALL), "\ + "RootConstants(num32BitConstants=1, b1, visibility=SHADER_VISIBILITY_VERTEX), "\ + "DescriptorTable(SRV(t3), "\ + "SRV(t4),"\ + "SRV(t5),"\ + "SRV(t6), visibility=SHADER_VISIBILITY_ALL), "\ + "DescriptorTable(SRV(t8, flags=DESCRIPTORS_VOLATILE),"\ + "SRV(t9, flags=DESCRIPTORS_VOLATILE), "\ + "SRV(t10, flags=DESCRIPTORS_VOLATILE), " \ + "SRV(t11, flags=DESCRIPTORS_VOLATILE), visibility=SHADER_VISIBILITY_ALL), "\ + "DescriptorTable(SRV(t12, flags=DESCRIPTORS_VOLATILE), visibility=SHADER_VISIBILITY_PIXEL), "\ + "DescriptorTable(UAV(u0, flags=DESCRIPTORS_VOLATILE | DATA_VOLATILE),"\ + "UAV(u1, flags=DATA_VOLATILE),"\ + "UAV(u2, flags=DESCRIPTORS_VOLATILE | DATA_VOLATILE),"\ + "UAV(u3, flags=DATA_VOLATILE), visibility=SHADER_VISIBILITY_PIXEL),"\ + "DescriptorTable(Sampler(s8),"\ + "Sampler(s9),"\ + "Sampler(s10),"\ + "Sampler(s11), visibility=SHADER_VISIBILITY_ALL),"\ + "DescriptorTable(Sampler(s13, flags=DESCRIPTORS_VOLATILE), visibility=SHADER_VISIBILITY_PIXEL) " diff --git a/third_party/rive_renderer/source/shaders/d3d/tessellate.hlsl_ b/third_party/rive_renderer/source/shaders/d3d/tessellate.hlsl_ new file mode 100644 index 0000000..c4b8324 --- /dev/null +++ b/third_party/rive_renderer/source/shaders/d3d/tessellate.hlsl_ @@ -0,0 +1,5 @@ +#include "hlsl.minified.glsl" +#include "constants.minified.glsl" +#include "common.minified.glsl" +#include "bezier_utils.minified.glsl" +#include "tessellate.minified.glsl" \ No newline at end of file diff --git a/third_party/rive_renderer/source/shaders/draw_clockwise_image_mesh.glsl b/third_party/rive_renderer/source/shaders/draw_clockwise_image_mesh.glsl new file mode 100644 index 0000000..a8855c4 --- /dev/null +++ b/third_party/rive_renderer/source/shaders/draw_clockwise_image_mesh.glsl @@ -0,0 +1,69 @@ +/* + * Copyright 2024 Rive + */ + +#ifdef @VERTEX +ATTR_BLOCK_BEGIN(PositionAttr) +ATTR(0, float2, @a_position); +ATTR_BLOCK_END + +ATTR_BLOCK_BEGIN(UVAttr) +ATTR(1, float2, @a_texCoord); +ATTR_BLOCK_END +#endif + +VARYING_BLOCK_BEGIN +NO_PERSPECTIVE VARYING(0, float2, v_texCoord); +VARYING_BLOCK_END + +#ifdef @VERTEX +VERTEX_TEXTURE_BLOCK_BEGIN +VERTEX_TEXTURE_BLOCK_END + +IMAGE_MESH_VERTEX_MAIN(@drawVertexMain, + PositionAttr, + position, + UVAttr, + uv, + _vertexID) +{ + ATTR_UNPACK(_vertexID, position, @a_position, float2); + ATTR_UNPACK(_vertexID, uv, @a_texCoord, float2); + + VARYING_INIT(v_texCoord, float2); + + float2 vertexPosition = + MUL(make_float2x2(imageDrawUniforms.viewMatrix), @a_position) + + imageDrawUniforms.translate; + v_texCoord = @a_texCoord; + float4 pos = RENDER_TARGET_COORD_TO_CLIP_COORD(vertexPosition); + + VARYING_PACK(v_texCoord); + EMIT_VERTEX(pos); +} +#endif + +#ifdef @FRAGMENT +FRAG_TEXTURE_BLOCK_BEGIN +TEXTURE_RGBA8(PER_DRAW_BINDINGS_SET, IMAGE_TEXTURE_IDX, @imageTexture); +FRAG_TEXTURE_BLOCK_END + +DYNAMIC_SAMPLER_BLOCK_BEGIN +SAMPLER_DYNAMIC(IMAGE_SAMPLER_IDX, imageSampler) +DYNAMIC_SAMPLER_BLOCK_END + +FRAG_STORAGE_BUFFER_BLOCK_BEGIN +FRAG_STORAGE_BUFFER_BLOCK_END + +FRAG_DATA_MAIN(half4, @drawFragmentMain) +{ + VARYING_UNPACK(v_texCoord, float2); + + half4 meshColor = + TEXTURE_SAMPLE_DYNAMIC(@imageTexture, imageSampler, v_texCoord); + meshColor = make_half4(unmultiply_rgb(meshColor), + meshColor.a * imageDrawUniforms.opacity); + + EMIT_FRAG_DATA(meshColor); +} +#endif // FRAGMENT diff --git a/third_party/rive_renderer/source/shaders/draw_clockwise_path.glsl b/third_party/rive_renderer/source/shaders/draw_clockwise_path.glsl new file mode 100644 index 0000000..62d0d80 --- /dev/null +++ b/third_party/rive_renderer/source/shaders/draw_clockwise_path.glsl @@ -0,0 +1,454 @@ +/* + * Copyright 2023 Rive + */ + +#ifdef @DRAW_PATH +#ifdef @VERTEX +ATTR_BLOCK_BEGIN(Attrs) +// [localVertexID, outset, fillCoverage, vertexType] +ATTR(0, float4, @a_patchVertexData); +ATTR(1, float4, @a_mirroredVertexData); +ATTR_BLOCK_END +#endif + +VARYING_BLOCK_BEGIN +FLAT VARYING(0, ushort, v_pathID); +NO_PERSPECTIVE VARYING(1, float4, v_coverages); +NO_PERSPECTIVE VARYING(2, float2, v_atlasCoord); +FLAT VARYING(3, uint2, v_coveragePlacement); +VARYING(4, float2, v_coverageCoord); +VARYING_BLOCK_END + +#ifdef @VERTEX +VERTEX_MAIN(@drawVertexMain, Attrs, attrs, _vertexID, _instanceID) +{ + ATTR_UNPACK(_vertexID, attrs, @a_patchVertexData, float4); + ATTR_UNPACK(_vertexID, attrs, @a_mirroredVertexData, float4); + + VARYING_INIT(v_pathID, ushort); + VARYING_INIT(v_coverages, float4); + VARYING_INIT(v_coveragePlacement, uint2); + VARYING_INIT(v_coverageCoord, float2); + + float4 pos; + uint pathID; + float2 vertexPosition; + if (unpack_tessellated_path_vertex(@a_patchVertexData, + @a_mirroredVertexData, + _instanceID, + pathID, + vertexPosition, + v_coverages VERTEX_CONTEXT_UNPACK)) + { + uint4 coverageData = + STORAGE_BUFFER_LOAD4(@pathBuffer, pathID * 4u + 3u); + v_pathID = pathID; + v_coveragePlacement = coverageData.xy; + v_coverageCoord = vertexPosition + uintBitsToFloat(coverageData.zw); + pos = RENDER_TARGET_COORD_TO_CLIP_COORD(vertexPosition); + } + else + { + pos = float4(uniforms.vertexDiscardValue, + uniforms.vertexDiscardValue, + uniforms.vertexDiscardValue, + uniforms.vertexDiscardValue); + } + + VARYING_PACK(v_pathID); + VARYING_PACK(v_coverages); + VARYING_PACK(v_coveragePlacement); + VARYING_PACK(v_coverageCoord); + EMIT_VERTEX(pos); +} +#endif // VERTEX +#endif // DRAW_PATH + +#ifdef @DRAW_INTERIOR_TRIANGLES +#ifdef @VERTEX +ATTR_BLOCK_BEGIN(Attrs) +ATTR(0, packed_float3, @a_triangleVertex); +ATTR_BLOCK_END +#endif + +VARYING_BLOCK_BEGIN +FLAT VARYING(0, ushort, v_pathID); +#ifdef @ATLAS_BLIT +NO_PERSPECTIVE VARYING(1, float2, v_atlasCoord); +#else +@OPTIONALLY_FLAT VARYING(1, half, v_windingWeight); +FLAT VARYING(2, uint2, v_coveragePlacement); +VARYING(3, float2, v_coverageCoord); +#endif +VARYING_BLOCK_END + +#ifdef @VERTEX +VERTEX_MAIN(@drawVertexMain, Attrs, attrs, _vertexID, _instanceID) +{ + ATTR_UNPACK(_vertexID, attrs, @a_triangleVertex, float3); + +#ifdef @ATLAS_BLIT + VARYING_INIT(v_atlasCoord, float2); +#else +#endif + VARYING_INIT(v_pathID, ushort); +#ifdef @ATLAS_BLIT + VARYING_INIT(v_atlasCoord, float2); +#else + VARYING_INIT(v_windingWeight, half); + VARYING_INIT(v_coveragePlacement, uint2); + VARYING_INIT(v_coverageCoord, float2); +#endif + + uint pathID; + float2 vertexPosition; +#ifdef @ATLAS_BLIT + vertexPosition = + unpack_atlas_coverage_vertex(@a_triangleVertex, + pathID, + v_atlasCoord VERTEX_CONTEXT_UNPACK); +#else + vertexPosition = + unpack_interior_triangle_vertex(@a_triangleVertex, + pathID, + v_windingWeight VERTEX_CONTEXT_UNPACK); + uint4 coverageData = STORAGE_BUFFER_LOAD4(@pathBuffer, pathID * 4u + 3u); + v_coveragePlacement = coverageData.xy; + v_coverageCoord = vertexPosition + uintBitsToFloat(coverageData.zw); +#endif + v_pathID = cast_uint_to_ushort(pathID); + float4 pos = RENDER_TARGET_COORD_TO_CLIP_COORD(vertexPosition); + + VARYING_PACK(v_pathID); +#ifdef @ATLAS_BLIT + VARYING_PACK(v_atlasCoord); +#else + VARYING_PACK(v_windingWeight); + VARYING_PACK(v_coveragePlacement); + VARYING_PACK(v_coverageCoord); +#endif + + EMIT_VERTEX(pos); +} +#endif // VERTEX +#endif // DRAW_INTERIOR_TRIANGLES + +#ifdef @FRAGMENT +FRAG_STORAGE_BUFFER_BLOCK_BEGIN +STORAGE_BUFFER_U32x2(PAINT_BUFFER_IDX, PaintBuffer, @paintBuffer); +STORAGE_BUFFER_F32x4(PAINT_AUX_BUFFER_IDX, PaintAuxBuffer, @paintAuxBuffer); +STORAGE_BUFFER_U32_ATOMIC(COVERAGE_BUFFER_IDX, CoverageBuffer, coverageBuffer); +FRAG_STORAGE_BUFFER_BLOCK_END + +#ifdef @BORROWED_COVERAGE_PREPASS +INLINE void apply_borrowed_coverage(half borrowedCoverage, uint coverageIndex) +{ + // Try to apply borrowedCoverage, assuming the existing coverage value + // is zero. + uint borrowedCoverageFixed = + uint(abs(borrowedCoverage) * CLOCKWISE_COVERAGE_PRECISION + .5); + uint targetCoverageValue = + uniforms.coverageBufferPrefix | + (CLOCKWISE_FILL_ZERO_VALUE - borrowedCoverageFixed); + uint coverageBeforeMax = STORAGE_BUFFER_ATOMIC_MAX(coverageBuffer, + coverageIndex, + targetCoverageValue); + if (coverageBeforeMax >= uniforms.coverageBufferPrefix) + { + // Coverage was not zero. Undo the atomicMax and then subtract + // borrowedCoverageFixed this time. + uint undoAtomicMax = + coverageBeforeMax - max(coverageBeforeMax, targetCoverageValue); + STORAGE_BUFFER_ATOMIC_ADD(coverageBuffer, + coverageIndex, + undoAtomicMax - borrowedCoverageFixed); + } +} +#endif + +INLINE void apply_stroke_coverage(INOUT(float) paintAlpha, + half fragCoverage, + uint coverageIndex) +{ + if (min(paintAlpha, fragCoverage) >= 1.) + { + // Solid stroke pixels don't need to work out coverage at all. We can + // just blast them out without ever touching the coverage buffer. + return; + } + + half X; + uint fragCoverageFixed = + uint(abs(fragCoverage) * CLOCKWISE_COVERAGE_PRECISION + .5); + uint coverageBeforeMax = STORAGE_BUFFER_ATOMIC_MAX( + coverageBuffer, + coverageIndex, + uniforms.coverageBufferPrefix | fragCoverageFixed); + if (coverageBeforeMax < uniforms.coverageBufferPrefix) + { + // This is the first fragment of the stroke to touch this pixel. Just + // multiply in our coverage and write it out. + X = fragCoverage; + } + else + { + // This pixel has been touched previously by a fragment in the stroke. + // Multiply in an incremental coverage value that mixes with what's + // already in the framebuffer. + half c1 = + cast_uint_to_half(coverageBeforeMax & CLOCKWISE_COVERAGE_MASK) * + CLOCKWISE_COVERAGE_INVERSE_PRECISION; + half c2 = max(c1, fragCoverage); + X = (c2 - c1) / (1. - c1 * paintAlpha); + } + + paintAlpha *= X; +} + +INLINE void apply_fill_coverage(INOUT(float) paintAlpha, + half fragCoverageRemaining, + uint coverageIndex) +{ + uint coverageInitialValue = + STORAGE_BUFFER_LOAD(coverageBuffer, coverageIndex); + if (min(paintAlpha, fragCoverageRemaining) >= 1. && + (coverageInitialValue < uniforms.coverageBufferPrefix || + coverageInitialValue >= + (uniforms.coverageBufferPrefix | CLOCKWISE_FILL_ZERO_VALUE))) + { + // If we're solid, AND the current coverage at this pixel is >= 0, then + // we can just write out or color without working out coverage any + // further. + return; + } + + half X = .0; // Amount by which to multiply paintAlpha. + uint fragCoverageRemainingFixed = + uint(abs(fragCoverageRemaining) * CLOCKWISE_COVERAGE_PRECISION + .5); + if (coverageInitialValue < uniforms.coverageBufferPrefix) + { + // The initial coverage value does not belong to this path. We *might* + // be the first fragment of the path to touch this pixel. Attempt to + // write out our coverage with an atomicMax. + uint targetCoverage = + uniforms.coverageBufferPrefix | + (CLOCKWISE_FILL_ZERO_VALUE + fragCoverageRemainingFixed); + uint coverageBeforeMax = STORAGE_BUFFER_ATOMIC_MAX(coverageBuffer, + coverageIndex, + targetCoverage); + if (coverageBeforeMax <= uniforms.coverageBufferPrefix) + { + // Success! We were the first fragment of the path at this pixel. + X = fragCoverageRemaining; // Just multiply paintAlpha by coverage. +#ifdef @DRAW_INTERIOR_TRIANGLES + X = min(X, 1.); +#endif + fragCoverageRemaining = .0; // We're done. + } + else if (coverageBeforeMax < targetCoverage) + { + // We were not first fragment of the path at this pixel, AND our + // atomicMax had an effect that we now have to account for in + // paintAlpha. Coverage increased from "coverageBeforeMax" to + // "fragCoverageRemaining". + // + // NOTE: because we know coverage was initially zero, and because + // coverage is always positive in this pass, we know + // coverageBeforeMax >= 0. + uint c1Fixed = (coverageBeforeMax & CLOCKWISE_COVERAGE_MASK) - + CLOCKWISE_FILL_ZERO_VALUE; + half c1 = cast_uint_to_half(c1Fixed) * + CLOCKWISE_COVERAGE_INVERSE_PRECISION; + half c2 = fragCoverageRemaining; +#ifdef @DRAW_INTERIOR_TRIANGLES + c2 = min(c2, 1.); +#endif + // Apply the coverage increase from the atomicMax here. The next + // step will apply the remaining increase. + X = (c2 - c1) / (1. - c1 * paintAlpha); + + // We increased coverage by an amount of "fragCoverageRemaining" - + // "coverageBeforeMax". However, we wanted to increase coverage by + // "fragCoverageRemaining". So the remaining amount we still need to + // increase by is "coverageBeforeMax". + fragCoverageRemainingFixed = c1Fixed; + fragCoverageRemaining = c1; + } + } + + if (fragCoverageRemaining > .0) + { + // At this point we know the value in the coverage buffer belongs to + // this path, so we can do a simple atomicAdd. + uint coverageBeforeAdd = + STORAGE_BUFFER_ATOMIC_ADD(coverageBuffer, + coverageIndex, + fragCoverageRemainingFixed); + half c1 = + cast_int_to_half(int((coverageBeforeAdd & CLOCKWISE_COVERAGE_MASK) - + CLOCKWISE_FILL_ZERO_VALUE)) * + CLOCKWISE_COVERAGE_INVERSE_PRECISION; + half c2 = c1 + fragCoverageRemaining; + c1 = clamp(c1, .0, 1.); + c2 = clamp(c2, .0, 1.); + // Apply the coverage increase from c1 -> c2 that we just did, in + // addition to any coverage that had been applied previously. + half one_minus_c1a = 1. - c1 * paintAlpha; + if (one_minus_c1a <= .0) + discard; + X += (1. - X * paintAlpha) * (c2 - c1) / one_minus_c1a; + } + + paintAlpha *= X; +} + +FRAG_DATA_MAIN(half4, @drawFragmentMain) +{ + VARYING_UNPACK(v_pathID, ushort); +#ifdef DRAW_PATH + VARYING_UNPACK(v_coverages, float4); +#elif defined(@ATLAS_BLIT) + VARYING_UNPACK(v_atlasCoord, float2); +#else + VARYING_UNPACK(v_windingWeight, half); +#endif +#ifndef @ATLAS_BLIT + VARYING_UNPACK(v_coveragePlacement, uint2); + VARYING_UNPACK(v_coverageCoord, float2); +#endif + + half4 paintColor; + uint pathID = v_pathID; + uint2 paintData = STORAGE_BUFFER_LOAD2(@paintBuffer, pathID); + uint paintType = paintData.x & 0xfu; + if (paintType <= SOLID_COLOR_PAINT_TYPE) // CLIP_UPDATE_PAINT_TYPE or + // SOLID_COLOR_PAINT_TYPE + { + paintColor = unpackUnorm4x8(paintData.y); + } + else // LINEAR_GRADIENT_PAINT_TYPE, + // RADIAL_GRADIENT_PAINT_TYPE, or + // IMAGE_PAINT_TYPE + { + float2x2 M = + make_float2x2(STORAGE_BUFFER_LOAD4(@paintAuxBuffer, pathID * 4u)); + float4 translate = + STORAGE_BUFFER_LOAD4(@paintAuxBuffer, pathID * 4u + 1u); + float2 paintCoord = MUL(M, _fragCoord) + translate.xy; + if (paintType != IMAGE_PAINT_TYPE) + { + float t = paintType == LINEAR_GRADIENT_PAINT_TYPE + ? /*linear*/ paintCoord.x + : /*radial*/ length(paintCoord); + t = clamp(t, .0, 1.); + float x = t * translate.z + translate.w; + float y = uintBitsToFloat(paintData.y); + paintColor = + TEXTURE_SAMPLE_LOD(@gradTexture, gradSampler, float2(x, y), .0); + } + else + { + float opacity = uintBitsToFloat(paintData.y); + float lod = translate.z; + paintColor = TEXTURE_SAMPLE_LOD(@imageTexture, + imageSampler, + paintCoord, + lod); + paintColor = + make_half4(unmultiply_rgb(paintColor), paintColor.a * opacity); + } + } + + if (paintColor.a == .0) + { + discard; + } + +#ifdef @ATLAS_BLIT + paintColor.a *= filter_feather_atlas( + v_atlasCoord, + uniforms.atlasTextureInverseSize TEXTURE_CONTEXT_FORWARD); +#else + // Swizzle the coverage buffer in a tiled format, starting with 32x32 + // row-major tiles. + uint coverageIndex = v_coveragePlacement.x; + uint coveragePitch = v_coveragePlacement.y; + uint2 coverageCoord = uint2(floor(v_coverageCoord)); + coverageIndex += (coverageCoord.y >> 5) * (coveragePitch << 5) + + (coverageCoord.x >> 5) * (32 << 5); + // Subdivide each main tile into 4x4 column-major tiles. + coverageIndex += ((coverageCoord.x & 0x1f) >> 2) * (32 << 2) + + ((coverageCoord.y & 0x1f) >> 2) * (4 << 2); + // Let the 4x4 tiles be row-major. + coverageIndex += (coverageCoord.y & 0x3) * 4 + (coverageCoord.x & 0x3); + +#ifdef @BORROWED_COVERAGE_PREPASS + if (@BORROWED_COVERAGE_PREPASS) + { +#ifdef @DRAW_INTERIOR_TRIANGLES + half borrowedCoverage = -v_windingWeight; +#else + half fragCoverage; +#ifdef @ENABLE_FEATHER + if (@ENABLE_FEATHER && is_feathered_fill(v_coverages)) + { + fragCoverage = + eval_feathered_fill(v_coverages TEXTURE_CONTEXT_FORWARD); + } + else +#endif + { + fragCoverage = v_coverages.x; + } + half borrowedCoverage = max(-fragCoverage, .0); +#endif + apply_borrowed_coverage(borrowedCoverage, coverageIndex); + discard; + } +#endif // BORROWED_COVERAGE_PREPASS + +#ifndef @DRAW_INTERIOR_TRIANGLES + if (is_stroke(v_coverages)) + { + half fragCoverage; +#ifdef @ENABLE_FEATHER + if (@ENABLE_FEATHER && is_feathered_stroke(v_coverages)) + { + fragCoverage = + eval_feathered_stroke(v_coverages TEXTURE_CONTEXT_FORWARD); + } + else +#endif + { + fragCoverage = min(v_coverages.x, v_coverages.y); + } + fragCoverage = clamp(fragCoverage, .0, 1.); + apply_stroke_coverage(paintColor.a, fragCoverage, coverageIndex); + } + else // It's a fill. +#endif // !DRAW_INTERIOR_TRIANGLES + { +#ifdef @DRAW_INTERIOR_TRIANGLES + half fragCoverage = v_windingWeight; +#else + half fragCoverage; +#ifdef @ENABLE_FEATHER + if (@ENABLE_FEATHER && is_feathered_fill(v_coverages)) + { + fragCoverage = + eval_feathered_fill(v_coverages TEXTURE_CONTEXT_FORWARD); + } + else +#endif + { + fragCoverage = v_coverages.x; + } + fragCoverage = clamp(fragCoverage, .0, 1.); +#endif + apply_fill_coverage(paintColor.a, fragCoverage, coverageIndex); + } +#endif // @ATLAS_BLIT + + EMIT_FRAG_DATA(paintColor); +} +#endif // FRAGMENT diff --git a/third_party/rive_renderer/source/shaders/draw_image_mesh.glsl b/third_party/rive_renderer/source/shaders/draw_image_mesh.glsl new file mode 100644 index 0000000..c62e517 --- /dev/null +++ b/third_party/rive_renderer/source/shaders/draw_image_mesh.glsl @@ -0,0 +1,204 @@ +/* + * Copyright 2023 Rive + */ + +#ifdef @VERTEX +ATTR_BLOCK_BEGIN(PositionAttr) +ATTR(0, float2, @a_position); +ATTR_BLOCK_END + +ATTR_BLOCK_BEGIN(UVAttr) +ATTR(1, float2, @a_texCoord); +ATTR_BLOCK_END +#endif + +VARYING_BLOCK_BEGIN +NO_PERSPECTIVE VARYING(0, float2, v_texCoord); +#ifdef @ENABLE_CLIPPING +@OPTIONALLY_FLAT VARYING(1, half, v_clipID); +#endif +#ifdef @ENABLE_CLIP_RECT +NO_PERSPECTIVE VARYING(2, float4, v_clipRect); +#endif +VARYING_BLOCK_END + +#ifdef @VERTEX +VERTEX_TEXTURE_BLOCK_BEGIN +VERTEX_TEXTURE_BLOCK_END + +IMAGE_MESH_VERTEX_MAIN(@drawVertexMain, + PositionAttr, + position, + UVAttr, + uv, + _vertexID) +{ + ATTR_UNPACK(_vertexID, position, @a_position, float2); + ATTR_UNPACK(_vertexID, uv, @a_texCoord, float2); + + VARYING_INIT(v_texCoord, float2); +#ifdef @ENABLE_CLIPPING + VARYING_INIT(v_clipID, half); +#endif +#ifdef @ENABLE_CLIP_RECT + VARYING_INIT(v_clipRect, float4); +#endif + + float2 vertexPosition = + MUL(make_float2x2(imageDrawUniforms.viewMatrix), @a_position) + + imageDrawUniforms.translate; + v_texCoord = @a_texCoord; +#ifdef @ENABLE_CLIPPING + if (@ENABLE_CLIPPING) + { + v_clipID = id_bits_to_f16(imageDrawUniforms.clipID, + uniforms.pathIDGranularity); + } +#endif +#ifdef @ENABLE_CLIP_RECT + if (@ENABLE_CLIP_RECT) + { +#ifndef @RENDER_MODE_MSAA + v_clipRect = find_clip_rect_coverage_distances( + make_float2x2(imageDrawUniforms.clipRectInverseMatrix), + imageDrawUniforms.clipRectInverseTranslate, + vertexPosition); +#else // RENDER_MODE_MSAA + set_clip_rect_plane_distances( + make_float2x2(imageDrawUniforms.clipRectInverseMatrix), + imageDrawUniforms.clipRectInverseTranslate, + vertexPosition); +#endif // RENDER_MODE_MSAA + } +#endif // ENABLE_CLIP_RECT + float4 pos = RENDER_TARGET_COORD_TO_CLIP_COORD(vertexPosition); +#ifdef @RENDER_MODE_MSAA + pos.z = normalize_z_index(imageDrawUniforms.zIndex); +#endif + + VARYING_PACK(v_texCoord); +#ifdef @ENABLE_CLIPPING + VARYING_PACK(v_clipID); +#endif +#ifdef @ENABLE_CLIP_RECT + VARYING_PACK(v_clipRect); +#endif + EMIT_VERTEX(pos); +} +#endif + +#ifdef @FRAGMENT +FRAG_TEXTURE_BLOCK_BEGIN +TEXTURE_RGBA8(PER_DRAW_BINDINGS_SET, IMAGE_TEXTURE_IDX, @imageTexture); +#ifdef @RENDER_MODE_MSAA +#ifdef @ENABLE_ADVANCED_BLEND +TEXTURE_RGBA8(PER_FLUSH_BINDINGS_SET, DST_COLOR_TEXTURE_IDX, @dstColorTexture); +#endif +#endif +FRAG_TEXTURE_BLOCK_END + +DYNAMIC_SAMPLER_BLOCK_BEGIN +SAMPLER_DYNAMIC(IMAGE_SAMPLER_IDX, imageSampler) +DYNAMIC_SAMPLER_BLOCK_END + +FRAG_STORAGE_BUFFER_BLOCK_BEGIN +FRAG_STORAGE_BUFFER_BLOCK_END + +#ifndef @RENDER_MODE_MSAA + +PLS_BLOCK_BEGIN +PLS_DECL4F(COLOR_PLANE_IDX, colorBuffer); +PLS_DECLUI(CLIP_PLANE_IDX, clipBuffer); +PLS_DECL4F(SCRATCH_COLOR_PLANE_IDX, scratchColorBuffer); +PLS_DECLUI(COVERAGE_PLANE_IDX, coverageCountBuffer); +PLS_BLOCK_END + +PLS_MAIN_WITH_IMAGE_UNIFORMS(@drawFragmentMain) +{ + VARYING_UNPACK(v_texCoord, float2); +#ifdef @ENABLE_CLIPPING + VARYING_UNPACK(v_clipID, half); +#endif +#ifdef @ENABLE_CLIP_RECT + VARYING_UNPACK(v_clipRect, float4); +#endif + + half4 color = + TEXTURE_SAMPLE_DYNAMIC(@imageTexture, imageSampler, v_texCoord); + half coverage = 1.; + +#ifdef @ENABLE_CLIP_RECT + if (@ENABLE_CLIP_RECT) + { + half clipRectCoverage = min_value(cast_float4_to_half4(v_clipRect)); + coverage = clamp(clipRectCoverage, make_half(.0), coverage); + } +#endif + + PLS_INTERLOCK_BEGIN; + +#ifdef @ENABLE_CLIPPING + if (@ENABLE_CLIPPING && v_clipID != .0) + { + half2 clipData = unpackHalf2x16(PLS_LOADUI(clipBuffer)); + half clipContentID = clipData.g; + half clipCoverage = + clipContentID == v_clipID ? clipData.r : make_half(.0); + coverage = min(coverage, clipCoverage); + } +#endif + + // Blend with the framebuffer color. + half4 dstColorPremul = PLS_LOAD4F(colorBuffer); +#ifdef @ENABLE_ADVANCED_BLEND + if (@ENABLE_ADVANCED_BLEND && imageDrawUniforms.blendMode != BLEND_SRC_OVER) + { + color.rgb = advanced_color_blend( + unmultiply_rgb(color), + dstColorPremul, + cast_uint_to_ushort(imageDrawUniforms.blendMode)) * + color.a; + } +#endif + color *= imageDrawUniforms.opacity * coverage; + color += dstColorPremul * (1. - color.a); + + PLS_STORE4F(colorBuffer, color); + PLS_PRESERVE_UI(clipBuffer); + PLS_PRESERVE_UI(coverageCountBuffer); + + PLS_INTERLOCK_END; + + EMIT_PLS; +} + +#else // RENDER_MODE_MSAA + +FRAG_DATA_MAIN(half4, @drawFragmentMain) +{ + VARYING_UNPACK(v_texCoord, float2); + + half4 color = + TEXTURE_SAMPLE_DYNAMIC(@imageTexture, imageSampler, v_texCoord) * + imageDrawUniforms.opacity; + +#ifdef @ENABLE_ADVANCED_BLEND + if (@ENABLE_ADVANCED_BLEND) + { + // Do the color portion of the blend mode in the shader. + half4 dstColorPremul = + TEXEL_FETCH(@dstColorTexture, int2(floor(_fragCoord.xy))); + color.rgb = advanced_color_blend(unmultiply_rgb(color), + dstColorPremul, + imageDrawUniforms.blendMode); + // Src-over blending is enabled, so just premultiply and let the HW + // finish the the the alpha portion of the blend mode. + color.rgb *= color.a; + } +#endif // !ENABLE_ADVANCED_BLEND + + EMIT_FRAG_DATA(color); +} + +#endif // RENDER_MODE_MSAA +#endif // FRAGMENT diff --git a/third_party/rive_renderer/source/shaders/draw_path.glsl b/third_party/rive_renderer/source/shaders/draw_path.glsl new file mode 100644 index 0000000..ab690ec --- /dev/null +++ b/third_party/rive_renderer/source/shaders/draw_path.glsl @@ -0,0 +1,696 @@ +/* + * Copyright 2022 Rive + */ + +#ifdef @ENABLE_ADVANCED_BLEND +// If advanced blend is enabled, we generate unmultiplied paint colors in the +// shader. Otherwise we would have to just turn around and unmultiply them in +// order to run the blend equation. +#define GENERATE_PREMULTIPLIED_PAINT_COLORS !@ENABLE_ADVANCED_BLEND +#else +// As long as advanced blend is not enabled, it's more efficient for the shader +// to generate premultiplied paint colors from the start. +#define GENERATE_PREMULTIPLIED_PAINT_COLORS true +#endif + +#ifdef @VERTEX +ATTR_BLOCK_BEGIN(Attrs) +#ifdef @DRAW_INTERIOR_TRIANGLES +ATTR(0, packed_float3, @a_triangleVertex); +#else +ATTR(0, + float4, + @a_patchVertexData); // [localVertexID, outset, fillCoverage, vertexType] +ATTR(1, float4, @a_mirroredVertexData); +#endif +ATTR_BLOCK_END +#endif + +VARYING_BLOCK_BEGIN +NO_PERSPECTIVE VARYING(0, float4, v_paint); + +#ifdef @ATLAS_BLIT +NO_PERSPECTIVE VARYING(1, float2, v_atlasCoord); +#elif !defined(@RENDER_MODE_MSAA) +#ifdef @DRAW_INTERIOR_TRIANGLES +@OPTIONALLY_FLAT VARYING(1, half, v_windingWeight); +#elif defined(@ENABLE_FEATHER) +NO_PERSPECTIVE VARYING(2, float4, v_coverages); +#else +NO_PERSPECTIVE VARYING(2, half2, v_coverages); +#endif //@DRAW_INTERIOR_TRIANGLES +@OPTIONALLY_FLAT VARYING(3, half, v_pathID); +#endif // !@RENDER_MODE_MSAA + +#ifdef @ENABLE_CLIPPING +@OPTIONALLY_FLAT VARYING(4, half2, v_clipIDs); // [clipID, outerClipID] +#endif +#ifdef @ENABLE_CLIP_RECT +NO_PERSPECTIVE VARYING(5, float4, v_clipRect); +#endif +#ifdef @ENABLE_ADVANCED_BLEND +@OPTIONALLY_FLAT VARYING(6, half, v_blendMode); +#endif +VARYING_BLOCK_END + +#ifdef @VERTEX +VERTEX_MAIN(@drawVertexMain, Attrs, attrs, _vertexID, _instanceID) +{ +#ifdef @DRAW_INTERIOR_TRIANGLES + ATTR_UNPACK(_vertexID, attrs, @a_triangleVertex, float3); +#else + ATTR_UNPACK(_vertexID, attrs, @a_patchVertexData, float4); + ATTR_UNPACK(_vertexID, attrs, @a_mirroredVertexData, float4); +#endif + + VARYING_INIT(v_paint, float4); + +#ifdef @ATLAS_BLIT + VARYING_INIT(v_atlasCoord, float2); +#elif !defined(@RENDER_MODE_MSAA) +#ifdef @DRAW_INTERIOR_TRIANGLES + VARYING_INIT(v_windingWeight, half); +#elif defined(@ENABLE_FEATHER) + VARYING_INIT(v_coverages, float4); +#else + VARYING_INIT(v_coverages, half2); +#endif //@DRAW_INTERIOR_TRIANGLES + VARYING_INIT(v_pathID, half); +#endif // !@RENDER_MODE_MSAA + +#ifdef @ENABLE_CLIPPING + VARYING_INIT(v_clipIDs, half2); +#endif +#ifdef @ENABLE_CLIP_RECT + VARYING_INIT(v_clipRect, float4); +#endif +#ifdef @ENABLE_ADVANCED_BLEND + VARYING_INIT(v_blendMode, half); +#endif + + bool shouldDiscardVertex = false; + uint pathID; + float2 vertexPosition; +#ifdef @RENDER_MODE_MSAA + ushort pathZIndex; +#endif + +#ifdef @ATLAS_BLIT + vertexPosition = + unpack_atlas_coverage_vertex(@a_triangleVertex, + pathID, +#ifdef @RENDER_MODE_MSAA + pathZIndex, +#endif + v_atlasCoord VERTEX_CONTEXT_UNPACK); +#elif defined(@DRAW_INTERIOR_TRIANGLES) + vertexPosition = unpack_interior_triangle_vertex(@a_triangleVertex, + pathID +#ifdef @RENDER_MODE_MSAA + , + pathZIndex +#else + , + v_windingWeight +#endif + VERTEX_CONTEXT_UNPACK); +#else // !@DRAW_INTERIOR_TRIANGLES + float4 coverages; + shouldDiscardVertex = + !unpack_tessellated_path_vertex(@a_patchVertexData, + @a_mirroredVertexData, + _instanceID, + pathID, + vertexPosition +#ifndef @RENDER_MODE_MSAA + , + coverages +#else + , + pathZIndex +#endif + VERTEX_CONTEXT_UNPACK); +#ifndef @RENDER_MODE_MSAA +#ifdef @ENABLE_FEATHER + v_coverages = coverages; +#else + v_coverages.xy = cast_float2_to_half2(coverages.xy); +#endif +#endif +#endif // !DRAW_INTERIOR_TRIANGLES + + uint2 paintData = STORAGE_BUFFER_LOAD2(@paintBuffer, pathID); + +#if !defined(@ATLAS_BLIT) && !defined(@RENDER_MODE_MSAA) + // Encode the integral pathID as a "half" that we know the hardware will see + // as a unique value in the fragment shader. + v_pathID = id_bits_to_f16(pathID, uniforms.pathIDGranularity); + + // Indicate even-odd fill rule by making pathID negative. + if ((paintData.x & PAINT_FLAG_EVEN_ODD_FILL) != 0u) + v_pathID = -v_pathID; +#endif // !@ATLAS_BLIT && !@RENDER_MODE_MSAA + + uint paintType = paintData.x & 0xfu; +#ifdef @ENABLE_CLIPPING + if (@ENABLE_CLIPPING) + { + uint clipIDBits = + (paintType == CLIP_UPDATE_PAINT_TYPE ? paintData.y : paintData.x) >> + 16; + half clipID = id_bits_to_f16(clipIDBits, uniforms.pathIDGranularity); + // Negative clipID means to update the clip buffer instead of the color + // buffer. + if (paintType == CLIP_UPDATE_PAINT_TYPE) + clipID = -clipID; + v_clipIDs.x = clipID; + } +#endif +#ifdef @ENABLE_ADVANCED_BLEND + if (@ENABLE_ADVANCED_BLEND) + { + v_blendMode = float((paintData.x >> 4) & 0xfu); + } +#endif + + // Paint matrices operate on the fragment shader's "_fragCoord", which is + // bottom-up in GL. + float2 fragCoord = vertexPosition; +#ifdef @FRAMEBUFFER_BOTTOM_UP + fragCoord.y = float(uniforms.renderTargetHeight) - fragCoord.y; +#endif + +#ifdef @ENABLE_CLIP_RECT + if (@ENABLE_CLIP_RECT) + { + // clipRectInverseMatrix transforms from pixel coordinates to a space + // where the clipRect is the normalized rectangle: [-1, -1, 1, 1]. + float2x2 clipRectInverseMatrix = make_float2x2( + STORAGE_BUFFER_LOAD4(@paintAuxBuffer, pathID * 4u + 2u)); + float4 clipRectInverseTranslate = + STORAGE_BUFFER_LOAD4(@paintAuxBuffer, pathID * 4u + 3u); +#ifndef @RENDER_MODE_MSAA + v_clipRect = + find_clip_rect_coverage_distances(clipRectInverseMatrix, + clipRectInverseTranslate.xy, + fragCoord); +#else // @RENDER_MODE_MSAA + set_clip_rect_plane_distances(clipRectInverseMatrix, + clipRectInverseTranslate.xy, + fragCoord); +#endif // @RENDER_MODE_MSAA + } +#endif // ENABLE_CLIP_RECT + + // Unpack the paint once we have a position. + if (paintType == SOLID_COLOR_PAINT_TYPE) + { + half4 color = unpackUnorm4x8(paintData.y); + if (GENERATE_PREMULTIPLIED_PAINT_COLORS) + color.rgb *= color.a; + v_paint = float4(color); + } +#ifdef @ENABLE_CLIPPING + else if (@ENABLE_CLIPPING && paintType == CLIP_UPDATE_PAINT_TYPE) + { + half outerClipID = + id_bits_to_f16(paintData.x >> 16, uniforms.pathIDGranularity); + v_clipIDs.y = outerClipID; + } +#endif + else + { + float2x2 paintMatrix = + make_float2x2(STORAGE_BUFFER_LOAD4(@paintAuxBuffer, pathID * 4u)); + float4 paintTranslate = + STORAGE_BUFFER_LOAD4(@paintAuxBuffer, pathID * 4u + 1u); + float2 paintCoord = MUL(paintMatrix, fragCoord) + paintTranslate.xy; + if (paintType == LINEAR_GRADIENT_PAINT_TYPE || + paintType == RADIAL_GRADIENT_PAINT_TYPE) + { + // v_paint.a contains "-row" of the gradient ramp at texel center, + // in normalized space. + v_paint.a = -uintBitsToFloat(paintData.y); + // abs(v_paint.b) contains either: + // - 2 if the gradient ramp spans an entire row. + // - x0 of the gradient ramp in normalized space, if it's a simple + // 2-texel ramp. + float gradientSpan = paintTranslate.z; + // gradientSpan is either ~1 (complex gradients span the whole width + // of the texture minus 1px), or 1/GRAD_TEXTURE_WIDTH (simple + // gradients span 1px). + if (gradientSpan > .9) + { + // Complex ramps span an entire row. Set it to 2 to convey this. + v_paint.b = 2.; + } + else + { + // This is a simple ramp. + v_paint.b = paintTranslate.w; + } + if (paintType == LINEAR_GRADIENT_PAINT_TYPE) + { + // The paint is a linear gradient. + v_paint.g = .0; + v_paint.r = paintCoord.x; + } + else + { + // The paint is a radial gradient. Mark v_paint.b negative to + // indicate this to the fragment shader. (v_paint.b can't be + // zero because the gradient ramp is aligned on pixel centers, + // so negating it will always produce a negative number.) + v_paint.b = -v_paint.b; + v_paint.rg = paintCoord.xy; + } + } + else // IMAGE_PAINT_TYPE + { + // v_paint.a <= -1. signals that the paint is an image. + // -v_paint.a - 2 is the texture mipmap level-of-detail. + // v_paint.b is the image opacity. + // v_paint.rg is the normalized image texture coordinate (built into + // the paintMatrix). + float opacity = uintBitsToFloat(paintData.y); + float lod = paintTranslate.z; + v_paint = float4(paintCoord.x, paintCoord.y, opacity, -2. - lod); + } + } + + float4 pos; + if (!shouldDiscardVertex) + { + pos = RENDER_TARGET_COORD_TO_CLIP_COORD(vertexPosition); +#ifdef @POST_INVERT_Y + pos.y = -pos.y; +#endif +#ifdef @RENDER_MODE_MSAA + pos.z = normalize_z_index(pathZIndex); +#endif + } + else + { + pos = float4(uniforms.vertexDiscardValue, + uniforms.vertexDiscardValue, + uniforms.vertexDiscardValue, + uniforms.vertexDiscardValue); + } + + VARYING_PACK(v_paint); +#ifdef @ATLAS_BLIT + VARYING_PACK(v_atlasCoord); +#elif !defined(@RENDER_MODE_MSAA) +#ifdef @DRAW_INTERIOR_TRIANGLES + VARYING_PACK(v_windingWeight); +#elif defined(@ENABLE_FEATHER) + VARYING_PACK(v_coverages); +#else + VARYING_PACK(v_coverages); +#endif //@DRAW_INTERIOR_TRIANGLES + VARYING_PACK(v_pathID); +#endif // !@RENDER_MODE_MSAA + +#ifdef @ENABLE_CLIPPING + VARYING_PACK(v_clipIDs); +#endif +#ifdef @ENABLE_CLIP_RECT + VARYING_PACK(v_clipRect); +#endif +#ifdef @ENABLE_ADVANCED_BLEND + VARYING_PACK(v_blendMode); +#endif + EMIT_VERTEX(pos); +} +#endif + +#ifdef @FRAGMENT +FRAG_STORAGE_BUFFER_BLOCK_BEGIN +FRAG_STORAGE_BUFFER_BLOCK_END + +INLINE half4 find_paint_color(float4 paint, + float coverage FRAGMENT_CONTEXT_DECL) +{ + half4 color; + if (paint.a >= .0) // Is the paint a solid color? + { + // The vertex shader will have premultiplied 'paint' (or not) based on + // GENERATE_PREMULTIPLIED_PAINT_COLORS. + color = cast_float4_to_half4(paint); + if (GENERATE_PREMULTIPLIED_PAINT_COLORS) + color *= coverage; + else + color.a *= coverage; + } + else if (paint.a > -1.) // Is paint is a gradient (linear or radial)? + { + float t = + paint.b > .0 ? /*linear*/ paint.r : /*radial*/ length(paint.rg); + t = clamp(t, .0, 1.); + float span = abs(paint.b); + float x = span > 1. + ? /*entire row*/ (1. - 1. / GRAD_TEXTURE_WIDTH) * t + + (.5 / GRAD_TEXTURE_WIDTH) + : /*two texels*/ (1. / GRAD_TEXTURE_WIDTH) * t + span; + float row = -paint.a; + // Our gradient texture is not mipmapped. Issue a texture-sample that + // explicitly does not find derivatives for LOD computation. + color = + TEXTURE_SAMPLE_LOD(@gradTexture, gradSampler, float2(x, row), .0); + color.a *= coverage; + // Gradients are always unmultiplied so we don't lose color data while + // doing the hardware filter. + if (GENERATE_PREMULTIPLIED_PAINT_COLORS) + color.rgb *= color.a; + } + else // The paint is an image. + { + half lod = -paint.a - 2.; + color = TEXTURE_SAMPLE_DYNAMIC_LOD(@imageTexture, + imageSampler, + paint.rg, + lod); + half opacity = paint.b * coverage; + // Images are always premultiplied so the (transparent) background color + // doesn't bleed into the edges during the hardware filter. + if (GENERATE_PREMULTIPLIED_PAINT_COLORS) + color *= opacity; + else + color = make_half4(unmultiply_rgb(color), color.a * opacity); + } + return color; +} + +#ifndef @RENDER_MODE_MSAA + +PLS_BLOCK_BEGIN +PLS_DECL4F(COLOR_PLANE_IDX, colorBuffer); +PLS_DECLUI(CLIP_PLANE_IDX, clipBuffer); +PLS_DECL4F(SCRATCH_COLOR_PLANE_IDX, scratchColorBuffer); +PLS_DECLUI(COVERAGE_PLANE_IDX, coverageCountBuffer); +PLS_BLOCK_END + +PLS_MAIN(@drawFragmentMain) +{ + VARYING_UNPACK(v_paint, float4); + +#ifdef @ATLAS_BLIT + VARYING_UNPACK(v_atlasCoord, float2); +#elif !defined(@RENDER_MODE_MSAA) +#ifdef @DRAW_INTERIOR_TRIANGLES + VARYING_UNPACK(v_windingWeight, half); +#elif defined(@ENABLE_FEATHER) + VARYING_UNPACK(v_coverages, float4); +#else + VARYING_UNPACK(v_coverages, half2); +#endif //@DRAW_INTERIOR_TRIANGLES + VARYING_UNPACK(v_pathID, half); +#endif // !@RENDER_MODE_MSAA + +#ifdef @ENABLE_CLIPPING + VARYING_UNPACK(v_clipIDs, half2); +#endif +#ifdef @ENABLE_CLIP_RECT + VARYING_UNPACK(v_clipRect, float4); +#endif +#ifdef @ENABLE_ADVANCED_BLEND + VARYING_UNPACK(v_blendMode, half); +#endif + +#if !defined(@DRAW_INTERIOR_TRIANGLES) || defined(@ATLAS_BLIT) + // Interior triangles don't overlap, so don't need raster ordering. + PLS_INTERLOCK_BEGIN; +#endif + + half coverage; +#ifdef @ATLAS_BLIT + coverage = filter_feather_atlas( + v_atlasCoord, + uniforms.atlasTextureInverseSize TEXTURE_CONTEXT_FORWARD); +#else + half2 coverageData = unpackHalf2x16(PLS_LOADUI(coverageCountBuffer)); + half coverageBufferID = coverageData.g; + half coverageCount = + coverageBufferID == v_pathID ? coverageData.r : make_half(.0); + +#ifdef @DRAW_INTERIOR_TRIANGLES + coverageCount += v_windingWeight; + PLS_PRESERVE_UI(coverageCountBuffer); +#else + if (is_stroke(v_coverages)) + { + half fragCoverage; +#ifdef @ENABLE_FEATHER + if (@ENABLE_FEATHER && is_feathered_stroke(v_coverages)) + { + fragCoverage = + eval_feathered_stroke(v_coverages TEXTURE_CONTEXT_FORWARD); + } + else +#endif // @ENABLE_FEATHER + { + fragCoverage = min(v_coverages.x, v_coverages.y); + } + coverageCount = max(fragCoverage, coverageCount); + } + else // Fill. (Back-face culling handles the sign of v_coverages.x.) + { + half fragCoverage; +#if defined(@ENABLE_FEATHER) + if (@ENABLE_FEATHER && is_feathered_fill(v_coverages)) + { + fragCoverage = + eval_feathered_fill(v_coverages TEXTURE_CONTEXT_FORWARD); + } + else +#endif // @CLOCKWISE_FILL && @ENABLE_FEATHER + { + fragCoverage = v_coverages.x; + } + coverageCount += fragCoverage; + } + + // Save the updated coverage. + PLS_STOREUI(coverageCountBuffer, + packHalf2x16(make_half2(coverageCount, v_pathID))); +#endif // !@DRAW_INTERIOR_TRIANGLES + + // Convert coverageCount to coverage. +#ifdef @CLOCKWISE_FILL + if (@CLOCKWISE_FILL) + { +#ifdef @VULKAN_VENDOR_ID + if (@VULKAN_VENDOR_ID == VULKAN_VENDOR_ARM) + { + // ARM hits a bug if we use clamp() here. + if (coverageCount < .0) + coverage = .0; + else if (coverageCount <= 1.) + coverage = coverageCount; + else + coverage = 1.; + } + else +#endif + { + coverage = clamp(coverageCount, make_half(.0), make_half(1.)); + } + } + else +#endif // CLOCKWISE_FILL + { + coverage = abs(coverageCount); +#ifdef @ENABLE_EVEN_ODD + if (@ENABLE_EVEN_ODD && v_pathID < .0 /*even-odd*/) + { + coverage = 1. - make_half(abs(fract(coverage * .5) * 2. + -1.)); + } +#endif + // This also caps stroke coverage, which can be >1. + coverage = min(coverage, make_half(1.)); + } +#endif // !@ATLAS_BLIT + +#ifdef @ENABLE_CLIPPING + if (@ENABLE_CLIPPING && v_clipIDs.x < .0) // Update the clip buffer. + { + half clipID = -v_clipIDs.x; +#ifdef @ENABLE_NESTED_CLIPPING + if (@ENABLE_NESTED_CLIPPING) + { + half outerClipID = v_clipIDs.y; + if (outerClipID != .0) + { + // This is a nested clip. Intersect coverage with the enclosing + // clip (outerClipID). + half2 clipData = unpackHalf2x16(PLS_LOADUI(clipBuffer)); + half clipContentID = clipData.g; + half outerClipCoverage; + if (clipContentID != clipID) + { + // First hit: either clipBuffer contains outerClipCoverage, + // or this pixel is not inside the outer clip and + // outerClipCoverage is zero. + outerClipCoverage = + clipContentID == outerClipID ? clipData.r : .0; +#ifndef @DRAW_INTERIOR_TRIANGLES + // Stash outerClipCoverage before overwriting clipBuffer, in + // case we hit this pixel again and need it. (Not necessary + // when drawing interior triangles because they always go + // last and don't overlap.) + PLS_STORE4F(scratchColorBuffer, + make_half4(outerClipCoverage, .0, .0, .0)); +#endif + } + else + { + // Subsequent hit: outerClipCoverage is stashed in + // scratchColorBuffer. + outerClipCoverage = PLS_LOAD4F(scratchColorBuffer).r; +#ifndef @DRAW_INTERIOR_TRIANGLES + // Since interior triangles are always last, there's no need + // to preserve this value. + PLS_PRESERVE_4F(scratchColorBuffer); +#endif + } + coverage = min(coverage, outerClipCoverage); + } + } +#endif // @ENABLE_NESTED_CLIPPING + PLS_STOREUI(clipBuffer, packHalf2x16(make_half2(coverage, clipID))); + PLS_PRESERVE_4F(colorBuffer); + } + else // Render to the main framebuffer. +#endif // @ENABLE_CLIPPING + { +#ifdef @ENABLE_CLIPPING + if (@ENABLE_CLIPPING) + { + // Apply the clip. + half clipID = v_clipIDs.x; + if (clipID != .0) + { + // Clip IDs are not necessarily drawn in monotonically + // increasing order, so always check exact equality of the + // clipID. + half2 clipData = unpackHalf2x16(PLS_LOADUI(clipBuffer)); + half clipContentID = clipData.g; + coverage = (clipContentID == clipID) ? min(clipData.r, coverage) + : make_half(.0); + } + } +#endif +#ifdef @ENABLE_CLIP_RECT + if (@ENABLE_CLIP_RECT) + { + half clipRectCoverage = min_value(cast_float4_to_half4(v_clipRect)); + coverage = clamp(clipRectCoverage, make_half(.0), coverage); + } +#endif // ENABLE_CLIP_RECT + + half4 color = + find_paint_color(v_paint, coverage FRAGMENT_CONTEXT_UNPACK); + + half4 dstColorPremul; +#ifdef @ATLAS_BLIT + dstColorPremul = PLS_LOAD4F(colorBuffer); +#else + if (coverageBufferID != v_pathID) + { + // This is the first fragment from pathID to touch this pixel. + dstColorPremul = PLS_LOAD4F(colorBuffer); +#ifndef @DRAW_INTERIOR_TRIANGLES + // We don't need to store coverage when drawing interior triangles + // because they always go last and don't overlap, so every fragment + // is the final one in the path. + PLS_STORE4F(scratchColorBuffer, dstColorPremul); +#endif + } + else + { + dstColorPremul = PLS_LOAD4F(scratchColorBuffer); +#ifndef @DRAW_INTERIOR_TRIANGLES + // Since interior triangles are always last, there's no need to + // preserve this value. + PLS_PRESERVE_4F(scratchColorBuffer); +#endif + } +#endif // @ATLAS_BLIT + + // Blend with the framebuffer color. +#ifdef @ENABLE_ADVANCED_BLEND + if (@ENABLE_ADVANCED_BLEND) + { + // GENERATE_PREMULTIPLIED_PAINT_COLORS is false in this case because + // advanced blend needs unmultiplied colors. + if (v_blendMode != cast_uint_to_half(BLEND_SRC_OVER)) + { + color.rgb = + advanced_color_blend(color.rgb, + dstColorPremul, + cast_half_to_ushort(v_blendMode)); + } + // Premultiply alpha now. + color.rgb *= color.a; + } +#endif + color += dstColorPremul * (1. - color.a); + + PLS_STORE4F(colorBuffer, color); + PLS_PRESERVE_UI(clipBuffer); + } + +#if !defined(@DRAW_INTERIOR_TRIANGLES) || defined(@ATLAS_BLIT) + // Interior triangles don't overlap, so don't need raster ordering. + PLS_INTERLOCK_END; +#endif + + EMIT_PLS; +} + +#else // @RENDER_MODE_MSAA + +FRAG_DATA_MAIN(half4, @drawFragmentMain) +{ + VARYING_UNPACK(v_paint, float4); +#ifdef @ATLAS_BLIT + VARYING_UNPACK(v_atlasCoord, float2); +#endif +#ifdef @ENABLE_ADVANCED_BLEND + VARYING_UNPACK(v_blendMode, half); +#endif + + half coverage = +#ifdef @ATLAS_BLIT + filter_feather_atlas( + v_atlasCoord, + uniforms.atlasTextureInverseSize TEXTURE_CONTEXT_FORWARD); +#else + 1.; +#endif + half4 color = find_paint_color(v_paint, coverage FRAGMENT_CONTEXT_UNPACK); + +#ifdef @ENABLE_ADVANCED_BLEND + if (@ENABLE_ADVANCED_BLEND) + { + // Do the color portion of the blend mode in the shader. + // + // NOTE: "color" is already unmultiplied because + // GENERATE_PREMULTIPLIED_PAINT_COLORS is false when using advanced + // blend. + half4 dstColorPremul = + TEXEL_FETCH(@dstColorTexture, int2(floor(_fragCoord.xy))); + color.rgb = advanced_color_blend(color.rgb, + dstColorPremul, + cast_half_to_ushort(v_blendMode)); + // Src-over blending is enabled, so just premultiply and let the HW + // finish the the the alpha portion of the blend mode. + color.rgb *= color.a; + } +#endif // ENABLE_ADVANCED_BLEND + EMIT_FRAG_DATA(color); +} + +#endif // !RENDER_MODE_MSAA + +#endif // FRAGMENT diff --git a/third_party/rive_renderer/source/shaders/draw_path_common.glsl b/third_party/rive_renderer/source/shaders/draw_path_common.glsl new file mode 100644 index 0000000..729d6c5 --- /dev/null +++ b/third_party/rive_renderer/source/shaders/draw_path_common.glsl @@ -0,0 +1,864 @@ +/* + * Copyright 2023 Rive + */ + +// Common functions shared by draw shaders. + +// Feathered coverage values get shifted by "FEATHER_COVERAGE_BIAS" in order +// to classify the coverage as belonging to a feather. +#define FEATHER_COVERAGE_BIAS -2. + +// Fragment shaders test if a coverage value is less than +// "FEATHER_COVERAGE_THRESHOLD" to see if the coverage belongs to a feather. +#define FEATHER_COVERAGE_THRESHOLD -1.5 + +// Since the sign of x dictates the sign of coverage, and since x may be 0 when +// feathering, bias x slightly upward so we don't lose the sign when it's 0. +#define FEATHER_X_COORD_BIAS .25 + +// Magnitude of cotan(theta) at which we decide an angle is flat when processing +// feathers. +#define HORIZONTAL_COTANGENT_THRESHOLD 1e3 + +// Value to assign cotTheta to ensure it gets treated as flat. +#define HORIZONTAL_COTANGENT_VALUE \ + (HORIZONTAL_COTANGENT_THRESHOLD * HORIZONTAL_COTANGENT_THRESHOLD) + +#ifdef @VERTEX +VERTEX_TEXTURE_BLOCK_BEGIN +TEXTURE_TESSDATA4(PER_FLUSH_BINDINGS_SET, + TESS_VERTEX_TEXTURE_IDX, + @tessVertexTexture); +#ifdef @ENABLE_FEATHER +TEXTURE_R16F_1D_ARRAY(PER_FLUSH_BINDINGS_SET, + FEATHER_TEXTURE_IDX, + @featherTexture); +#endif +VERTEX_TEXTURE_BLOCK_END + +VERTEX_STORAGE_BUFFER_BLOCK_BEGIN +STORAGE_BUFFER_U32x4(PATH_BUFFER_IDX, PathBuffer, @pathBuffer); +STORAGE_BUFFER_U32x2(PAINT_BUFFER_IDX, PaintBuffer, @paintBuffer); +STORAGE_BUFFER_F32x4(PAINT_AUX_BUFFER_IDX, PaintAuxBuffer, @paintAuxBuffer); +STORAGE_BUFFER_U32x4(CONTOUR_BUFFER_IDX, ContourBuffer, @contourBuffer); +VERTEX_STORAGE_BUFFER_BLOCK_END +#endif // @VERTEX + +#if defined(@ENABLE_FEATHER) || defined(@ATLAS_BLIT) +SAMPLER_LINEAR(FEATHER_TEXTURE_IDX, featherSampler) +#endif + +#ifdef @FRAGMENT +FRAG_TEXTURE_BLOCK_BEGIN +TEXTURE_RGBA8(PER_FLUSH_BINDINGS_SET, GRAD_TEXTURE_IDX, @gradTexture); +#if defined(@ENABLE_FEATHER) || defined(@ATLAS_BLIT) +TEXTURE_R16F_1D_ARRAY(PER_FLUSH_BINDINGS_SET, + FEATHER_TEXTURE_IDX, + @featherTexture); +#endif +#ifdef @ATLAS_BLIT +TEXTURE_R16F(PER_DRAW_BINDINGS_SET, ATLAS_TEXTURE_IDX, @atlasTexture); +#endif +TEXTURE_RGBA8(PER_DRAW_BINDINGS_SET, IMAGE_TEXTURE_IDX, @imageTexture); +#if defined(@RENDER_MODE_MSAA) && defined(@ENABLE_ADVANCED_BLEND) +TEXTURE_RGBA8(PER_FLUSH_BINDINGS_SET, DST_COLOR_TEXTURE_IDX, @dstColorTexture); +#endif +FRAG_TEXTURE_BLOCK_END + +SAMPLER_LINEAR(GRAD_TEXTURE_IDX, gradSampler) +// Metal defines @VERTEX and @FRAGMENT at the same time, so yield to the vertex +// definition of featherSampler in this case. +#ifdef @ATLAS_BLIT +SAMPLER_LINEAR(ATLAS_TEXTURE_IDX, atlasSampler) +#endif +DYNAMIC_SAMPLER_BLOCK_BEGIN +SAMPLER_DYNAMIC(IMAGE_SAMPLER_IDX, imageSampler) +DYNAMIC_SAMPLER_BLOCK_END +#endif // @FRAGMENT + +// We distinguish between strokes and fills by the sign of coverages.y, +// regardless of whether feathering is enabled (coverages are float4), or +// disabled (coverages are half2), +#ifdef @FRAGMENT +INLINE bool is_stroke(float4 coverages) { return coverages.y >= .0; } +INLINE bool is_stroke(half2 coverages) { return coverages.y >= .0; } +#endif // FRAGMENT + +#if defined(@FRAGMENT) && defined(@ENABLE_FEATHER) +// We can also classify a fragments as feathered/not-feathered strokes/fills by +// looking at coverages. +INLINE bool is_feathered_stroke(float4 coverages) +{ + return coverages.x < FEATHER_COVERAGE_THRESHOLD; +} + +INLINE bool is_feathered_fill(float4 coverages) +{ + return coverages.y < FEATHER_COVERAGE_THRESHOLD; +} +#endif // @FRAGMENT && @ENABLE_FEATHER + +#ifdef @VERTEX +// Packs all the info to evaluate a feathered fill into 4 varying floats. +float4 pack_feathered_fill_coverages(float cornerTheta, + float2 spokeNorm, + float outset) +{ + // Find the corner's local coordinate within the feather convolution, where + // the convolution matrix is centered on [.5, .5] and spans 0..1, and the + // first edge of the corner runs horizontal and to the left. + float2 cornerLocalCoord = (1. - spokeNorm * abs(outset)) * .5; + + // Calculate cotTheta and y0 for the fragment shader. + // (See eval_feathered_fill() for details.) + float cotTheta, y0; + if (abs(cornerTheta - PI_OVER_2) < 1. / HORIZONTAL_COTANGENT_THRESHOLD) + { + cotTheta = .0; + y0 = .0; + } + else + { + float tanTheta = tan(cornerTheta); + cotTheta = sign(PI_OVER_2 - cornerTheta) / + max(abs(tanTheta), 1. / HORIZONTAL_COTANGENT_VALUE); + y0 = cotTheta >= .0 + ? cornerLocalCoord.y - (1. - cornerLocalCoord.x) * tanTheta + : cornerLocalCoord.y + cornerLocalCoord.x * tanTheta; + } + + // Bias x & y for additional information: + // + // * x will be negated later on if the triangle is back-facing. This tells + // the fragment shader what sign to give feathered coverage. Ensure it's + // greater than zero. + // + // * y < FEATHER_COVERAGE_BIAS tells the fragment shader this is a feather. + // + float4 coverages; + coverages.x = max(cornerLocalCoord.x, .0) + FEATHER_X_COORD_BIAS; + coverages.y = -cornerLocalCoord.y + FEATHER_COVERAGE_BIAS; + coverages.z = cotTheta; + coverages.w = y0; + return coverages; +} +#endif // @VERTEX + +#ifdef @ENABLE_FEATHER +INLINE half eval_feathered_fill(float4 coverages TEXTURE_CONTEXT_DECL) +{ + // x and y are the relative coordinates of the corner vertex within the + // feather convolution. They are oriented above center=[.5, .5], with the + // first edge running horizontal and to the left. + // + // The second edge exits x,y at an angle of theta. "y0" is the location + // where it intersects with either the left or right edge of the + // convolution (left if cotTheta < 0, right if cotTheta > 0). + // + // y0 and cotTheta are both 0 when the corner angle is pi/2. + half cotTheta = coverages.z; + half y0 = max(coverages.w, .0); // Clamp y0 at the top of the convolution. + + // First compute the upper area of the convolution that is fully contained + // within both edges. (i.e., the area above y0.) + // + // NOTE: If we aren't a corner, this will be the entire feather. + half featherCoverage = cotTheta >= .0 ? FEATHER(y0) : .0; + + // If we're a (not flat) corner, the bottom area of the convolution needs to + // account for both edges. + // + // Integrate the area contained within both edges, taking advantage of the + // separability property of our convolution: + // _ + // t=y / \. + // | + // | FEATHER(t * m + b) * FEATHER'(t) * dt + // | + // t=y0 \_/ + // + // NOTE: The derivative FEATHER'(t) is the normal distribution with: + // + // mu = 1/2 + // sigma = 1 / (2 * FEATHER_TEXTURE_STDDEVS) + // + // We can evaluate this directly without a lookup table. + // + // For performance constraints, we only take 4 samples on the integral. + if (abs(cotTheta) < HORIZONTAL_COTANGENT_THRESHOLD) + { + // Unpack x & y from the varying coverages. + half x = abs(coverages.x) - FEATHER_X_COORD_BIAS; + half y = -coverages.y + FEATHER_COVERAGE_BIAS; + + // Find the height of each sample, and pre-scale by 1/(sigma*sqrt(2pi)) + // from the normal distribution (to save on multiplies later). + // + // dt = (y - y0) / 4 / (sigma * sqrt(2pi)) + // + half dt = (y - y0) * 0.5984134206; + + // Subdivide into 4 bars of even height, and sample at the centers. + // (Reuse dt so we don't have to recompute "y - y1" again.) + // + // t = lerp(y0, y1, [1/8, 3/8, 5/8, 7/8]) + // + half4 t = y0 + dt * make_half4(0.20888568955, + 0.62665706865, + 1.04442844776, + 1.46219982687); + + // Feather horizontally where each sample intersects the second edge. + half4 u = t * -cotTheta + (y * cotTheta + x); + half4 feathers = make_half4(FEATHER(u[0]), + FEATHER(u[1]), + FEATHER(u[2]), + FEATHER(u[3])); + + // Evaluate the normal distribution at each vertical sample. + // (Scale t_ by sqrt(log2(e)) to change the base of the function from + // e^x to 2^x.) + // + // t_ = 1/sqrt(2) * (x - mu) / sigma * sqrt(log2(e)) + // normalDistro = 2^(-t_ * t_) + // + half4 t_ = t * 5.09593080173 + -2.54796540086; + half4 ddtFeather = exp2(-t_ * t_); + + // Take the sum of "FEATHER(u) * FEATHER'(t) * dt" at all 4 samples. + featherCoverage += dot(feathers, ddtFeather) * dt; + } + + // Clockwise triangles add to the featherCoverage, counterclockwise + // triangles subtract from it. + return featherCoverage * sign(coverages.x); +} + +INLINE half eval_feathered_stroke(float4 coverages TEXTURE_CONTEXT_DECL) +{ + // Feathered stroke is: + // 1 - feather(1 - leftCoverage) - feather(1 - rightCoverage) + float featherCoverage = 1.; + + // The portion OUTSIDE the featherCoverage is "1 - featherCoverage". + // (coverages.x is biased in order to classify this featherCoverage as a + // feather, so also remove the bias.) + float leftOutsideCoverage = (1. - FEATHER_COVERAGE_BIAS) + coverages.x; + featherCoverage -= FEATHER(leftOutsideCoverage); + + float rightOutsideCoverage = 1. - coverages.y; + featherCoverage -= FEATHER(rightOutsideCoverage); + + return featherCoverage; +} +#endif // @ENABLE_FEATHER + +#if defined(@FRAGMENT) && defined(@ATLAS_BLIT) +// Upscales a pre-rendered feather from the atlas, converting from gaussian +// space to linear before doing a bilerp. +INLINE half +filter_feather_atlas(float2 atlasCoord, + float2 atlasTextureInverseSize TEXTURE_CONTEXT_DECL) +{ + // Gather the quad of pixels we need to filter. + // Gather from the exact center of the quad to make sure there are no + // rounding differences between us and the texture unit. + float2 atlasQuadCenter = round(atlasCoord); + half4 coverages = TEXTURE_GATHER(@atlasTexture, + atlasSampler, + atlasQuadCenter, + atlasTextureInverseSize); + // Convert each pixel from gaussian space back to linear. + coverages = make_half4(INVERSE_FEATHER(coverages.x), + INVERSE_FEATHER(coverages.y), + INVERSE_FEATHER(coverages.z), + INVERSE_FEATHER(coverages.w)); + // Bilerp in linear space. + coverages.xw = mix(coverages.xw, + coverages.yz, + make_half(atlasCoord.x + .5 - atlasQuadCenter.x)); + coverages.x = mix(coverages.w, + coverages.x, + make_half(atlasCoord.y + .5 - atlasQuadCenter.y)); + // Go back to gaussian now that the bilerp is finished. + return FEATHER(coverages.x); +} +#endif // @FRAGMENT && @ATLAS_BLIT + +#if defined(@VERTEX) && defined(@DRAW_PATH) +INLINE int2 tess_texel_coord(int texelIndex) +{ + return int2(texelIndex & ((1 << TESS_TEXTURE_WIDTH_LOG2) - 1), + texelIndex >> TESS_TEXTURE_WIDTH_LOG2); +} + +INLINE float manhattan_pixel_width(float2x2 M, float2 normalized) +{ + + float2 v = MUL(M, normalized); + return (abs(v.x) + abs(v.y)) * (1. / dot(v, v)); +} + +INLINE bool unpack_tessellated_path_vertex(float4 patchVertexData, + float4 mirroredVertexData, + int _instanceID, + OUT(uint) outPathID, + OUT(float2) outVertexPosition +#ifndef @RENDER_MODE_MSAA + , + OUT(float4) outCoverages +#else + , + OUT(ushort) outPathZIndex +#endif + VERTEX_CONTEXT_DECL) +{ + // Unpack patchVertexData. + int localVertexID = int(patchVertexData.x); + float outset = patchVertexData.y; + float fillCoverage = patchVertexData.z; + int patchSegmentSpan = floatBitsToInt(patchVertexData.w) >> 2; + int vertexType = floatBitsToInt(patchVertexData.w) & 3; + + // Fetch a vertex that definitely belongs to the contour we're drawing. + int vertexIDOnContour = min(localVertexID, patchSegmentSpan - 1); + int tessVertexIdx = _instanceID * patchSegmentSpan + vertexIDOnContour; + TESSDATA4 tessVertexData = + TEXEL_FETCH(@tessVertexTexture, tess_texel_coord(tessVertexIdx)); + uint contourIDWithFlags = TESSDATA_AS_UINT(tessVertexData.w); + + // Fetch and unpack the contour referenced by the tessellation vertex. + uint4 contourData = + STORAGE_BUFFER_LOAD4(@contourBuffer, + contour_data_idx(contourIDWithFlags)); + float2 midpoint = uintBitsToFloat(contourData.xy); + outPathID = contourData.z & 0xffffu; + uint vertexIndex0 = contourData.w; + + // Fetch and unpack the path. + float2x2 M = make_float2x2( + uintBitsToFloat(STORAGE_BUFFER_LOAD4(@pathBuffer, outPathID * 4u))); + uint4 pathData = STORAGE_BUFFER_LOAD4(@pathBuffer, outPathID * 4u + 1u); + float2 translate = uintBitsToFloat(pathData.xy); + float strokeRadius = uintBitsToFloat(pathData.z); + float featherRadius = uintBitsToFloat(pathData.w); + + // Fix the tessellation vertex if we fetched the wrong one in order to + // guarantee we got the correct contour ID and flags, or if we belong to a + // mirrored contour and this vertex has an alternate position when mirrored. + uint mirroredContourFlag = + contourIDWithFlags & MIRRORED_CONTOUR_CONTOUR_FLAG; + if (mirroredContourFlag != 0u) + { + localVertexID = int(mirroredVertexData.x); + outset = mirroredVertexData.y; + fillCoverage = mirroredVertexData.z; + } + if (localVertexID != vertexIDOnContour) + { + // This can peek one vertex before or after the contour, but the + // tessellator guarantees there is always at least one padding vertex at + // the beginning and end of the data. + int replacementTessVertexIdx = + tessVertexIdx + localVertexID - vertexIDOnContour; + TESSDATA4 replacementTessVertexData = + TEXEL_FETCH(@tessVertexTexture, + tess_texel_coord(replacementTessVertexIdx)); + if ((TESSDATA_AS_UINT(replacementTessVertexData.w) & + (MIRRORED_CONTOUR_CONTOUR_FLAG | 0xffffu)) != + (contourIDWithFlags & (MIRRORED_CONTOUR_CONTOUR_FLAG | 0xffffu))) + { + // We crossed over into a new contour. Either wrap to the first + // vertex in the contour or leave it clamped at the final vertex of + // the contour. + bool isClosed = strokeRadius == .0 || // filled + midpoint.x != .0; // explicity closed stroke + if (isClosed) + { + tessVertexIdx = int(vertexIndex0); + tessVertexData = TEXEL_FETCH(@tessVertexTexture, + tess_texel_coord(tessVertexIdx)); + } + } + else + { + tessVertexIdx = replacementTessVertexIdx; + tessVertexData = replacementTessVertexData; + } + // MIRRORED_CONTOUR_CONTOUR_FLAG is not preserved at vertexIndex0. + // Preserve it here. By not preserving this flag, the normal and + // mirrored contour can both share the same contour record. + contourIDWithFlags = (TESSDATA_AS_UINT(tessVertexData.w) & + ~MIRRORED_CONTOUR_CONTOUR_FLAG) | + mirroredContourFlag; + } + + // Find the tangent angle of the curve at our vertex. + float theta; +#ifdef @ENABLE_FEATHER + float featherJoinEdge0Theta; + float featherJoinCornerTheta; + if ((contourIDWithFlags & JOIN_TYPE_MASK) == FEATHER_JOIN_CONTOUR_FLAG && + vertexType == STROKE_VERTEX) + { + // Feather joins work out their stepping here in the vertex shader. + // Instead of emitting just the tangent angle, the tessellation shader + // gave us the original tessellation parameters. + uint joinDataPacked = TESSDATA_AS_UINT(tessVertexData.z); + float joinVertexID = float(joinDataPacked & 0xffffu); + float joinSegmentCount = float(joinDataPacked >> 16); + + // Find the tessellation vertices immediately before and after the + // feather join in order to work out the corner angles. + int2 edgeVertexOffsets = + int2(-joinVertexID - 1., joinSegmentCount - joinVertexID + 1.); + if ((contourIDWithFlags & MIRRORED_CONTOUR_CONTOUR_FLAG) != 0u) + edgeVertexOffsets = -edgeVertexOffsets; + TESSDATA4 tessDataBeforeJoin = + TEXEL_FETCH(@tessVertexTexture, + tess_texel_coord(tessVertexIdx + edgeVertexOffsets.x)); + TESSDATA4 tessDataAfterJoin = + TEXEL_FETCH(@tessVertexTexture, + tess_texel_coord(tessVertexIdx + edgeVertexOffsets.y)); + if ((TESSDATA_AS_UINT(tessDataAfterJoin.w) & + (MIRRORED_CONTOUR_CONTOUR_FLAG | 0xffffu)) != + (TESSDATA_AS_UINT(tessDataBeforeJoin.w) & + (MIRRORED_CONTOUR_CONTOUR_FLAG | 0xffffu))) + { + // We reached over into a new contour. The edge immediately after + // this feather join is actually the first vertex in the countour. + tessDataAfterJoin = + TEXEL_FETCH(@tessVertexTexture, + tess_texel_coord(int(vertexIndex0))); + } + + featherJoinEdge0Theta = TESSDATA_AS_FLOAT(tessDataBeforeJoin.z); + float featherJoinEdge1Theta = TESSDATA_AS_FLOAT(tessDataAfterJoin.z); + featherJoinCornerTheta = featherJoinEdge1Theta - featherJoinEdge0Theta; + if (abs(featherJoinCornerTheta) > PI) + featherJoinCornerTheta -= _2PI * sign(featherJoinCornerTheta); + + // Feather joins draw backwards segments across the angle outside the + // join, in order to erase some of the coverage that got written. Divide + // the forward and backward segments proportionally to their respective + // angles. + float nonHelperSegmentCount = + joinSegmentCount + 1. - float(FEATHER_JOIN_HELPER_VERTEX_COUNT); + float forwardSegmentCount = clamp( + round(abs(featherJoinCornerTheta) / PI * nonHelperSegmentCount), + 1., + nonHelperSegmentCount - 1.); + float backwardSegmentCount = + nonHelperSegmentCount - forwardSegmentCount; + if (joinVertexID <= backwardSegmentCount) + { + // We're a backwards segment of the feather join. + featherJoinCornerTheta = + -(PI * sign(featherJoinCornerTheta) - featherJoinCornerTheta); + joinSegmentCount = backwardSegmentCount; + // On the final backward vertex, negate outset (later we will use + // theta=featherJoinEdge1Theta instead of + // featherJoinEdge1Theta - PI). This creates a crack-free + // tessellation with the edge we're joining. + if (joinVertexID == backwardSegmentCount) + outset = -outset; + } + else if (joinVertexID == backwardSegmentCount + 1.) + { + // There's a discontinuous jump between the backward and forward + // segments. This is a throwaway vertex to disconnect them. + joinVertexID = .0; + joinSegmentCount = .0; + outset = .0; + } + else + { + // We're a forward segment of the feather join. + joinVertexID -= backwardSegmentCount + 2.; + joinSegmentCount = forwardSegmentCount; + } + + if (joinVertexID == joinSegmentCount) + { + // Emit "featherJoinEdge1Theta" precisely (instead of the + // approximate lerp below) to create crack-free tessellation with + // the edges we're joining. + theta = featherJoinEdge1Theta; + } + else + { + theta = featherJoinEdge0Theta + + featherJoinCornerTheta * (joinVertexID / joinSegmentCount); + } + } + else +#endif // @ENABLE_FEATHER + { + theta = TESSDATA_AS_FLOAT(tessVertexData.z); + } + float2 norm = float2(sin(theta), -cos(theta)); + float2 origin = TESSDATA_AS_FLOAT(tessVertexData.xy); + float2 postTransformVertexOffset = float2(0, 0); + + if (featherRadius != .0) + { + // Never use a feather harder than 1.5 standard deviations across a + // radius of 1/2px. This is the point where feathering just looks like + // antialiasing, and any harder looks aliased. + featherRadius = + max(featherRadius, + (FEATHER_TEXTURE_STDDEVS / 3.) / length(MUL(M, norm))); + } + + if (strokeRadius != .0) // Is this a stroke? + { + // Ensure strokes always emit clockwise triangles. + outset *= sign(determinant(M)); + + // Joins only emanate from the outer side of the stroke. + if ((contourIDWithFlags & LEFT_JOIN_CONTOUR_FLAG) != 0u) + outset = min(outset, .0); + if ((contourIDWithFlags & RIGHT_JOIN_CONTOUR_FLAG) != 0u) + outset = max(outset, .0); + + float aaRadius = featherRadius != .0 + ? featherRadius + : manhattan_pixel_width(M, norm) * AA_RADIUS; + half globalCoverage = 1.; + if (aaRadius > strokeRadius && featherRadius == .0) + { + // The stroke is narrower than the AA ramp. Instead of emitting + // subpixel geometry, make the stroke as wide as the AA ramp and + // apply a global coverage multiplier. + globalCoverage = + cast_float_to_half(strokeRadius) / cast_float_to_half(aaRadius); + strokeRadius = aaRadius; + } + + // Extend the vertex by half the width of the AA ramp. + float2 vertexOffset = + norm * (strokeRadius + aaRadius); // Bloat stroke width for AA. + +#ifndef @RENDER_MODE_MSAA + // Calculate the AA distance to both the outset and inset edges of the + // stroke. The fragment shader will use whichever is lesser. + float x = outset * (strokeRadius + aaRadius); + outCoverages.xy = + (1. / (aaRadius * 2.)) * (float2(x, -x) + strokeRadius) + .5; + outCoverages.zw = make_float2(.0); +#endif + + uint joinType = contourIDWithFlags & JOIN_TYPE_MASK; + if (joinType > ROUND_JOIN_CONTOUR_FLAG) + { + // This vertex belongs to a miter or bevel join. Begin by finding + // the bisector, which is the same as the miter line. The first two + // vertices in the join peek forward to figure out the bisector, and + // the final two peek backward. + int peekDir = 2; + if ((contourIDWithFlags & JOIN_TANGENT_0_CONTOUR_FLAG) == 0u) + peekDir = -peekDir; + if ((contourIDWithFlags & MIRRORED_CONTOUR_CONTOUR_FLAG) != 0u) + peekDir = -peekDir; + int2 otherJoinTexelCoord = + tess_texel_coord(tessVertexIdx + peekDir); + TESSDATA4 otherJoinData = + TEXEL_FETCH(@tessVertexTexture, otherJoinTexelCoord); + float otherJoinTheta = TESSDATA_AS_FLOAT(otherJoinData.z); + float joinAngle = abs(otherJoinTheta - theta); + if (joinAngle > PI) + joinAngle = _2PI - joinAngle; + bool isTan0 = + (contourIDWithFlags & JOIN_TANGENT_0_CONTOUR_FLAG) != 0u; + bool isLeftJoin = + (contourIDWithFlags & LEFT_JOIN_CONTOUR_FLAG) != 0u; + float bisectTheta = + joinAngle * (isTan0 == isLeftJoin ? -.5 : .5) + theta; + float2 bisector = float2(sin(bisectTheta), -cos(bisectTheta)); + float bisectPixelWidth = manhattan_pixel_width(M, bisector); + + // Generalize everything to a "miter-clip", which is proposed in the + // SVG-2 draft. Bevel joins are converted to miter-clip joins with a + // miter limit of 1/2 pixel. They technically bleed out 1/2 pixel + // when drawn this way, but they seem to look fine and there is not + // an obvious solution to antialias them without an ink bleed. + float miterRatio = cos(joinAngle * .5); + float clipRadius; + if ((joinType == MITER_CLIP_JOIN_CONTOUR_FLAG) || + (joinType == MITER_REVERT_JOIN_CONTOUR_FLAG && + miterRatio >= .25)) + { + // Miter! (Or square cap.) + // We currently use hard coded miter limits: + // * 1 for square caps being emulated as miter-clip joins. + // * 4, which is the SVG default, for all other miter joins. + float miterInverseLimit = + (contourIDWithFlags & EMULATED_STROKE_CAP_CONTOUR_FLAG) != + 0u + ? 1. + : .25; + clipRadius = + strokeRadius * (1. / max(miterRatio, miterInverseLimit)); + } + else + { + // Bevel! (Or butt cap.) + clipRadius = strokeRadius * miterRatio + + /* 1/2px bleed! */ bisectPixelWidth * .5; + } + float clipAARadius = clipRadius + bisectPixelWidth * AA_RADIUS; + if ((contourIDWithFlags & JOIN_TANGENT_INNER_CONTOUR_FLAG) != 0u) + { + // Reposition the inner join vertices at the miter-clip + // positions. Leave the outer join vertices as duplicates on the + // surrounding curve endpoints. We emit duplicate vertex + // positions because we need a hard stop on the clip distance + // (see below). + // + // Use aaRadius here because we're tracking AA on the mitered + // edge, NOT the outer clip edge. + float strokeAARaidus = strokeRadius + aaRadius; + // clipAARadius must be 1/16 of an AA ramp (~1/16 pixel) longer + // than the miter length before we start clipping, to ensure we + // are solving for a numerically stable intersection. + float slop = aaRadius * .125; + if (strokeAARaidus <= clipAARadius * miterRatio + slop) + { + // The miter point is before the clip line. Extend out to + // the miter point. + float miterAARadius = strokeAARaidus * (1. / miterRatio); + vertexOffset = bisector * miterAARadius; + } + else + { + // The clip line is before the miter point. Find where the + // clip line and the mitered edge intersect. + float2 bisectAAOffset = bisector * clipAARadius; + float2 k = float2(dot(vertexOffset, vertexOffset), + dot(bisectAAOffset, bisectAAOffset)); + vertexOffset = + MUL(k, inverse(float2x2(vertexOffset, bisectAAOffset))); + } + } + // The clip distance tells us how to antialias the outer clipped + // edge. Since joins only emanate from the outset side of the + // stroke, we can repurpose the inset distance as the clip distance. + float2 pt = abs(outset) * vertexOffset; + float clipDistance = (clipAARadius - dot(pt, bisector)) / + (bisectPixelWidth * (AA_RADIUS * 2.)); +#ifndef @RENDER_MODE_MSAA + if ((contourIDWithFlags & LEFT_JOIN_CONTOUR_FLAG) != 0u) + outCoverages.y = clipDistance; + else + outCoverages.x = clipDistance; +#endif + } + +#ifndef @RENDER_MODE_MSAA + outCoverages.xy *= globalCoverage; + + // Bias outCoverages.y slightly upwards in order to guarantee + // outCoverages.y is >= 0 at every pixel. "outCoverages.y < 0" is + // used to differentiate between strokes and fills. + outCoverages.y = max(outCoverages.y, 1e-4); + + if (featherRadius != .0) + { + // Bias x to tell the fragment shader that this is a feathered + // stroke. + outCoverages.x = FEATHER_COVERAGE_BIAS - outCoverages.x; + } +#endif + + postTransformVertexOffset = MUL(M, outset * vertexOffset); + + // Throw away the fan triangles since we're a stroke. + if (vertexType != STROKE_VERTEX) + return false; + } + else // This is a fill. + { +#ifndef @RENDER_MODE_MSAA + // "outCoverages.y < 0" indicates to the fragment shader that this is + // a fill, as opposed to a stroke. + outCoverages = float4(fillCoverage, -1., .0, .0); + +#ifdef @ENABLE_FEATHER + if (featherRadius != .0) + { + // Bias y to tell the fragment shader that this is a feathered edge. + outCoverages.y = FEATHER_COVERAGE_BIAS; + + // "outCoverages.z = HORIZONTAL_COTANGENT_VALUE" initializes us + // in a default state of feathering a flat edge (as opposed to a + // corner). + outCoverages.z = HORIZONTAL_COTANGENT_VALUE; + + // eval_feathered_fill() just feathers outCoverages.w=y0 when + // we're a flat edge, so initialize it with fillCoverage. + outCoverages.w = fillCoverage; + + if ((contourIDWithFlags & JOIN_TYPE_MASK) == + FEATHER_JOIN_CONTOUR_FLAG && + vertexType == STROKE_VERTEX) + { + // Feathered corners are symmetric; swap the first and second + // edge if needed so the corner angle is always positive. + if (featherJoinCornerTheta < .0) + { + featherJoinEdge0Theta += featherJoinCornerTheta; + featherJoinCornerTheta = -featherJoinCornerTheta; + } + + // Find the angle and local outset direction of our specific + // spoke in the feather join, relative to the first edge. Take + // advantage of the fact that feathered corners are symmetric + // again, and limit spokeTheta to the first half of the join + // angle. + float spokeTheta = theta - featherJoinEdge0Theta; + spokeTheta = mod(spokeTheta + PI_OVER_2, _2PI) - PI_OVER_2; + spokeTheta = clamp(spokeTheta, .0, featherJoinCornerTheta); + if (spokeTheta > featherJoinCornerTheta * .5) + { + spokeTheta = featherJoinCornerTheta - spokeTheta; + } + float2 spokeNorm = float2(sin(spokeTheta), cos(spokeTheta)); + + // TODO: This contraction logic generates cracks in geometry. It + // needs more investigation. +#if 0 + // When coners have stong curvature, their feather diminishes + // faster than it does for flat edges. In this scenario we can + // contract the tessellation a little to save on performance + // without losing visual fidelity. + // + // This code attempts to be somewhat methodical, but it's just + // hackery. The idea is to measure actual feather coverage at an + // outset of N standard deviations, compare that to what + // coverage would have been for a flat edge, and contract + // accordingly. By observation, a logarithmic function of + // featherJoinCornerTheta gives values for N with a good balance + // of perf and quality. + float N = + 1. + .33 * log2(PI_OVER_2 / + (PI - min(featherJoinCornerTheta, PI - PI / 16.))); + float4 coveragesAtNStddevOutset = + pack_feathered_fill_coverages(featherJoinCornerTheta, + spokeNorm, + .5 * (N / 3.)); + float featherAtNStddevOutset = eval_feathered_fill( + coveragesAtNStddevOutset TEXTURE_CONTEXT_FORWARD); + float inverseFeather = + INVERSE_FEATHER(featherAtNStddevOutset); + float stddevsAwayFromCenter = + (.5 - inverseFeather) * (FEATHER_TEXTURE_STDDEVS * 2.); + float contraction = N / max(stddevsAwayFromCenter, N); + outset *= contraction; +#endif + + // Emit coverage values for the fragment shader. + outCoverages = + pack_feathered_fill_coverages(featherJoinCornerTheta, + spokeNorm, + outset); + } + // Offset the vertex for feathering. + postTransformVertexOffset = MUL(M, (outset * featherRadius) * norm); + } + else +#endif // @ENABLE_FEATHER + { + // Offset the vertex for Manhattan AA. + postTransformVertexOffset = + sign(MUL(outset * norm, inverse(M))) * AA_RADIUS; + } + + if (bool(contourIDWithFlags & MIRRORED_CONTOUR_CONTOUR_FLAG) != + bool(contourIDWithFlags & NEGATE_PATH_FILL_COVERAGE_FLAG)) + { + outCoverages.x = -outCoverages.x; + } +#endif // !RENDER_MODE_MSAA + + // Place the fan point. + if (vertexType == FAN_MIDPOINT_VERTEX) + origin = midpoint; + + // If we're actually just drawing a triangle, throw away the entire + // patch except a single fan triangle. + if ((contourIDWithFlags & RETROFITTED_TRIANGLE_CONTOUR_FLAG) != 0u && + vertexType != FAN_VERTEX) + { + return false; + } + } + + outVertexPosition = MUL(M, origin) + postTransformVertexOffset + translate; + +#ifdef @RENDER_MODE_MSAA + uint4 pathData2 = STORAGE_BUFFER_LOAD4(@pathBuffer, outPathID * 4u + 2u); + outPathZIndex = cast_uint_to_ushort(pathData2.r); +#else + // Force coverage to solid when wireframe is enabled so we can see the + // triangles. + outCoverages.xy = mix(outCoverages.xy, + float2(1., -1.), + make_bool2(uniforms.wireframeEnabled != 0u)); +#endif + + return true; +} +#endif // @VERTEX && @DRAW_PATH + +#if defined(@VERTEX) && defined(@DRAW_INTERIOR_TRIANGLES) +INLINE float2 unpack_interior_triangle_vertex(float3 triangleVertex, + OUT(uint) outPathID +#ifdef @RENDER_MODE_MSAA + , + OUT(ushort) outPathZIndex +#else + , + OUT(half) outWindingWeight +#endif + VERTEX_CONTEXT_DECL) +{ + outPathID = floatBitsToUint(triangleVertex.z) & 0xffffu; +#ifdef @RENDER_MODE_MSAA + uint4 pathData2 = STORAGE_BUFFER_LOAD4(@pathBuffer, outPathID * 4u + 2u); + outPathZIndex = cast_uint_to_ushort(pathData2.x); +#else + outWindingWeight = cast_int_to_half(floatBitsToInt(triangleVertex.z) >> 16); +#endif + float2 vertexPos = triangleVertex.xy; + // ATLAS_BLIT draws vertices in screen space. + float2x2 M = make_float2x2( + uintBitsToFloat(STORAGE_BUFFER_LOAD4(@pathBuffer, outPathID * 4u))); + uint4 pathData = STORAGE_BUFFER_LOAD4(@pathBuffer, outPathID * 4u + 1u); + float2 translate = uintBitsToFloat(pathData.xy); + vertexPos = MUL(M, vertexPos) + translate; + return vertexPos; +} +#endif // @VERTEX && @DRAW_INTERIOR_TRIANGLES + +#if defined(@VERTEX) && defined(@ATLAS_BLIT) +INLINE float2 +unpack_atlas_coverage_vertex(float3 triangleVertex, + OUT(uint) outPathID, +#ifdef @RENDER_MODE_MSAA + OUT(ushort) outPathZIndex, +#endif + OUT(float2) outAtlasCoord VERTEX_CONTEXT_DECL) +{ + outPathID = floatBitsToUint(triangleVertex.z) & 0xffffu; + uint4 pathData2 = STORAGE_BUFFER_LOAD4(@pathBuffer, outPathID * 4u + 2u); +#ifdef @RENDER_MODE_MSAA + outPathZIndex = cast_uint_to_ushort(pathData2.x); +#endif + float2 vertexPos = triangleVertex.xy; + // outAtlasCoord tells the fragment shader where to fetch coverage from the + // atlas, when using atlas coverage. + float3 atlasTransform = uintBitsToFloat(pathData2.yzw); + outAtlasCoord = vertexPos * atlasTransform.x + atlasTransform.yz; + return vertexPos; +} +#endif // @VERTEX && @ATLAS_BLIT diff --git a/third_party/rive_renderer/source/shaders/glsl.glsl b/third_party/rive_renderer/source/shaders/glsl.glsl new file mode 100644 index 0000000..9baebc7 --- /dev/null +++ b/third_party/rive_renderer/source/shaders/glsl.glsl @@ -0,0 +1,596 @@ +/* + * Copyright 2023 Rive + */ + +// This header provides GLSL-specific #defines and declarations that enable our +// shaders to be compiled on MSL and GLSL both. + +#define GLSL + +#ifndef @GLSL_VERSION +// In "#version 320 es", Qualcomm incorrectly substitutes __VERSION__ to 300. +// @GLSL_VERSION is a workaround for this. +#define @GLSL_VERSION __VERSION__ +#endif + +#define float2 vec2 +#define float3 vec3 +#define packed_float3 vec3 +#define float4 vec4 + +#define half mediump float +#define half2 mediump vec2 +#define half3 mediump vec3 +#define half4 mediump vec4 +#define half3x3 mediump mat3x3 +#define half2x3 mediump mat2x3 + +#define int2 ivec2 +#define int3 ivec3 +#define int4 ivec4 + +#define short mediump int +#define short2 mediump ivec2 +#define short3 mediump ivec3 +#define short4 mediump ivec4 + +#define uint2 uvec2 +#define uint3 uvec3 +#define uint4 uvec4 + +#define ushort mediump uint +#define ushort2 mediump uvec2 +#define ushort3 mediump uvec3 +#define ushort4 mediump uvec4 + +#define bool2 bvec2 +#define bool3 bvec3 +#define bool4 bvec4 + +#define float2x2 mat2 + +#define INLINE +#define OUT(ARG_TYPE) out ARG_TYPE +#define INOUT(ARG_TYPE) inout ARG_TYPE + +#ifdef GL_ANGLE_base_vertex_base_instance_shader_builtin +#extension GL_ANGLE_base_vertex_base_instance_shader_builtin : require +#endif + +#ifdef @ENABLE_KHR_BLEND +#extension GL_KHR_blend_equation_advanced : require +#endif + +// clang-format off +#if defined(@RENDER_MODE_MSAA) && defined(@ENABLE_CLIP_RECT) && defined(GL_ES) +// clang-format on +#ifdef GL_EXT_clip_cull_distance +#extension GL_EXT_clip_cull_distance : require +#elif defined(GL_ANGLE_clip_cull_distance) +#extension GL_ANGLE_clip_cull_distance : require +#endif +#endif // RENDER_MODE_MSAA && ENABLE_CLIP_RECT + +#if @GLSL_VERSION >= 310 +#define UNIFORM_BLOCK_BEGIN(IDX, NAME) \ + layout(binding = IDX, std140) uniform NAME \ + { +#else +#define UNIFORM_BLOCK_BEGIN(IDX, NAME) \ + layout(std140) uniform NAME \ + { +#endif +// clang-format barrier... Otherwise it tries to merge this #define into the +// above macro... +#define UNIFORM_BLOCK_END(NAME) \ + } \ + NAME; + +#define ATTR_BLOCK_BEGIN(NAME) +#define ATTR(IDX, TYPE, NAME) layout(location = IDX) in TYPE NAME +#define ATTR_BLOCK_END +#define ATTR_LOAD(A, B, C, D) +#define ATTR_UNPACK(ID, attrs, NAME, TYPE) + +#ifdef @VERTEX +#if @GLSL_VERSION >= 310 +#define VARYING(IDX, TYPE, NAME) layout(location = IDX) out TYPE NAME +#else +#define VARYING(IDX, TYPE, NAME) out TYPE NAME +#endif +#else +#if @GLSL_VERSION >= 310 +#define VARYING(IDX, TYPE, NAME) layout(location = IDX) in TYPE NAME +#else +#define VARYING(IDX, TYPE, NAME) in TYPE NAME +#endif +#endif +#define FLAT flat +#define VARYING_BLOCK_BEGIN +#define VARYING_BLOCK_END + +// clang-format off +#ifdef @TARGET_VULKAN + // Since Vulkan is compiled offline and not all platforms support noperspective, don't use it. +# define NO_PERSPECTIVE +#else +# ifdef GL_NV_shader_noperspective_interpolation +# extension GL_NV_shader_noperspective_interpolation : require +# define NO_PERSPECTIVE noperspective +# else +# define NO_PERSPECTIVE +# endif +#endif +// clang-format on + +#ifdef @VERTEX +#define VERTEX_TEXTURE_BLOCK_BEGIN +#define VERTEX_TEXTURE_BLOCK_END +#endif + +#ifdef @FRAGMENT +#define FRAG_TEXTURE_BLOCK_BEGIN +#define FRAG_TEXTURE_BLOCK_END +#endif + +#define DYNAMIC_SAMPLER_BLOCK_BEGIN +#define DYNAMIC_SAMPLER_BLOCK_END + +#ifdef @TARGET_VULKAN +#define TEXTURE_RGBA32UI(SET, IDX, NAME) \ + layout(set = SET, binding = IDX) uniform highp utexture2D NAME +#define TEXTURE_RGBA32F(SET, IDX, NAME) \ + layout(set = SET, binding = IDX) uniform highp texture2D NAME +#define TEXTURE_RGBA8(SET, IDX, NAME) \ + layout(set = SET, binding = IDX) uniform mediump texture2D NAME +#define TEXTURE_R16F(SET, IDX, NAME) \ + layout(binding = IDX) uniform mediump texture2D NAME +#elif @GLSL_VERSION >= 310 +#define TEXTURE_RGBA32UI(SET, IDX, NAME) \ + layout(binding = IDX) uniform highp usampler2D NAME +#define TEXTURE_RGBA32F(SET, IDX, NAME) \ + layout(binding = IDX) uniform highp sampler2D NAME +#define TEXTURE_RGBA8(SET, IDX, NAME) \ + layout(binding = IDX) uniform mediump sampler2D NAME +#define TEXTURE_R16F(SET, IDX, NAME) \ + layout(binding = IDX) uniform mediump sampler2D NAME +#else +#define TEXTURE_RGBA32UI(SET, IDX, NAME) uniform highp usampler2D NAME +#define TEXTURE_RGBA32F(SET, IDX, NAME) uniform highp sampler2D NAME +#define TEXTURE_RGBA8(SET, IDX, NAME) uniform mediump sampler2D NAME +#define TEXTURE_R16F(SET, IDX, NAME) uniform mediump sampler2D NAME +#endif + +#ifdef @TARGET_VULKAN +#define SAMPLER_LINEAR(TEXTURE_IDX, NAME) \ + layout(set = IMMUTABLE_SAMPLER_BINDINGS_SET, binding = TEXTURE_IDX) \ + uniform mediump sampler NAME; +#define SAMPLER_MIPMAP(TEXTURE_IDX, NAME) \ + layout(set = IMMUTABLE_SAMPLER_BINDINGS_SET, binding = TEXTURE_IDX) \ + uniform mediump sampler NAME; +#define SAMPLER_DYNAMIC(TEXTURE_IDX, NAME) \ + layout(set = PER_DRAW_BINDINGS_SET, binding = TEXTURE_IDX) \ + uniform mediump sampler NAME; +#define TEXTURE_SAMPLE(NAME, SAMPLER_NAME, COORD) \ + texture(sampler2D(NAME, SAMPLER_NAME), COORD) +#define TEXTURE_SAMPLE_LOD(NAME, SAMPLER_NAME, COORD, LOD) \ + textureLod(sampler2D(NAME, SAMPLER_NAME), COORD, LOD) +#define TEXTURE_SAMPLE_GRAD(NAME, SAMPLER_NAME, COORD, DDX, DDY) \ + textureGrad(sampler2D(NAME, SAMPLER_NAME), COORD, DDX, DDY) +#else +// SAMPLER_LINEAR and SAMPLER_MIPMAP are no-ops because in GL, sampling +// parameters are API-level state tied to the texture. +#define SAMPLER_LINEAR(TEXTURE_IDX, NAME) +#define SAMPLER_MIPMAP(TEXTURE_IDX, NAME) +#define SAMPLER_DYNAMIC(TEXTURE_IDX, NAME) +#define TEXTURE_SAMPLE(NAME, SAMPLER_NAME, COORD) texture(NAME, COORD) +#define TEXTURE_SAMPLE_LOD(NAME, SAMPLER_NAME, COORD, LOD) \ + textureLod(NAME, COORD, LOD) +#define TEXTURE_SAMPLE_GRAD(NAME, SAMPLER_NAME, COORD, DDX, DDY) \ + textureGrad(NAME, COORD, DDX, DDY) +#endif // !@TARGET_VULKAN + +#define TEXTURE_SAMPLE_DYNAMIC(TEXTURE, SAMPLER_NAME, COORD) \ + TEXTURE_SAMPLE(TEXTURE, SAMPLER_NAME, COORD) +#define TEXTURE_SAMPLE_DYNAMIC_LOD(TEXTURE, SAMPLER_NAME, COORD, LOD) \ + TEXTURE_SAMPLE_LOD(TEXTURE, SAMPLER_NAME, COORD, LOD) + +// Polyfill the feather texture as a sampler2D since ES doesn't support +// sampler1DArray. This is why the macro needs "ARRAY_INDEX_NORMALIZED": when +// polyfilled as a 2D texture, the "array index" needs to be a 0..1 normalized +// y coordinate instead of the literal array index. +#define TEXTURE_R16F_1D_ARRAY(SET, IDX, NAME) TEXTURE_R16F(SET, IDX, NAME) +// clang-format off +// Clang formatting on this line trips up the Qualcomm compiler. +#define TEXTURE_SAMPLE_LOD_1D_ARRAY(NAME, SAMPLER_NAME, X, ARRAY_INDEX, ARRAY_INDEX_NORMALIZED, LOD) \ + TEXTURE_SAMPLE_LOD(NAME, SAMPLER_NAME, float2(X, ARRAY_INDEX_NORMALIZED), LOD) +// clang-format on + +#define TEXTURE_RG32UI(SET, IDX, NAME) TEXTURE_RGBA32UI(SET, IDX, NAME) + +#define TEXTURE_CONTEXT_DECL + +#define TEXTURE_CONTEXT_FORWARD +#define TEXEL_FETCH(NAME, COORD) texelFetch(NAME, COORD, 0) + +#ifdef @TARGET_VULKAN +#define TEXTURE_GATHER(NAME, SAMPLER_NAME, COORD, TEXTURE_INVERSE_SIZE) \ + textureGather(sampler2D(NAME, SAMPLER_NAME), \ + (COORD) * (TEXTURE_INVERSE_SIZE)) +#elif @GLSL_VERSION >= 310 +#define TEXTURE_GATHER(NAME, SAMPLER_NAME, COORD, TEXTURE_INVERSE_SIZE) \ + textureGather(NAME, (COORD) * (TEXTURE_INVERSE_SIZE)) +#else +#define TEXTURE_GATHER(NAME, SAMPLER_NAME, COORD, TEXTURE_INVERSE_SIZE) \ + make_half4(TEXEL_FETCH(NAME, int2(COORD) + int2(-1, 0)).r, \ + TEXEL_FETCH(NAME, int2(COORD) + int2(0, 0)).r, \ + TEXEL_FETCH(NAME, int2(COORD) + int2(0, -1)).r, \ + TEXEL_FETCH(NAME, int2(COORD) + int2(-1, -1)).r) +#endif + +#define VERTEX_STORAGE_BUFFER_BLOCK_BEGIN +#define VERTEX_STORAGE_BUFFER_BLOCK_END + +#define FRAG_STORAGE_BUFFER_BLOCK_BEGIN +#define FRAG_STORAGE_BUFFER_BLOCK_END + +#ifdef @DISABLE_SHADER_STORAGE_BUFFERS + +#define STORAGE_BUFFER_U32x2(IDX, GLSL_STRUCT_NAME, NAME) \ + TEXTURE_RGBA32UI(PER_FLUSH_BINDINGS_SET, IDX, NAME) +#define STORAGE_BUFFER_U32x4(IDX, GLSL_STRUCT_NAME, NAME) \ + TEXTURE_RG32UI(PER_FLUSH_BINDINGS_SET, IDX, NAME) +#define STORAGE_BUFFER_F32x4(IDX, GLSL_STRUCT_NAME, NAME) \ + TEXTURE_RGBA32F(PER_FLUSH_BINDINGS_SET, IDX, NAME) +#define STORAGE_BUFFER_LOAD4(NAME, I) \ + TEXEL_FETCH( \ + NAME, \ + int2((I) & STORAGE_TEXTURE_MASK_X, (I) >> STORAGE_TEXTURE_SHIFT_Y)) +#define STORAGE_BUFFER_LOAD2(NAME, I) \ + TEXEL_FETCH( \ + NAME, \ + int2((I) & STORAGE_TEXTURE_MASK_X, (I) >> STORAGE_TEXTURE_SHIFT_Y)) \ + .xy + +#else + +#ifdef GL_ARB_shader_storage_buffer_object +#extension GL_ARB_shader_storage_buffer_object : require +#endif +#define STORAGE_BUFFER_U32x2(IDX, GLSL_STRUCT_NAME, NAME) \ + layout(std430, binding = IDX) readonly buffer GLSL_STRUCT_NAME \ + { \ + uint2 _values[]; \ + } \ + NAME +#define STORAGE_BUFFER_U32x4(IDX, GLSL_STRUCT_NAME, NAME) \ + layout(std430, binding = IDX) readonly buffer GLSL_STRUCT_NAME \ + { \ + uint4 _values[]; \ + } \ + NAME +#define STORAGE_BUFFER_F32x4(IDX, GLSL_STRUCT_NAME, NAME) \ + layout(std430, binding = IDX) readonly buffer GLSL_STRUCT_NAME \ + { \ + float4 _values[]; \ + } \ + NAME +#define STORAGE_BUFFER_U32_ATOMIC(IDX, GLSL_STRUCT_NAME, NAME) \ + layout(std430, binding = IDX) buffer GLSL_STRUCT_NAME { uint _values[]; } \ + NAME +#define STORAGE_BUFFER_LOAD4(NAME, I) NAME._values[I] +#define STORAGE_BUFFER_LOAD2(NAME, I) NAME._values[I] +#define STORAGE_BUFFER_LOAD(NAME, I) NAME._values[I] +#define STORAGE_BUFFER_ATOMIC_MAX(NAME, I, X) atomicMax(NAME._values[I], X) +#define STORAGE_BUFFER_ATOMIC_ADD(NAME, I, X) atomicAdd(NAME._values[I], X) + +#endif // DISABLE_SHADER_STORAGE_BUFFERS + +// Define macros for implementing pixel local storage based on available +// extensions. +#ifdef @PLS_IMPL_ANGLE + +#extension GL_ANGLE_shader_pixel_local_storage : require + +#define PLS_BLOCK_BEGIN +#define PLS_DECL4F(IDX, NAME) \ + layout(binding = IDX, rgba8) uniform lowp pixelLocalANGLE NAME +#define PLS_DECLUI(IDX, NAME) \ + layout(binding = IDX, r32ui) uniform highp upixelLocalANGLE NAME +#define PLS_BLOCK_END + +#define PLS_LOAD4F(PLANE) pixelLocalLoadANGLE(PLANE) +#define PLS_LOADUI(PLANE) pixelLocalLoadANGLE(PLANE).r +#define PLS_STORE4F(PLANE, VALUE) pixelLocalStoreANGLE(PLANE, VALUE) +#define PLS_STOREUI(PLANE, VALUE) pixelLocalStoreANGLE(PLANE, uvec4(VALUE)) + +#define PLS_PRESERVE_4F(PLANE) +#define PLS_PRESERVE_UI(PLANE) + +#define PLS_INTERLOCK_BEGIN +#define PLS_INTERLOCK_END + +#endif // PLS_IMPL_ANGLE + +#ifdef @PLS_IMPL_EXT_NATIVE + +#extension GL_EXT_shader_pixel_local_storage : enable + +#define PLS_BLOCK_BEGIN \ + __pixel_localEXT PLS \ + { +#define PLS_DECL4F(IDX, NAME) layout(rgba8) lowp vec4 NAME +#define PLS_DECLUI(IDX, NAME) layout(r32ui) highp uint NAME +#define PLS_BLOCK_END \ + } \ + ; + +#define PLS_LOAD4F(PLANE) PLANE +#define PLS_LOADUI(PLANE) PLANE +#define PLS_STORE4F(PLANE, VALUE) PLANE = (VALUE) +#define PLS_STOREUI(PLANE, VALUE) PLANE = (VALUE) + +#define PLS_PRESERVE_4F(PLANE) PLANE = PLANE +#define PLS_PRESERVE_UI(PLANE) PLANE = PLANE + +#define PLS_INTERLOCK_BEGIN +#define PLS_INTERLOCK_END + +#endif + +#ifdef @PLS_IMPL_FRAMEBUFFER_FETCH + +#extension GL_EXT_shader_framebuffer_fetch : require + +#define PLS_BLOCK_BEGIN +#define PLS_DECL4F(IDX, NAME) layout(location = IDX) inout lowp vec4 NAME +#define PLS_DECLUI(IDX, NAME) layout(location = IDX) inout highp uvec4 NAME +#define PLS_BLOCK_END + +#define PLS_LOAD4F(PLANE) PLANE +#define PLS_LOADUI(PLANE) PLANE.r +#define PLS_STORE4F(PLANE, VALUE) PLANE = (VALUE) +#define PLS_STOREUI(PLANE, VALUE) PLANE.r = (VALUE) + +// When using multiple color attachments, we have to write a value to every +// color attachment, every shader invocation, or else the contents become +// undefined. +#define PLS_PRESERVE_4F(PLANE) PLS_STORE4F(PLANE, PLS_LOAD4F(PLANE)) +#define PLS_PRESERVE_UI(PLANE) PLS_STOREUI(PLANE, PLS_LOADUI(PLANE)) + +#define PLS_INTERLOCK_BEGIN +#define PLS_INTERLOCK_END + +#endif // PLS_IMPL_FRAMEBUFFER_FETCH + +#ifdef @PLS_IMPL_STORAGE_TEXTURE + +#ifdef GL_ARB_shader_image_load_store +#extension GL_ARB_shader_image_load_store : require +#endif +#if defined(GL_ARB_fragment_shader_interlock) +#extension GL_ARB_fragment_shader_interlock : require +#define PLS_INTERLOCK_BEGIN beginInvocationInterlockARB() +#define PLS_INTERLOCK_END endInvocationInterlockARB() +#elif defined(GL_INTEL_fragment_shader_ordering) +#extension GL_INTEL_fragment_shader_ordering : require +#define PLS_INTERLOCK_BEGIN beginFragmentShaderOrderingINTEL() +#define PLS_INTERLOCK_END +#else +#define PLS_INTERLOCK_BEGIN +#define PLS_INTERLOCK_END +#endif + +#define PLS_BLOCK_BEGIN +#ifdef @TARGET_VULKAN +#define PLS_DECL4F(IDX, NAME) \ + layout(set = PLS_TEXTURE_BINDINGS_SET, binding = IDX, rgba8) \ + uniform lowp coherent image2D NAME +#define PLS_DECLUI(IDX, NAME) \ + layout(set = PLS_TEXTURE_BINDINGS_SET, binding = IDX, r32ui) \ + uniform highp coherent uimage2D NAME +#else +#define PLS_DECL4F(IDX, NAME) \ + layout(binding = IDX, rgba8) uniform lowp coherent image2D NAME +#define PLS_DECLUI(IDX, NAME) \ + layout(binding = IDX, r32ui) uniform highp coherent uimage2D NAME +#endif +#define PLS_BLOCK_END + +#define PLS_LOAD4F(PLANE) imageLoad(PLANE, _plsCoord) +#define PLS_LOADUI(PLANE) imageLoad(PLANE, _plsCoord).r +#define PLS_STORE4F(PLANE, VALUE) imageStore(PLANE, _plsCoord, VALUE) +#define PLS_STOREUI(PLANE, VALUE) imageStore(PLANE, _plsCoord, uvec4(VALUE)) + +#define PLS_PRESERVE_4F(PLANE) +#define PLS_PRESERVE_UI(PLANE) + +#ifndef @USING_PLS_STORAGE_TEXTURES +#define @USING_PLS_STORAGE_TEXTURES + +#endif // PLS_IMPL_STORAGE_TEXTURE + +#endif // PLS_IMPL_STORAGE_TEXTURE + +#ifdef @PLS_IMPL_SUBPASS_LOAD + +#define PLS_BLOCK_BEGIN +#define PLS_DECL4F_READONLY(IDX, NAME) \ + layout(input_attachment_index = IDX, \ + binding = IDX, \ + set = PLS_TEXTURE_BINDINGS_SET) \ + uniform lowp subpassInput _in_##NAME; +#define PLS_DECL4F(IDX, NAME) \ + PLS_DECL4F_READONLY(IDX, NAME); \ + layout(location = IDX) out lowp vec4 NAME +#define PLS_DECLUI(IDX, NAME) \ + layout(input_attachment_index = IDX, \ + binding = IDX, \ + set = PLS_TEXTURE_BINDINGS_SET) \ + uniform highp usubpassInput _in_##NAME; \ + layout(location = IDX) out highp uvec4 NAME +#define PLS_BLOCK_END + +#define PLS_LOAD4F(PLANE) subpassLoad(_in_##PLANE) +#define PLS_LOADUI(PLANE) subpassLoad(_in_##PLANE).r +#define PLS_STORE4F(PLANE, VALUE) PLANE = (VALUE) +#define PLS_STOREUI(PLANE, VALUE) PLANE.r = (VALUE) + +#define PLS_PRESERVE_4F(PLANE) PLS_STORE4F(PLANE, subpassLoad(_in_##PLANE)) +#define PLS_PRESERVE_UI(PLANE) PLS_STOREUI(PLANE, subpassLoad(_in_##PLANE).r) + +#define PLS_INTERLOCK_BEGIN +#define PLS_INTERLOCK_END + +#endif + +#ifdef @PLS_IMPL_NONE + +#define PLS_BLOCK_BEGIN +#define PLS_DECL4F(IDX, NAME) layout(location = IDX) out lowp vec4 NAME +#define PLS_DECLUI(IDX, NAME) layout(location = IDX) out highp uvec4 NAME +#define PLS_BLOCK_END + +#define PLS_LOAD4F(PLANE) vec4(0) +#define PLS_LOADUI(PLANE) 0u +#define PLS_STORE4F(PLANE, VALUE) PLANE = (VALUE) +#define PLS_STOREUI(PLANE, VALUE) PLANE.r = (VALUE) + +#define PLS_PRESERVE_4F(PLANE) PLANE = vec4(0) +#define PLS_PRESERVE_UI(PLANE) PLANE.r = 0u + +#define PLS_INTERLOCK_BEGIN +#define PLS_INTERLOCK_END + +#endif + +#ifdef @TARGET_VULKAN +#define gl_VertexID gl_VertexIndex +#endif + +// clang-format off +#ifdef @ENABLE_INSTANCE_INDEX +# ifdef @TARGET_VULKAN +# define INSTANCE_INDEX gl_InstanceIndex +# else +# ifdef @BASE_INSTANCE_UNIFORM_NAME + // gl_BaseInstance isn't supported on this platform. The rendering + // backend will set this uniform for us instead. + uniform highp int @BASE_INSTANCE_UNIFORM_NAME; +# define INSTANCE_INDEX (gl_InstanceID + @BASE_INSTANCE_UNIFORM_NAME) +# else +# define INSTANCE_INDEX (gl_InstanceID + gl_BaseInstance) +# endif +# endif +#else +# define INSTANCE_INDEX 0 +#endif +// clang-format on + +#define VERTEX_CONTEXT_DECL +#define VERTEX_CONTEXT_UNPACK + +#define VERTEX_MAIN(NAME, Attrs, attrs, _vertexID, _instanceID) \ + void main() \ + { \ + int _vertexID = gl_VertexID; \ + int _instanceID = INSTANCE_INDEX; + +#define IMAGE_RECT_VERTEX_MAIN VERTEX_MAIN + +// clang-format off +#define IMAGE_MESH_VERTEX_MAIN(NAME, PositionAttr, position, UVAttr, uv, _vertexID) \ + VERTEX_MAIN(NAME, PositionAttr, position, _vertexID, _instanceID) +// clang-format on + +#define VARYING_INIT(NAME, TYPE) +#define VARYING_PACK(NAME) +#define VARYING_UNPACK(NAME, TYPE) + +#define EMIT_VERTEX(_pos) \ + gl_Position = _pos; \ + } + +#define FRAG_DATA_MAIN(DATA_TYPE, NAME) \ + layout(location = 0) out DATA_TYPE _fd; \ + void main() + +#define EMIT_FRAG_DATA(VALUE) _fd = VALUE + +#define _fragCoord gl_FragCoord.xy + +#define FRAGMENT_CONTEXT_DECL +#define FRAGMENT_CONTEXT_UNPACK + +#ifdef @USING_PLS_STORAGE_TEXTURES + +#ifdef @TARGET_VULKAN +#define PLS_DECLUI_ATOMIC(IDX, NAME) \ + layout(set = PLS_TEXTURE_BINDINGS_SET, binding = IDX, r32ui) \ + uniform highp coherent uimage2D NAME +#else +#define PLS_DECLUI_ATOMIC(IDX, NAME) \ + layout(binding = IDX, r32ui) uniform highp coherent uimage2D NAME +#endif +#define PLS_LOADUI_ATOMIC(PLANE) imageLoad(PLANE, _plsCoord).r +#define PLS_STOREUI_ATOMIC(PLANE, VALUE) \ + imageStore(PLANE, _plsCoord, uvec4(VALUE)) +#define PLS_ATOMIC_MAX(PLANE, X) imageAtomicMax(PLANE, _plsCoord, X) +#define PLS_ATOMIC_ADD(PLANE, X) imageAtomicAdd(PLANE, _plsCoord, X) + +#define PLS_CONTEXT_DECL , int2 _plsCoord +#define PLS_CONTEXT_UNPACK , _plsCoord + +#define PLS_MAIN(NAME) \ + void main() \ + { \ + int2 _plsCoord = ivec2(floor(_fragCoord)); + +#define EMIT_PLS } + +#else // !USING_PLS_STORAGE_TEXTURES + +#define PLS_CONTEXT_DECL +#define PLS_CONTEXT_UNPACK + +#define PLS_MAIN(NAME) void main() +#define EMIT_PLS + +#endif // !USING_PLS_STORAGE_TEXTURES + +#define PLS_MAIN_WITH_IMAGE_UNIFORMS(NAME) PLS_MAIN(NAME) + +#define PLS_FRAG_COLOR_MAIN(NAME) \ + layout(location = 0) out half4 _fragColor; \ + PLS_MAIN(NAME) + +#define PLS_FRAG_COLOR_MAIN_WITH_IMAGE_UNIFORMS(NAME) \ + layout(location = 0) out half4 _fragColor; \ + PLS_MAIN(NAME) + +#define EMIT_PLS_AND_FRAG_COLOR EMIT_PLS + +#define MUL(A, B) ((A) * (B)) + +precision highp float; +precision highp int; + +#if @GLSL_VERSION < 310 +// Polyfill ES 3.1+ methods. +INLINE half4 unpackUnorm4x8(uint u) +{ + uint4 vals = uint4(u & 0xffu, (u >> 8) & 0xffu, (u >> 16) & 0xffu, u >> 24); + return float4(vals) * (1. / 255.); +} +#endif + +// clang-format off +#if @GLSL_VERSION >= 310 && defined(@VERTEX) && defined(@RENDER_MODE_MSAA) && defined(@ENABLE_CLIP_RECT) +out gl_PerVertex +{ + // Redeclare gl_ClipDistance with exactly 4 clip planes. + float gl_ClipDistance[4]; + float4 gl_Position; +}; +#endif +// clang-format on diff --git a/third_party/rive_renderer/source/shaders/hlsl.glsl b/third_party/rive_renderer/source/shaders/hlsl.glsl new file mode 100644 index 0000000..e17e23a --- /dev/null +++ b/third_party/rive_renderer/source/shaders/hlsl.glsl @@ -0,0 +1,427 @@ +/* + * Copyright 2023 Rive + */ + +// This header provides GLSL-specific #defines and declarations that enable our +// shaders to be compiled on MSL and GLSL both. + +// HLSL warns that it will unroll the loops through r,g,b values in +// advanced_blend.glsl, but unrolling these loops is exactly what we want. +#pragma $warning($disable : 3550) + +// Don't warn about uninitialized variables. If we leave one uninitialized it's +// because we know what we're doing and don't want to pay the cost of +// initializing it. +#pragma $warning($disable : 4000) + +// #define native hlsl types if their names are being rewritten. +#define _ARE_TOKEN_NAMES_PRESERVED +#ifndef $_ARE_TOKEN_NAMES_PRESERVED +#define half $half +#define half2 $half2 +#define half3 $half3 +#define half4 $half4 +#define float2 $float2 +#define float3 $float3 +#define float4 $float4 +#define bool2 $bool2 +#define bool3 $bool3 +#define bool4 $bool4 +#define uint2 $uint2 +#define uint3 $uint3 +#define uint4 $uint4 +#define int2 $int2 +#define int3 $int3 +#define int4 $int4 +#define float4x2 $float4x2 +#define float2x2 $float2x2 +#define half3x3 $half3x3 +#define half2x3 $half2x3 +#endif + +$typedef float3 packed_float3; + +#ifdef @ENABLE_MIN_16_PRECISION + +// Use #define instead of typedef because typedef generates +// "error X3093: out of memory while parsing". +#define short $min16int +#define short2 $min16int2 +#define ushort $min16uint + +#else + +// Use #define instead of typedef because typedef generates +// "error X3093: out of memory while parsing". +#define short int +#define short2 int2 +#define ushort uint + +#endif + +#define INLINE $inline +#define OUT(ARG_TYPE) out ARG_TYPE +#define INOUT(ARG_TYPE) inout ARG_TYPE + +#define ATTR_BLOCK_BEGIN(NAME) \ + struct NAME \ + { +#define ATTR(IDX, TYPE, NAME) TYPE NAME : NAME +#define ATTR_BLOCK_END \ + } \ + ; +#define ATTR_LOAD(T, A, N, I) +#define ATTR_UNPACK(ID, attrs, NAME, TYPE) TYPE NAME = attrs.NAME + +#define UNIFORM_BUFFER_REGISTER(IDX) $register($b##IDX) + +#define UNIFORM_BLOCK_BEGIN(IDX, NAME) \ + $cbuffer NAME : UNIFORM_BUFFER_REGISTER(IDX) \ + { \ + struct \ + { + +#define UNIFORM_BLOCK_END(NAME) \ + } \ + NAME; \ + } + +#define VARYING_BLOCK_BEGIN \ + struct Varyings \ + { + +#define NO_PERSPECTIVE $noperspective +#define @OPTIONALLY_FLAT $nointerpolation +#define FLAT $nointerpolation +#define VARYING(IDX, TYPE, NAME) TYPE NAME : $TEXCOORD##IDX + +#define VARYING_BLOCK_END \ + float4 _pos : $SV_Position; \ + } \ + ; + +#define VARYING_INIT(NAME, TYPE) TYPE NAME +#define VARYING_PACK(NAME) _varyings.NAME = NAME +#define VARYING_UNPACK(NAME, TYPE) TYPE NAME = _varyings.NAME + +#ifdef @VERTEX +#define VERTEX_TEXTURE_BLOCK_BEGIN +#define VERTEX_TEXTURE_BLOCK_END +#endif + +#ifdef @FRAGMENT +#define FRAG_TEXTURE_BLOCK_BEGIN +#define FRAG_TEXTURE_BLOCK_END +#endif + +#define DYNAMIC_SAMPLER_BLOCK_BEGIN +#define DYNAMIC_SAMPLER_BLOCK_END + +#define TEXTURE_RGBA32UI(SET, IDX, NAME) \ + uniform $Texture2D NAME : $register($t##IDX) +#define TEXTURE_RGBA32F(SET, IDX, NAME) \ + uniform $Texture2D NAME : $register($t##IDX) +#define TEXTURE_RGBA8(SET, IDX, NAME) \ + uniform $Texture2D<$unorm float4> NAME : $register($t##IDX) +#define TEXTURE_R16F(SET, IDX, NAME) \ + uniform $Texture2D NAME : $register($t##IDX) +#define TEXTURE_R16F_1D_ARRAY(SET, IDX, NAME) \ + uniform $Texture1DArray NAME : $register($t##IDX) + +// SAMPLER_LINEAR and SAMPLER_MIPMAP are the same because in d3d11, sampler +// parameters are defined at the API level. +#define SAMPLER(TEXTURE_IDX, NAME) \ + $SamplerState NAME : $register($s##TEXTURE_IDX); +#define SAMPLER_LINEAR SAMPLER +#define SAMPLER_MIPMAP SAMPLER +#define SAMPLER_DYNAMIC SAMPLER + +#define TEXEL_FETCH(NAME, COORD) NAME[COORD] +#define TEXTURE_SAMPLE(NAME, SAMPLER_NAME, COORD) \ + NAME.$Sample(SAMPLER_NAME, COORD) +#define TEXTURE_SAMPLE_LOD(NAME, SAMPLER_NAME, COORD, LOD) \ + NAME.$SampleLevel(SAMPLER_NAME, COORD, LOD) +#define TEXTURE_SAMPLE_GRAD(NAME, SAMPLER_NAME, COORD, DDX, DDY) \ + NAME.$SampleGrad(SAMPLER_NAME, COORD, DDX, DDY) +#define TEXTURE_GATHER(NAME, SAMPLER_NAME, COORD, TEXTURE_INVERSE_SIZE) \ + NAME.$Gather(SAMPLER_NAME, (COORD) * (TEXTURE_INVERSE_SIZE)) +#define TEXTURE_SAMPLE_LOD_1D_ARRAY(NAME, \ + SAMPLER_NAME, \ + X, \ + ARRAY_INDEX, \ + ARRAY_INDEX_NORMALIZED, \ + LOD) \ + NAME.$SampleLevel(SAMPLER_NAME, float2(X, ARRAY_INDEX), LOD) + +#define TEXTURE_SAMPLE_DYNAMIC(TEXTURE, SAMPLER_NAME, COORD) \ + TEXTURE_SAMPLE(TEXTURE, SAMPLER_NAME, COORD) +#define TEXTURE_SAMPLE_DYNAMIC_LOD(TEXTURE, SAMPLER_NAME, COORD, LOD) \ + TEXTURE_SAMPLE_LOD(TEXTURE, SAMPLER_NAME, COORD, LOD) + +#define PLS_INTERLOCK_BEGIN +#define PLS_INTERLOCK_END + +#ifdef @ENABLE_RASTERIZER_ORDERED_VIEWS +#define PLS_TEX2D $RasterizerOrderedTexture2D +#else +#define PLS_TEX2D $RWTexture2D +#endif + +#define PLS_BLOCK_BEGIN +#ifdef @ENABLE_TYPED_UAV_LOAD_STORE +#define PLS_DECL4F(IDX, NAME) \ + uniform PLS_TEX2D<$unorm half4> NAME : $register($u##IDX) +#else +#define PLS_DECL4F(IDX, NAME) uniform PLS_TEX2D NAME : $register($u##IDX) +#endif +#define PLS_DECL4F_READONLY PLS_DECL4F +#define PLS_DECLUI(IDX, NAME) uniform PLS_TEX2D NAME : $register($u##IDX) +#define PLS_DECLUI_ATOMIC PLS_DECLUI +#define PLS_LOADUI_ATOMIC PLS_LOADUI +#define PLS_STOREUI_ATOMIC PLS_STOREUI +#define PLS_BLOCK_END + +#ifdef @ENABLE_TYPED_UAV_LOAD_STORE +#define PLS_LOAD4F(PLANE) PLANE[_plsCoord] +#else +#define PLS_LOAD4F(PLANE) unpackUnorm4x8(PLANE[_plsCoord]) +#endif +#define PLS_LOADUI(PLANE) PLANE[_plsCoord] +#ifdef @ENABLE_TYPED_UAV_LOAD_STORE +#define PLS_STORE4F(PLANE, VALUE) PLANE[_plsCoord] = (VALUE) +#else +#define PLS_STORE4F(PLANE, VALUE) PLANE[_plsCoord] = packUnorm4x8(VALUE) +#endif +#define PLS_STOREUI(PLANE, VALUE) PLANE[_plsCoord] = (VALUE) + +INLINE uint pls_atomic_max(PLS_TEX2D plane, int2 _plsCoord, uint x) +{ + uint originalValue; + $InterlockedMax(plane[_plsCoord], x, originalValue); + return originalValue; +} + +#define PLS_ATOMIC_MAX(PLANE, X) pls_atomic_max(PLANE, _plsCoord, X) + +INLINE uint pls_atomic_add(PLS_TEX2D plane, int2 _plsCoord, uint x) +{ + uint originalValue; + $InterlockedAdd(plane[_plsCoord], x, originalValue); + return originalValue; +} + +#define PLS_ATOMIC_ADD(PLANE, X) pls_atomic_add(PLANE, _plsCoord, X) + +#define PLS_PRESERVE_4F(PLANE) +#define PLS_PRESERVE_UI(PLANE) + +#define VERTEX_CONTEXT_DECL +#define VERTEX_CONTEXT_UNPACK + +#define TEXTURE_CONTEXT_DECL +#define TEXTURE_CONTEXT_FORWARD + +#define VERTEX_MAIN(NAME, Attrs, attrs, _vertexID, _instanceID) \ + $cbuffer DrawUniforms \ + : UNIFORM_BUFFER_REGISTER(PATH_BASE_INSTANCE_UNIFORM_BUFFER_IDX) \ + { \ + uint baseInstance; \ + uint NAME##_pad0; \ + uint NAME##_pad1; \ + uint NAME##_pad2; \ + } \ + Varyings main(Attrs attrs, uint _vertexID \ + : $SV_VertexID, uint _instanceIDWithoutBase \ + : $SV_InstanceID) \ + { \ + uint _instanceID = _instanceIDWithoutBase + baseInstance; \ + Varyings _varyings; + +#define IMAGE_RECT_VERTEX_MAIN(NAME, Attrs, attrs, _vertexID, _instanceID) \ + Varyings main(Attrs attrs, uint _vertexID : $SV_VertexID) \ + { \ + Varyings _varyings; \ + float4 _pos; + +#define IMAGE_MESH_VERTEX_MAIN(NAME, \ + PositionAttr, \ + position, \ + UVAttr, \ + uv, \ + _vertexID) \ + Varyings main(PositionAttr position, UVAttr uv, uint _vertexID \ + : $SV_VertexID) \ + { \ + Varyings _varyings; \ + float4 _pos; + +#define EMIT_VERTEX(POSITION) \ + _varyings._pos = POSITION; \ + } \ + return _varyings; + +#define FRAG_DATA_MAIN(DATA_TYPE, NAME) \ + DATA_TYPE main(Varyings _varyings) : $SV_Target \ + { + +#define EMIT_FRAG_DATA(VALUE) \ + return VALUE; \ + } + +#define FRAGMENT_CONTEXT_DECL , float2 _fragCoord +#define FRAGMENT_CONTEXT_UNPACK , _fragCoord + +#define PLS_CONTEXT_DECL , int2 _plsCoord +#define PLS_CONTEXT_UNPACK , _plsCoord + +#define PLS_MAIN(NAME) [$earlydepthstencil] void main(Varyings _varyings) { \ + float2 _fragCoord = _varyings._pos.xy;\ + int2 _plsCoord = int2(floor(_fragCoord)); + +#define PLS_MAIN_WITH_IMAGE_UNIFORMS(NAME) PLS_MAIN(NAME) + +#define EMIT_PLS } + +#define PLS_FRAG_COLOR_MAIN(NAME) \ + [$earlydepthstencil] half4 main(Varyings _varyings) : $SV_Target \ + { \ + float2 _fragCoord = _varyings._pos.xy; \ + int2 _plsCoord = int2(floor(_fragCoord)); \ + half4 _fragColor; + +#define PLS_FRAG_COLOR_MAIN_WITH_IMAGE_UNIFORMS(NAME) PLS_FRAG_COLOR_MAIN(NAME) + +#define EMIT_PLS_AND_FRAG_COLOR \ + } \ + return _fragColor; + +#define uintBitsToFloat $asfloat +#define intBitsToFloat $asfloat +#define floatBitsToInt $asint +#define floatBitsToUint $asuint +#define inversesqrt $rsqrt +#define equal(A, B) ((A) == (B)) +#define notEqual(A, B) ((A) != (B)) +#define lessThanEqual(A, B) ((A) <= (B)) +#define lessThan(A, B) ((A) < (B)) +#define greaterThan(A, B) ((A) > (B)) +#define greaterThanEqual(A, B) ((A) >= (B)) + +// HLSL matrices are stored in row-major order, and therefore transposed from +// their counterparts in GLSL and Metal. We can work around this entirely by +// reversing the arguments to mul(). +#define MUL(A, B) $mul(B, A) + +#define VERTEX_STORAGE_BUFFER_BLOCK_BEGIN +#define VERTEX_STORAGE_BUFFER_BLOCK_END + +#define FRAG_STORAGE_BUFFER_BLOCK_BEGIN +#define FRAG_STORAGE_BUFFER_BLOCK_END + +#define STORAGE_BUFFER_U32x2(IDX, GLSL_STRUCT_NAME, NAME) \ + $StructuredBuffer NAME : $register($t##IDX) +#define STORAGE_BUFFER_U32x4(IDX, GLSL_STRUCT_NAME, NAME) \ + $StructuredBuffer NAME : $register($t##IDX) +#define STORAGE_BUFFER_F32x4(IDX, GLSL_STRUCT_NAME, NAME) \ + $StructuredBuffer NAME : $register($t##IDX) + +#define STORAGE_BUFFER_LOAD4(NAME, I) NAME[I] +#define STORAGE_BUFFER_LOAD2(NAME, I) NAME[I] + +INLINE half2 unpackHalf2x16(uint u) +{ + uint y = (u >> 16); + uint x = u & 0xffffu; + return half2($f16tof32(x), $f16tof32(y)); +} + +INLINE uint packHalf2x16(float2 v) +{ + uint x = $f32tof16(v.x); + uint y = $f32tof16(v.y); + return (y << 16) | x; +} + +INLINE half4 unpackUnorm4x8(uint u) +{ + uint4 vals = uint4(u & 0xffu, (u >> 8) & 0xffu, (u >> 16) & 0xffu, u >> 24); + return half4(vals) * (1. / 255.); +} + +INLINE uint packUnorm4x8(half4 color) +{ + uint4 vals = (uint4(color * 255.) & 0xff) << uint4(0, 8, 16, 24); + vals.rg |= vals.ba; + vals.r |= vals.g; + return vals.r; +} + +INLINE float2x2 inverse(float2x2 m) +{ + float2x2 adjoint = float2x2(m[1][1], -m[0][1], -m[1][0], m[0][0]); + return adjoint * (1. / determinant(m)); +} + +// Redirects for intrinsics that have different names in HLSL + +INLINE float mix(float x, float y, float s) { return $lerp(x, y, s); } +INLINE float2 mix(float2 x, float2 y, float2 s) { return $lerp(x, y, s); } +INLINE float3 mix(float3 x, float3 y, float3 s) { return $lerp(x, y, s); } +INLINE float4 mix(float4 x, float4 y, float4 s) { return $lerp(x, y, s); } + +INLINE half mix(half x, half y, half s) { return x + s * (y - x); } +INLINE half2 mix(half2 x, half2 y, half2 s) { return x + s * (y - x); } +INLINE half3 mix(half3 x, half3 y, half3 s) { return x + s * (y - x); } +INLINE half4 mix(half4 x, half4 y, half4 s) { return x + s * (y - x); } + +INLINE float fract(float x) { return $frac(x); } +INLINE float2 fract(float2 x) { return $frac(x); } +INLINE float3 fract(float3 x) { return $frac(x); } +INLINE float4 fract(float4 x) { return $frac(x); } + +INLINE half fract(half x) { return $frac(x); } +INLINE half2 fract(half2 x) { return half2($frac(x)); } +INLINE half3 fract(half3 x) { return half3($frac(x)); } +INLINE half4 fract(half4 x) { return half4($frac(x)); } + +INLINE float mod(float x, float y) { return $fmod(x, y); } + +// Reimplement intrinsics for half types. +// This shadows the intrinsic function for floats, so we also have to declare +// that overload. + +INLINE half rive_sign(half x) { return sign(x); } +INLINE half2 rive_sign(half2 x) { return half2(sign(x)); } +INLINE half3 rive_sign(half3 x) { return half3(sign(x)); } +INLINE half4 rive_sign(half4 x) { return half4(sign(x)); } + +INLINE float rive_sign(float x) { return sign(x); } +INLINE float2 rive_sign(float2 x) { return sign(x); } +INLINE float3 rive_sign(float3 x) { return sign(x); } +INLINE float4 rive_sign(float4 x) { return sign(x); } + +#define sign rive_sign + +INLINE half rive_abs(half x) { return abs(x); } +INLINE half2 rive_abs(half2 x) { return half2(abs(x)); } +INLINE half3 rive_abs(half3 x) { return half3(abs(x)); } +INLINE half4 rive_abs(half4 x) { return half4(abs(x)); } + +INLINE float rive_abs(float x) { return abs(x); } +INLINE float2 rive_abs(float2 x) { return abs(x); } +INLINE float3 rive_abs(float3 x) { return abs(x); } +INLINE float4 rive_abs(float4 x) { return abs(x); } + +#define abs rive_abs + +INLINE half rive_sqrt(half x) { return sqrt(x); } +INLINE half2 rive_sqrt(half2 x) { return half2(sqrt(x)); } +INLINE half3 rive_sqrt(half3 x) { return half3(sqrt(x)); } +INLINE half4 rive_sqrt(half4 x) { return half4(sqrt(x)); } + +INLINE float rive_sqrt(float x) { return sqrt(x); } +INLINE float2 rive_sqrt(float2 x) { return sqrt(x); } +INLINE float3 rive_sqrt(float3 x) { return sqrt(x); } +INLINE float4 rive_sqrt(float4 x) { return sqrt(x); } + +#define sqrt rive_sqrt diff --git a/third_party/rive_renderer/source/shaders/metal.glsl b/third_party/rive_renderer/source/shaders/metal.glsl new file mode 100644 index 0000000..18a0cfb --- /dev/null +++ b/third_party/rive_renderer/source/shaders/metal.glsl @@ -0,0 +1,548 @@ +/* + * Copyright 2023 Rive + */ + +// This header provides Metal-specific #defines and declarations that enable our +// shaders to be compiled on MSL and GLSL both. + +#define METAL + +// #define native metal types if their names are being rewritten. +#define _ARE_TOKEN_NAMES_PRESERVED +#ifndef $_ARE_TOKEN_NAMES_PRESERVED +#define half $half +#define half2 $half2 +#define half3 $half3 +#define half4 $half4 +#define short $short +#define short2 $short2 +#define short3 $short3 +#define short4 $short4 +#define ushort $ushort +#define ushort2 $ushort2 +#define ushort3 $ushort3 +#define ushort4 $ushort4 +#define float2 $float2 +#define float3 $float3 +#define packed_float3 $packed_float3 +#define float4 $float4 +#define bool2 $bool2 +#define bool3 $bool3 +#define bool4 $bool4 +#define uint2 $uint2 +#define uint3 $uint3 +#define uint4 $uint4 +#define int2 $int2 +#define int3 $int3 +#define int4 $int4 +#define float4x2 $float4x2 +#define ushort $ushort +#define float2x2 $float2x2 +#define half3x3 $half3x3 +#define half2x3 $half2x3 +#endif + +#define INLINE $inline +#define OUT(ARG_TYPE) $thread ARG_TYPE& +#define INOUT(ARG_TYPE) $thread ARG_TYPE& + +#define equal(A, B) ((A) == (B)) +#define notEqual(A, B) ((A) != (B)) +#define lessThanEqual(A, B) ((A) <= (B)) +#define lessThan(A, B) ((A) < (B)) +#define greaterThan(A, B) ((A) > (B)) +#define greaterThanEqual(A, B) ((A) >= (B)) +#define MUL(A, B) ((A) * (B)) +#define inversesqrt $rsqrt + +#define UNIFORM_BLOCK_BEGIN(IDX, NAME) \ + struct NAME \ + { +#define UNIFORM_BLOCK_END(NAME) \ + } \ + ; + +#define ATTR_BLOCK_BEGIN(NAME) \ + struct NAME \ + { +#define ATTR(IDX, TYPE, NAME) TYPE NAME +#define ATTR_BLOCK_END \ + } \ + ; +#define ATTR_UNPACK(ID, attrs, NAME, TYPE) TYPE NAME = attrs[ID].NAME + +#define VARYING_BLOCK_BEGIN \ + struct Varyings \ + { +#define VARYING(IDX, TYPE, NAME) TYPE NAME +#define FLAT [[flat]] +#define NO_PERSPECTIVE [[$center_no_perspective]] +#ifndef @OPTIONALLY_FLAT +// Don't use no-perspective interpolation for varyings that need to be flat. +// No-persective interpolation appears to break the guarantee that a varying == +// "x" when all barycentric values also == "x". Default (perspective-correct) +// interpolation does preserve this guarantee, and seems to be faster faster +// than flat on Apple Silicon. +#define @OPTIONALLY_FLAT +#endif +#define VARYING_BLOCK_END \ + float4 _pos [[$position]] [[$invariant]]; \ + } \ + ; + +#define VARYING_INIT(NAME, TYPE) $thread TYPE& NAME = _varyings.NAME +#define VARYING_PACK(NAME) +#define VARYING_UNPACK(NAME, TYPE) TYPE NAME = _varyings.NAME + +#define VERTEX_STORAGE_BUFFER_BLOCK_BEGIN \ + struct VertexStorageBuffers \ + { +#define VERTEX_STORAGE_BUFFER_BLOCK_END \ + } \ + ; + +#define FRAG_STORAGE_BUFFER_BLOCK_BEGIN \ + struct FragmentStorageBuffers \ + { +#define FRAG_STORAGE_BUFFER_BLOCK_END \ + } \ + ; + +#define STORAGE_BUFFER_U32x2(IDX, GLSL_STRUCT_NAME, NAME) \ + $constant uint2* NAME [[$buffer(METAL_BUFFER_IDX(IDX))]] +#define STORAGE_BUFFER_U32x4(IDX, GLSL_STRUCT_NAME, NAME) \ + $constant uint4* NAME [[$buffer(METAL_BUFFER_IDX(IDX))]] +#define STORAGE_BUFFER_F32x4(IDX, GLSL_STRUCT_NAME, NAME) \ + $constant float4* NAME [[$buffer(METAL_BUFFER_IDX(IDX))]] +#define STORAGE_BUFFER_LOAD4(NAME, I) _buffers.NAME[I] +#define STORAGE_BUFFER_LOAD2(NAME, I) _buffers.NAME[I] + +#define VERTEX_TEXTURE_BLOCK_BEGIN \ + struct VertexTextures \ + { +#define VERTEX_TEXTURE_BLOCK_END \ + } \ + ; + +#define FRAG_TEXTURE_BLOCK_BEGIN \ + struct FragmentTextures \ + { +#define FRAG_TEXTURE_BLOCK_END \ + } \ + ; + +#define DYNAMIC_SAMPLER_BLOCK_BEGIN \ + struct DynamicSamplers \ + { +#define DYNAMIC_SAMPLER_BLOCK_END \ + } \ + ; + +#define TEXTURE_RGBA32UI(SET, IDX, NAME) [[$texture(IDX)]] $texture2d NAME +#define TEXTURE_RGBA32F(SET, IDX, NAME) [[$texture(IDX)]] $texture2d NAME +#define TEXTURE_RGBA8(SET, IDX, NAME) [[$texture(IDX)]] $texture2d NAME +#define TEXTURE_R16F(SET, IDX, NAME) [[$texture(IDX)]] $texture2d NAME +#define TEXTURE_R16F_1D_ARRAY(SET, IDX, NAME) \ + [[$texture(IDX)]] $texture1d_array NAME + +#define SAMPLER_LINEAR(TEXTURE_IDX, NAME) \ + $constexpr $sampler NAME($filter::$linear, $mip_filter::$none); +#define SAMPLER_MIPMAP(TEXTURE_IDX, NAME) \ + $constexpr $sampler NAME($filter::$linear, $mip_filter::$linear); +#define SAMPLER_DYNAMIC(SAMPLER_IDX, NAME) \ + [[$sampler(SAMPLER_IDX)]] $sampler NAME; +#define TEXEL_FETCH(TEXTURE, COORD) _textures.TEXTURE.$read(uint2(COORD)) +#define TEXTURE_SAMPLE(TEXTURE, SAMPLER_NAME, COORD) \ + _textures.TEXTURE.$sample(SAMPLER_NAME, COORD) +#define TEXTURE_SAMPLE_LOD(TEXTURE, SAMPLER_NAME, COORD, LOD) \ + _textures.TEXTURE.$sample(SAMPLER_NAME, COORD, $level(LOD)) +#define TEXTURE_SAMPLE_GRAD(TEXTURE, SAMPLER_NAME, COORD, DDX, DDY) \ + _textures.TEXTURE.$sample(SAMPLER_NAME, COORD, $gradient2d(DDX, DDY)) +#define TEXTURE_GATHER(TEXTURE, SAMPLER_NAME, COORD, TEXTURE_INVERSE_SIZE) \ + _textures.TEXTURE.$gather(SAMPLER_NAME, (COORD) * (TEXTURE_INVERSE_SIZE)) +#define TEXTURE_SAMPLE_DYNAMIC(TEXTURE, SAMPLER_NAME, COORD) \ + _textures.TEXTURE.$sample(_dynamicSampler.SAMPLER_NAME, COORD) +#define TEXTURE_SAMPLE_DYNAMIC_LOD(TEXTURE, SAMPLER_NAME, COORD, LOD) \ + _textures.TEXTURE.$sample(_dynamicSampler.SAMPLER_NAME, COORD, $level(LOD)) +#define TEXTURE_SAMPLE_LOD_1D_ARRAY(TEXTURE, \ + SAMPLER_NAME, \ + X, \ + ARRAY_INDEX, \ + ARRAY_INDEX_NORMALIZED, \ + LOD) \ + _textures.TEXTURE.$sample(SAMPLER_NAME, X, ARRAY_INDEX) + +#define VERTEX_CONTEXT_DECL \ + , $constant @FlushUniforms &uniforms, VertexTextures _textures, \ + VertexStorageBuffers _buffers +#define VERTEX_CONTEXT_UNPACK , uniforms, _textures, _buffers + +#ifdef @ENABLE_INSTANCE_INDEX +#define VERTEX_MAIN(NAME, Attrs, attrs, _vertexID, _instanceID) \ + $__attribute__(($visibility("default"))) Varyings $vertex NAME( \ + uint _vertexID [[$vertex_id]], \ + uint _instanceID [[$instance_id]], \ + $constant uint& _baseInstance \ + [[$buffer(METAL_BUFFER_IDX(PATH_BASE_INSTANCE_UNIFORM_BUFFER_IDX))]], \ + $constant @FlushUniforms& uniforms \ + [[$buffer(METAL_BUFFER_IDX(FLUSH_UNIFORM_BUFFER_IDX))]], \ + $constant Attrs* attrs [[$buffer(0)]], \ + VertexTextures _textures, \ + VertexStorageBuffers _buffers) \ + { \ + _instanceID += _baseInstance; \ + Varyings _varyings; +#else +#define VERTEX_MAIN(NAME, Attrs, attrs, _vertexID, _instanceID) \ + $__attribute__(($visibility("default"))) Varyings $vertex NAME( \ + uint _vertexID [[$vertex_id]], \ + uint _instanceID [[$instance_id]], \ + $constant @FlushUniforms& uniforms \ + [[$buffer(METAL_BUFFER_IDX(FLUSH_UNIFORM_BUFFER_IDX))]], \ + $constant Attrs* attrs [[$buffer(0)]], \ + VertexTextures _textures, \ + VertexStorageBuffers _buffers) \ + { \ + Varyings _varyings; +#endif + +#define IMAGE_RECT_VERTEX_MAIN(NAME, Attrs, attrs, _vertexID, _instanceID) \ + $__attribute__(($visibility("default"))) Varyings $vertex NAME( \ + uint _vertexID [[$vertex_id]], \ + $constant @FlushUniforms& uniforms \ + [[$buffer(METAL_BUFFER_IDX(FLUSH_UNIFORM_BUFFER_IDX))]], \ + $constant @ImageDrawUniforms& imageDrawUniforms \ + [[$buffer(METAL_BUFFER_IDX(IMAGE_DRAW_UNIFORM_BUFFER_IDX))]], \ + $constant Attrs* attrs [[$buffer(0)]], \ + VertexTextures _textures, \ + VertexStorageBuffers _buffers) \ + { \ + Varyings _varyings; + +#define IMAGE_MESH_VERTEX_MAIN(NAME, \ + PositionAttr, \ + position, \ + UVAttr, \ + uv, \ + _vertexID) \ + $__attribute__(($visibility("default"))) Varyings $vertex NAME( \ + uint _vertexID [[$vertex_id]], \ + $constant @FlushUniforms& uniforms \ + [[$buffer(METAL_BUFFER_IDX(FLUSH_UNIFORM_BUFFER_IDX))]], \ + $constant @ImageDrawUniforms& imageDrawUniforms \ + [[$buffer(METAL_BUFFER_IDX(IMAGE_DRAW_UNIFORM_BUFFER_IDX))]], \ + $constant PositionAttr* position [[$buffer(0)]], \ + $constant UVAttr* uv [[$buffer(1)]]) \ + { \ + Varyings _varyings; + +#define EMIT_VERTEX(POSITION) \ + _varyings._pos = POSITION; \ + } \ + return _varyings; + +#define FRAG_DATA_MAIN(DATA_TYPE, NAME) \ + DATA_TYPE $__attribute__(($visibility("default"))) $fragment NAME( \ + Varyings _varyings [[$stage_in]], \ + FragmentTextures _textures) \ + { + +#define EMIT_FRAG_DATA(VALUE) \ + return VALUE; \ + } + +#define FRAGMENT_CONTEXT_DECL \ + , float2 _fragCoord, FragmentTextures _textures, \ + FragmentStorageBuffers _buffers, DynamicSamplers _dynamicSampler +#define FRAGMENT_CONTEXT_UNPACK \ + , _fragCoord, _textures, _buffers, _dynamicSampler + +#define TEXTURE_CONTEXT_DECL , FragmentTextures _textures +#define TEXTURE_CONTEXT_FORWARD , _textures + +#ifdef @PLS_IMPL_DEVICE_BUFFER + +#define PLS_BLOCK_BEGIN \ + struct PLS \ + { +#ifdef @PLS_IMPL_DEVICE_BUFFER_RASTER_ORDERED +// Apple Silicon doesn't support fragment-fragment memory barriers, so on this +// hardware we use raster order groups instead. Since the PLS plane indices +// collide with other buffer bindings, offset the binding indices of these +// buffers by DEFAULT_BINDINGS_SET_SIZE. +#define PLS_DECL4F(IDX, NAME) \ + $device uint* NAME \ + [[$buffer(METAL_BUFFER_IDX(IDX + DEFAULT_BINDINGS_SET_SIZE)), \ + $raster_order_group(0)]] +#define PLS_DECLUI(IDX, NAME) \ + $device uint* NAME \ + [[$buffer(METAL_BUFFER_IDX(IDX + DEFAULT_BINDINGS_SET_SIZE)), \ + $raster_order_group(0)]] +#define PLS_DECLUI_ATOMIC(IDX, NAME) \ + $device $atomic_uint* NAME \ + [[$buffer(METAL_BUFFER_IDX(IDX + DEFAULT_BINDINGS_SET_SIZE)), \ + $raster_order_group(0)]] +#else +// Since the PLS plane indices collide with other buffer bindings, offset the +// binding indices of these buffers by DEFAULT_BINDINGS_SET_SIZE. +#define PLS_DECL4F(IDX, NAME) \ + $device uint* NAME \ + [[$buffer(METAL_BUFFER_IDX(IDX + DEFAULT_BINDINGS_SET_SIZE))]] +#define PLS_DECLUI(IDX, NAME) \ + $device uint* NAME \ + [[$buffer(METAL_BUFFER_IDX(IDX + DEFAULT_BINDINGS_SET_SIZE))]] +#define PLS_DECLUI_ATOMIC(IDX, NAME) \ + $device $atomic_uint* NAME \ + [[$buffer(METAL_BUFFER_IDX(IDX + DEFAULT_BINDINGS_SET_SIZE))]] +#endif // @PLS_IMPL_DEVICE_BUFFER_RASTER_ORDERED +#define PLS_BLOCK_END \ + } \ + ; +#define PLS_CONTEXT_DECL , PLS _pls, uint _plsIdx +#define PLS_CONTEXT_UNPACK , _pls, _plsIdx + +#define PLS_LOAD4F(PLANE) unpackUnorm4x8(_pls.PLANE[_plsIdx]) +#define PLS_LOADUI(PLANE) _pls.PLANE[_plsIdx] +#define PLS_LOADUI_ATOMIC(PLANE) \ + $atomic_load_explicit(&_pls.PLANE[_plsIdx], \ + $memory_order::$memory_order_relaxed) +#define PLS_STORE4F(PLANE, VALUE) _pls.PLANE[_plsIdx] = packUnorm4x8(VALUE) +#define PLS_STOREUI(PLANE, VALUE) _pls.PLANE[_plsIdx] = (VALUE) +#define PLS_STOREUI_ATOMIC(PLANE, VALUE) \ + $atomic_store_explicit(&_pls.PLANE[_plsIdx], \ + VALUE, \ + $memory_order::$memory_order_relaxed) +#define PLS_PRESERVE_4F(PLANE) +#define PLS_PRESERVE_UI(PLANE) + +#define PLS_ATOMIC_MAX(PLANE, X) \ + $atomic_fetch_max_explicit(&_pls.PLANE[_plsIdx], \ + X, \ + $memory_order::$memory_order_relaxed) + +#define PLS_ATOMIC_ADD(PLANE, X) \ + $atomic_fetch_add_explicit(&_pls.PLANE[_plsIdx], \ + X, \ + $memory_order::$memory_order_relaxed) + +#define PLS_INTERLOCK_BEGIN +#define PLS_INTERLOCK_END + +#define PLS_METAL_MAIN(NAME) \ + $__attribute__(($visibility("default"))) $fragment NAME( \ + PLS _pls, \ + $constant @FlushUniforms& uniforms \ + [[$buffer(METAL_BUFFER_IDX(FLUSH_UNIFORM_BUFFER_IDX))]], \ + Varyings _varyings [[$stage_in]], \ + FragmentTextures _textures, \ + DynamicSamplers _dynamicSampler, \ + FragmentStorageBuffers _buffers) \ + { \ + float2 _fragCoord = _varyings._pos.xy; \ + uint2 _plsCoord = uint2($metal::floor(_fragCoord)); \ + uint _plsIdx = _plsCoord.y * uniforms.renderTargetWidth + _plsCoord.x; + +#define PLS_METAL_MAIN_WITH_IMAGE_UNIFORMS(NAME) \ + $__attribute__(($visibility("default"))) $fragment NAME( \ + PLS _pls, \ + $constant @FlushUniforms& uniforms \ + [[$buffer(METAL_BUFFER_IDX(FLUSH_UNIFORM_BUFFER_IDX))]], \ + $constant @ImageDrawUniforms& imageDrawUniforms \ + [[$buffer(METAL_BUFFER_IDX(IMAGE_DRAW_UNIFORM_BUFFER_IDX))]], \ + Varyings _varyings [[$stage_in]], \ + DynamicSamplers _dynamicSampler, \ + FragmentTextures _textures, \ + FragmentStorageBuffers _buffers) \ + { \ + float2 _fragCoord = _varyings._pos.xy; \ + uint2 _plsCoord = uint2($metal::floor(_fragCoord)); \ + uint _plsIdx = _plsCoord.y * uniforms.renderTargetWidth + _plsCoord.x; + +#define PLS_MAIN(NAME) void PLS_METAL_MAIN(NAME) +#define PLS_MAIN_WITH_IMAGE_UNIFORMS(NAME) \ + void PLS_METAL_MAIN_WITH_IMAGE_UNIFORMS(NAME) +#define EMIT_PLS } + +#define PLS_FRAG_COLOR_MAIN(NAME) \ + half4 PLS_METAL_MAIN(NAME) \ + { \ + half4 _fragColor; + +#define PLS_FRAG_COLOR_MAIN_WITH_IMAGE_UNIFORMS(NAME) \ + half4 PLS_METAL_MAIN_WITH_IMAGE_UNIFORMS(NAME) \ + { \ + half4 _fragColor; + +#define EMIT_PLS_AND_FRAG_COLOR \ + } \ + return _fragColor; \ + EMIT_PLS + +#else // Default implementation -- framebuffer reads. + +#define PLS_BLOCK_BEGIN \ + struct PLS \ + { +#define PLS_DECL4F(IDX, NAME) [[$color(IDX)]] half4 NAME +#define PLS_DECLUI(IDX, NAME) [[$color(IDX)]] uint NAME +#define PLS_DECLUI_ATOMIC PLS_DECLUI +#define PLS_BLOCK_END \ + } \ + ; +#define PLS_CONTEXT_DECL , $thread PLS &_inpls, $thread PLS &_pls +#define PLS_CONTEXT_UNPACK , _inpls, _pls + +#define PLS_LOAD4F(PLANE) _inpls.PLANE +#define PLS_LOADUI(PLANE) _inpls.PLANE +#define PLS_LOADUI_ATOMIC(PLANE) PLS_LOADUI +#define PLS_STORE4F(PLANE, VALUE) _pls.PLANE = (VALUE) +#define PLS_STOREUI(PLANE, VALUE) _pls.PLANE = (VALUE) +#define PLS_STOREUI_ATOMIC(PLANE) PLS_STOREUI +#define PLS_PRESERVE_4F(PLANE) _pls.PLANE = _inpls.PLANE +#define PLS_PRESERVE_UI(PLANE) _pls.PLANE = _inpls.PLANE + +INLINE uint pls_atomic_max($thread uint& dst, uint x) +{ + uint originalValue = dst; + dst = $metal::max(originalValue, x); + return originalValue; +} + +#define PLS_ATOMIC_MAX(PLANE, X) pls_atomic_max(_pls.PLANE, X) + +INLINE uint pls_atomic_add($thread uint& dst, uint x) +{ + uint originalValue = dst; + dst = originalValue + x; + return originalValue; +} + +#define PLS_ATOMIC_ADD(PLANE, X) pls_atomic_add(_pls.PLANE, X) + +#define PLS_INTERLOCK_BEGIN +#define PLS_INTERLOCK_END + +#define PLS_METAL_MAIN(NAME, ...) \ + PLS $__attribute__(($visibility("default"))) $fragment NAME($__VA_ARGS__) \ + { \ + float2 _fragCoord [[$maybe_unused]] = _varyings._pos.xy; \ + PLS _pls; + +#define PLS_MAIN(NAME, ...) \ + PLS_METAL_MAIN(NAME, \ + PLS _inpls, \ + $constant @FlushUniforms& uniforms \ + [[$buffer(METAL_BUFFER_IDX(FLUSH_UNIFORM_BUFFER_IDX))]], \ + Varyings _varyings [[$stage_in]], \ + DynamicSamplers _dynamicSampler, \ + FragmentTextures _textures, \ + FragmentStorageBuffers _buffers) + +#define PLS_MAIN_WITH_IMAGE_UNIFORMS(NAME) \ + PLS_METAL_MAIN( \ + NAME, \ + PLS _inpls, \ + Varyings _varyings [[$stage_in]], \ + FragmentTextures _textures, \ + FragmentStorageBuffers _buffers, \ + DynamicSamplers _dynamicSampler, \ + $constant @ImageDrawUniforms& imageDrawUniforms \ + [[$buffer(METAL_BUFFER_IDX(IMAGE_DRAW_UNIFORM_BUFFER_IDX))]]) + +#define EMIT_PLS \ + } \ + return _pls; + +#define PLS_FRAG_COLOR_METAL_MAIN(NAME, ...) \ + struct FragmentOut \ + { \ + half4 _color [[color(0)]]; \ + PLS _pls; \ + }; \ + FragmentOut $__attribute__(($visibility("default"))) $fragment NAME( \ + $__VA_ARGS__) \ + { \ + float2 _fragCoord [[$maybe_unused]] = _varyings._pos.xy; \ + half4 _fragColor; \ + PLS _pls; + +#define PLS_FRAG_COLOR_MAIN(NAME) \ + PLS_FRAG_COLOR_METAL_MAIN(NAME, \ + PLS _inpls, \ + Varyings _varyings [[$stage_in]], \ + FragmentTextures _textures, \ + FragmentStorageBuffers _buffers) + +#define PLS_FRAG_COLOR_MAIN_WITH_IMAGE_UNIFORMS(NAME) \ + PLS_FRAG_COLOR_METAL_MAIN( \ + NAME, \ + PLS _inpls, \ + Varyings _varyings [[$stage_in]], \ + FragmentTextures _textures, \ + FragmentStorageBuffers _buffers, \ + $__VA_ARGS__ $constant @ImageDrawUniforms& imageDrawUniforms \ + [[$buffer(METAL_BUFFER_IDX(IMAGE_DRAW_UNIFORM_BUFFER_IDX))]]) + +#define EMIT_PLS_AND_FRAG_COLOR \ + } \ + return {._color = _fragColor, ._pls = _pls}; + +#endif // PLS_IMPL_DEVICE_BUFFER + +#define PLS_DECL4F_READONLY PLS_DECL4F + +#define discard $discard_fragment() + +$using $namespace $metal; + +$template INLINE $vec floatBitsToUint($vec x) +{ + return $as_type<$vec>(x); +} + +$template INLINE $vec floatBitsToInt($vec x) +{ + return $as_type<$vec>(x); +} + +INLINE uint floatBitsToUint(float x) { return $as_type(x); } + +INLINE int floatBitsToInt(float x) { return $as_type(x); } + +$template INLINE $vec uintBitsToFloat($vec x) +{ + return $as_type<$vec>(x); +} + +INLINE float uintBitsToFloat(uint x) { return $as_type(x); } +INLINE half2 unpackHalf2x16(uint x) { return $as_type(x); } +INLINE uint packHalf2x16(half2 x) { return $as_type(x); } +INLINE half4 unpackUnorm4x8(uint x) { return $unpack_unorm4x8_to_half(x); } +INLINE uint packUnorm4x8(half4 x) { return $pack_half_to_unorm4x8(x); } + +INLINE float2x2 inverse(float2x2 m) +{ + float2x2 m_ = float2x2(m[1][1], -m[0][1], -m[1][0], m[0][0]); + float det = (m_[0][0] * m[0][0]) + (m_[0][1] * m[1][0]); + return m_ * (1 / det); +} + +INLINE half3 mix(half3 a, half3 b, bool3 c) +{ + half3 result; + for (int i = 0; i < 3; ++i) + result[i] = c[i] ? b[i] : a[i]; + return result; +} + +INLINE float2 mix(float2 a, float2 b, bool2 c) +{ + float2 result; + for (int i = 0; i < 2; ++i) + result[i] = c[i] ? b[i] : a[i]; + return result; +} + +INLINE float2 mix(float2 a, float2 b, float t) { return mix(a, b, float2(t)); } + +INLINE float mod(float x, float y) { return $fmod(x, y); } diff --git a/third_party/rive_renderer/source/shaders/metal/color_ramp.metal b/third_party/rive_renderer/source/shaders/metal/color_ramp.metal new file mode 100644 index 0000000..9c0f0c0 --- /dev/null +++ b/third_party/rive_renderer/source/shaders/metal/color_ramp.metal @@ -0,0 +1,9 @@ +#include + +#define VERTEX +#define FRAGMENT + +#include "metal.minified.glsl" +#include "constants.minified.glsl" +#include "common.minified.glsl" +#include "color_ramp.minified.glsl" diff --git a/third_party/rive_renderer/source/shaders/metal/draw.metal b/third_party/rive_renderer/source/shaders/metal/draw.metal new file mode 100644 index 0000000..674f429 --- /dev/null +++ b/third_party/rive_renderer/source/shaders/metal/draw.metal @@ -0,0 +1,40 @@ +#include + +// Add baseInstance to the instanceID for path draws. +#define ENABLE_INSTANCE_INDEX + +#define FRAGMENT + +#define VERTEX +#include "metal.minified.glsl" +#include "constants.minified.glsl" +#define DRAW_IMAGE +#include "common.minified.glsl" +#undef DRAW_IMAGE +#define DRAW_PATH +#define DRAW_INTERIOR_TRIANGLES +#define ENABLE_FEATHER +#define ATLAS_BLIT +#include "draw_path_common.minified.glsl" + +#define ATLAS_FEATHERED_FILL +#define ATLAS_FEATHERED_STROKE +#include "render_atlas.minified.glsl" +#undef ATLAS_FEATHERED_FILL +#undef ATLAS_FEATHERED_STROKE + +#undef ATLAS_BLIT +#undef ENABLE_FEATHER +#undef DRAW_INTERIOR_TRIANGLES +#undef DRAW_PATH +#undef VERTEX + +#define ENABLE_ADVANCED_BLEND 1 +#define ENABLE_HSL_BLEND_MODES 1 +#include "advanced_blend.minified.glsl" +#undef ENABLE_HSL_BLEND_MODES +#undef ENABLE_ADVANCED_BLEND + +#undef FRAGMENT + +#include "draw_combinations.metal" diff --git a/third_party/rive_renderer/source/shaders/metal/generate_draw_combinations.py b/third_party/rive_renderer/source/shaders/metal/generate_draw_combinations.py new file mode 100644 index 0000000..31a44ff --- /dev/null +++ b/third_party/rive_renderer/source/shaders/metal/generate_draw_combinations.py @@ -0,0 +1,148 @@ +import itertools +import sys +from enum import Enum + +# Organizes all combinations of valid features for draw.glsl into their own custom-named namespace. +# Generates MSL code to declare each namespace and #include draw.glsl with corresponding #defines. + +class Feature(): + def __init__(self, name, index): + self.name = name + self.index = index + +# Each feature has a specific index. These must stay in sync with render_context_metal_impl.mm. +ENABLE_CLIPPING = Feature('ENABLE_CLIPPING', 0) +ENABLE_CLIP_RECT = Feature('ENABLE_CLIP_RECT', 1) +ENABLE_ADVANCED_BLEND = Feature('ENABLE_ADVANCED_BLEND', 2) +ENABLE_FEATHER = Feature('ENABLE_FEATHER', 3) +ENABLE_EVEN_ODD = Feature('ENABLE_EVEN_ODD', 4) +ENABLE_NESTED_CLIPPING = Feature('ENABLE_NESTED_CLIPPING', 5) +ENABLE_HSL_BLEND_MODES = Feature('ENABLE_HSL_BLEND_MODES', 6) +DRAW_INTERIOR_TRIANGLES = Feature('DRAW_INTERIOR_TRIANGLES', 7) +ATLAS_BLIT = Feature('ATLAS_BLIT', 8) + +whole_program_features = {ENABLE_CLIPPING, + ENABLE_CLIP_RECT, + ENABLE_ADVANCED_BLEND, + ENABLE_FEATHER} + +fragment_only_features = {ENABLE_EVEN_ODD, + ENABLE_NESTED_CLIPPING, + ENABLE_HSL_BLEND_MODES} + +all_features = whole_program_features.union(fragment_only_features) + +# Returns whether a valid program exists for the given feature set. +def is_valid_feature_set(feature_set): + if ENABLE_NESTED_CLIPPING in feature_set and ENABLE_CLIPPING not in feature_set: + return False + if ENABLE_HSL_BLEND_MODES in feature_set and ENABLE_ADVANCED_BLEND not in feature_set: + return False + return True + +# Returns whether the given feature set is the *simplest* set that defines a unique vertex shader. +# (Many feature sets produce identical vertex shaders.) +def is_unique_vertex_feature_set(feature_set): + # Fragment-only features have no effect on the vertex shader. + if fragment_only_features.intersection(feature_set): + return False + return True + +non_atlas_coverage_features = {ENABLE_FEATHER, + ENABLE_EVEN_ODD, + ENABLE_NESTED_CLIPPING} + +non_image_mesh_features = {ENABLE_FEATHER, + ENABLE_EVEN_ODD, + ENABLE_NESTED_CLIPPING, + DRAW_INTERIOR_TRIANGLES, + ATLAS_BLIT} + +# Returns whether the given feature set is compatible with an image mesh shader. +def is_image_mesh_feature_set(feature_set): + return not non_image_mesh_features.intersection(feature_set) + +ShaderType = Enum('ShaderType', ['VERTEX', 'FRAGMENT']) +DrawType = Enum('DrawType', ['PATH', 'IMAGE_MESH']) +FillType = Enum('FillType', ['CLOCKWISE', 'LEGACY']) + +def emit_shader(out, shader_type, draw_type, fill_type, feature_set): + assert(is_valid_feature_set(feature_set)) + if shader_type == ShaderType.VERTEX: + assert(is_unique_vertex_feature_set(feature_set)) + out.write('#define VERTEX\n') + else: + out.write('#define FRAGMENT\n') + if draw_type == DrawType.IMAGE_MESH: + assert(is_image_mesh_feature_set(feature_set)) + namespace_id = ['0', '0', '0', '0', '0', '0', '0', '0', '0'] + for feature in feature_set: + namespace_id[feature.index] = '1' + for feature in feature_set: + out.write('#define %s 1\n' % feature.name) + if fill_type == FillType.CLOCKWISE: + out.write('#define CLOCKWISE_FILL 1\n') + if draw_type == DrawType.PATH: + out.write('namespace %s%s\n' % + ('c' if fill_type == FillType.CLOCKWISE else 'p', + ''.join(namespace_id))) + out.write('{\n') + out.write('#include "draw_path.minified.glsl"\n') + out.write('}\n') + else: + out.write('namespace m%s\n' % ''.join(namespace_id)) + out.write('{\n') + out.write('#include "draw_image_mesh.minified.glsl"\n') + out.write('}\n') + for feature in feature_set: + out.write('#undef %s\n' % feature.name) + if shader_type == ShaderType.VERTEX: + out.write('#undef VERTEX\n') + else: + out.write('#undef FRAGMENT\n') + if fill_type == FillType.CLOCKWISE: + out.write('#undef CLOCKWISE_FILL\n') + out.write('\n') + +# Organize all combinations of valid features into their own namespace. +out = open(sys.argv[1], 'w', newline='\n') + +# Precompile the bare minimum set of shaders required to draw everything. We can compile more +# specialized shaders in the background at runtime, and use the fully-featured (slower) shaders +# while waiting for the compilations to complete. + +# Path tessellation shaders. +emit_shader(out, ShaderType.VERTEX, DrawType.PATH, FillType.LEGACY, + whole_program_features) +emit_shader(out, ShaderType.FRAGMENT, DrawType.PATH, FillType.LEGACY, all_features) +emit_shader(out, ShaderType.FRAGMENT, DrawType.PATH, FillType.CLOCKWISE, all_features) + +# Interior triangulation shaders. +emit_shader(out, ShaderType.VERTEX, DrawType.PATH, FillType.LEGACY, + whole_program_features.union({DRAW_INTERIOR_TRIANGLES})) +emit_shader(out, ShaderType.FRAGMENT, DrawType.PATH, FillType.LEGACY, + all_features.union({DRAW_INTERIOR_TRIANGLES})) +emit_shader(out, ShaderType.FRAGMENT, DrawType.PATH, FillType.CLOCKWISE, + all_features.union({DRAW_INTERIOR_TRIANGLES})) + +# Atlas blit shaders. +emit_shader(out, ShaderType.VERTEX, DrawType.PATH, FillType.LEGACY, + whole_program_features\ + .union({DRAW_INTERIOR_TRIANGLES, ATLAS_BLIT})\ + .difference(non_atlas_coverage_features)) +emit_shader(out, ShaderType.FRAGMENT, DrawType.PATH, FillType.LEGACY, + all_features\ + .union({DRAW_INTERIOR_TRIANGLES, ATLAS_BLIT})\ + .difference(non_atlas_coverage_features)) + +# Image mesh shaders. +emit_shader(out, ShaderType.VERTEX, DrawType.IMAGE_MESH, FillType.LEGACY, + whole_program_features.difference(non_image_mesh_features)) +emit_shader(out, ShaderType.FRAGMENT, DrawType.IMAGE_MESH, FillType.LEGACY, + all_features.difference(non_image_mesh_features)) + +# If we wanted to emit all combos... +# for n in range(0, len(all_features) + 1): +# for feature_set in itertools.combinations(all_features, n): +# if not is_valid_feature_set(feature_set): +# continue diff --git a/third_party/rive_renderer/source/shaders/metal/tessellate.metal b/third_party/rive_renderer/source/shaders/metal/tessellate.metal new file mode 100644 index 0000000..26d542b --- /dev/null +++ b/third_party/rive_renderer/source/shaders/metal/tessellate.metal @@ -0,0 +1,10 @@ +#include + +#define VERTEX +#define FRAGMENT + +#include "metal.minified.glsl" +#include "constants.minified.glsl" +#include "common.minified.glsl" +#include "bezier_utils.minified.glsl" +#include "tessellate.minified.glsl" diff --git a/third_party/rive_renderer/source/shaders/minify.py b/third_party/rive_renderer/source/shaders/minify.py new file mode 100644 index 0000000..5edc6b2 --- /dev/null +++ b/third_party/rive_renderer/source/shaders/minify.py @@ -0,0 +1,600 @@ +import argparse +import glob +import os +import re +import sys +from collections import defaultdict + +parser = argparse.ArgumentParser(description=""" +Process a batch of .glsl files. Minify and export them to C++ strings. + +Performs the following transformations: + * Strip comments. + * Strip whitespace. + * Strip unused #defines. + * Rename stpq and rgba swizzles to xyzw. + * Rename variables. + - No new name begins with the '_' character, so internal code can begin names with '_' + without fear of renaming collisions. + - GLSL keywords and builtins are not renamed. + - Tokens beginning with '@' have their new name exported to a header file. + - Tokens beginning with '$' are not renamed, with the exception of removing the leading '$'. + +"file.glsl" gets exported to: + * "outdir/file.exports.h", with #defines for the rewritten names of each identifier that began + with '@' in the original shader. + * "outdir/file.glsl.cpp", with a global `const char file_glsl[]` in the rive::glsl + namespace that contains the minified shader code. This variable is intentionally declared as a + global in order to generate a link error if the user includes the string more than once in + the build process. + * "outdir/file.minified.glsl" for offline compiling, with all variables renamed except for + exported #defines names (since the offline compiling process will set those defines). +""") +parser.add_argument("files", type=str, nargs="+", help="a list of glsl files") +parser.add_argument("-o", "--outdir", required=True, + help="OUTPUT directory to store the header files") +parser.add_argument("-H", "--human-readable", action='store_true', + help="don't rename or strip out comments or whitespace") +parser.add_argument("-p", "--ply-path", required=True, type=str, help="path to ply module") + +args = parser.parse_args() + +# Convert posix path to windows +convertedPath = args.ply_path +if sys.platform.startswith('win32') and args.ply_path[:2] == '/c': + convertedPath = 'C:\\' + args.ply_path[2:] + print('Using ply path:' + convertedPath) + +sys.path.append(convertedPath) + +import ply.lex as lex + +# tokens used by PLY to run lexical analysis on our glsl files. +tokens = [ + "DEFINE", + "IFDEF", + "DEFINED_ID", + "TOKEN_PASTE", + "DIRECTIVE", + "LINE_COMMENT", + "BLOCK_COMMENT", + "WHITESPACE", + "OP", + "FLOAT", + "HEX", + "INT", + "ID", + "UNKNOWN", +] + +# tracks which exported identifiers (identifiers whose @name begins with '@') are used as switches +# inside an #ifdef, #if defined(), etc. +exported_switches = set() + +# counts the number of times each ID is seen, to prioritize which IDs get the shortest names +all_id_counts = defaultdict(int); +all_id_reference_counts = defaultdict(int); +def parse_id(name, exports, *, is_reference): + all_id_counts[name] += 1 + if is_reference: + all_id_reference_counts[name] += 1 + # identifiers that begin with '@' get exported to C++ through #defines. + if name[0] == '@': + exports.add(name) + +# lexing functions used by PLY. +def t_DEFINE(tok): + r"\#[ \t]*define[ \t]+(?P[\@\$]?[A-Za-z_][A-Za-z0-9_]*)(?P\((\n|[^\)])*\))?(?P(((\\\n|.)(?!\/[\/\*]))*))?" + tok.define_id = re.match(t_DEFINE.__doc__, tok.value)['id'] + arglist = re.match(t_DEFINE.__doc__, tok.value)['arglist'] + tok.define_arglist = Minifier(arglist, "", tok.lexer.exports) if arglist else None + val = re.match(t_DEFINE.__doc__, tok.value)['val'] + tok.define_val = Minifier(val, "", tok.lexer.exports) if val else None + parse_id(tok.define_id, tok.lexer.exports, is_reference=False) + tok.lexer.lineno += tok.value.count('\n') + return tok + +def t_IFDEF(tok): + r"\#[ \t]*(?Pifn?def)[ \t]+(?P[\@\$]?[A-Za-z_][A-Za-z0-9_]*)" + tok.ifdef_tag = re.match(t_IFDEF.__doc__, tok.value)['tag'] + tok.ifdef_id = re.match(t_IFDEF.__doc__, tok.value)['ifdef_id'] + if tok.ifdef_id[0] == '@': + exported_switches.add(tok.ifdef_id) + parse_id(tok.ifdef_id, tok.lexer.exports, is_reference=True) + return tok + +def t_DEFINED_ID(tok): + r"defined\((?P[\@\$]?[A-Za-z_][A-Za-z0-9_]*)\)" + tok.defined_id = re.match(t_DEFINED_ID.__doc__, tok.value)['defined_id'] + if tok.defined_id[0] == '@': + exported_switches.add(tok.defined_id) + parse_id(tok.defined_id, tok.lexer.exports, is_reference=True) + return tok + +def t_TOKEN_PASTE(tok): + r"\#\#" + return tok + +def t_DIRECTIVE(tok): + r"\#[ \t]*(?P(((\\\n|.)(?!\/[\/\*]))*))" + val = re.match(t_DIRECTIVE.__doc__, tok.value)['val'] + tok.directive_val = Minifier(val, "", tok.lexer.exports) if val else None + tok.lexer.lineno += tok.value.count('\n') + return tok + +def t_LINE_COMMENT(tok): + r"//(\\\n|.)*" + tok.lexer.lineno += tok.value.count('\n') + return tok + +def t_BLOCK_COMMENT(tok): + r"\/\*(\*(?!\/)|[^*])*\*\/" + tok.lexer.lineno += tok.value.count('\n') + return tok + +def t_WHITESPACE(tok): + r"(\s|\\\r?\n)+" + tok.lexer.lineno += tok.value.count('\n') + return tok + +def t_OP(tok): + r"[~!%^&\*\(\)\-=+\/\[\]{}\?:\<\>\.\,|;]" + return tok + +def t_FLOAT(tok): + r"([0-9]*\.[0-9]+|[0-9]+\.)([eE][+\-]?[0-9]+)?|([0-9]+[eE][+\-]?[0-9]+)" + return tok + +def t_HEX(tok): + r"0x[0-9a-fA-F]+u?" + return tok + +def t_INT(tok): + r"[0-9]+u?" + return tok + +def t_ID(tok): + r"[\@\$]?[A-Za-z_][A-Za-z0-9_]*" + parse_id(tok.value, tok.lexer.exports, is_reference=True) + return tok + +def t_UNKNOWN(tok): + r"." + return tok + +def t_error(tok): + raise Exception("Illegal character '%s' at line %d" % (tok.value[0], tok.lexer.lineno)) + +# identifier names that cannot be renamed +glsl_reserved = { + "EmitStreamVertex", "EmitVertex", "EmitVertex", "EndPrimitive", "EndPrimitive", + "EndStreamPrimitive", "abs", "abs", "abs", "acos", "acosh", "all", "allInvocations", + "allInvocationsEqual", "any", "anyInvocation", "asin", "asinh", "atan", "atan", "atanh", + "atomicAdd", "atomicAdd", "atomicAnd", "atomicAnd", "atomicCompSwap", "atomicCompSwap", + "atomicCounter", "atomicCounterAdd", "atomicCounterAnd", "atomicCounterCompSwap", + "atomicCounterDecrement", "atomicCounterExchange", "atomicCounterIncrement", "atomicCounterMax", + "atomicCounterMin", "atomicCounterOr", "atomicCounterSubtract", "atomicCounterXor", + "atomicExchange", "atomicExchange", "atomicMax", "atomicMax", "atomicMin", "atomicMin", + "atomicOr", "atomicOr", "atomicXor", "atomicXor", "barrier", "barrier", + "beginFragmentShaderOrderingINTEL", "beginInvocationInterlockARB", "beginInvocationInterlockNV", + "binding", "bitCount", "bitCount", "bitfieldExtract", "bitfieldExtract", "bitfieldInsert", + "bitfieldInsert", "bitfieldReverse", "bitfieldReverse", "bool", "break", "bvec2", "bvec3", + "bvec4", "case", "ceil", "ceil", "centroid", "clamp", "clamp", "clamp", "clamp", "clamp", + "clamp", "clamp", "clamp", "coherent", "const", "continue", "cos", "cosh", "cross", "cross", + "dFdx", "dFdx", "dFdxCoarse", "dFdxFine", "dFdy", "dFdy", "dFdyCoarse", "dFdyFine", "default", + "degrees", "determinant", "determinant", "determinant", "discard", "distance", "distance", "do", + "dot", "dot", "else", "endInvocationInterlockARB", "endInvocationInterlockNV", "equal", "equal", + "equal", "equal", "exp", "exp2", "faceforward", "faceforward", "false", "findLSB", "findLSB", + "findMSB", "findMSB", "flat", "float", "floatBitsToInt", "floatBitsToUint", "floor", "floor", + "fma", "fma", "fma", "for", "fract", "fract", "frexp", "frexp", "ftransform", "fwidth", + "fwidth", "fwidthCoarse", "fwidthFine", "greaterThan", "greaterThan", "greaterThan", + "greaterThanEqual", "greaterThanEqual", "greaterThanEqual", "groupMemoryBarrier", "highp", "if", + "iimage2D", "image2D", "imageAtomicAdd", "imageAtomicAdd", "imageAtomicAdd", "imageAtomicAdd", + "imageAtomicAnd", "imageAtomicAnd", "imageAtomicAnd", "imageAtomicAnd", "imageAtomicCompSwap", + "imageAtomicCompSwap", "imageAtomicCompSwap", "imageAtomicCompSwap", "imageAtomicExchange", + "imageAtomicExchange", "imageAtomicExchange", "imageAtomicExchange", "imageAtomicExchange", + "imageAtomicMax", "imageAtomicMax", "imageAtomicMax", "imageAtomicMax", "imageAtomicMin", + "imageAtomicMin", "imageAtomicMin", "imageAtomicMin", "imageAtomicOr", "imageAtomicOr", + "imageAtomicOr", "imageAtomicOr", "imageAtomicXor", "imageAtomicXor", "imageAtomicXor", + "imageAtomicXor", "imageLoad", "imageLoad", "imageLoad", "imageLoad", "imageLoad", "imageLoad", + "imageLoad", "imageLoad", "imageSamples", "imageSamples", "imageSize", "imageSize", "imageSize", + "imageSize", "imageSize", "imageSize", "imageSize", "imageSize", "imageSize", "imageSize", + "imageSize", "imageSize", "imageSize", "imageSize", "imageSize", "imageSize", "imageSize", + "imageSize", "imageSize", "imageStore", "imageStore", "imageStore", "imageStore", "imageStore", + "imageStore", "imageStore", "imageStore", "imageStore", "imulExtended", "in", "inout", "int", + "intBitsToFloat", "interpolateAtCentroid", "interpolateAtCentroid", "interpolateAtCentroid", + "interpolateAtCentroid", "interpolateAtCentroid", "interpolateAtCentroid", + "interpolateAtCentroid", "interpolateAtCentroid", "interpolateAtOffset", "interpolateAtOffset", + "interpolateAtOffset", "interpolateAtOffset", "interpolateAtOffset", "interpolateAtOffset", + "interpolateAtOffset", "interpolateAtSample", "interpolateAtSample", "interpolateAtSample", + "interpolateAtSample", "interpolateAtSample", "interpolateAtSample", "interpolateAtSample", + "interpolateAtSample", "invariant", "inverse", "inverse", "inverse", "inversesqrt", + "inversesqrt", "isampler2D", "isampler2DArray", "isampler3D", "isamplerCube", "isinf", "isinf", + "isnan", "isnan", "ivec2", "ivec3", "ivec4", "layout", "ldexp", "ldexp", "length", "length", + "lessThan", "lessThan", "lessThan", "lessThanEqual", "lessThanEqual", "lessThanEqual", + "location", "log", "log2", "lowp", "main", "mat2", "mat2x2", "mat2x3", "mat2x4", "mat3", + "mat3x2", "mat3x3", "mat3x4", "mat4", "mat4x2", "mat4x3", "mat4x4", "matrixCompMult", + "matrixCompMult", "matrixCompMult", "matrixCompMult", "matrixCompMult", "matrixCompMult", + "matrixCompMult", "matrixCompMult", "matrixCompMult", "max", "max", "max", "max", "max", "max", + "max", "max", "mediump", "memoryBarrier", "memoryBarrierAtomicCounter", "memoryBarrierBuffer", + "memoryBarrierImage", "memoryBarrierShared", "min", "min", "min", "min", "min", "min", "min", + "min", "mix", "mix", "mix", "mix", "mix", "mix", "mix", "mix", "mix", "mod", "mod", "mod", + "mod", "modf", "modf", "noise1", "noise2", "noise3", "noise4", "noperspective", "normalize", + "normalize", "not", "notEqual", "notEqual", "notEqual", "notEqual", "out", "outerProduct", + "outerProduct", "outerProduct", "outerProduct", "outerProduct", "outerProduct", "outerProduct", + "outerProduct", "outerProduct", "packDouble2x32", "packHalf2x16", "packSnorm2x16", + "packSnorm4x8", "packUnorm2x16", "packUnorm4x8", "pixelLocalLoadANGLE", "pixelLocalStoreANGLE", + "pow", "precision", "r16f", "r32f", "r32ui", "radians", "reflect", "reflect", "refract", + "refract", "return", "rg16f", "rgb_2_yuv", "rgba8", "rgba8i", "rgba8ui", "round", "round", + "roundEven", "roundEven", "sampler2D", "sampler2DArray", "sampler2DArrayShadow", + "sampler2DShadow", "sampler3D", "samplerCube", "samplerCubeShadow", "shadow1D", "shadow1DLod", + "shadow1DProj", "shadow1DProj", "shadow1DProjLod", "shadow2D", "shadow2D", "shadow2DEXT", + "shadow2DLod", "shadow2DProj", "shadow2DProj", "shadow2DProjEXT", "shadow2DProjLod", "sign", + "sign", "sign", "sin", "sinh", "smooth", "smoothstep", "smoothstep", "smoothstep", "smoothstep", + "sqrt", "sqrt", "std140", "std430", "step", "step", "step", "step", "struct", "subpassLoad", + "subpassLoad", "switch", "tan", "tanh", "texelFetch", "texelFetch", "texelFetch", "texelFetch", + "texelFetch", "texelFetch", "texelFetch", "texelFetch", "texelFetch", "texelFetch", + "texelFetch", "texelFetch", "texelFetch", "texelFetchOffset", "texelFetchOffset", + "texelFetchOffset", "texelFetchOffset", "texelFetchOffset", "texelFetchOffset", "texture", + "texture", "texture", "texture", "texture", "texture", "texture", "texture", "texture", + "texture", "texture", "texture", "texture", "texture", "texture", "texture", "texture", + "texture", "texture", "texture", "texture", "texture", "texture", "texture", "texture", + "texture", "texture", "texture", "texture", "texture", "texture", "texture", "texture", + "texture", "texture", "texture", "texture1D", "texture1D", "texture1DLod", "texture1DProj", + "texture1DProj", "texture1DProj", "texture1DProj", "texture1DProjLod", "texture1DProjLod", + "texture2D", "texture2D", "texture2D", "texture2DGradEXT", "texture2DLod", "texture2DLod", + "texture2DLodEXT", "texture2DProj", "texture2DProj", "texture2DProj", "texture2DProj", + "texture2DProj", "texture2DProj", "texture2DProjGradEXT", "texture2DProjGradEXT", + "texture2DProjLod", "texture2DProjLod", "texture2DProjLod", "texture2DProjLod", + "texture2DProjLodEXT", "texture2DProjLodEXT", "texture2DRect", "texture2DRectProj", + "texture2DRectProj", "texture3D", "texture3D", "texture3D", "texture3D", "texture3DLod", + "texture3DLod", "texture3DProj", "texture3DProj", "texture3DProj", "texture3DProj", + "texture3DProjLod", "texture3DProjLod", "textureCube", "textureCube", "textureCubeGradEXT", + "textureCubeLod", "textureCubeLod", "textureCubeLodEXT", "textureGather", "textureGather", + "textureGather", "textureGather", "textureGather", "textureGather", "textureGather", + "textureGather", "textureGather", "textureGather", "textureGather", "textureGather", + "textureGather", "textureGather", "textureGather", "textureGather", "textureGather", + "textureGather", "textureGather", "textureGather", "textureGather", "textureGatherOffset", + "textureGatherOffset", "textureGatherOffset", "textureGatherOffset", "textureGatherOffset", + "textureGatherOffset", "textureGatherOffset", "textureGatherOffset", "textureGatherOffset", + "textureGatherOffsets", "textureGatherOffsets", "textureGatherOffsets", "textureGatherOffsets", + "textureGatherOffsets", "textureGatherOffsets", "textureGatherOffsets", "textureGatherOffsets", + "textureGatherOffsets", "textureGatherOffsets", "textureGatherOffsets", "textureGatherOffsets", + "textureGatherOffsets", "textureGatherOffsets", "textureGatherOffsets", "textureGrad", + "textureGrad", "textureGrad", "textureGrad", "textureGrad", "textureGrad", "textureGrad", + "textureGrad", "textureGrad", "textureGrad", "textureGrad", "textureGrad", "textureGrad", + "textureGrad", "textureGrad", "textureGradOffset", "textureGradOffset", "textureGradOffset", + "textureGradOffset", "textureGradOffset", "textureGradOffset", "textureGradOffset", + "textureGradOffset", "textureGradOffset", "textureGradOffset", "textureGradOffset", + "textureLod", "textureLod", "textureLod", "textureLod", "textureLod", "textureLod", + "textureLod", "textureLod", "textureLod", "textureLod", "textureLod", "textureLodOffset", + "textureLodOffset", "textureLodOffset", "textureLodOffset", "textureLodOffset", + "textureLodOffset", "textureLodOffset", "textureLodOffset", "textureOffset", "textureOffset", + "textureOffset", "textureOffset", "textureOffset", "textureOffset", "textureOffset", + "textureOffset", "textureOffset", "textureOffset", "textureOffset", "textureOffset", + "textureOffset", "textureOffset", "textureOffset", "textureOffset", "textureOffset", + "textureOffset", "textureOffset", "textureProj", "textureProj", "textureProj", "textureProj", + "textureProj", "textureProj", "textureProj", "textureProj", "textureProj", "textureProj", + "textureProj", "textureProj", "textureProj", "textureProj", "textureProj", "textureProj", + "textureProj", "textureProj", "textureProj", "textureProj", "textureProj", "textureProj", + "textureProj", "textureProj", "textureProj", "textureProj", "textureProjGrad", + "textureProjGrad", "textureProjGrad", "textureProjGrad", "textureProjGrad", "textureProjGrad", + "textureProjGrad", "textureProjGrad", "textureProjGrad", "textureProjGrad", + "textureProjGradOffset", "textureProjGradOffset", "textureProjGradOffset", + "textureProjGradOffset", "textureProjGradOffset", "textureProjGradOffset", + "textureProjGradOffset", "textureProjGradOffset", "textureProjGradOffset", + "textureProjGradOffset", "textureProjLod", "textureProjLod", "textureProjLod", "textureProjLod", + "textureProjLod", "textureProjLod", "textureProjLod", "textureProjLodOffset", + "textureProjLodOffset", "textureProjLodOffset", "textureProjLodOffset", "textureProjLodOffset", + "textureProjLodOffset", "textureProjLodOffset", "textureProjOffset", "textureProjOffset", + "textureProjOffset", "textureProjOffset", "textureProjOffset", "textureProjOffset", + "textureProjOffset", "textureProjOffset", "textureProjOffset", "textureProjOffset", + "textureProjOffset", "textureProjOffset", "textureProjOffset", "textureProjOffset", + "textureProjOffset", "textureProjOffset", "textureProjOffset", "textureQueryLevels", + "textureQueryLevels", "textureQueryLevels", "textureQueryLevels", "textureQueryLevels", + "textureQueryLevels", "textureQueryLevels", "textureQueryLevels", "textureQueryLevels", + "textureQueryLevels", "textureQueryLevels", "textureQueryLevels", "textureQueryLevels", + "textureQueryLod", "textureQueryLod", "textureQueryLod", "textureQueryLod", "textureQueryLod", + "textureQueryLod", "textureQueryLod", "textureQueryLod", "textureQueryLod", "textureQueryLod", + "textureQueryLod", "textureQueryLod", "textureQueryLod", "textureSamples", "textureSamples", + "textureSize", "textureSize", "textureSize", "textureSize", "textureSize", "textureSize", + "textureSize", "textureSize", "textureSize", "textureSize", "textureSize", "textureSize", + "textureSize", "textureSize", "textureSize", "textureSize", "textureSize", "textureSize", + "textureSize", "textureSize", "textureSize", "textureSize", "textureSize", "textureSize", + "textureVideoWEBGL", "transpose", "transpose", "transpose", "transpose", "transpose", + "transpose", "transpose", "transpose", "transpose", "true", "trunc", "trunc", "uaddCarry", + "uimage2D", "uint", "uintBitsToFloat", "umulExtended", "uniform", "unpackDouble2x32", + "unpackHalf2x16", "unpackSnorm2x16", "unpackSnorm4x8", "unpackUnorm2x16", "usampler2D", + "usampler2DArray", "usampler3D", "usamplerCube", "usubBorrow", "uvec2", "uvec3", "uvec4", + "vec2", "vec3", "vec4", "void", "volatile", "while", "yuv_2_rgb", "__pixel_localEXT", + "__pixel_local_inEXT", "__pixel_local_outEXT", "set", "texture2D", "utexture2D", "sampler", + "subpassInput", "usubpassInput", "input_attachment_index", "readonly", "buffer", + "unpackUnorm4x8", "defined", "elif", "extension", "enable", "require", "endif", "undef", + "pragma", "__VERSION__", "constant_id", "blend_support_all_equations", "blend_support_multiply", + "blend_support_screen", "blend_support_overlay", "blend_support_darken", + "blend_support_lighten", "blend_support_colordodge", "blend_support_colorburn", + "blend_support_hardlight", "blend_support_softlight", "blend_support_difference", + "blend_support_exclusion", +} + +# rgba and stpq get rewritten to xyzw, so we only need to check xyzw here. This way we can keep +# renaming to names like, e.g., "rg". +xyzw_pattern = re.compile(r"^[xyzw]{1,4}$") + +# HLSL registers base names can't be overwritten by macro arguments if token pasting (e.g. t##IDX). +hlsl_register_base_names = ['t', 's', 'u', 'b'] + +# HLSL registers (e.g., t0, u1) can't be overwritten by a #define. +hlsl_register_pattern = re.compile(r"^[tsub]\d+$") + +# can we rename to or from 'name'? +def is_reserved_keyword(name): + return name in glsl_reserved\ + or xyzw_pattern.match(name)\ + or name in hlsl_register_base_names\ + or hlsl_register_pattern.match(name)\ + or name.startswith("$")\ + or name.startswith("gl_")\ + or name.startswith("GL_")\ + or name.startswith("__pixel_local")\ + or name.endswith("ANGLE") + +def remove_leading_annotation(name): + if name[0] == '@': + # A leading '@' indicates identifier names that should be exported. Rename '@my_var' to + # '_EXPORTED_my_var' to enforce that '@my_var' and 'my_var' are not interchangeable. + return '_EXPORTED_' + name[1:] + if name[0] == '$': + # A leading '$' indicates identifier names that should not be renamed. + return name[1:] + return name + +# Generates new identifier names to rewrite our variables. +class NameGenerator: + def __init__(self, first_letter_chars, additional_letter_chars): + self.first_letter_chars = first_letter_chars + self.additional_letter_chars = additional_letter_chars + self.name_index = 0 + + def next_name(self): + i = self.name_index + # Generate the first character from 'self.first_letter_chars' + name = self.first_letter_chars[i % len(self.first_letter_chars)] + i = i // len(self.first_letter_chars) + while i > 0: + # Generate the remaining characters from 'self.additional_letter_chars' + name += self.additional_letter_chars[i % len(self.additional_letter_chars)] + i = i // len(self.additional_letter_chars) + self.name_index = self.name_index + 1 + return name + +# Exported variables only use upper case letters in their names. HLSL semantics are not case +# sensitive and may also assign special meaning to numbers. +upper_case_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +upper_case_name_generator = NameGenerator(upper_case_chars, upper_case_chars + "_") + +# Don't begin new names with the the '_' character. Internal code can begin names with '_' without +# fear of renaming collisions. +lower_and_upper_chars = "abcdefghijklmnopqrstuvwxyz" + upper_case_chars +general_name_generator = NameGenerator(lower_and_upper_chars, "_0123456789" + lower_and_upper_chars) + +used_new_names = set() + +def generate_new_name(*, force_upper_case): + name_generator = upper_case_name_generator if force_upper_case else general_name_generator + while True: + name = name_generator.next_name() + if not is_reserved_keyword(name) and not name in used_new_names: + used_new_names.add(name) + return name + +# mapping from original identifiers to new names. +new_names = {} +def generate_new_names(): + for name,count in sorted(all_id_counts.items(), key=lambda x:x[1], reverse=True): + new_name = (remove_leading_annotation(name) + if args.human_readable or is_reserved_keyword(name) + # HLSL semantics are not case sensitive and can assign special meaning to + # numbers. Make all exported names upper case with no numbers. + else generate_new_name(force_upper_case=name[0] == '@')) + new_names[name] = new_name + +# used to rewrite rgba and stpq swizzles to xyzw. +rgba_stpq_pattern = re.compile(r"^([rgba]{1,4}|[stpq]{1,4})$") +rgba_stpq_remap = {'r':'x', 'g':'y', 'b':'z', 'a':'w', + 's':'x', 't':'y', 'p':'z', 'q':'w',} + + +# minifies a single GLSL file. +class Minifier: + def __init__(self, code, basename, exports=set()): + # parse tokens. + lexer = lex.lex() + lexer.exports = exports + lexer.input(code) + self.tokens = [tok for tok in lexer]; + self.exports = exports + self.basename = basename + + + # Strips unneeded code from the tokens. Called after all Minifiers have been parsed. + def strip_tokens(self): + assert(not args.human_readable) + + # strip comments. + self.tokens = \ + [tok for tok in self.tokens if "COMMENT" not in tok.type] + + # strip unused defines. + self.tokens = [tok for tok in self.tokens if tok.type != "DEFINE"\ + or all_id_reference_counts[tok.define_id] > 0] + + # merge whitespace. + unmerged,self.tokens = self.tokens,[] + for tok in unmerged: + if tok.type == "DEFINE": + if tok.define_arglist != None: + tok.define_arglist.strip_tokens() + if tok.define_val != None: + tok.define_val.strip_tokens() + if tok.type == "DIRECTIVE": + if tok.directive_val != None: + tok.directive_val.strip_tokens() + if (tok.type == "WHITESPACE" + and len(self.tokens) > 0 + and self.tokens[-1].type == "WHITESPACE"): + self.tokens[-1].value += tok.value + else: + self.tokens.append(tok) + + + # generates rewritten glsl from our tokens. + def emit_tokens_to_rewritten_glsl(self, out, *, preserve_exported_switches): + # stand-in for a null token. + lasttoken = lambda : None + lasttoken.type = "" + lasttoken.value = "" + + lasttoken_needs_whitespace = False + is_newline = True + + for tok in self.tokens: + if tok.type == "WHITESPACE": + if args.human_readable: + out.write(tok.value) + is_newline = tok.value[-1] == '\n' + lasttoken_needs_whitespace = False + continue + + is_directive = tok.type in ["DEFINE", "IFDEF", "DIRECTIVE"] + needs_whitespace = tok.type in ["FLOAT", "INT", "HEX", "ID", "DEFINED_ID"] + if is_directive and not is_newline: + out.write('\n') + elif needs_whitespace and lasttoken_needs_whitespace: + out.write(' ') + + # is_newline will be false once we output the token (unless this value otherwise gets + # updated). + is_newline = False + + if tok.type == "ID": + if (rgba_stpq_pattern.match(tok.value) + and lasttoken.type == "OP" + and lasttoken.value == "."): + # convert rgba and stpq to xyzw. + out.write(''.join([rgba_stpq_remap[ch] for ch in tok.value])) + else: + self.write_identifier(out, tok.value, preserve_exported_switches) + + elif tok.type == "DEFINE": + out.write("#define ") + self.write_identifier(out, tok.define_id, preserve_exported_switches) + if tok.define_arglist != None: + is_newline = tok.define_arglist.emit_tokens_to_rewritten_glsl(\ + out,\ + preserve_exported_switches=preserve_exported_switches) + assert(not is_newline) + if tok.define_val != None: + out.write(' ') + is_newline = tok.define_val.emit_tokens_to_rewritten_glsl(\ + out,\ + preserve_exported_switches=preserve_exported_switches) + + elif tok.type == "IFDEF": + out.write('#') + out.write(tok.ifdef_tag) + out.write(' ') + self.write_identifier(out, tok.ifdef_id, preserve_exported_switches) + + elif tok.type == "DEFINED_ID": + out.write('defined(') + self.write_identifier(out, tok.defined_id, preserve_exported_switches) + out.write(')') + + elif tok.type == "DIRECTIVE": + out.write("#") + if tok.directive_val != None: + is_newline = tok.directive_val.emit_tokens_to_rewritten_glsl(\ + out,\ + preserve_exported_switches=preserve_exported_switches) + + else: + out.write(tok.value) + + # Since we preserve whitespace in 'human_readable' mode, the newline after a + # preprocessor directive will happen for us automatically unless 'human_readable' is + # false. + if not args.human_readable and is_directive and not is_newline: + out.write('\n') + is_newline = True + + lasttoken = tok + lasttoken_needs_whitespace = needs_whitespace + + return is_newline + + + def write_identifier(self, out, identifier, preserve_exported_switches): + if preserve_exported_switches and identifier in exported_switches: + assert(identifier[0] == '@') + out.write(identifier[1:]) + else: + out.write(new_names[identifier]) + + + def write_exports(self, outdir): + output_path = os.path.join(outdir, os.path.splitext(self.basename)[0] + ".exports.h") + print("Exporting %s <- %s" % (output_path, self.basename)) + out = open(output_path, "w", newline='\n') + out.write('#pragma once\n\n') + for exp in sorted(self.exports): + out.write('#define GLSL_%s "%s"\n' % (exp[1:], new_names[exp])) + out.write('#define GLSL_%s_raw %s\n' % (exp[1:], new_names[exp])) + out.close() + + + def write_embedded_glsl(self, outdir): + output_path = os.path.join(outdir, self.basename + ".hpp") + print("Embedding %s <- %s" % (output_path, self.basename)) + out = open(output_path, "w", newline='\n') + out.write("#pragma once\n\n") + + out.write('#include "%s"\n\n' % (os.path.splitext(self.basename)[0] + ".exports.h")) + + # emit shader code. + out.write("namespace rive {\n") + out.write("namespace gpu {\n") + out.write("namespace glsl {\n") + out.write('const char %s[] = R"===(' % os.path.splitext(self.basename)[0]) + + is_newline = self.emit_tokens_to_rewritten_glsl(out, preserve_exported_switches=False) + if not is_newline: + out.write('\n') + + out.write(')===";\n') + out.write("} // namespace glsl\n") + out.write("} // namespace gpu\n") + out.write("} // namespace rive") + out.close() + + def write_offline_glsl(self, outdir): + output_path = os.path.join(outdir, os.path.splitext(self.basename)[0] + ".minified.glsl") + print("Minifying %s <- %s" % (output_path, self.basename)) + out = open(output_path, "w", newline='\n') + self.emit_tokens_to_rewritten_glsl(out, preserve_exported_switches=True) + out.close() + + +# parse all GLSL files before renaming. This keeps the renaming consistent across files. +minifiers = [Minifier(open(f).read(), os.path.basename(f)) for f in args.files] +generate_new_names() + +# minify all GLSL files. +if not os.path.exists(args.outdir): + os.makedirs(args.outdir) +for m in minifiers: + if not args.human_readable: + m.strip_tokens() + m.write_exports(args.outdir) + m.write_embedded_glsl(args.outdir) + m.write_offline_glsl(args.outdir) diff --git a/third_party/rive_renderer/source/shaders/pls_load_store_ext.glsl b/third_party/rive_renderer/source/shaders/pls_load_store_ext.glsl new file mode 100644 index 0000000..75ce403 --- /dev/null +++ b/third_party/rive_renderer/source/shaders/pls_load_store_ext.glsl @@ -0,0 +1,102 @@ +/* + * Copyright 2022 Rive + */ + +// The EXT_shader_pixel_local_storage extension does not provide a mechanism to +// load, store, or clear pixel local storage contents. This shader performs +// custom load, store, and clear operations via fullscreen draws. + +#ifdef @VERTEX +void main() +{ + // [-1, -1] .. [+1, +1] + gl_Position = vec4(mix(vec2(-1, 1), + vec2(1, -1), + equal(gl_VertexID & ivec2(1, 2), ivec2(0))), + 0, + 1); +} +#endif + +#ifdef @FRAGMENT + +#extension GL_EXT_shader_pixel_local_storage : require +#ifdef GL_ARM_shader_framebuffer_fetch +#extension GL_ARM_shader_framebuffer_fetch : require +#else +#extension GL_EXT_shader_framebuffer_fetch : require +#endif + +#ifdef @CLEAR_COLOR +#if __VERSION__ >= 310 +layout(binding = 0, std140) uniform ClearColor { uniform highp vec4 value; } +clearColor; +#else +uniform mediump vec4 @clearColor; +#endif +#endif + +#ifdef GL_EXT_shader_pixel_local_storage + +#ifdef @STORE_COLOR +__pixel_local_inEXT PLS +#else +__pixel_local_outEXT PLS +#endif +{ + layout(rgba8) mediump vec4 colorBuffer; + layout(r32ui) highp uint clipBuffer; + layout(rgba8) mediump vec4 scratchColorBuffer; + layout(r32ui) highp uint coverageCountBuffer; +}; + +#ifndef GL_ARM_shader_framebuffer_fetch +#ifdef @LOAD_COLOR +layout(location = 0) inout mediump vec4 fragColor; +#endif +#endif + +#ifdef @STORE_COLOR +layout(location = 0) out mediump vec4 fragColor; +#endif + +void main() +{ +#ifdef @CLEAR_COLOR +#if __VERSION__ >= 310 + colorBuffer = clearColor.value; +#else + colorBuffer = @clearColor; +#endif +#endif + +#ifdef @LOAD_COLOR +#ifdef GL_ARM_shader_framebuffer_fetch + colorBuffer = gl_LastFragColorARM; +#else + colorBuffer = fragColor; +#endif +#endif + +#ifdef @CLEAR_COVERAGE + coverageCountBuffer = 0u; +#endif + +#ifdef @CLEAR_CLIP + clipBuffer = 0u; +#endif + +#ifdef @STORE_COLOR + fragColor = colorBuffer; +#endif +} + +#else + +// This shader is being parsed by WebGPU for introspection purposes. +layout(location = 0) out mediump vec4 unused; +void main() { unused = vec4(0, 1, 0, 1); } + +#endif // GL_EXT_shader_pixel_local_storage + +#endif // FRAGMENT diff --git a/third_party/rive_renderer/source/shaders/render_atlas.glsl b/third_party/rive_renderer/source/shaders/render_atlas.glsl new file mode 100644 index 0000000..32c0d23 --- /dev/null +++ b/third_party/rive_renderer/source/shaders/render_atlas.glsl @@ -0,0 +1,75 @@ +/* + * Copyright 2025 Rive + */ + +#ifdef @VERTEX +ATTR_BLOCK_BEGIN(Attrs) +// [localVertexID, outset, fillCoverage, vertexType] +ATTR(0, float4, @a_patchVertexData); +ATTR(1, float4, @a_mirroredVertexData); +ATTR_BLOCK_END +#endif + +VARYING_BLOCK_BEGIN +NO_PERSPECTIVE VARYING(0, float4, v_coverages); +VARYING_BLOCK_END + +#ifdef @VERTEX +VERTEX_MAIN(@atlasVertexMain, Attrs, attrs, _vertexID, _instanceID) +{ + ATTR_UNPACK(_vertexID, attrs, @a_patchVertexData, float4); + ATTR_UNPACK(_vertexID, attrs, @a_mirroredVertexData, float4); + + VARYING_INIT(v_coverages, float4); + + float4 pos; + uint pathID; + float2 vertexPosition; + if (unpack_tessellated_path_vertex(@a_patchVertexData, + @a_mirroredVertexData, + _instanceID, + pathID, + vertexPosition, + v_coverages VERTEX_CONTEXT_UNPACK)) + { + // Offset from on-screen coordinates to atlas coordinates. + uint4 pathData2 = STORAGE_BUFFER_LOAD4(@pathBuffer, pathID * 4u + 2u); + float3 atlasTransform = uintBitsToFloat(pathData2.yzw); + vertexPosition = vertexPosition * atlasTransform.x + atlasTransform.yz; + + pos = pixel_coord_to_clip_coord(vertexPosition, + uniforms.atlasContentInverseViewport.x, + uniforms.atlasContentInverseViewport.y); + } + else + { + pos = float4(uniforms.vertexDiscardValue, + uniforms.vertexDiscardValue, + uniforms.vertexDiscardValue, + uniforms.vertexDiscardValue); + } + + VARYING_PACK(v_coverages); + EMIT_VERTEX(pos); +} +#endif // @VERTEX + +#ifdef @FRAGMENT + +#ifdef @ATLAS_FEATHERED_FILL +FRAG_DATA_MAIN(float, @atlasFillFragmentMain) +{ + VARYING_UNPACK(v_coverages, float4); + EMIT_FRAG_DATA(eval_feathered_fill(v_coverages TEXTURE_CONTEXT_FORWARD)); +} +#endif // @ATLAS_FEATHERED_FILL + +#ifdef @ATLAS_FEATHERED_STROKE +FRAG_DATA_MAIN(float, @atlasStrokeFragmentMain) +{ + VARYING_UNPACK(v_coverages, float4); + EMIT_FRAG_DATA(eval_feathered_stroke(v_coverages TEXTURE_CONTEXT_FORWARD)); +} +#endif // @ATLAS_FEATHERED_STROKE + +#endif // FRAGMENT diff --git a/third_party/rive_renderer/source/shaders/rhi.glsl b/third_party/rive_renderer/source/shaders/rhi.glsl new file mode 100644 index 0000000..84dd462 --- /dev/null +++ b/third_party/rive_renderer/source/shaders/rhi.glsl @@ -0,0 +1,405 @@ +/* + * Copyright 2023 Rive + */ + +// This header provides GLSL-specific #defines and declarations that enable our +// shaders to be compiled on MSL and GLSL both. + +// HLSL warns that it will unroll the loops through r,g,b values in +// advanced_blend.glsl, but unrolling these loops is exactly what we want. +#pragma $warning($disable : 3550) + +// Don't warn about uninitialized variables. If we leave one uninitialized it's +// because we know what we're doing and don't want to pay the cost of +// initializing it. +#pragma $warning($disable : 4000) + +// #define native hlsl types if their names are being rewritten. +#define _ARE_TOKEN_NAMES_PRESERVED +#ifndef $_ARE_TOKEN_NAMES_PRESERVED +#define half $half +#define half2 $half2 +#define half3 $half3 +#define half4 $half4 +#define short $short +#define short2 $short2 +#define short3 $short3 +#define short4 $short4 +#define ushort $ushort +#define ushort2 $ushort2 +#define ushort3 $ushort3 +#define ushort4 $ushort4 +#define float2 $float2 +#define float3 $float3 +#define float4 $float4 +#define bool2 $bool2 +#define bool3 $bool3 +#define bool4 $bool4 +#define uint2 $uint2 +#define uint3 $uint3 +#define uint4 $uint4 +#define int2 $int2 +#define int3 $int3 +#define int4 $int4 +#define float4x2 $float4x2 +#define ushort $ushort +#define float2x2 $float2x2 +#define half3x3 $half3x3 +#define half2x3 $half2x3 +#endif + +$typedef float3 packed_float3; + +#ifdef @ENABLE_MIN_16_PRECISION + +#if NEEDS_USHORT_DEFINE + +$typedef $min16uint ushort; + +#endif // NEEDS_USHORT_DEFINE + +#else + +#if NEEDS_USHORT_DEFINE + +$typedef $uint ushort; + +#endif // NEEDS_USHORT_DEFINE + +#endif // ENABLE_MIN_16_PRECISION + +#define SPLAT(A, B) A##B + +#define INLINE $inline +#define OUT(ARG_TYPE) out ARG_TYPE +#define INOUT(ARG_TYPE) inout ARG_TYPE + +#define ATTR_BLOCK_BEGIN(NAME) \ + struct NAME \ + { +#define ATTR(IDX, TYPE, NAME) TYPE NAME : SPLAT(ATTRIBUTE, IDX) +#define ATTR_BLOCK_END \ + } \ + ; +#define ATTR_LOAD(T, A, N, I) +#define ATTR_UNPACK(ID, attrs, NAME, TYPE) TYPE NAME = attrs.NAME + +#define UNIFORM_BLOCK_BEGIN(IDX, NAME) \ + $cbuffer NAME \ + { \ + struct \ + { + +#define UNIFORM_BLOCK_END(NAME) \ + } \ + NAME; \ + } + +#define VARYING_BLOCK_BEGIN \ + struct Varyings \ + { + +#define NO_PERSPECTIVE $noperspective +#define @OPTIONALLY_FLAT $nointerpolation +#define FLAT $nointerpolation +#define VARYING(IDX, TYPE, NAME) TYPE NAME : SPLAT($TEXCOORD, IDX) + +#define VARYING_BLOCK_END \ + float4 _pos : $SV_Position; \ + } \ + ; + +#define VARYING_INIT(NAME, TYPE) TYPE NAME +#define VARYING_PACK(NAME) _varyings.NAME = NAME +#define VARYING_UNPACK(NAME, TYPE) TYPE NAME = _varyings.NAME + +#ifdef @VERTEX +#define VERTEX_TEXTURE_BLOCK_BEGIN +#define VERTEX_TEXTURE_BLOCK_END +#endif + +#ifdef @FRAGMENT +#define FRAG_TEXTURE_BLOCK_BEGIN +#define FRAG_TEXTURE_BLOCK_END +#endif + +#define DYNAMIC_SAMPLER_BLOCK_BEGIN +#define DYNAMIC_SAMPLER_BLOCK_END + +#define TEXTURE_RGBA32UI(SET, IDX, NAME) uniform $Texture2D NAME +#define TEXTURE_RGBA32F(SET, IDX, NAME) uniform $Texture2D NAME +#define TEXTURE_RGBA8(SET, IDX, NAME) uniform $Texture2D NAME +#define TEXTURE_R16F(SET, IDX, NAME) uniform $Texture2D NAME +#define TEXTURE_R16F_1D_ARRAY(SET, IDX, NAME) uniform $Texture2DArray NAME +#define SAMPLED_R16F_REF(NAME, SAMPLER_NAME) \ + $Texture2D NAME, $SamplerState SAMPLER_NAME +#define SAMPLED_R16F(NAME, SAMPLER_NAME) NAME, SAMPLER_NAME + +// SAMPLER_LINEAR and SAMPLER_MIPMAP are the same because in d3d11, sampler +// parameters are defined at the API level. +#define SAMPLER(TEXTURE_IDX, NAME) $SamplerState NAME; +#define SAMPLER_LINEAR SAMPLER +#define SAMPLER_MIPMAP SAMPLER +#define SAMPLER_DYNAMIC SAMPLER + +#define TEXEL_FETCH(NAME, COORD) NAME[COORD] +#define TEXTURE_SAMPLE(NAME, SAMPLER_NAME, COORD) \ + NAME.$Sample(SAMPLER_NAME, COORD) +#define TEXTURE_SAMPLE_LOD(NAME, SAMPLER_NAME, COORD, LOD) \ + NAME.$SampleLevel(SAMPLER_NAME, COORD, LOD) +#define TEXTURE_REF_SAMPLE_LOD TEXTURE_SAMPLE_LOD +#define TEXTURE_SAMPLE_GRAD(NAME, SAMPLER_NAME, COORD, DDX, DDY) \ + NAME.$SampleGrad(SAMPLER_NAME, COORD, DDX, DDY) +#define TEXTURE_GATHER(NAME, SAMPLER_NAME, COORD, TEXTURE_INVERSE_SIZE) \ + NAME.$Gather(SAMPLER_NAME, (COORD) * (TEXTURE_INVERSE_SIZE)) +#define TEXTURE_SAMPLE_LOD_1D_ARRAY(NAME, \ + SAMPLER_NAME, \ + X, \ + ARRAY_INDEX, \ + ARRAY_INDEX_NORMALIZED, \ + LOD) \ + NAME.$SampleLevel(SAMPLER_NAME, float3(X, 0.5, ARRAY_INDEX), LOD) + +#define TEXTURE_SAMPLE_DYNAMIC(TEXTURE, SAMPLER_NAME, COORD) \ + TEXTURE_SAMPLE(TEXTURE, SAMPLER_NAME, COORD) +#define TEXTURE_SAMPLE_DYNAMIC_LOD(TEXTURE, SAMPLER_NAME, COORD, LOD) \ + TEXTURE_SAMPLE_LOD(TEXTURE, SAMPLER_NAME, COORD, LOD) + +#define PLS_INTERLOCK_BEGIN +#define PLS_INTERLOCK_END + +#ifdef @ENABLE_RASTERIZER_ORDERED_VIEWS +#define PLS_TEX2D $RasterizerOrderedTexture2D +#else +#define PLS_TEX2D $RWTexture2D +#endif + +#define PLS_BLOCK_BEGIN +#ifdef @ENABLE_TYPED_UAV_LOAD_STORE +#define PLS_DECL4F(IDX, NAME) uniform PLS_TEX2D NAME +#else +#define PLS_DECL4F(IDX, NAME) uniform PLS_TEX2D NAME +#endif +#define PLS_DECL4F_READONLY PLS_DECL4F +#define PLS_DECLUI(IDX, NAME) uniform PLS_TEX2D NAME +#define PLS_DECLUI_ATOMIC PLS_DECLUI +#define PLS_LOADUI_ATOMIC PLS_LOADUI +#define PLS_STOREUI_ATOMIC PLS_STOREUI +#define PLS_BLOCK_END + +#ifdef @ENABLE_TYPED_UAV_LOAD_STORE +#define PLS_LOAD4F(PLANE) PLANE[_plsCoord] +#else +#define PLS_LOAD4F(PLANE) unpackUnorm4x8(PLANE[_plsCoord]) +#endif +#define PLS_LOADUI(PLANE) PLANE[_plsCoord] +#ifdef @ENABLE_TYPED_UAV_LOAD_STORE +#define PLS_STORE4F(PLANE, VALUE) PLANE[_plsCoord] = (VALUE) +#else +#define PLS_STORE4F(PLANE, VALUE) PLANE[_plsCoord] = packUnorm4x8(VALUE) +#endif +#define PLS_STOREUI(PLANE, VALUE) PLANE[_plsCoord] = (VALUE) + +INLINE uint pls_atomic_max(PLS_TEX2D plane, int2 _plsCoord, uint x) +{ + uint originalValue; + $InterlockedMax(plane[_plsCoord], x, originalValue); + return originalValue; +} + +#define PLS_ATOMIC_MAX(PLANE, X) pls_atomic_max(PLANE, _plsCoord, X) + +INLINE uint pls_atomic_add(PLS_TEX2D plane, int2 _plsCoord, uint x) +{ + uint originalValue; + $InterlockedAdd(plane[_plsCoord], x, originalValue); + return originalValue; +} + +#define PLS_ATOMIC_ADD(PLANE, X) pls_atomic_add(PLANE, _plsCoord, X) + +#define PLS_PRESERVE_4F(PLANE) +#define PLS_PRESERVE_UI(PLANE) + +#define VERTEX_CONTEXT_DECL +#define VERTEX_CONTEXT_UNPACK + +#define TEXTURE_CONTEXT_DECL +#define TEXTURE_CONTEXT_FORWARD + +#define VERTEX_MAIN(NAME, Attrs, attrs, _vertexID, _instanceID) \ + \ + uint $baseInstance; \ + \ + Varyings NAME(Attrs attrs, uint _vertexID \ + : $SV_VertexID, uint _instanceIDWithoutBase \ + : $SV_InstanceID) \ + { \ + uint _instanceID = _instanceIDWithoutBase + $baseInstance; \ + Varyings _varyings; + +#define IMAGE_RECT_VERTEX_MAIN(NAME, Attrs, attrs, _vertexID, _instanceID) \ + Varyings NAME(Attrs attrs, uint _vertexID : $SV_VertexID) \ + { \ + Varyings _varyings; \ + float4 _pos; + +#define IMAGE_MESH_VERTEX_MAIN(NAME, \ + PositionAttr, \ + position, \ + UVAttr, \ + uv, \ + _vertexID) \ + Varyings NAME(PositionAttr position, UVAttr uv, uint _vertexID \ + : $SV_VertexID) \ + { \ + Varyings _varyings; \ + float4 _pos; + +#define EMIT_VERTEX(POSITION) \ + _varyings._pos = POSITION; \ + } \ + return _varyings; + +#define FRAG_DATA_MAIN(DATA_TYPE, NAME) \ + DATA_TYPE NAME(Varyings _varyings) : $SV_Target \ + { + +#define EMIT_FRAG_DATA(VALUE) \ + return VALUE; \ + } + +#define FRAGMENT_CONTEXT_DECL , float2 _fragCoord +#define FRAGMENT_CONTEXT_UNPACK , _fragCoord + +#define PLS_CONTEXT_DECL , int2 _plsCoord +#define PLS_CONTEXT_UNPACK , _plsCoord + +#define PLS_MAIN(NAME) \ + EARLYDEPTHSTENCIL void NAME(Varyings _varyings) \ + { \ + float2 _fragCoord = _varyings._pos.xy; \ + int2 _plsCoord = int2(floor(_fragCoord)); + +#define PLS_MAIN_WITH_IMAGE_UNIFORMS(NAME) PLS_MAIN(NAME) + +#define EMIT_PLS } + +#define PLS_FRAG_COLOR_MAIN(NAME) \ + EARLYDEPTHSTENCIL half4 NAME(Varyings _varyings) : $SV_Target \ + { \ + float2 _fragCoord = _varyings._pos.xy; \ + int2 _plsCoord = int2(floor(_fragCoord)); \ + half4 _fragColor; + +#define PLS_FRAG_COLOR_MAIN_WITH_IMAGE_UNIFORMS(NAME) PLS_FRAG_COLOR_MAIN(NAME) + +#define EMIT_PLS_AND_FRAG_COLOR \ + } \ + return _fragColor; + +#define uintBitsToFloat $asfloat +#define intBitsToFloat $asfloat +#define floatBitsToInt $asint +#define floatBitsToUint $asuint +#define inversesqrt $rsqrt +#define equal(A, B) ((A) == (B)) +#define notEqual(A, B) ((A) != (B)) +#define lessThanEqual(A, B) ((A) <= (B)) +#define lessThan(A, B) ((A) < (B)) +#define greaterThan(A, B) ((A) > (B)) +#define greaterThanEqual(A, B) ((A) >= (B)) + +// HLSL matrices are stored in row-major order, and therefore transposed from +// their counterparts in GLSL and Metal. We can work around this entirely by +// reversing the arguments to mul(). +#define MUL(A, B) $mul(B, A) + +#define VERTEX_STORAGE_BUFFER_BLOCK_BEGIN +#define VERTEX_STORAGE_BUFFER_BLOCK_END + +#define FRAG_STORAGE_BUFFER_BLOCK_BEGIN +#define FRAG_STORAGE_BUFFER_BLOCK_END + +#define STORAGE_BUFFER_U32x2(IDX, GLSL_STRUCT_NAME, NAME) \ + $StructuredBuffer NAME +#define STORAGE_BUFFER_U32x4(IDX, GLSL_STRUCT_NAME, NAME) \ + $StructuredBuffer NAME +#define STORAGE_BUFFER_F32x4(IDX, GLSL_STRUCT_NAME, NAME) \ + $StructuredBuffer NAME + +#define STORAGE_BUFFER_LOAD4(NAME, I) NAME[I] +#define STORAGE_BUFFER_LOAD2(NAME, I) NAME[I] + +INLINE half2 unpackHalf2x16(uint u) +{ + uint y = (u >> 16); + uint x = u & 0xffffu; + return half2($f16tof32(x), $f16tof32(y)); +} + +INLINE uint packHalf2x16(float2 v) +{ + uint x = $f32tof16(v.x); + uint y = $f32tof16(v.y); + return (y << 16) | x; +} + +INLINE half4 unpackUnorm4x8(uint u) +{ + uint4 vals = uint4(u & 0xffu, (u >> 8) & 0xffu, (u >> 16) & 0xffu, u >> 24); + return half4(vals) * (1. / 255.); +} + +INLINE uint packUnorm4x8(half4 color) +{ + uint4 vals = (uint4(color * 255.) & 0xff) << uint4(0, 8, 16, 24); + vals.rg |= vals.ba; + vals.r |= vals.g; + return vals.r; +} + +INLINE float2x2 inverse(float2x2 m) +{ + float2x2 adjoint = float2x2(m[1][1], -m[0][1], -m[1][0], m[0][0]); + return adjoint * (1. / determinant(m)); +} + +// Redirects for intrinsics that have different names in HLSL + +INLINE float mix(float x, float y, float s) { return $lerp(x, y, s); } +INLINE float2 mix(float2 x, float2 y, float2 s) { return $lerp(x, y, s); } +INLINE float3 mix(float3 x, float3 y, float3 s) { return $lerp(x, y, s); } +INLINE float4 mix(float4 x, float4 y, float4 s) { return $lerp(x, y, s); } + +INLINE float fract(float x) { return $frac(x); } +INLINE float2 fract(float2 x) { return $frac(x); } +INLINE float3 fract(float3 x) { return $frac(x); } +INLINE float4 fract(float4 x) { return $frac(x); } + +INLINE float mod(float x, float y) { return $fmod(x, y); } + +// Reimplement intrinsics for half types. +// This shadows the intrinsic function for floats, so we also have to declare +// that overload. + +INLINE float rive_sign(float x) { return sign(x); } +INLINE float2 rive_sign(float2 x) { return sign(x); } +INLINE float3 rive_sign(float3 x) { return sign(x); } +INLINE float4 rive_sign(float4 x) { return sign(x); } + +#define sign rive_sign + +INLINE float rive_abs(float x) { return abs(x); } +INLINE float2 rive_abs(float2 x) { return abs(x); } +INLINE float3 rive_abs(float3 x) { return abs(x); } +INLINE float4 rive_abs(float4 x) { return abs(x); } + +#define abs rive_abs + +INLINE float rive_sqrt(float x) { return sqrt(x); } +INLINE float2 rive_sqrt(float2 x) { return sqrt(x); } +INLINE float3 rive_sqrt(float3 x) { return sqrt(x); } +INLINE float4 rive_sqrt(float4 x) { return sqrt(x); } + +#define sqrt rive_sqrt diff --git a/third_party/rive_renderer/source/shaders/specialization.glsl b/third_party/rive_renderer/source/shaders/specialization.glsl new file mode 100644 index 0000000..d2d119e --- /dev/null +++ b/third_party/rive_renderer/source/shaders/specialization.glsl @@ -0,0 +1,31 @@ +layout(constant_id = CLIPPING_SPECIALIZATION_IDX) const + bool kEnableClipping = true; +layout(constant_id = CLIP_RECT_SPECIALIZATION_IDX) const + bool kEnableClipRect = true; +layout(constant_id = ADVANCED_BLEND_SPECIALIZATION_IDX) const + bool kEnableAdvancedBlend = true; +layout(constant_id = FEATHER_SPECIALIZATION_IDX) const + bool kEnableFeather = true; +layout(constant_id = EVEN_ODD_SPECIALIZATION_IDX) const + bool kEnableEvenOdd = true; +layout(constant_id = NESTED_CLIPPING_SPECIALIZATION_IDX) const + bool kEnableNestedClipping = true; +layout(constant_id = HSL_BLEND_MODES_SPECIALIZATION_IDX) const + bool kEnableHSLBlendModes = true; +layout(constant_id = CLOCKWISE_FILL_SPECIALIZATION_IDX) const + bool kClockwiseFill = true; +layout(constant_id = BORROWED_COVERAGE_PREPASS_SPECIALIZATION_IDX) const + bool kBorrowedCoveragePrepass = true; +layout(constant_id = VULKAN_VENDOR_ID_SPECIALIZATION_IDX) const uint + kVulkanVendorID = 0; + +#define @ENABLE_CLIPPING kEnableClipping +#define @ENABLE_CLIP_RECT kEnableClipRect +#define @ENABLE_ADVANCED_BLEND kEnableAdvancedBlend +#define @ENABLE_FEATHER kEnableFeather +#define @ENABLE_EVEN_ODD kEnableEvenOdd +#define @ENABLE_NESTED_CLIPPING kEnableNestedClipping +#define @ENABLE_HSL_BLEND_MODES kEnableHSLBlendModes +#define @CLOCKWISE_FILL kClockwiseFill +#define @BORROWED_COVERAGE_PREPASS kBorrowedCoveragePrepass +#define @VULKAN_VENDOR_ID kVulkanVendorID diff --git a/third_party/rive_renderer/source/shaders/spirv/atomic_base.glsl b/third_party/rive_renderer/source/shaders/spirv/atomic_base.glsl new file mode 100644 index 0000000..decb95e --- /dev/null +++ b/third_party/rive_renderer/source/shaders/spirv/atomic_base.glsl @@ -0,0 +1,13 @@ +#extension GL_EXT_samplerless_texture_functions : require +#define ENABLE_INSTANCE_INDEX +#define PLS_IMPL_SUBPASS_LOAD +#define USING_PLS_STORAGE_TEXTURES +#define PLS_BLEND_SRC_OVER +#define OPTIONALLY_FLAT flat +#include "glsl.minified.glsl" +#include "constants.minified.glsl" +#include "specialization.minified.glsl" +#include "common.minified.glsl" +#include "advanced_blend.minified.glsl" +#include "draw_path_common.minified.glsl" +#include "atomic_draw.minified.glsl" diff --git a/third_party/rive_renderer/source/shaders/spirv/atomic_draw_atlas_blit.main b/third_party/rive_renderer/source/shaders/spirv/atomic_draw_atlas_blit.main new file mode 100644 index 0000000..1446b5e --- /dev/null +++ b/third_party/rive_renderer/source/shaders/spirv/atomic_draw_atlas_blit.main @@ -0,0 +1,5 @@ +#version 460 +#extension GL_GOOGLE_include_directive : require +#define DRAW_INTERIOR_TRIANGLES +#define ATLAS_BLIT +#include "atomic_base.glsl" diff --git a/third_party/rive_renderer/source/shaders/spirv/atomic_draw_image_mesh.main b/third_party/rive_renderer/source/shaders/spirv/atomic_draw_image_mesh.main new file mode 100644 index 0000000..999ceb8 --- /dev/null +++ b/third_party/rive_renderer/source/shaders/spirv/atomic_draw_image_mesh.main @@ -0,0 +1,5 @@ +#version 460 +#extension GL_GOOGLE_include_directive : require +#define DRAW_IMAGE +#define DRAW_IMAGE_MESH +#include "atomic_base.glsl" diff --git a/third_party/rive_renderer/source/shaders/spirv/atomic_draw_image_rect.main b/third_party/rive_renderer/source/shaders/spirv/atomic_draw_image_rect.main new file mode 100644 index 0000000..8b69855 --- /dev/null +++ b/third_party/rive_renderer/source/shaders/spirv/atomic_draw_image_rect.main @@ -0,0 +1,5 @@ +#version 460 +#extension GL_GOOGLE_include_directive : require +#define DRAW_IMAGE +#define DRAW_IMAGE_RECT +#include "atomic_base.glsl" diff --git a/third_party/rive_renderer/source/shaders/spirv/atomic_draw_interior_triangles.main b/third_party/rive_renderer/source/shaders/spirv/atomic_draw_interior_triangles.main new file mode 100644 index 0000000..83bcc25 --- /dev/null +++ b/third_party/rive_renderer/source/shaders/spirv/atomic_draw_interior_triangles.main @@ -0,0 +1,4 @@ +#version 460 +#extension GL_GOOGLE_include_directive : require +#define DRAW_INTERIOR_TRIANGLES +#include "atomic_base.glsl" diff --git a/third_party/rive_renderer/source/shaders/spirv/atomic_draw_path.main b/third_party/rive_renderer/source/shaders/spirv/atomic_draw_path.main new file mode 100644 index 0000000..46b9627 --- /dev/null +++ b/third_party/rive_renderer/source/shaders/spirv/atomic_draw_path.main @@ -0,0 +1,4 @@ +#version 460 +#extension GL_GOOGLE_include_directive : require +#define DRAW_PATH +#include "atomic_base.glsl" diff --git a/third_party/rive_renderer/source/shaders/spirv/atomic_resolve.main b/third_party/rive_renderer/source/shaders/spirv/atomic_resolve.main new file mode 100644 index 0000000..0518964 --- /dev/null +++ b/third_party/rive_renderer/source/shaders/spirv/atomic_resolve.main @@ -0,0 +1,5 @@ +#version 460 +#extension GL_GOOGLE_include_directive : require +#define DRAW_RENDER_TARGET_UPDATE_BOUNDS +#define RESOLVE_PLS +#include "atomic_base.glsl" diff --git a/third_party/rive_renderer/source/shaders/spirv/atomic_resolve_coalesced.main b/third_party/rive_renderer/source/shaders/spirv/atomic_resolve_coalesced.main new file mode 100644 index 0000000..67f40c2 --- /dev/null +++ b/third_party/rive_renderer/source/shaders/spirv/atomic_resolve_coalesced.main @@ -0,0 +1,6 @@ +#version 460 +#extension GL_GOOGLE_include_directive : require +#define DRAW_RENDER_TARGET_UPDATE_BOUNDS +#define RESOLVE_PLS +#define COALESCED_PLS_RESOLVE_AND_TRANSFER +#include "atomic_base.glsl" diff --git a/third_party/rive_renderer/source/shaders/spirv/blit_texture_as_draw.main b/third_party/rive_renderer/source/shaders/spirv/blit_texture_as_draw.main new file mode 100644 index 0000000..75c4ec7 --- /dev/null +++ b/third_party/rive_renderer/source/shaders/spirv/blit_texture_as_draw.main @@ -0,0 +1,6 @@ +#version 310 es +#extension GL_GOOGLE_include_directive : require +#extension GL_EXT_samplerless_texture_functions : require +#include "glsl.minified.glsl" +#include "constants.minified.glsl" +#include "blit_texture_as_draw.minified.glsl" diff --git a/third_party/rive_renderer/source/shaders/spirv/color_ramp.main b/third_party/rive_renderer/source/shaders/spirv/color_ramp.main new file mode 100644 index 0000000..32fc241 --- /dev/null +++ b/third_party/rive_renderer/source/shaders/spirv/color_ramp.main @@ -0,0 +1,6 @@ +#version 310 es +#extension GL_GOOGLE_include_directive : require +#include "glsl.minified.glsl" +#include "constants.minified.glsl" +#include "common.minified.glsl" +#include "color_ramp.minified.glsl" diff --git a/third_party/rive_renderer/source/shaders/spirv/draw_atlas_blit.main b/third_party/rive_renderer/source/shaders/spirv/draw_atlas_blit.main new file mode 100644 index 0000000..111f1a2 --- /dev/null +++ b/third_party/rive_renderer/source/shaders/spirv/draw_atlas_blit.main @@ -0,0 +1,14 @@ +#version 460 +#extension GL_GOOGLE_include_directive : require +#extension GL_EXT_samplerless_texture_functions : require +#define PLS_IMPL_SUBPASS_LOAD +#define OPTIONALLY_FLAT flat +#define DRAW_INTERIOR_TRIANGLES +#define ATLAS_BLIT +#include "glsl.minified.glsl" +#include "constants.minified.glsl" +#include "specialization.minified.glsl" +#include "common.minified.glsl" +#include "draw_path_common.minified.glsl" +#include "advanced_blend.minified.glsl" +#include "draw_path.minified.glsl" diff --git a/third_party/rive_renderer/source/shaders/spirv/draw_clockwise_atlas_blit.main b/third_party/rive_renderer/source/shaders/spirv/draw_clockwise_atlas_blit.main new file mode 100644 index 0000000..0d34211 --- /dev/null +++ b/third_party/rive_renderer/source/shaders/spirv/draw_clockwise_atlas_blit.main @@ -0,0 +1,14 @@ +#version 460 +#extension GL_GOOGLE_include_directive : require +#extension GL_EXT_samplerless_texture_functions : require +#define PLS_IMPL_SUBPASS_LOAD +#define OPTIONALLY_FLAT flat +#define DRAW_INTERIOR_TRIANGLES +#define ATLAS_BLIT +#include "glsl.minified.glsl" +#include "constants.minified.glsl" +#include "specialization.minified.glsl" +#include "common.minified.glsl" +#include "draw_path_common.minified.glsl" +#include "advanced_blend.minified.glsl" +#include "draw_clockwise_path.minified.glsl" diff --git a/third_party/rive_renderer/source/shaders/spirv/draw_clockwise_image_mesh.main b/third_party/rive_renderer/source/shaders/spirv/draw_clockwise_image_mesh.main new file mode 100644 index 0000000..7d6a449 --- /dev/null +++ b/third_party/rive_renderer/source/shaders/spirv/draw_clockwise_image_mesh.main @@ -0,0 +1,13 @@ +#version 460 +#extension GL_GOOGLE_include_directive : require +#extension GL_EXT_samplerless_texture_functions : require +#define ENABLE_INSTANCE_INDEX +#define PLS_IMPL_SUBPASS_LOAD +#define OPTIONALLY_FLAT flat +#define DRAW_IMAGE +#include "glsl.minified.glsl" +#include "constants.minified.glsl" +#include "specialization.minified.glsl" +#include "common.minified.glsl" +#include "advanced_blend.minified.glsl" +#include "draw_clockwise_image_mesh.minified.glsl" diff --git a/third_party/rive_renderer/source/shaders/spirv/draw_clockwise_interior_triangles.main b/third_party/rive_renderer/source/shaders/spirv/draw_clockwise_interior_triangles.main new file mode 100644 index 0000000..1f456a3 --- /dev/null +++ b/third_party/rive_renderer/source/shaders/spirv/draw_clockwise_interior_triangles.main @@ -0,0 +1,13 @@ +#version 460 +#extension GL_GOOGLE_include_directive : require +#extension GL_EXT_samplerless_texture_functions : require +#define PLS_IMPL_SUBPASS_LOAD +#define OPTIONALLY_FLAT flat +#define DRAW_INTERIOR_TRIANGLES +#include "glsl.minified.glsl" +#include "constants.minified.glsl" +#include "specialization.minified.glsl" +#include "common.minified.glsl" +#include "draw_path_common.minified.glsl" +#include "advanced_blend.minified.glsl" +#include "draw_clockwise_path.minified.glsl" diff --git a/third_party/rive_renderer/source/shaders/spirv/draw_clockwise_path.main b/third_party/rive_renderer/source/shaders/spirv/draw_clockwise_path.main new file mode 100644 index 0000000..ba10481 --- /dev/null +++ b/third_party/rive_renderer/source/shaders/spirv/draw_clockwise_path.main @@ -0,0 +1,14 @@ +#version 460 +#extension GL_GOOGLE_include_directive : require +#extension GL_EXT_samplerless_texture_functions : require +#define ENABLE_INSTANCE_INDEX +#define PLS_IMPL_SUBPASS_LOAD +#define OPTIONALLY_FLAT flat +#define DRAW_PATH +#include "glsl.minified.glsl" +#include "constants.minified.glsl" +#include "specialization.minified.glsl" +#include "common.minified.glsl" +#include "draw_path_common.minified.glsl" +#include "advanced_blend.minified.glsl" +#include "draw_clockwise_path.minified.glsl" diff --git a/third_party/rive_renderer/source/shaders/spirv/draw_image_mesh.main b/third_party/rive_renderer/source/shaders/spirv/draw_image_mesh.main new file mode 100644 index 0000000..2c967ee --- /dev/null +++ b/third_party/rive_renderer/source/shaders/spirv/draw_image_mesh.main @@ -0,0 +1,13 @@ +#version 460 +#extension GL_GOOGLE_include_directive : require +#extension GL_EXT_samplerless_texture_functions : require +#define PLS_IMPL_SUBPASS_LOAD +#define OPTIONALLY_FLAT flat +#define DRAW_IMAGE +#define DRAW_IMAGE_MESH +#include "glsl.minified.glsl" +#include "constants.minified.glsl" +#include "specialization.minified.glsl" +#include "common.minified.glsl" +#include "advanced_blend.minified.glsl" +#include "draw_image_mesh.minified.glsl" diff --git a/third_party/rive_renderer/source/shaders/spirv/draw_interior_triangles.main b/third_party/rive_renderer/source/shaders/spirv/draw_interior_triangles.main new file mode 100644 index 0000000..f8c67dd --- /dev/null +++ b/third_party/rive_renderer/source/shaders/spirv/draw_interior_triangles.main @@ -0,0 +1,13 @@ +#version 460 +#extension GL_GOOGLE_include_directive : require +#extension GL_EXT_samplerless_texture_functions : require +#define PLS_IMPL_SUBPASS_LOAD +#define OPTIONALLY_FLAT flat +#define DRAW_INTERIOR_TRIANGLES +#include "glsl.minified.glsl" +#include "constants.minified.glsl" +#include "specialization.minified.glsl" +#include "common.minified.glsl" +#include "draw_path_common.minified.glsl" +#include "advanced_blend.minified.glsl" +#include "draw_path.minified.glsl" diff --git a/third_party/rive_renderer/source/shaders/spirv/draw_path.main b/third_party/rive_renderer/source/shaders/spirv/draw_path.main new file mode 100644 index 0000000..f405142 --- /dev/null +++ b/third_party/rive_renderer/source/shaders/spirv/draw_path.main @@ -0,0 +1,14 @@ +#version 460 +#extension GL_GOOGLE_include_directive : require +#extension GL_EXT_samplerless_texture_functions : require +#define ENABLE_INSTANCE_INDEX +#define PLS_IMPL_SUBPASS_LOAD +#define OPTIONALLY_FLAT flat +#define DRAW_PATH +#include "glsl.minified.glsl" +#include "constants.minified.glsl" +#include "specialization.minified.glsl" +#include "common.minified.glsl" +#include "draw_path_common.minified.glsl" +#include "advanced_blend.minified.glsl" +#include "draw_path.minified.glsl" diff --git a/third_party/rive_renderer/source/shaders/spirv/render_atlas.vert b/third_party/rive_renderer/source/shaders/spirv/render_atlas.vert new file mode 100644 index 0000000..3a32a55 --- /dev/null +++ b/third_party/rive_renderer/source/shaders/spirv/render_atlas.vert @@ -0,0 +1,3 @@ +#version 310 es +#extension GL_GOOGLE_include_directive : require +#include "render_atlas_common.glsl" diff --git a/third_party/rive_renderer/source/shaders/spirv/render_atlas_common.glsl b/third_party/rive_renderer/source/shaders/spirv/render_atlas_common.glsl new file mode 100644 index 0000000..cfa8697 --- /dev/null +++ b/third_party/rive_renderer/source/shaders/spirv/render_atlas_common.glsl @@ -0,0 +1,10 @@ +#extension GL_EXT_samplerless_texture_functions : require +#define ENABLE_INSTANCE_INDEX +#define OPTIONALLY_FLAT flat +#define DRAW_PATH +#define ENABLE_FEATHER true +#include "glsl.minified.glsl" +#include "constants.minified.glsl" +#include "common.minified.glsl" +#include "draw_path_common.minified.glsl" +#include "render_atlas.minified.glsl" diff --git a/third_party/rive_renderer/source/shaders/spirv/render_atlas_fill.frag b/third_party/rive_renderer/source/shaders/spirv/render_atlas_fill.frag new file mode 100644 index 0000000..57f14b3 --- /dev/null +++ b/third_party/rive_renderer/source/shaders/spirv/render_atlas_fill.frag @@ -0,0 +1,4 @@ +#version 310 es +#extension GL_GOOGLE_include_directive : require +#define ATLAS_FEATHERED_FILL +#include "render_atlas_common.glsl" diff --git a/third_party/rive_renderer/source/shaders/spirv/render_atlas_stroke.frag b/third_party/rive_renderer/source/shaders/spirv/render_atlas_stroke.frag new file mode 100644 index 0000000..b165ee3 --- /dev/null +++ b/third_party/rive_renderer/source/shaders/spirv/render_atlas_stroke.frag @@ -0,0 +1,4 @@ +#version 310 es +#extension GL_GOOGLE_include_directive : require +#define ATLAS_FEATHERED_STROKE +#include "render_atlas_common.glsl" diff --git a/third_party/rive_renderer/source/shaders/spirv/tessellate.main b/third_party/rive_renderer/source/shaders/spirv/tessellate.main new file mode 100644 index 0000000..49ec881 --- /dev/null +++ b/third_party/rive_renderer/source/shaders/spirv/tessellate.main @@ -0,0 +1,8 @@ +#version 310 es +#extension GL_GOOGLE_include_directive : require +#extension GL_EXT_samplerless_texture_functions : require +#include "glsl.minified.glsl" +#include "constants.minified.glsl" +#include "common.minified.glsl" +#include "bezier_utils.minified.glsl" +#include "tessellate.minified.glsl" diff --git a/third_party/rive_renderer/source/shaders/stencil_draw.glsl b/third_party/rive_renderer/source/shaders/stencil_draw.glsl new file mode 100644 index 0000000..0b065e0 --- /dev/null +++ b/third_party/rive_renderer/source/shaders/stencil_draw.glsl @@ -0,0 +1,30 @@ +/* + * Copyright 2024 Rive + */ + +#ifdef @VERTEX +ATTR_BLOCK_BEGIN(Attrs) +ATTR(0, packed_float3, @a_triangleVertex); +ATTR_BLOCK_END + +VERTEX_TEXTURE_BLOCK_BEGIN +VERTEX_TEXTURE_BLOCK_END + +VERTEX_STORAGE_BUFFER_BLOCK_BEGIN +VERTEX_STORAGE_BUFFER_BLOCK_END + +VERTEX_MAIN(@stencilVertexMain, Attrs, attrs, _vertexID, _instanceID) +{ + float4 pos = RENDER_TARGET_COORD_TO_CLIP_COORD(@a_triangleVertex.xy); + uint zIndex = floatBitsToUint(@a_triangleVertex.z) & 0xffffu; + pos.z = normalize_z_index(zIndex); + EMIT_VERTEX(pos); +} +#endif + +#ifdef @FRAGMENT +FRAG_TEXTURE_BLOCK_BEGIN +FRAG_TEXTURE_BLOCK_END + +FRAG_DATA_MAIN(half4, @blitFragmentMain) { EMIT_FRAG_DATA(make_half4(.0)); } +#endif // FRAGMENT diff --git a/third_party/rive_renderer/source/shaders/tessellate.glsl b/third_party/rive_renderer/source/shaders/tessellate.glsl new file mode 100644 index 0000000..e5c3eb2 --- /dev/null +++ b/third_party/rive_renderer/source/shaders/tessellate.glsl @@ -0,0 +1,551 @@ +/* + * Copyright 2020 Google LLC. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Initial import from + * skia:src/gpu/ganesh/tessellate/GrStrokeTessellationShader.cpp + * + * Copyright 2022 Rive + */ + +#define MAX_PARAMETRIC_SEGMENTS_LOG2 10 // Max 1024 segments. + +#ifdef @VERTEX +ATTR_BLOCK_BEGIN(Attrs) +ATTR( + 0, + float4, + @a_p0p1_); // End in '_' because D3D interprets the '1' as a semantic index. +ATTR(1, float4, @a_p2p3_); +ATTR(2, float4, @a_joinTan_and_ys); // [joinTangent, y, reflectionY] +#ifdef SPLIT_UINT4_ATTRIBUTES +ATTR(3, uint, @a_x0x1); +ATTR(4, uint, @a_reflectionX0X1); +ATTR(5, uint, @a_segmentCounts); +ATTR(6, uint, @a_contourIDWithFlags); +#else +ATTR(3, + uint4, + @a_args); // [x0x1, reflectionX0X1, segmentCounts, contourIDWithFlags] +#endif +ATTR_BLOCK_END +#endif + +VARYING_BLOCK_BEGIN +NO_PERSPECTIVE VARYING(0, float4, v_p0p1); +NO_PERSPECTIVE VARYING(1, float4, v_p2p3); +// [vertexIdx, totalVertexCount, joinSegmentCount, +// parametricSegmentCount, radsPerPolarSegment] +NO_PERSPECTIVE VARYING(2, float4, v_args); +// [joinTangent, radsPerJoinSegment] +NO_PERSPECTIVE VARYING(3, float3, v_joinArgs); +FLAT VARYING(4, uint, v_contourIDWithFlags); +VARYING_BLOCK_END + +#ifdef @VERTEX +VERTEX_TEXTURE_BLOCK_BEGIN +TEXTURE_R16F_1D_ARRAY(PER_FLUSH_BINDINGS_SET, + FEATHER_TEXTURE_IDX, + @featherTexture); +VERTEX_TEXTURE_BLOCK_END + +SAMPLER_LINEAR(FEATHER_TEXTURE_IDX, featherSampler) + +VERTEX_STORAGE_BUFFER_BLOCK_BEGIN +STORAGE_BUFFER_U32x4(PATH_BUFFER_IDX, PathBuffer, @pathBuffer); +STORAGE_BUFFER_U32x4(CONTOUR_BUFFER_IDX, ContourBuffer, @contourBuffer); +VERTEX_STORAGE_BUFFER_BLOCK_END + +VERTEX_MAIN(@tessellateVertexMain, Attrs, attrs, _vertexID, _instanceID) +{ + // Each instance repeats twice. Once for normal patch(es) and once for + // reflection(s). + ATTR_UNPACK(_instanceID, attrs, @a_p0p1_, float4); + ATTR_UNPACK(_instanceID, attrs, @a_p2p3_, float4); + ATTR_UNPACK(_instanceID, attrs, @a_joinTan_and_ys, float4); +#ifdef SPLIT_UINT4_ATTRIBUTES + ATTR_UNPACK(_instanceID, attrs, @a_x0x1, uint); + ATTR_UNPACK(_instanceID, attrs, @a_reflectionX0X1, uint); + ATTR_UNPACK(_instanceID, attrs, @a_segmentCounts, uint); + ATTR_UNPACK(_instanceID, attrs, @a_contourIDWithFlags, uint); + + uint4 @a_args = uint4(@a_x0x1, + @a_reflectionX0X1, + @a_segmentCounts, + @a_contourIDWithFlags); +#else + ATTR_UNPACK(_instanceID, attrs, @a_args, uint4); +#endif + + VARYING_INIT(v_p0p1, float4); + VARYING_INIT(v_p2p3, float4); + VARYING_INIT(v_args, float4); + VARYING_INIT(v_joinArgs, float3); + VARYING_INIT(v_contourIDWithFlags, uint); + + float2 p0 = @a_p0p1_.xy; + float2 p1 = @a_p0p1_.zw; + float2 p2 = @a_p2p3_.xy; + float2 p3 = @a_p2p3_.zw; + // Each instance has two spans, potentially for both a forward copy and and + // reflection. (If the second span isn't needed, the client will have placed + // it offscreen.) + bool isFirstSpan = _vertexID < 4; + float y = isFirstSpan ? @a_joinTan_and_ys.z : @a_joinTan_and_ys.w; + int x0x1 = int(isFirstSpan ? @a_args.x : @a_args.y); +#ifdef GLSL + int x1up = x0x1 << 16; + if (@a_args.z == 0xffffffffu) + { + // Pixel 8 with ARM Mali-G715 throws away "x0x1 << 16 >> 16". We need + // this in order to sign-extend the bottom 16 bits of x0x1. Create a + // branch that we know won't be taken, in order to convince the compiler + // not to throw this operation away. NOTE: we could use + // bitfieldExtract(), but it isn't available on ES 3.0. + --x1up; + } + float x0 = float(x1up >> 16); +#else + float x0 = float(x0x1 << 16 >> 16); +#endif + float x1 = float(x0x1 >> 16); + float2 coord = float2((_vertexID & 1) == 0 ? x0 : x1, + (_vertexID & 2) == 0 ? y + 1. : y); + if ((x1 - x0) * uniforms.tessInverseViewportY < .0) + { + // Make sure we always emit clockwise triangles. Swap the top and bottom + // vertices. + coord.y = 2. * y + 1. - coord.y; + } + + // Unpack arguments. + uint parametricSegmentCount = @a_args.z & 0x3ffu; + uint polarSegmentCount = (@a_args.z >> 10) & 0x3ffu; + uint joinSegmentCount = @a_args.z >> 20; + uint contourIDWithFlags = @a_args.w; + uint pathID = + contourIDWithFlags != INVALID_CONTOUR_ID_WITH_FLAGS + ? STORAGE_BUFFER_LOAD4(@contourBuffer, + contour_data_idx(contourIDWithFlags)) + .z + : 0u; + uint4 pathData = pathID != 0u + ? STORAGE_BUFFER_LOAD4(@pathBuffer, pathID * 4u + 1u) + : uint4(0u, 0u, 0u, 0u); + float strokeRadius = uintBitsToFloat(pathData.z); + float featherRadius = uintBitsToFloat(pathData.w); + + if (featherRadius != .0 && strokeRadius == .0) + { + // We're a cubic from a feathered fill. To simulate the + // feather-softening effect that happens with curvature, reduce the + // height of the curve proportionally. + // Start by finding the point of maximum height on the cubic. + float maxHeightT; + float height = find_cubic_max_height(p0, p1, p2, p3, maxHeightT); + + // Measure curvature across one standard deviation of the feather. + float oneStddev = featherRadius * (1. / FEATHER_TEXTURE_STDDEVS); + float curvature = measure_cubic_local_curvature(p0, + p1, + p2, + p3, + maxHeightT, + oneStddev); + + // The feather gets softer with curvature. Find a dimming factor based + // on the strength of curvature at maximum height. + float dimming = 1. - curvature * (1. / PI); + + // It gets hard to measure curvature on short segments. Also taper down + // to completely flat as the distance between endpoints moves from 2 + // standard deviations to 1. + float stddevsPow2 = dot(p3 - p0, p3 - p0) / (oneStddev * oneStddev); + float dimmingByStddevs = (stddevsPow2 - 1.) * .5; + dimming = min(dimming, dimmingByStddevs); + + // Unfortunately, the best method we have to get rid of some final + // speckles on cusps is to dim everything by 1%. + dimming = min(dimming, .99); + + // Soften the feather by reducing the curve height. Find a new height + // such that the center of the feather (currently 50% opacity) is + // reduced to "50% * dimming". + float desiredOpacityOnCenter = .5 * dimming; + float x = INVERSE_FEATHER(desiredOpacityOnCenter) * -2. + 1.; + float softness = clamped_divide(x * featherRadius, height); + + // Flatten the curve down to "softenedHeight". (Height scales linearly + // as we lerp the control points to "flatLinePoints".) + float4 flatLinePoints = + mix(p0.xyxy, p3.xyxy, float4(1. / 3., 1. / 3., 2. / 3., 2. / 3.)); + p1 = mix(p1, flatLinePoints.xy, softness); + p2 = mix(p2, flatLinePoints.zw, softness); + } + + if ((contourIDWithFlags & CULL_EXCESS_TESSELLATION_SEGMENTS_CONTOUR_FLAG) != + 0u) + { + // This span may have more tessellation vertices allocated to it than + // necessary (e.g., outerCurve patches all have a fixed patch size, + // regardless of how many segments the curve actually needs). Re-run + // Wang's formula to figure out how many segments we actually need, and + // make any excess segments degenerate by co-locating their vertices at + // T=0. + float2x2 mat = make_float2x2( + uintBitsToFloat(STORAGE_BUFFER_LOAD4(@pathBuffer, pathID * 4u))); + float2 d0 = MUL(mat, -2. * p1 + p2 + p0); + + float2 d1 = MUL(mat, -2. * p2 + p3 + p1); + float m = max(dot(d0, d0), dot(d1, d1)); + float n = max(ceil(sqrt(.75 * 4. * sqrt(m))), 1.); + parametricSegmentCount = min(uint(n), parametricSegmentCount); + } + + // Polar and parametric segments share the same beginning and ending + // vertices, so the merged *vertex* count is equal to the sum of polar and + // parametric *segment* counts. + uint totalVertexCount = + parametricSegmentCount + polarSegmentCount + joinSegmentCount - 1u; + + float2x2 tangents = find_cubic_tangents(p0, p1, p2, p3); + float theta = acos(cosine_between_vectors(tangents[0], tangents[1])); + float radsPerPolarSegment = theta / float(polarSegmentCount); + // Adjust sign of radsPerPolarSegment to match the direction the curve + // turns. + // NOTE: Since the curve is not allowed to inflect, we can just check + // F'(.5) x F''(.5). + // NOTE: F'(.5) x F''(.5) has the same sign as (p2 - p0) x (p3 - p1). + float turn = determinant(float2x2(p2 - p0, p3 - p1)); + // This is the case for joins and cusps where points are co-located. + if (turn == .0) + turn = determinant(tangents); + if (turn < .0) + radsPerPolarSegment = -radsPerPolarSegment; + + v_p0p1 = float4(p0, p1); + v_p2p3 = float4(p2, p3); + v_args = float4(float(totalVertexCount) - abs(x1 - coord.x), // vertexIdx + float(totalVertexCount), // totalVertexCount + (joinSegmentCount << 10) | parametricSegmentCount, + radsPerPolarSegment); + if (joinSegmentCount > 1u) + { + float2x2 joinTangents = float2x2(tangents[1], @a_joinTan_and_ys.xy); + float joinTheta = + acos(cosine_between_vectors(joinTangents[0], joinTangents[1])); + float joinSpan = float(joinSegmentCount); + if ((contourIDWithFlags & + (JOIN_TYPE_MASK | EMULATED_STROKE_CAP_CONTOUR_FLAG)) == + (ROUND_JOIN_CONTOUR_FLAG | EMULATED_STROKE_CAP_CONTOUR_FLAG)) + { + // Round caps emulated as joins need to emit vertices at T=0 and + // T=1, unlike normal round joins. The fragment shader will handle + // most of this, but here we need to adjust radsPerJoinSegment to + // account for the fact that this join will be rotating around two + // more segments. + joinSpan -= 2.; + } + float radsPerJoinSegment = joinTheta / joinSpan; + if (determinant(joinTangents) < .0) + radsPerJoinSegment = -radsPerJoinSegment; + v_joinArgs.xy = @a_joinTan_and_ys.xy; + v_joinArgs.z = radsPerJoinSegment; + } + + if (x1 < x0) // Reflections are drawn right to left. + { + contourIDWithFlags |= MIRRORED_CONTOUR_CONTOUR_FLAG; + } + + v_contourIDWithFlags = contourIDWithFlags; + + float4 pos = pixel_coord_to_clip_coord(coord, + 2. / TESS_TEXTURE_WIDTH, + uniforms.tessInverseViewportY); + + VARYING_PACK(v_p0p1); + VARYING_PACK(v_p2p3); + VARYING_PACK(v_args); + VARYING_PACK(v_joinArgs); + VARYING_PACK(v_contourIDWithFlags); + EMIT_VERTEX(pos); +} +#endif + +#ifdef @FRAGMENT +FRAG_TEXTURE_BLOCK_BEGIN +FRAG_TEXTURE_BLOCK_END + +FRAG_DATA_MAIN(TESSDATA4, @tessellateFragmentMain) +{ + VARYING_UNPACK(v_p0p1, float4); + VARYING_UNPACK(v_p2p3, float4); + VARYING_UNPACK(v_args, float4); + VARYING_UNPACK(v_joinArgs, float3); + VARYING_UNPACK(v_contourIDWithFlags, uint); + + float2 p0 = v_p0p1.xy; + float2 p1 = v_p0p1.zw; + float2 p2 = v_p2p3.xy; + float2 p3 = v_p2p3.zw; + float2x2 tangents = find_cubic_tangents(p0, p1, p2, p3); + // Colocate any padding vertices at T=0. + float vertexIdx = max(floor(v_args.x), .0); + float totalVertexCount = v_args.y; + uint joinSegmentCount_and_parametricSegmentCount = uint(v_args.z); + float parametricSegmentCount = + float(joinSegmentCount_and_parametricSegmentCount & 0x3ffu); + float joinSegmentCount = + float(joinSegmentCount_and_parametricSegmentCount >> 10); + float radsPerPolarSegment = v_args.w; + uint contourIDWithFlags = v_contourIDWithFlags; + + // mergedVertexID/mergedSegmentCount are relative to the sub-section of the + // instance this vertex belongs to (either the curve section that consists + // of merged polar and parametric segments, or the join section composed of + // just polar segments). + // + // Begin with the assumption that we belong to the curve section. + float mergedSegmentCount = totalVertexCount - joinSegmentCount; + float mergedVertexID = vertexIdx; + if (mergedVertexID <= mergedSegmentCount) + { + // We do belong to the curve section. Clear out any stroke join flags. + contourIDWithFlags &= ~JOIN_TYPE_MASK; + } + else + { + // We actually belong to the join section following the curve. Construct + // a point-cubic with rotation. + p0 = p1 = p2 = p3; + tangents = float2x2(tangents[1], v_joinArgs.xy /*joinTangent*/); + parametricSegmentCount = 1.; + mergedVertexID -= mergedSegmentCount; + mergedSegmentCount = joinSegmentCount; + radsPerPolarSegment = v_joinArgs.z; // radsPerJoinSegment. + if ((contourIDWithFlags & JOIN_TYPE_MASK) > ROUND_JOIN_CONTOUR_FLAG) + { + // Miter or bevel join vertices snap to either tangents[0] or + // tangents[1], and get adjusted in the shader that follows. + if (mergedVertexID < 2.5) // With 5 join segments, this branch will + // see IDs: 1, 2, 3, 4. + contourIDWithFlags |= JOIN_TANGENT_0_CONTOUR_FLAG; + if (mergedVertexID > 1.5 && mergedVertexID < 3.5) + contourIDWithFlags |= JOIN_TANGENT_INNER_CONTOUR_FLAG; + } + else if ((contourIDWithFlags & EMULATED_STROKE_CAP_CONTOUR_FLAG) != + 0u || + (contourIDWithFlags & JOIN_TYPE_MASK) == + FEATHER_JOIN_CONTOUR_FLAG) + { + // Round caps emulated as joins and feather joins need to emit + // vertices at T=0 and T=1, unlike normal round joins. Preserve + // the same number of vertices, but adjust our stepping + // parameters so we begin at T=0 and end at T=1. (The CPU should + // have known we were going to add vertices here and increased our + // count to make sure the tessellation would still be smooth). + mergedSegmentCount -= 2.; + --mergedVertexID; + } + contourIDWithFlags |= radsPerPolarSegment < .0 + ? LEFT_JOIN_CONTOUR_FLAG + : RIGHT_JOIN_CONTOUR_FLAG; + } + + float2 tessCoord; + float theta = .0; + if (mergedVertexID == .0 || mergedVertexID == mergedSegmentCount || + (contourIDWithFlags & JOIN_TYPE_MASK) > ROUND_JOIN_CONTOUR_FLAG) + { + // Tessellated vertices at the beginning and end of the strip use exact + // endpoints and tangents. This ensures crack-free seaming between + // instances. + bool isTan0 = mergedVertexID < mergedSegmentCount * .5; + tessCoord = isTan0 ? p0 : p3; + theta = atan2(isTan0 ? tangents[0] : tangents[1]); + } + else if ((contourIDWithFlags & RETROFITTED_TRIANGLE_CONTOUR_FLAG) != 0u) + { + // This cubic should actually be drawn as the single, non-AA triangle: + // [p0, p1, p3]. This is used to squeeze in more rare triangles, like + // "grout" triangles from self intersections on interior triangulation, + // where it wouldn't be worth it to put them in their own dedicated draw + // call. + tessCoord = p1; + } + else + { + float T, polarT; + if (parametricSegmentCount == mergedSegmentCount) + { + // There are no polar vertices. This is (probably) a fill. Vertices + // are spaced evenly in parametric space. + T = mergedVertexID / parametricSegmentCount; + polarT = .0; // Set polarT != T to ensure we calculate the + // parametric tangent later. + } + else + { + // Compute the location and tangent direction of the tessellated + // stroke vertex with the integral id "mergedVertexID", where + // mergedVertexID is the sorted-order index of parametric and polar + // vertices. Start by finding the tangent function's power basis + // coefficients. These define a tangent direction (scaled by some + // uniform value) as: + // + // |T^2| + // Tangent_Direction(T) = dx,dy = |A 2B C| * |T | + // |. . .| |1 | + float2 A, B, C = p1 - p0; + float2 D = p3 - p0; + float2 E = p2 - p1; + B = E - C; + A = -3. * E + D; + // FIXME(crbug.com/800804,skbug.com/11268): Consider normalizing the + // exponents in A,B,C at this point in order to prevent fp32 + // overflow. + + // Now find the coefficients that give a tangent direction from a + // parametric vertex ID: + // + // Tangent_Direction(parametricVertexID) = dx,dy = + // + // |parametricVertexID^2| + // |A B_ C_| * |parametricVertexID | + // |. . .| |1 | + // + float2 B_ = B * (parametricSegmentCount * 2.); + float2 C_ = C * (parametricSegmentCount * parametricSegmentCount); + + // Run a binary search to determine the highest parametric vertex + // that is located on or before the mergedVertexID. A merged ID is + // determined by the sum of complete parametric and polar segments + // behind it. i.e., find the highest parametric vertex where: + // + // parametricVertexID + floor(numPolarSegmentsAtParametricT) <= + // mergedVertexID + // + float lastParametricVertexID = .0; + float maxParametricVertexID = + min(parametricSegmentCount - 1., mergedVertexID); + // FIXME(crbug.com/800804,skbug.com/11268): This normalize() can + // overflow. + float2 tan0norm = normalize(tangents[0]); + float negAbsRadsPerSegment = -abs(radsPerPolarSegment); + float maxRotation0 = + (1. + mergedVertexID) * abs(radsPerPolarSegment); + for (int p = MAX_PARAMETRIC_SEGMENTS_LOG2 - 1; p >= 0; --p) + { + // Test the parametric vertex at lastParametricVertexID + 2^p. + float testParametricID = + lastParametricVertexID + exp2(float(p)); + if (testParametricID <= maxParametricVertexID) + { + float2 testTan = testParametricID * A + B_; + testTan = testParametricID * testTan + C_; + float cosRotation = dot(normalize(testTan), tan0norm); + float maxRotation = + testParametricID * negAbsRadsPerSegment + maxRotation0; + maxRotation = min(maxRotation, PI); + // Is rotation <= maxRotation? (i.e., is the number of + // complete polar segments behind testT, + testParametricID + // <= mergedVertexID?) + if (cosRotation >= cos(maxRotation)) + lastParametricVertexID = testParametricID; + } + } + + // Find the T value of the parametric vertex at + // lastParametricVertexID. + float parametricT = lastParametricVertexID / parametricSegmentCount; + + // Now that we've identified the highest parametric vertex on or + // before the mergedVertexID, the highest polar vertex is easy: + float lastPolarVertexID = mergedVertexID - lastParametricVertexID; + + // Find the angle of tan0, or the angle between tan0norm and the + // positive x axis. + float theta0 = acos(clamp(tan0norm.x, -1., 1.)); + theta0 = tan0norm.y >= .0 ? theta0 : -theta0; + + // Find the tangent vector on the vertex at lastPolarVertexID. + theta = lastPolarVertexID * radsPerPolarSegment + theta0; + float2 norm = float2(sin(theta), -cos(theta)); + + // Find the T value where the tangent is orthogonal to norm. This is + // a quadratic: + // + // dot(norm, Tangent_Direction(T)) == 0 + // + // |T^2| + // norm * |A 2B C| * |T | == 0 + // |. . .| |1 | + // + float a = dot(norm, A), b_over_2 = dot(norm, B), c = dot(norm, C); + float discr_over_4 = max(b_over_2 * b_over_2 - a * c, .0); + float q = sqrt(discr_over_4); + if (b_over_2 > .0) + q = -q; + q -= b_over_2; + + // Roots are q/a and c/q. Since each curve section does not inflect + // or rotate more than 180 degrees, there can only be one tangent + // orthogonal to "norm" inside 0..1. Pick the root nearest .5. + float _5qa = -.5 * q * a; + float2 root = (abs(q * q + _5qa) < abs(a * c + _5qa)) + ? float2(q, a) + : float2(c, q); + polarT = (root.t != .0) ? root.s / root.t : .0; + polarT = clamp(polarT, .0, 1.); + + // The root finder above can become unstable when lastPolarVertexID + // == 0 (e.g., if there are roots at exatly 0 and 1 both). polarT + // should always == 0 in this case. + if (lastPolarVertexID == .0) + polarT = .0; + + // Now that we've identified the T values of the last parametric and + // polar vertices, our final T value for mergedVertexID is whichever + // is larger. + T = max(parametricT, polarT); + } + + // Evaluate the cubic at T. Use De Casteljau's for its accuracy and + // stability. + float2 ab = unchecked_mix(p0, p1, T); + float2 bc = unchecked_mix(p1, p2, T); + float2 cd = unchecked_mix(p2, p3, T); + float2 abc = unchecked_mix(ab, bc, T); + float2 bcd = unchecked_mix(bc, cd, T); + tessCoord = unchecked_mix(abc, bcd, T); + + // If we went with T=parametricT, then update theta. Otherwise leave it + // at the polar theta found previously. (In the event that + // parametricT == polarT, we keep the polar theta.) + if (T != polarT) + theta = atan2(bcd - abc); + } + + TESSDATA4 tessData; + tessData.xy = FLOAT_AS_TESSDATA(tessCoord); + if ((contourIDWithFlags & JOIN_TYPE_MASK) == FEATHER_JOIN_CONTOUR_FLAG) + { + // Feather joins work out their stepping in the vertex shader, so we + // emit the original tessellation parameters instead of just the tangent + // angle and let the vertex shader work it all out. + // Pack these as integers instead of using packHalf2x16() because the + // latter does not work on ARM Mali. + tessData.z = UINT_AS_TESSDATA((uint(mergedSegmentCount) << 16) | + uint(mergedVertexID)); + } + else + { + tessData.z = FLOAT_AS_TESSDATA(mod(theta, _2PI)); + } + tessData.w = UINT_AS_TESSDATA(contourIDWithFlags); + EMIT_FRAG_DATA(tessData); +} +#endif diff --git a/third_party/rive_renderer/source/shaders/unreal/atomic_base.ush b/third_party/rive_renderer/source/shaders/unreal/atomic_base.ush new file mode 100644 index 0000000..d0f8ee4 --- /dev/null +++ b/third_party/rive_renderer/source/shaders/unreal/atomic_base.ush @@ -0,0 +1,14 @@ +#pragma once +#define USING_PLS_STORAGE_TEXTURES 1 +#define OPTIONALLY_FLAT flat + +#ifdef UNIFORM_DEFINITIONS_AUTO_GENERATED +#include "/Engine/Generated/GeneratedUniformBuffers.ush" +#endif +#include "parse_environment.ush" +#include "Generated/rhi.minified.ush" +#include "Generated/constants.minified.ush" +#include "Generated/common.minified.ush" +#include "Generated/advanced_blend.minified.ush" +#include "Generated/draw_path_common.minified.ush" +#include "Generated/atomic_draw.minified.ush" diff --git a/third_party/rive_renderer/source/shaders/unreal/atomic_draw_atlas_blit.usf b/third_party/rive_renderer/source/shaders/unreal/atomic_draw_atlas_blit.usf new file mode 100644 index 0000000..0773cf3 --- /dev/null +++ b/third_party/rive_renderer/source/shaders/unreal/atomic_draw_atlas_blit.usf @@ -0,0 +1,4 @@ +#define DRAW_INTERIOR_TRIANGLES +#define ATLAS_BLIT +#include "/Engine/Public/Platform.ush" +#include "atomic_base.ush" diff --git a/third_party/rive_renderer/source/shaders/unreal/atomic_draw_image_mesh.usf b/third_party/rive_renderer/source/shaders/unreal/atomic_draw_image_mesh.usf new file mode 100644 index 0000000..8eb85ed --- /dev/null +++ b/third_party/rive_renderer/source/shaders/unreal/atomic_draw_image_mesh.usf @@ -0,0 +1,4 @@ +#define DRAW_IMAGE +#define DRAW_IMAGE_MESH +#include "/Engine/Public/Platform.ush" +#include "atomic_base.ush" diff --git a/third_party/rive_renderer/source/shaders/unreal/atomic_draw_image_rect.usf b/third_party/rive_renderer/source/shaders/unreal/atomic_draw_image_rect.usf new file mode 100644 index 0000000..36fb167 --- /dev/null +++ b/third_party/rive_renderer/source/shaders/unreal/atomic_draw_image_rect.usf @@ -0,0 +1,4 @@ +#define DRAW_IMAGE +#define DRAW_IMAGE_RECT +#include "/Engine/Public/Platform.ush" +#include "atomic_base.ush" diff --git a/third_party/rive_renderer/source/shaders/unreal/atomic_draw_interior_triangles.usf b/third_party/rive_renderer/source/shaders/unreal/atomic_draw_interior_triangles.usf new file mode 100644 index 0000000..c883d71 --- /dev/null +++ b/third_party/rive_renderer/source/shaders/unreal/atomic_draw_interior_triangles.usf @@ -0,0 +1,3 @@ +#define DRAW_INTERIOR_TRIANGLES +#include "/Engine/Public/Platform.ush" +#include "atomic_base.ush" diff --git a/third_party/rive_renderer/source/shaders/unreal/atomic_draw_path.usf b/third_party/rive_renderer/source/shaders/unreal/atomic_draw_path.usf new file mode 100644 index 0000000..b0c7452 --- /dev/null +++ b/third_party/rive_renderer/source/shaders/unreal/atomic_draw_path.usf @@ -0,0 +1,3 @@ +#define DRAW_PATH +#include "/Engine/Public/Platform.ush" +#include "atomic_base.ush" diff --git a/third_party/rive_renderer/source/shaders/unreal/atomic_resolve_pls.usf b/third_party/rive_renderer/source/shaders/unreal/atomic_resolve_pls.usf new file mode 100644 index 0000000..62da1f3 --- /dev/null +++ b/third_party/rive_renderer/source/shaders/unreal/atomic_resolve_pls.usf @@ -0,0 +1,4 @@ +#define DRAW_RENDER_TARGET_UPDATE_BOUNDS 1 +#define RESOLVE_PLS 1 +#include "/Engine/Public/Platform.ush" +#include "atomic_base.ush" \ No newline at end of file diff --git a/third_party/rive_renderer/source/shaders/unreal/blt_u324_to_f4.usf b/third_party/rive_renderer/source/shaders/unreal/blt_u324_to_f4.usf new file mode 100644 index 0000000..f28c12d --- /dev/null +++ b/third_party/rive_renderer/source/shaders/unreal/blt_u324_to_f4.usf @@ -0,0 +1,9 @@ +#include "/Engine/Public/Platform.ush" +Texture2D SourceTexture; + +void FragmentMain( in float4 Position : SV_Position, + out float4 OutColor : SV_Target0) +{ + uint4 Result = SourceTexture[Position.xy]; + OutColor = float4( float(Result.r), float(Result.g), float(Result.b), 1.0 ); +} diff --git a/third_party/rive_renderer/source/shaders/unreal/blt_u32_as_f4.usf b/third_party/rive_renderer/source/shaders/unreal/blt_u32_as_f4.usf new file mode 100644 index 0000000..2bbbee5 --- /dev/null +++ b/third_party/rive_renderer/source/shaders/unreal/blt_u32_as_f4.usf @@ -0,0 +1,9 @@ +#include "/Engine/Public/Platform.ush" +Texture2D SourceTexture; + +void FragmentMain( in float4 Position : SV_Position, + out float4 OutColor : SV_Target0) +{ + uint Result = SourceTexture[Position.xy]; + OutColor = float4( Result, 0, 0, 1.0 ); +} diff --git a/third_party/rive_renderer/source/shaders/unreal/color_ramp.usf b/third_party/rive_renderer/source/shaders/unreal/color_ramp.usf new file mode 100644 index 0000000..e28095a --- /dev/null +++ b/third_party/rive_renderer/source/shaders/unreal/color_ramp.usf @@ -0,0 +1,12 @@ +#include "/Engine/Public/Platform.ush" +#define SPLIT_UINT4_ATTRIBUTES 1 + +#ifdef UNIFORM_DEFINITIONS_AUTO_GENERATED +#include "/Engine/Generated/GeneratedUniformBuffers.ush" +#endif + +#include "parse_environment.ush" +#include "Generated/rhi.minified.ush" +#include "Generated/constants.minified.ush" +#include "Generated/common.minified.ush" +#include "Generated/color_ramp.minified.ush" diff --git a/third_party/rive_renderer/source/shaders/unreal/draw_atlas_fill.usf b/third_party/rive_renderer/source/shaders/unreal/draw_atlas_fill.usf new file mode 100644 index 0000000..5691787 --- /dev/null +++ b/third_party/rive_renderer/source/shaders/unreal/draw_atlas_fill.usf @@ -0,0 +1,14 @@ +#include "/Engine/Public/Platform.ush" +#define DRAW_PATH +#define ENABLE_FEATHER +#define ATLAS_FEATHERED_FILL + +#ifdef UNIFORM_DEFINITIONS_AUTO_GENERATED +#include "/Engine/Generated/GeneratedUniformBuffers.ush" +#endif + +#include "Generated/rhi.minified.ush" +#include "Generated/constants.minified.ush" +#include "Generated/common.minified.ush" +#include "Generated/draw_path_common.minified.ush" +#include "Generated/render_atlas.minified.ush" diff --git a/third_party/rive_renderer/source/shaders/unreal/draw_atlas_stroke.usf b/third_party/rive_renderer/source/shaders/unreal/draw_atlas_stroke.usf new file mode 100644 index 0000000..57f6d39 --- /dev/null +++ b/third_party/rive_renderer/source/shaders/unreal/draw_atlas_stroke.usf @@ -0,0 +1,14 @@ +#include "/Engine/Public/Platform.ush" +#define DRAW_PATH +#define ENABLE_FEATHER +#define ATLAS_FEATHERED_STROKE + +#ifdef UNIFORM_DEFINITIONS_AUTO_GENERATED +#include "/Engine/Generated/GeneratedUniformBuffers.ush" +#endif + +#include "Generated/rhi.minified.ush" +#include "Generated/constants.minified.ush" +#include "Generated/common.minified.ush" +#include "Generated/draw_path_common.minified.ush" +#include "Generated/render_atlas.minified.ush" diff --git a/third_party/rive_renderer/source/shaders/unreal/draw_image_mesh.usf b/third_party/rive_renderer/source/shaders/unreal/draw_image_mesh.usf new file mode 100644 index 0000000..fd49117 --- /dev/null +++ b/third_party/rive_renderer/source/shaders/unreal/draw_image_mesh.usf @@ -0,0 +1,17 @@ +#define PLS_IMPL_SUBPASS_LOAD +#define OPTIONALLY_FLAT flat +#define DRAW_IMAGE +#define DRAW_IMAGE_MESH + +#include "/Engine/Public/Platform.ush" +#ifdef UNIFORM_DEFINITIONS_AUTO_GENERATED +#include "/Engine/Generated/GeneratedUniformBuffers.ush" +#endif + +#include "parse_environment.ush" +#include "Generated/rhi.minified.ush" +#include "Generated/constants.minified.ush" +#include "Generated/specialization.minified.ush" +#include "Generated/common.minified.ush" +#include "Generated/advanced_blend.minified.ush" +#include "Generated/draw_image_mesh.minified.ush" diff --git a/third_party/rive_renderer/source/shaders/unreal/draw_interior_triangles.usf b/third_party/rive_renderer/source/shaders/unreal/draw_interior_triangles.usf new file mode 100644 index 0000000..8698435 --- /dev/null +++ b/third_party/rive_renderer/source/shaders/unreal/draw_interior_triangles.usf @@ -0,0 +1,16 @@ +#define PLS_IMPL_SUBPASS_LOAD +#define OPTIONALLY_FLAT flat +#define DRAW_INTERIOR_TRIANGLES + +#include "/Engine/Public/Platform.ush" +#ifdef UNIFORM_DEFINITIONS_AUTO_GENERATED +#include "/Engine/Generated/GeneratedUniformBuffers.ush" +#endif + +#include "parse_environment.ush" +#include "Generated/rhi.minified.ush" +#include "Generated/constants.minified.ush" +#include "Generated/common.minified.ush" +#include "Generated/draw_path_common.minified.ush" +#include "Generated/advanced_blend.minified.ush" +#include "Generated/draw_path.minified.ush" diff --git a/third_party/rive_renderer/source/shaders/unreal/draw_path.usf b/third_party/rive_renderer/source/shaders/unreal/draw_path.usf new file mode 100644 index 0000000..888ce2f --- /dev/null +++ b/third_party/rive_renderer/source/shaders/unreal/draw_path.usf @@ -0,0 +1,17 @@ +#define ENABLE_INSTANCE_INDEX +#define PLS_IMPL_SUBPASS_LOAD +#define OPTIONALLY_FLAT flat +#define DRAW_PATH + +#include "/Engine/Public/Platform.ush" +#ifdef UNIFORM_DEFINITIONS_AUTO_GENERATED +#include "/Engine/Generated/GeneratedUniformBuffers.ush" +#endif + +#include "parse_environment.ush" +#include "Generated/rhi.minified.ush" +#include "Generated/constants.minified.ush" +#include "Generated/common.minified.ush" +#include "Generated/draw_path_common.minified.ush" +#include "Generated/advanced_blend.minified.ush" +#include "Generated/draw_path.minified.ush" diff --git a/third_party/rive_renderer/source/shaders/unreal/parse_environment.ush b/third_party/rive_renderer/source/shaders/unreal/parse_environment.ush new file mode 100644 index 0000000..50348ce --- /dev/null +++ b/third_party/rive_renderer/source/shaders/unreal/parse_environment.ush @@ -0,0 +1,41 @@ +// unreal rhi always defines the permutation values, however, we expect them to either exist or not. so +// here we check if its set to false and undef if it is +#if !ENABLE_CLIPPING +#undef ENABLE_CLIPPING +#endif + +#if !ENABLE_CLIP_RECT +#undef ENABLE_CLIP_RECT +#endif + +#if !ENABLE_ADVANCED_BLEND +#undef ENABLE_ADVANCED_BLEND +#endif + +#if !FIXED_FUNCTION_COLOR_OUTPUT +#undef FIXED_FUNCTION_COLOR_OUTPUT +#endif + +#if !ENABLE_HSL_BLEND_MODES +#undef ENABLE_HSL_BLEND_MODES +#endif + +#if !ENABLE_NESTED_CLIPPING +#undef ENABLE_NESTED_CLIPPING +#endif + +#if !ENABLE_EVEN_ODD +#undef ENABLE_EVEN_ODD +#endif + +#if !ENABLE_TYPED_UAV_LOAD_STORE +#undef ENABLE_TYPED_UAV_LOAD_STORE +#endif + +#if !ENABLE_FEATHER +#undef ENABLE_FEATHER +#endif + +#if !ATLAS_COVERAGE +#undef ATLAS_COVERAGE +#endif diff --git a/third_party/rive_renderer/source/shaders/unreal/tessellate.usf b/third_party/rive_renderer/source/shaders/unreal/tessellate.usf new file mode 100644 index 0000000..99f178f --- /dev/null +++ b/third_party/rive_renderer/source/shaders/unreal/tessellate.usf @@ -0,0 +1,13 @@ +#include "/Engine/Public/Platform.ush" +#define SPLIT_UINT4_ATTRIBUTES 1 + +#ifdef UNIFORM_DEFINITIONS_AUTO_GENERATED +#include "/Engine/Generated/GeneratedUniformBuffers.ush" +#endif + +#include "parse_environment.ush" +#include "Generated/rhi.minified.ush" +#include "Generated/constants.minified.ush" +#include "Generated/common.minified.ush" +#include "Generated/bezier_utils.minified.ush" +#include "Generated/tessellate.minified.ush" diff --git a/third_party/rive_renderer/source/shaders/unreal/visualize_buffer.usf b/third_party/rive_renderer/source/shaders/unreal/visualize_buffer.usf new file mode 100644 index 0000000..b1ce7a4 --- /dev/null +++ b/third_party/rive_renderer/source/shaders/unreal/visualize_buffer.usf @@ -0,0 +1,23 @@ +#include "/Engine/Public/Platform.ush" +StructuredBuffer SourceBuffer; + +uint2 ViewSize; +uint BufferSize; + +inline float usin(uint v) +{ + return (sin(float(v)) + 1.0) / 2.0; +} + +inline float ucos(uint v) +{ + return (cos(float(v)) + 1.0) / 2.0; +} + +void FragmentMain( in float4 Position : SV_Position, + out float4 OutColor : SV_Target0) +{ + float index = (((Position.y * ViewSize.g) + Position.y) / (ViewSize.r * ViewSize.g)) * BufferSize; + uint2 Result = SourceBuffer[index]; + OutColor = float4( ucos(Result.r), usin(Result.g), 0, 1.0 ); +} \ No newline at end of file diff --git a/third_party/rive_renderer/source/sk_rectanizer_skyline.cpp b/third_party/rive_renderer/source/sk_rectanizer_skyline.cpp new file mode 100644 index 0000000..36c3252 --- /dev/null +++ b/third_party/rive_renderer/source/sk_rectanizer_skyline.cpp @@ -0,0 +1,155 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Initial import from + * skia:b4171f5ba83048039097bbc664eaa076190f6239@src/gpu/RectanizerSkyline.cpp + * + * Copyright 2025 Rive + */ + +#include "rive/renderer/sk_rectanizer_skyline.hpp" + +#include +#include + +namespace skgpu +{ + +bool RectanizerSkyline::addRect(int width, int height, int16_t* x, int16_t* y) +{ + if ((unsigned)width > (unsigned)this->width() || + (unsigned)height > (unsigned)this->height()) + { + return false; + } + + // find position for new rectangle + int bestWidth = this->width() + 1; + int bestX = 0; + int bestY = this->height() + 1; + int bestIndex = -1; + for (int i = 0; i < fSkyline.size(); ++i) + { + int y; + if (this->rectangleFits(i, width, height, &y)) + { + // minimize y position first, then width of skyline + if (y < bestY || (y == bestY && fSkyline[i].fWidth < bestWidth)) + { + bestIndex = i; + bestWidth = fSkyline[i].fWidth; + bestX = fSkyline[i].fX; + bestY = y; + } + } + } + + // add rectangle to skyline + if (-1 != bestIndex) + { + this->addSkylineLevel(bestIndex, bestX, bestY, width, height); + *x = bestX; + *y = bestY; + + fAreaSoFar += width * height; + return true; + } + + *x = 0; + *y = 0; + return false; +} + +bool RectanizerSkyline::rectangleFits(int skylineIndex, + int width, + int height, + int* ypos) const +{ + int x = fSkyline[skylineIndex].fX; + if (x + width > this->width()) + { + return false; + } + + int widthLeft = width; + int i = skylineIndex; + int y = fSkyline[skylineIndex].fY; + while (widthLeft > 0) + { + y = std::max(y, fSkyline[i].fY); + if (y + height > this->height()) + { + return false; + } + widthLeft -= fSkyline[i].fWidth; + ++i; + assert(i < fSkyline.size() || widthLeft <= 0); + } + + *ypos = y; + return true; +} + +void RectanizerSkyline::addSkylineLevel(int skylineIndex, + int x, + int y, + int width, + int height) +{ + SkylineSegment& newSegment = + *fSkyline.emplace(fSkyline.begin() + skylineIndex); + newSegment.fX = x; + newSegment.fY = y + height; + newSegment.fWidth = width; + + assert(newSegment.fX + newSegment.fWidth <= this->width()); + assert(newSegment.fY <= this->height()); + + // delete width of the new skyline segment from following ones + for (int i = skylineIndex + 1; i < fSkyline.size(); ++i) + { + // The new segment subsumes all or part of fSkyline[i] + assert(fSkyline[i - 1].fX <= fSkyline[i].fX); + + if (fSkyline[i].fX < fSkyline[i - 1].fX + fSkyline[i - 1].fWidth) + { + int shrink = + fSkyline[i - 1].fX + fSkyline[i - 1].fWidth - fSkyline[i].fX; + + fSkyline[i].fX += shrink; + fSkyline[i].fWidth -= shrink; + + if (fSkyline[i].fWidth <= 0) + { + // fully consumed + fSkyline.erase(fSkyline.begin() + i); + --i; + } + else + { + // only partially consumed + break; + } + } + else + { + break; + } + } + + // merge fSkylines + for (int i = 0; i < fSkyline.size() - 1; ++i) + { + if (fSkyline[i].fY == fSkyline[i + 1].fY) + { + fSkyline[i].fWidth += fSkyline[i + 1].fWidth; + fSkyline.erase(fSkyline.begin() + i + 1); + --i; + } + } +} + +} // End of namespace skgpu diff --git a/third_party/rive_renderer/source/vulkan/draw_shader_vulkan.cpp b/third_party/rive_renderer/source/vulkan/draw_shader_vulkan.cpp new file mode 100644 index 0000000..4337174 --- /dev/null +++ b/third_party/rive_renderer/source/vulkan/draw_shader_vulkan.cpp @@ -0,0 +1,431 @@ +/* + * Copyright 2023 Rive + */ + +#include "draw_shader_vulkan.hpp" + +#include "rive/renderer/vulkan/vkutil.hpp" +#include "rive/renderer/vulkan/vulkan_context.hpp" +#include "shaders/constants.glsl" + +namespace rive::gpu +{ +namespace spirv_embedded +{ +// Draw setup shaders. +#include "generated/shaders/spirv/color_ramp.vert.h" +#include "generated/shaders/spirv/color_ramp.frag.h" +#include "generated/shaders/spirv/tessellate.vert.h" +#include "generated/shaders/spirv/tessellate.frag.h" +#include "generated/shaders/spirv/render_atlas.vert.h" +#include "generated/shaders/spirv/render_atlas_fill.frag.h" +#include "generated/shaders/spirv/render_atlas_stroke.frag.h" + +// InterlockMode::rasterOrdering shaders. +#include "generated/shaders/spirv/draw_path.vert.h" +#include "generated/shaders/spirv/draw_path.frag.h" +#include "generated/shaders/spirv/draw_interior_triangles.vert.h" +#include "generated/shaders/spirv/draw_interior_triangles.frag.h" +#include "generated/shaders/spirv/draw_atlas_blit.vert.h" +#include "generated/shaders/spirv/draw_atlas_blit.frag.h" +#include "generated/shaders/spirv/draw_image_mesh.vert.h" +#include "generated/shaders/spirv/draw_image_mesh.frag.h" + +// InterlockMode::atomics shaders. +#include "generated/shaders/spirv/atomic_draw_path.vert.h" +#include "generated/shaders/spirv/atomic_draw_path.frag.h" +#include "generated/shaders/spirv/atomic_draw_path.fixedcolor_frag.h" +#include "generated/shaders/spirv/atomic_draw_interior_triangles.vert.h" +#include "generated/shaders/spirv/atomic_draw_interior_triangles.frag.h" +#include "generated/shaders/spirv/atomic_draw_interior_triangles.fixedcolor_frag.h" +#include "generated/shaders/spirv/atomic_draw_atlas_blit.vert.h" +#include "generated/shaders/spirv/atomic_draw_atlas_blit.frag.h" +#include "generated/shaders/spirv/atomic_draw_atlas_blit.fixedcolor_frag.h" +#include "generated/shaders/spirv/atomic_draw_image_rect.vert.h" +#include "generated/shaders/spirv/atomic_draw_image_rect.frag.h" +#include "generated/shaders/spirv/atomic_draw_image_rect.fixedcolor_frag.h" +#include "generated/shaders/spirv/atomic_draw_image_mesh.vert.h" +#include "generated/shaders/spirv/atomic_draw_image_mesh.frag.h" +#include "generated/shaders/spirv/atomic_draw_image_mesh.fixedcolor_frag.h" +#include "generated/shaders/spirv/atomic_resolve.vert.h" +#include "generated/shaders/spirv/atomic_resolve.frag.h" +#include "generated/shaders/spirv/atomic_resolve.fixedcolor_frag.h" +#include "generated/shaders/spirv/atomic_resolve_coalesced.vert.h" +#include "generated/shaders/spirv/atomic_resolve_coalesced.frag.h" + +// InterlockMode::clockwiseAtomic shaders. +#include "generated/shaders/spirv/draw_clockwise_path.vert.h" +#include "generated/shaders/spirv/draw_clockwise_path.frag.h" +#include "generated/shaders/spirv/draw_clockwise_interior_triangles.vert.h" +#include "generated/shaders/spirv/draw_clockwise_interior_triangles.frag.h" +#include "generated/shaders/spirv/draw_clockwise_atlas_blit.vert.h" +#include "generated/shaders/spirv/draw_clockwise_atlas_blit.frag.h" +#include "generated/shaders/spirv/draw_clockwise_image_mesh.vert.h" +#include "generated/shaders/spirv/draw_clockwise_image_mesh.frag.h" +}; // namespace spirv_embedded + +namespace spirv +{ +rive::Span color_ramp_vert = + rive::make_span(spirv_embedded::color_ramp_vert); +rive::Span color_ramp_frag = + rive::make_span(spirv_embedded::color_ramp_frag); +rive::Span tessellate_vert = + rive::make_span(spirv_embedded::tessellate_vert); +rive::Span tessellate_frag = + rive::make_span(spirv_embedded::tessellate_frag); +rive::Span render_atlas_vert = + rive::make_span(spirv_embedded::render_atlas_vert); +rive::Span render_atlas_fill_frag = + rive::make_span(spirv_embedded::render_atlas_fill_frag); +rive::Span render_atlas_stroke_frag = + rive::make_span(spirv_embedded::render_atlas_stroke_frag); +rive::Span draw_path_vert = + rive::make_span(spirv_embedded::draw_path_vert); +rive::Span draw_path_frag = + rive::make_span(spirv_embedded::draw_path_frag); +rive::Span draw_interior_triangles_vert = + rive::make_span(spirv_embedded::draw_interior_triangles_vert); +rive::Span draw_interior_triangles_frag = + rive::make_span(spirv_embedded::draw_interior_triangles_frag); +rive::Span draw_atlas_blit_vert = + rive::make_span(spirv_embedded::draw_atlas_blit_vert); +rive::Span draw_atlas_blit_frag = + rive::make_span(spirv_embedded::draw_atlas_blit_frag); +rive::Span draw_image_mesh_vert = + rive::make_span(spirv_embedded::draw_image_mesh_vert); +rive::Span draw_image_mesh_frag = + rive::make_span(spirv_embedded::draw_image_mesh_frag); +rive::Span atomic_draw_path_vert = + rive::make_span(spirv_embedded::atomic_draw_path_vert); +rive::Span atomic_draw_path_frag = + rive::make_span(spirv_embedded::atomic_draw_path_frag); +rive::Span atomic_draw_path_fixedcolor_frag = rive::make_span( + spirv_embedded::atomic_draw_path_fixedcolor_frag, + std::size(spirv_embedded::atomic_draw_path_fixedcolor_frag)); +rive::Span atomic_draw_interior_triangles_vert = + rive::make_span(spirv_embedded::atomic_draw_interior_triangles_vert); +rive::Span atomic_draw_interior_triangles_frag = + rive::make_span(spirv_embedded::atomic_draw_interior_triangles_frag); +rive::Span atomic_draw_interior_triangles_fixedcolor_frag = + rive::make_span( + spirv_embedded::atomic_draw_interior_triangles_fixedcolor_frag); +rive::Span atomic_draw_atlas_blit_vert = + rive::make_span(spirv_embedded::atomic_draw_atlas_blit_vert); +rive::Span atomic_draw_atlas_blit_frag = + rive::make_span(spirv_embedded::atomic_draw_atlas_blit_frag); +rive::Span atomic_draw_atlas_blit_fixedcolor_frag = + rive::make_span(spirv_embedded::atomic_draw_atlas_blit_fixedcolor_frag); +rive::Span atomic_draw_image_rect_vert = + rive::make_span(spirv_embedded::atomic_draw_image_rect_vert); +rive::Span atomic_draw_image_rect_frag = + rive::make_span(spirv_embedded::atomic_draw_image_rect_frag); +rive::Span atomic_draw_image_rect_fixedcolor_frag = + rive::make_span(spirv_embedded::atomic_draw_image_rect_fixedcolor_frag); +rive::Span atomic_draw_image_mesh_vert = + rive::make_span(spirv_embedded::atomic_draw_image_mesh_vert); +rive::Span atomic_draw_image_mesh_frag = + rive::make_span(spirv_embedded::atomic_draw_image_mesh_frag); +rive::Span atomic_draw_image_mesh_fixedcolor_frag = + rive::make_span(spirv_embedded::atomic_draw_image_mesh_fixedcolor_frag); +rive::Span atomic_resolve_vert = + rive::make_span(spirv_embedded::atomic_resolve_vert); +rive::Span atomic_resolve_frag = + rive::make_span(spirv_embedded::atomic_resolve_frag); +rive::Span atomic_resolve_fixedcolor_frag = + rive::make_span(spirv_embedded::atomic_resolve_fixedcolor_frag, + std::size(spirv_embedded::atomic_resolve_fixedcolor_frag)); +rive::Span atomic_resolve_coalesced_vert = + rive::make_span(spirv_embedded::atomic_resolve_coalesced_vert); +rive::Span atomic_resolve_coalesced_frag = + rive::make_span(spirv_embedded::atomic_resolve_coalesced_frag); +rive::Span draw_clockwise_path_vert = + rive::make_span(spirv_embedded::draw_clockwise_path_vert); +rive::Span draw_clockwise_path_frag = + rive::make_span(spirv_embedded::draw_clockwise_path_frag); +rive::Span draw_clockwise_interior_triangles_vert = + rive::make_span(spirv_embedded::draw_clockwise_interior_triangles_vert); +rive::Span draw_clockwise_interior_triangles_frag = + rive::make_span(spirv_embedded::draw_clockwise_interior_triangles_frag); +rive::Span draw_clockwise_atlas_blit_vert = + rive::make_span(spirv_embedded::draw_clockwise_atlas_blit_vert); +rive::Span draw_clockwise_atlas_blit_frag = + rive::make_span(spirv_embedded::draw_clockwise_atlas_blit_frag); +rive::Span draw_clockwise_image_mesh_vert = + rive::make_span(spirv_embedded::draw_clockwise_image_mesh_vert); +rive::Span draw_clockwise_image_mesh_frag = + rive::make_span(spirv_embedded::draw_clockwise_image_mesh_frag); + +void hotload_shaders(rive::Span spirvData) +{ + size_t spirvIndex = 0; + auto readNextBytecodeSpan = [spirvData, + &spirvIndex]() -> rive::Span { + size_t insnCount = spirvData[spirvIndex++]; + const uint32_t* insnData = spirvData.data() + spirvIndex; + spirvIndex += insnCount; + return rive::make_span(insnData, insnCount); + }; + + spirv::color_ramp_vert = readNextBytecodeSpan(); + spirv::color_ramp_frag = readNextBytecodeSpan(); + spirv::tessellate_vert = readNextBytecodeSpan(); + spirv::tessellate_frag = readNextBytecodeSpan(); + spirv::render_atlas_vert = readNextBytecodeSpan(); + spirv::render_atlas_fill_frag = readNextBytecodeSpan(); + spirv::render_atlas_stroke_frag = readNextBytecodeSpan(); + spirv::draw_path_vert = readNextBytecodeSpan(); + spirv::draw_path_frag = readNextBytecodeSpan(); + spirv::draw_interior_triangles_vert = readNextBytecodeSpan(); + spirv::draw_interior_triangles_frag = readNextBytecodeSpan(); + spirv::draw_atlas_blit_vert = readNextBytecodeSpan(); + spirv::draw_atlas_blit_frag = readNextBytecodeSpan(); + spirv::draw_image_mesh_vert = readNextBytecodeSpan(); + spirv::draw_image_mesh_frag = readNextBytecodeSpan(); + spirv::atomic_draw_path_vert = readNextBytecodeSpan(); + spirv::atomic_draw_path_frag = readNextBytecodeSpan(); + spirv::atomic_draw_path_fixedcolor_frag = readNextBytecodeSpan(); + spirv::atomic_draw_interior_triangles_vert = readNextBytecodeSpan(); + spirv::atomic_draw_interior_triangles_frag = readNextBytecodeSpan(); + spirv::atomic_draw_interior_triangles_fixedcolor_frag = + readNextBytecodeSpan(); + spirv::atomic_draw_atlas_blit_vert = readNextBytecodeSpan(); + spirv::atomic_draw_atlas_blit_frag = readNextBytecodeSpan(); + spirv::atomic_draw_atlas_blit_fixedcolor_frag = readNextBytecodeSpan(); + spirv::atomic_draw_image_rect_vert = readNextBytecodeSpan(); + spirv::atomic_draw_image_rect_frag = readNextBytecodeSpan(); + spirv::atomic_draw_image_rect_fixedcolor_frag = readNextBytecodeSpan(); + spirv::atomic_draw_image_mesh_vert = readNextBytecodeSpan(); + spirv::atomic_draw_image_mesh_frag = readNextBytecodeSpan(); + spirv::atomic_draw_image_mesh_fixedcolor_frag = readNextBytecodeSpan(); + spirv::atomic_resolve_vert = readNextBytecodeSpan(); + spirv::atomic_resolve_frag = readNextBytecodeSpan(); + spirv::atomic_resolve_fixedcolor_frag = readNextBytecodeSpan(); + spirv::atomic_resolve_coalesced_vert = readNextBytecodeSpan(); + spirv::atomic_resolve_coalesced_frag = readNextBytecodeSpan(); + spirv::draw_clockwise_path_vert = readNextBytecodeSpan(); + spirv::draw_clockwise_path_frag = readNextBytecodeSpan(); + spirv::draw_clockwise_interior_triangles_vert = readNextBytecodeSpan(); + spirv::draw_clockwise_interior_triangles_frag = readNextBytecodeSpan(); + spirv::draw_clockwise_atlas_blit_vert = readNextBytecodeSpan(); + spirv::draw_clockwise_atlas_blit_frag = readNextBytecodeSpan(); + spirv::draw_clockwise_image_mesh_vert = readNextBytecodeSpan(); + spirv::draw_clockwise_image_mesh_frag = readNextBytecodeSpan(); +} +}; // namespace spirv + +DrawShaderVulkan::DrawShaderVulkan(VulkanContext* vk, + gpu::DrawType drawType, + gpu::InterlockMode interlockMode, + gpu::ShaderFeatures shaderFeatures, + gpu::ShaderMiscFlags shaderMiscFlags) : + m_vk(ref_rcp(vk)) +{ + VkShaderModuleCreateInfo vsInfo = { + .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO}; + VkShaderModuleCreateInfo fsInfo = { + .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO}; + + if (interlockMode == gpu::InterlockMode::rasterOrdering) + { + switch (drawType) + { + case DrawType::midpointFanPatches: + case DrawType::midpointFanCenterAAPatches: + case DrawType::outerCurvePatches: + vkutil::set_shader_code(vsInfo, spirv::draw_path_vert); + vkutil::set_shader_code(fsInfo, spirv::draw_path_frag); + break; + + case DrawType::interiorTriangulation: + vkutil::set_shader_code(vsInfo, + spirv::draw_interior_triangles_vert); + vkutil::set_shader_code(fsInfo, + spirv::draw_interior_triangles_frag); + break; + + case DrawType::atlasBlit: + vkutil::set_shader_code(vsInfo, spirv::draw_atlas_blit_vert); + vkutil::set_shader_code(fsInfo, spirv::draw_atlas_blit_frag); + break; + + case DrawType::imageMesh: + vkutil::set_shader_code(vsInfo, spirv::draw_image_mesh_vert); + vkutil::set_shader_code(fsInfo, spirv::draw_image_mesh_frag); + break; + + case DrawType::imageRect: + case DrawType::atomicResolve: + case DrawType::atomicInitialize: + case DrawType::msaaStrokes: + case DrawType::msaaMidpointFanBorrowedCoverage: + case DrawType::msaaMidpointFans: + case DrawType::msaaMidpointFanStencilReset: + case DrawType::msaaMidpointFanPathsStencil: + case DrawType::msaaMidpointFanPathsCover: + case DrawType::msaaOuterCubics: + case DrawType::msaaStencilClipReset: + RIVE_UNREACHABLE(); + } + } + else if (interlockMode == gpu::InterlockMode::atomics) + { + assert(interlockMode == gpu::InterlockMode::atomics); + bool fixedFunctionColorOutput = + shaderMiscFlags & gpu::ShaderMiscFlags::fixedFunctionColorOutput; + switch (drawType) + { + case DrawType::midpointFanPatches: + case DrawType::midpointFanCenterAAPatches: + case DrawType::outerCurvePatches: + vkutil::set_shader_code(vsInfo, spirv::atomic_draw_path_vert); + vkutil::set_shader_code_if_then_else( + fsInfo, + fixedFunctionColorOutput, + spirv::atomic_draw_path_fixedcolor_frag, + spirv::atomic_draw_path_frag); + break; + + case DrawType::interiorTriangulation: + vkutil::set_shader_code( + vsInfo, + spirv::atomic_draw_interior_triangles_vert); + vkutil::set_shader_code_if_then_else( + fsInfo, + fixedFunctionColorOutput, + spirv::atomic_draw_interior_triangles_fixedcolor_frag, + spirv::atomic_draw_interior_triangles_frag); + break; + + case DrawType::atlasBlit: + vkutil::set_shader_code(vsInfo, + spirv::atomic_draw_atlas_blit_vert); + vkutil::set_shader_code_if_then_else( + fsInfo, + fixedFunctionColorOutput, + spirv::atomic_draw_atlas_blit_fixedcolor_frag, + spirv::atomic_draw_atlas_blit_frag); + break; + + case DrawType::imageRect: + vkutil::set_shader_code(vsInfo, + spirv::atomic_draw_image_rect_vert); + vkutil::set_shader_code_if_then_else( + fsInfo, + fixedFunctionColorOutput, + spirv::atomic_draw_image_rect_fixedcolor_frag, + spirv::atomic_draw_image_rect_frag); + break; + + case DrawType::imageMesh: + vkutil::set_shader_code(vsInfo, + spirv::atomic_draw_image_mesh_vert); + vkutil::set_shader_code_if_then_else( + fsInfo, + fixedFunctionColorOutput, + spirv::atomic_draw_image_mesh_fixedcolor_frag, + spirv::atomic_draw_image_mesh_frag); + break; + + case DrawType::atomicResolve: + if (shaderMiscFlags & + gpu::ShaderMiscFlags::coalescedResolveAndTransfer) + { + vkutil::set_shader_code( + vsInfo, + spirv::atomic_resolve_coalesced_vert); + vkutil::set_shader_code( + fsInfo, + spirv::atomic_resolve_coalesced_frag); + } + else + { + vkutil::set_shader_code(vsInfo, spirv::atomic_resolve_vert); + vkutil::set_shader_code_if_then_else( + fsInfo, + fixedFunctionColorOutput, + spirv::atomic_resolve_fixedcolor_frag, + spirv::atomic_resolve_frag); + } + break; + + case DrawType::atomicInitialize: + case DrawType::msaaStrokes: + case DrawType::msaaMidpointFanBorrowedCoverage: + case DrawType::msaaMidpointFans: + case DrawType::msaaMidpointFanStencilReset: + case DrawType::msaaMidpointFanPathsStencil: + case DrawType::msaaMidpointFanPathsCover: + case DrawType::msaaOuterCubics: + case DrawType::msaaStencilClipReset: + RIVE_UNREACHABLE(); + } + } + else + { + assert(interlockMode == gpu::InterlockMode::clockwiseAtomic); + switch (drawType) + { + case DrawType::midpointFanPatches: + case DrawType::midpointFanCenterAAPatches: + case DrawType::outerCurvePatches: + vkutil::set_shader_code(vsInfo, + spirv::draw_clockwise_path_vert); + vkutil::set_shader_code(fsInfo, + spirv::draw_clockwise_path_frag); + break; + + case DrawType::interiorTriangulation: + vkutil::set_shader_code( + vsInfo, + spirv::draw_clockwise_interior_triangles_vert); + vkutil::set_shader_code( + fsInfo, + spirv::draw_clockwise_interior_triangles_frag); + break; + + case DrawType::atlasBlit: + vkutil::set_shader_code(vsInfo, + spirv::draw_clockwise_atlas_blit_vert); + vkutil::set_shader_code(fsInfo, + spirv::draw_clockwise_atlas_blit_frag); + break; + + case DrawType::imageMesh: + vkutil::set_shader_code(vsInfo, + spirv::draw_clockwise_image_mesh_vert); + vkutil::set_shader_code(fsInfo, + spirv::draw_clockwise_image_mesh_frag); + break; + + case DrawType::imageRect: + case DrawType::atomicResolve: + case DrawType::atomicInitialize: + case DrawType::msaaStrokes: + case DrawType::msaaMidpointFanBorrowedCoverage: + case DrawType::msaaMidpointFans: + case DrawType::msaaMidpointFanStencilReset: + case DrawType::msaaMidpointFanPathsStencil: + case DrawType::msaaMidpointFanPathsCover: + case DrawType::msaaOuterCubics: + case DrawType::msaaStencilClipReset: + RIVE_UNREACHABLE(); + } + } + + VK_CHECK(m_vk->CreateShaderModule(m_vk->device, + &vsInfo, + nullptr, + &m_vertexModule)); + VK_CHECK(m_vk->CreateShaderModule(m_vk->device, + &fsInfo, + nullptr, + &m_fragmentModule)); +} + +DrawShaderVulkan::~DrawShaderVulkan() +{ + m_vk->DestroyShaderModule(m_vk->device, m_vertexModule, nullptr); + m_vk->DestroyShaderModule(m_vk->device, m_fragmentModule, nullptr); +} +} // namespace rive::gpu diff --git a/third_party/rive_renderer/source/vulkan/draw_shader_vulkan.hpp b/third_party/rive_renderer/source/vulkan/draw_shader_vulkan.hpp new file mode 100644 index 0000000..e65d6bb --- /dev/null +++ b/third_party/rive_renderer/source/vulkan/draw_shader_vulkan.hpp @@ -0,0 +1,94 @@ +/* + * Copyright 2023 Rive + */ + +#pragma once + +#include "rive/refcnt.hpp" +#include "rive/renderer/gpu.hpp" +#include + +namespace rive::gpu +{ +namespace spirv +{ +// Draw setup shaders. +extern rive::Span color_ramp_vert; +extern rive::Span color_ramp_frag; +extern rive::Span tessellate_vert; +extern rive::Span tessellate_frag; +extern rive::Span render_atlas_vert; +extern rive::Span render_atlas_fill_frag; +extern rive::Span render_atlas_stroke_frag; + +// InterlockMode::rasterOrdering shaders. +extern rive::Span draw_path_vert; +extern rive::Span draw_path_frag; +extern rive::Span draw_interior_triangles_vert; +extern rive::Span draw_interior_triangles_frag; +extern rive::Span draw_atlas_blit_vert; +extern rive::Span draw_atlas_blit_frag; +extern rive::Span draw_image_mesh_vert; +extern rive::Span draw_image_mesh_frag; + +// InterlockMode::atomics shaders. +extern rive::Span atomic_draw_path_vert; +extern rive::Span atomic_draw_path_frag; +extern rive::Span atomic_draw_path_fixedcolor_frag; +extern rive::Span atomic_draw_interior_triangles_vert; +extern rive::Span atomic_draw_interior_triangles_frag; +extern rive::Span + atomic_draw_interior_triangles_fixedcolor_frag; +extern rive::Span atomic_draw_atlas_blit_vert; +extern rive::Span atomic_draw_atlas_blit_frag; +extern rive::Span atomic_draw_atlas_blit_fixedcolor_frag; +extern rive::Span atomic_draw_image_rect_vert; +extern rive::Span atomic_draw_image_rect_frag; +extern rive::Span atomic_draw_image_rect_fixedcolor_frag; +extern rive::Span atomic_draw_image_mesh_vert; +extern rive::Span atomic_draw_image_mesh_frag; +extern rive::Span atomic_draw_image_mesh_fixedcolor_frag; +extern rive::Span atomic_resolve_vert; +extern rive::Span atomic_resolve_frag; +extern rive::Span atomic_resolve_fixedcolor_frag; +extern rive::Span atomic_resolve_coalesced_vert; +extern rive::Span atomic_resolve_coalesced_frag; + +// InterlockMode::clockwiseAtomic shaders. +extern rive::Span draw_clockwise_path_vert; +extern rive::Span draw_clockwise_path_frag; +extern rive::Span draw_clockwise_interior_triangles_vert; +extern rive::Span draw_clockwise_interior_triangles_frag; +extern rive::Span draw_clockwise_atlas_blit_vert; +extern rive::Span draw_clockwise_atlas_blit_frag; +extern rive::Span draw_clockwise_image_mesh_vert; +extern rive::Span draw_clockwise_image_mesh_frag; + +// Reload global SPIRV buffers from runtime data. +void hotload_shaders(rive::Span spirvData); +}; // namespace spirv + +class VulkanContext; + +// Wraps vertex and fragment shader modules for a specific combination of +// DrawType, InterlockMode, and ShaderFeatures. +class DrawShaderVulkan +{ +public: + DrawShaderVulkan(VulkanContext*, + gpu::DrawType, + gpu::InterlockMode, + gpu::ShaderFeatures, + gpu::ShaderMiscFlags); + + ~DrawShaderVulkan(); + + VkShaderModule vertexModule() const { return m_vertexModule; } + VkShaderModule fragmentModule() const { return m_fragmentModule; } + +private: + const rcp m_vk; + VkShaderModule m_vertexModule = VK_NULL_HANDLE; + VkShaderModule m_fragmentModule = VK_NULL_HANDLE; +}; +} // namespace rive::gpu diff --git a/third_party/rive_renderer/source/vulkan/render_context_vulkan_impl.cpp b/third_party/rive_renderer/source/vulkan/render_context_vulkan_impl.cpp new file mode 100644 index 0000000..55fe55b --- /dev/null +++ b/third_party/rive_renderer/source/vulkan/render_context_vulkan_impl.cpp @@ -0,0 +1,3591 @@ +/* + * Copyright 2023 Rive + */ + +#include "rive/renderer/vulkan/render_context_vulkan_impl.hpp" + +#include "draw_shader_vulkan.hpp" +#include "rive/renderer/stack_vector.hpp" +#include "rive/renderer/texture.hpp" +#include "rive/renderer/rive_render_buffer.hpp" +#include "rive/renderer/vulkan/render_target_vulkan.hpp" +#include "shaders/constants.glsl" + +// Common layout descriptors shared by various pipelines. +namespace layout +{ +constexpr static VkVertexInputBindingDescription PATH_INPUT_BINDINGS[] = {{ + .binding = 0, + .stride = sizeof(rive::gpu::PatchVertex), + .inputRate = VK_VERTEX_INPUT_RATE_VERTEX, +}}; +constexpr static VkVertexInputAttributeDescription PATH_VERTEX_ATTRIBS[] = { + { + .location = 0, + .binding = 0, + .format = VK_FORMAT_R32G32B32A32_SFLOAT, + .offset = 0, + }, + { + .location = 1, + .binding = 0, + .format = VK_FORMAT_R32G32B32A32_SFLOAT, + .offset = 4 * sizeof(float), + }, +}; +constexpr static VkPipelineVertexInputStateCreateInfo PATH_VERTEX_INPUT_STATE = + { + .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, + .vertexBindingDescriptionCount = std::size(PATH_INPUT_BINDINGS), + .pVertexBindingDescriptions = PATH_INPUT_BINDINGS, + .vertexAttributeDescriptionCount = std::size(PATH_VERTEX_ATTRIBS), + .pVertexAttributeDescriptions = PATH_VERTEX_ATTRIBS, +}; + +constexpr static VkVertexInputBindingDescription INTERIOR_TRI_INPUT_BINDINGS[] = + {{ + .binding = 0, + .stride = sizeof(rive::gpu::TriangleVertex), + .inputRate = VK_VERTEX_INPUT_RATE_VERTEX, + }}; +constexpr static VkVertexInputAttributeDescription + INTERIOR_TRI_VERTEX_ATTRIBS[] = { + { + .location = 0, + .binding = 0, + .format = VK_FORMAT_R32G32B32_SFLOAT, + .offset = 0, + }, +}; +constexpr static VkPipelineVertexInputStateCreateInfo + INTERIOR_TRI_VERTEX_INPUT_STATE = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, + .vertexBindingDescriptionCount = std::size(INTERIOR_TRI_INPUT_BINDINGS), + .pVertexBindingDescriptions = INTERIOR_TRI_INPUT_BINDINGS, + .vertexAttributeDescriptionCount = + std::size(INTERIOR_TRI_VERTEX_ATTRIBS), + .pVertexAttributeDescriptions = INTERIOR_TRI_VERTEX_ATTRIBS, +}; + +constexpr static VkVertexInputBindingDescription IMAGE_RECT_INPUT_BINDINGS[] = { + { + .binding = 0, + .stride = sizeof(rive::gpu::ImageRectVertex), + .inputRate = VK_VERTEX_INPUT_RATE_VERTEX, + }}; +constexpr static VkVertexInputAttributeDescription IMAGE_RECT_VERTEX_ATTRIBS[] = + { + { + .location = 0, + .binding = 0, + .format = VK_FORMAT_R32G32B32A32_SFLOAT, + .offset = 0, + }, +}; +constexpr static VkPipelineVertexInputStateCreateInfo + IMAGE_RECT_VERTEX_INPUT_STATE = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, + .vertexBindingDescriptionCount = std::size(IMAGE_RECT_INPUT_BINDINGS), + .pVertexBindingDescriptions = IMAGE_RECT_INPUT_BINDINGS, + .vertexAttributeDescriptionCount = std::size(IMAGE_RECT_VERTEX_ATTRIBS), + .pVertexAttributeDescriptions = IMAGE_RECT_VERTEX_ATTRIBS, +}; + +constexpr static VkVertexInputBindingDescription IMAGE_MESH_INPUT_BINDINGS[] = { + { + .binding = 0, + .stride = sizeof(float) * 2, + .inputRate = VK_VERTEX_INPUT_RATE_VERTEX, + }, + { + .binding = 1, + .stride = sizeof(float) * 2, + .inputRate = VK_VERTEX_INPUT_RATE_VERTEX, + }, +}; +constexpr static VkVertexInputAttributeDescription IMAGE_MESH_VERTEX_ATTRIBS[] = + { + { + .location = 0, + .binding = 0, + .format = VK_FORMAT_R32G32_SFLOAT, + .offset = 0, + }, + { + .location = 1, + .binding = 1, + .format = VK_FORMAT_R32G32_SFLOAT, + .offset = 0, + }, +}; +constexpr static VkPipelineVertexInputStateCreateInfo + IMAGE_MESH_VERTEX_INPUT_STATE = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, + .vertexBindingDescriptionCount = std::size(IMAGE_MESH_INPUT_BINDINGS), + .pVertexBindingDescriptions = IMAGE_MESH_INPUT_BINDINGS, + .vertexAttributeDescriptionCount = std::size(IMAGE_MESH_VERTEX_ATTRIBS), + .pVertexAttributeDescriptions = IMAGE_MESH_VERTEX_ATTRIBS, +}; + +constexpr static VkPipelineVertexInputStateCreateInfo EMPTY_VERTEX_INPUT_STATE = + { + .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, + .vertexBindingDescriptionCount = 0, + .vertexAttributeDescriptionCount = 0, +}; + +constexpr static VkPipelineInputAssemblyStateCreateInfo + INPUT_ASSEMBLY_TRIANGLE_STRIP = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, + .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, +}; + +constexpr static VkPipelineInputAssemblyStateCreateInfo + INPUT_ASSEMBLY_TRIANGLE_LIST = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, + .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, +}; + +constexpr static VkPipelineViewportStateCreateInfo SINGLE_VIEWPORT = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, + .viewportCount = 1, + .scissorCount = 1, +}; + +constexpr static VkPipelineRasterizationStateCreateInfo + RASTER_STATE_CULL_BACK_CCW = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, + .polygonMode = VK_POLYGON_MODE_FILL, + .cullMode = VK_CULL_MODE_BACK_BIT, + .frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE, + .lineWidth = 1.f, +}; + +constexpr static VkPipelineRasterizationStateCreateInfo + RASTER_STATE_CULL_BACK_CW = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, + .polygonMode = VK_POLYGON_MODE_FILL, + .cullMode = VK_CULL_MODE_BACK_BIT, + .frontFace = VK_FRONT_FACE_CLOCKWISE, + .lineWidth = 1.f, +}; + +constexpr static VkPipelineMultisampleStateCreateInfo MSAA_DISABLED = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, + .rasterizationSamples = VK_SAMPLE_COUNT_1_BIT, +}; + +constexpr static VkPipelineColorBlendAttachmentState BLEND_DISABLED_VALUES = { + .colorWriteMask = rive::gpu::vkutil::kColorWriteMaskRGBA}; +constexpr static VkPipelineColorBlendStateCreateInfo + SINGLE_ATTACHMENT_BLEND_DISABLED = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, + .attachmentCount = 1, + .pAttachments = &BLEND_DISABLED_VALUES, +}; + +constexpr static VkDynamicState DYNAMIC_VIEWPORT_SCISSOR_VALUES[] = { + VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_SCISSOR, +}; +constexpr static VkPipelineDynamicStateCreateInfo DYNAMIC_VIEWPORT_SCISSOR = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, + .dynamicStateCount = std::size(DYNAMIC_VIEWPORT_SCISSOR_VALUES), + .pDynamicStates = DYNAMIC_VIEWPORT_SCISSOR_VALUES, +}; + +constexpr static VkAttachmentReference SINGLE_ATTACHMENT_SUBPASS_REFERENCE = { + .attachment = 0, + .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, +}; +constexpr static VkSubpassDescription SINGLE_ATTACHMENT_SUBPASS = { + .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, + .colorAttachmentCount = 1, + .pColorAttachments = &SINGLE_ATTACHMENT_SUBPASS_REFERENCE, +}; +} // namespace layout + +namespace rive::gpu +{ +// This is the render pass attachment index for the final color output in the +// "coalesced" atomic resolve. +// NOTE: This attachment is still referenced as color attachment 0 by the +// resolve subpass, so the shader doesn't need to know about it. +// NOTE: Atomic mode does not use SCRATCH_COLOR_PLANE_IDX, which is why we chose +// to alias this one. +constexpr static uint32_t COALESCED_ATOMIC_RESOLVE_IDX = + SCRATCH_COLOR_PLANE_IDX; + +static VkBufferUsageFlagBits render_buffer_usage_flags( + RenderBufferType renderBufferType) +{ + switch (renderBufferType) + { + case RenderBufferType::index: + return VK_BUFFER_USAGE_INDEX_BUFFER_BIT; + case RenderBufferType::vertex: + return VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; + } + RIVE_UNREACHABLE(); +} + +class RenderBufferVulkanImpl + : public LITE_RTTI_OVERRIDE(RiveRenderBuffer, RenderBufferVulkanImpl) +{ +public: + RenderBufferVulkanImpl(rcp vk, + RenderBufferType renderBufferType, + RenderBufferFlags renderBufferFlags, + size_t sizeInBytes) : + lite_rtti_override(renderBufferType, renderBufferFlags, sizeInBytes), + m_bufferPool(make_rcp( + std::move(vk), + render_buffer_usage_flags(renderBufferType), + sizeInBytes)) + {} + + vkutil::Buffer* currentBuffer() { return m_currentBuffer.get(); } + +protected: + void* onMap() override + { + m_bufferPool->recycle(std::move(m_currentBuffer)); + m_currentBuffer = m_bufferPool->acquire(); + return m_currentBuffer->contents(); + } + + void onUnmap() override { m_currentBuffer->flushContents(); } + +private: + rcp m_bufferPool; + rcp m_currentBuffer; +}; + +rcp RenderContextVulkanImpl::makeRenderBuffer( + RenderBufferType type, + RenderBufferFlags flags, + size_t sizeInBytes) +{ + return make_rcp(m_vk, type, flags, sizeInBytes); +} + +rcp RenderContextVulkanImpl::makeImageTexture( + uint32_t width, + uint32_t height, + uint32_t mipLevelCount, + const uint8_t imageDataRGBAPremul[]) +{ + auto texture = m_vk->makeTexture2D({ + .format = VK_FORMAT_R8G8B8A8_UNORM, + .extent = {width, height}, + .mipLevels = mipLevelCount, + }); + texture->stageContentsForUpload(imageDataRGBAPremul, height * width * 4); + return texture; +} + +// Renders color ramps to the gradient texture. +class RenderContextVulkanImpl::ColorRampPipeline +{ +public: + ColorRampPipeline(RenderContextVulkanImpl* impl) : + m_vk(ref_rcp(impl->vulkanContext())) + { + VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, + .setLayoutCount = 1, + .pSetLayouts = &impl->m_perFlushDescriptorSetLayout, + }; + + VK_CHECK(m_vk->CreatePipelineLayout(m_vk->device, + &pipelineLayoutCreateInfo, + nullptr, + &m_pipelineLayout)); + + VkShaderModuleCreateInfo shaderModuleCreateInfo = { + .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, + .codeSize = spirv::color_ramp_vert.size_bytes(), + .pCode = spirv::color_ramp_vert.data(), + }; + + VkShaderModule vertexShader; + VK_CHECK(m_vk->CreateShaderModule(m_vk->device, + &shaderModuleCreateInfo, + nullptr, + &vertexShader)); + + shaderModuleCreateInfo = { + .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, + .codeSize = spirv::color_ramp_frag.size_bytes(), + .pCode = spirv::color_ramp_frag.data(), + }; + + VkShaderModule fragmentShader; + VK_CHECK(m_vk->CreateShaderModule(m_vk->device, + &shaderModuleCreateInfo, + nullptr, + &fragmentShader)); + + VkPipelineShaderStageCreateInfo stages[] = { + { + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + .stage = VK_SHADER_STAGE_VERTEX_BIT, + .module = vertexShader, + .pName = "main", + }, + { + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + .stage = VK_SHADER_STAGE_FRAGMENT_BIT, + .module = fragmentShader, + .pName = "main", + }, + }; + + VkVertexInputBindingDescription vertexInputBindingDescription = { + .binding = 0, + .stride = sizeof(gpu::GradientSpan), + .inputRate = VK_VERTEX_INPUT_RATE_INSTANCE, + }; + + VkVertexInputAttributeDescription vertexAttributeDescription = { + .location = 0, + .binding = 0, + .format = VK_FORMAT_R32G32B32A32_UINT, + }; + + VkPipelineVertexInputStateCreateInfo + pipelineVertexInputStateCreateInfo = { + .sType = + VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, + .vertexBindingDescriptionCount = 1, + .pVertexBindingDescriptions = &vertexInputBindingDescription, + .vertexAttributeDescriptionCount = 1, + .pVertexAttributeDescriptions = &vertexAttributeDescription, + }; + + VkAttachmentDescription attachment = { + .format = VK_FORMAT_R8G8B8A8_UNORM, + .samples = VK_SAMPLE_COUNT_1_BIT, + .loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, + .storeOp = VK_ATTACHMENT_STORE_OP_STORE, + .initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + .finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + }; + VkRenderPassCreateInfo renderPassCreateInfo = { + .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, + .attachmentCount = 1, + .pAttachments = &attachment, + .subpassCount = 1, + .pSubpasses = &layout::SINGLE_ATTACHMENT_SUBPASS, + }; + + VK_CHECK(m_vk->CreateRenderPass(m_vk->device, + &renderPassCreateInfo, + nullptr, + &m_renderPass)); + + VkGraphicsPipelineCreateInfo pipelineCreateInfo = { + .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, + .stageCount = 2, + .pStages = stages, + .pVertexInputState = &pipelineVertexInputStateCreateInfo, + .pInputAssemblyState = &layout::INPUT_ASSEMBLY_TRIANGLE_STRIP, + .pViewportState = &layout::SINGLE_VIEWPORT, + .pRasterizationState = &layout::RASTER_STATE_CULL_BACK_CCW, + .pMultisampleState = &layout::MSAA_DISABLED, + .pColorBlendState = &layout::SINGLE_ATTACHMENT_BLEND_DISABLED, + .pDynamicState = &layout::DYNAMIC_VIEWPORT_SCISSOR, + .layout = m_pipelineLayout, + .renderPass = m_renderPass, + }; + + VK_CHECK(m_vk->CreateGraphicsPipelines(m_vk->device, + VK_NULL_HANDLE, + 1, + &pipelineCreateInfo, + nullptr, + &m_renderPipeline)); + + m_vk->DestroyShaderModule(m_vk->device, vertexShader, nullptr); + m_vk->DestroyShaderModule(m_vk->device, fragmentShader, nullptr); + } + + ~ColorRampPipeline() + { + m_vk->DestroyPipelineLayout(m_vk->device, m_pipelineLayout, nullptr); + m_vk->DestroyRenderPass(m_vk->device, m_renderPass, nullptr); + m_vk->DestroyPipeline(m_vk->device, m_renderPipeline, nullptr); + } + + VkPipelineLayout pipelineLayout() const { return m_pipelineLayout; } + VkRenderPass renderPass() const { return m_renderPass; } + VkPipeline renderPipeline() const { return m_renderPipeline; } + +private: + rcp m_vk; + VkPipelineLayout m_pipelineLayout; + VkRenderPass m_renderPass; + VkPipeline m_renderPipeline; +}; + +// Renders tessellated vertices to the tessellation texture. +class RenderContextVulkanImpl::TessellatePipeline +{ +public: + TessellatePipeline(RenderContextVulkanImpl* impl) : + m_vk(ref_rcp(impl->vulkanContext())) + { + VkDescriptorSetLayout pipelineDescriptorSetLayouts[] = { + impl->m_perFlushDescriptorSetLayout, + impl->m_emptyDescriptorSetLayout, + impl->m_immutableSamplerDescriptorSetLayout, + }; + static_assert(PER_FLUSH_BINDINGS_SET == 0); + static_assert(IMMUTABLE_SAMPLER_BINDINGS_SET == 2); + + VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, + .setLayoutCount = std::size(pipelineDescriptorSetLayouts), + .pSetLayouts = pipelineDescriptorSetLayouts, + }; + + VK_CHECK(m_vk->CreatePipelineLayout(m_vk->device, + &pipelineLayoutCreateInfo, + nullptr, + &m_pipelineLayout)); + + VkShaderModuleCreateInfo shaderModuleCreateInfo = { + .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, + .codeSize = spirv::tessellate_vert.size_bytes(), + .pCode = spirv::tessellate_vert.data(), + }; + + VkShaderModule vertexShader; + VK_CHECK(m_vk->CreateShaderModule(m_vk->device, + &shaderModuleCreateInfo, + nullptr, + &vertexShader)); + + shaderModuleCreateInfo = { + .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, + .codeSize = spirv::tessellate_frag.size_bytes(), + .pCode = spirv::tessellate_frag.data(), + }; + + VkShaderModule fragmentShader; + VK_CHECK(m_vk->CreateShaderModule(m_vk->device, + &shaderModuleCreateInfo, + nullptr, + &fragmentShader)); + + VkPipelineShaderStageCreateInfo stages[] = { + { + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + .stage = VK_SHADER_STAGE_VERTEX_BIT, + .module = vertexShader, + .pName = "main", + }, + { + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + .stage = VK_SHADER_STAGE_FRAGMENT_BIT, + .module = fragmentShader, + .pName = "main", + }, + }; + + VkVertexInputBindingDescription vertexInputBindingDescription = { + .binding = 0, + .stride = sizeof(gpu::TessVertexSpan), + .inputRate = VK_VERTEX_INPUT_RATE_INSTANCE, + }; + + VkVertexInputAttributeDescription vertexAttributeDescriptions[] = { + { + .location = 0, + .binding = 0, + .format = VK_FORMAT_R32G32B32A32_SFLOAT, + .offset = 0, + }, + { + .location = 1, + .binding = 0, + .format = VK_FORMAT_R32G32B32A32_SFLOAT, + .offset = 4 * sizeof(float), + }, + { + .location = 2, + .binding = 0, + .format = VK_FORMAT_R32G32B32A32_SFLOAT, + .offset = 8 * sizeof(float), + }, + { + .location = 3, + .binding = 0, + .format = VK_FORMAT_R32G32B32A32_UINT, + .offset = 12 * sizeof(float), + }, + }; + + VkPipelineVertexInputStateCreateInfo + pipelineVertexInputStateCreateInfo = { + .sType = + VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, + .vertexBindingDescriptionCount = 1, + .pVertexBindingDescriptions = &vertexInputBindingDescription, + .vertexAttributeDescriptionCount = 4, + .pVertexAttributeDescriptions = vertexAttributeDescriptions, + }; + + VkAttachmentDescription attachment = { + .format = VK_FORMAT_R32G32B32A32_UINT, + .samples = VK_SAMPLE_COUNT_1_BIT, + .loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, + .storeOp = VK_ATTACHMENT_STORE_OP_STORE, + .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, + .finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + }; + VkRenderPassCreateInfo renderPassCreateInfo = { + .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, + .attachmentCount = 1, + .pAttachments = &attachment, + .subpassCount = 1, + .pSubpasses = &layout::SINGLE_ATTACHMENT_SUBPASS, + }; + + VK_CHECK(m_vk->CreateRenderPass(m_vk->device, + &renderPassCreateInfo, + nullptr, + &m_renderPass)); + + VkGraphicsPipelineCreateInfo pipelineCreateInfo = { + .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, + .stageCount = 2, + .pStages = stages, + .pVertexInputState = &pipelineVertexInputStateCreateInfo, + .pInputAssemblyState = &layout::INPUT_ASSEMBLY_TRIANGLE_LIST, + .pViewportState = &layout::SINGLE_VIEWPORT, + .pRasterizationState = &layout::RASTER_STATE_CULL_BACK_CCW, + .pMultisampleState = &layout::MSAA_DISABLED, + .pColorBlendState = &layout::SINGLE_ATTACHMENT_BLEND_DISABLED, + .pDynamicState = &layout::DYNAMIC_VIEWPORT_SCISSOR, + .layout = m_pipelineLayout, + .renderPass = m_renderPass, + }; + + VK_CHECK(m_vk->CreateGraphicsPipelines(m_vk->device, + VK_NULL_HANDLE, + 1, + &pipelineCreateInfo, + nullptr, + &m_renderPipeline)); + + m_vk->DestroyShaderModule(m_vk->device, vertexShader, nullptr); + m_vk->DestroyShaderModule(m_vk->device, fragmentShader, nullptr); + } + + ~TessellatePipeline() + { + m_vk->DestroyPipelineLayout(m_vk->device, m_pipelineLayout, nullptr); + m_vk->DestroyRenderPass(m_vk->device, m_renderPass, nullptr); + m_vk->DestroyPipeline(m_vk->device, m_renderPipeline, nullptr); + } + + VkPipelineLayout pipelineLayout() const { return m_pipelineLayout; } + VkRenderPass renderPass() const { return m_renderPass; } + VkPipeline renderPipeline() const { return m_renderPipeline; } + +private: + rcp m_vk; + VkPipelineLayout m_pipelineLayout; + VkRenderPass m_renderPass; + VkPipeline m_renderPipeline; +}; + +// Renders feathers to the atlas. +class RenderContextVulkanImpl::AtlasPipeline +{ +public: + AtlasPipeline(RenderContextVulkanImpl* impl) : + m_vk(ref_rcp(impl->vulkanContext())) + { + VkDescriptorSetLayout pipelineDescriptorSetLayouts[] = { + impl->m_perFlushDescriptorSetLayout, + impl->m_emptyDescriptorSetLayout, + impl->m_immutableSamplerDescriptorSetLayout, + }; + static_assert(PER_FLUSH_BINDINGS_SET == 0); + static_assert(IMMUTABLE_SAMPLER_BINDINGS_SET == 2); + + VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, + .setLayoutCount = std::size(pipelineDescriptorSetLayouts), + .pSetLayouts = pipelineDescriptorSetLayouts, + }; + + VK_CHECK(m_vk->CreatePipelineLayout(m_vk->device, + &pipelineLayoutCreateInfo, + nullptr, + &m_pipelineLayout)); + + VkShaderModuleCreateInfo shaderModuleCreateInfo = { + .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, + .codeSize = spirv::render_atlas_vert.size_bytes(), + .pCode = spirv::render_atlas_vert.data(), + }; + + VkShaderModule vertexShader; + VK_CHECK(m_vk->CreateShaderModule(m_vk->device, + &shaderModuleCreateInfo, + nullptr, + &vertexShader)); + + shaderModuleCreateInfo = { + .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, + .codeSize = spirv::render_atlas_fill_frag.size_bytes(), + .pCode = spirv::render_atlas_fill_frag.data(), + }; + + VkShaderModule fragmentFillShader; + VK_CHECK(m_vk->CreateShaderModule(m_vk->device, + &shaderModuleCreateInfo, + nullptr, + &fragmentFillShader)); + + shaderModuleCreateInfo = { + .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, + .codeSize = spirv::render_atlas_stroke_frag.size_bytes(), + .pCode = spirv::render_atlas_stroke_frag.data(), + }; + + VkShaderModule fragmentStrokeShader; + VK_CHECK(m_vk->CreateShaderModule(m_vk->device, + &shaderModuleCreateInfo, + VK_NULL_HANDLE, + &fragmentStrokeShader)); + + VkPipelineShaderStageCreateInfo stages[] = { + { + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + .stage = VK_SHADER_STAGE_VERTEX_BIT, + .module = vertexShader, + .pName = "main", + }, + { + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + .stage = VK_SHADER_STAGE_FRAGMENT_BIT, + // Set for individual fill/stroke pipelines. + .module = VK_NULL_HANDLE, + .pName = "main", + }, + }; + + VkAttachmentDescription attachment = { + .format = impl->m_atlasFormat, + .samples = VK_SAMPLE_COUNT_1_BIT, + .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, + .storeOp = VK_ATTACHMENT_STORE_OP_STORE, + .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, + .finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + }; + VkRenderPassCreateInfo renderPassCreateInfo = { + .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, + .attachmentCount = 1, + .pAttachments = &attachment, + .subpassCount = 1, + .pSubpasses = &layout::SINGLE_ATTACHMENT_SUBPASS, + }; + VK_CHECK(m_vk->CreateRenderPass(m_vk->device, + &renderPassCreateInfo, + nullptr, + &m_renderPass)); + + VkPipelineColorBlendAttachmentState blendState = + VkPipelineColorBlendAttachmentState{ + .blendEnable = VK_TRUE, + .srcColorBlendFactor = VK_BLEND_FACTOR_ONE, + .dstColorBlendFactor = VK_BLEND_FACTOR_ONE, + .colorWriteMask = VK_COLOR_COMPONENT_R_BIT, + }; + VkPipelineColorBlendStateCreateInfo blendStateCreateInfo = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, + .attachmentCount = 1u, + .pAttachments = &blendState, + }; + + VkGraphicsPipelineCreateInfo pipelineCreateInfo = { + .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, + .stageCount = std::size(stages), + .pStages = stages, + .pVertexInputState = &layout::PATH_VERTEX_INPUT_STATE, + .pInputAssemblyState = &layout::INPUT_ASSEMBLY_TRIANGLE_LIST, + .pViewportState = &layout::SINGLE_VIEWPORT, + .pRasterizationState = &layout::RASTER_STATE_CULL_BACK_CW, + .pMultisampleState = &layout::MSAA_DISABLED, + .pColorBlendState = &blendStateCreateInfo, + .pDynamicState = &layout::DYNAMIC_VIEWPORT_SCISSOR, + .layout = m_pipelineLayout, + .renderPass = m_renderPass, + }; + + stages[1].module = fragmentFillShader; + blendState.colorBlendOp = VK_BLEND_OP_ADD; + VK_CHECK(m_vk->CreateGraphicsPipelines(m_vk->device, + VK_NULL_HANDLE, + 1, + &pipelineCreateInfo, + nullptr, + &m_fillPipeline)); + + stages[1].module = fragmentStrokeShader; + blendState.colorBlendOp = VK_BLEND_OP_MAX; + VK_CHECK(m_vk->CreateGraphicsPipelines(m_vk->device, + VK_NULL_HANDLE, + 1, + &pipelineCreateInfo, + nullptr, + &m_strokePipeline)); + + m_vk->DestroyShaderModule(m_vk->device, vertexShader, nullptr); + m_vk->DestroyShaderModule(m_vk->device, fragmentFillShader, nullptr); + m_vk->DestroyShaderModule(m_vk->device, fragmentStrokeShader, nullptr); + } + + ~AtlasPipeline() + { + m_vk->DestroyPipelineLayout(m_vk->device, m_pipelineLayout, nullptr); + m_vk->DestroyRenderPass(m_vk->device, m_renderPass, nullptr); + m_vk->DestroyPipeline(m_vk->device, m_fillPipeline, nullptr); + m_vk->DestroyPipeline(m_vk->device, m_strokePipeline, nullptr); + } + + VkPipelineLayout pipelineLayout() const { return m_pipelineLayout; } + VkRenderPass renderPass() const { return m_renderPass; } + VkPipeline fillPipeline() const { return m_fillPipeline; } + VkPipeline strokePipeline() const { return m_strokePipeline; } + +private: + rcp m_vk; + VkPipelineLayout m_pipelineLayout; + VkRenderPass m_renderPass; + VkPipeline m_fillPipeline; + VkPipeline m_strokePipeline; +}; + +// VkPipelineLayout wrapper for Rive flushes. +class RenderContextVulkanImpl::DrawPipelineLayout +{ +public: + // Number of render pass variants that can be used with a single + // DrawPipelineLayout (framebufferFormat x loadOp). + constexpr static int kRenderPassVariantCount = 6; + + DrawPipelineLayout(RenderContextVulkanImpl* impl, + gpu::InterlockMode interlockMode, + DrawPipelineLayoutOptions options) : + m_vk(ref_rcp(impl->vulkanContext())), + m_interlockMode(interlockMode), + m_options(options) + { + assert(interlockMode != gpu::InterlockMode::msaa); // TODO: msaa. + + if (interlockMode == gpu::InterlockMode::rasterOrdering || + interlockMode == gpu::InterlockMode::atomics) + { + // PLS planes get bound per flush as input attachments or storage + // textures. + VkDescriptorSetLayoutBinding plsLayoutBindings[] = { + { + .binding = COLOR_PLANE_IDX, + .descriptorType = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, + .descriptorCount = 1, + .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT, + }, + { + .binding = CLIP_PLANE_IDX, + .descriptorType = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, + .descriptorCount = 1, + .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT, + }, + { + .binding = SCRATCH_COLOR_PLANE_IDX, + .descriptorType = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, + .descriptorCount = 1, + .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT, + }, + { + .binding = COVERAGE_PLANE_IDX, + .descriptorType = + m_interlockMode == gpu::InterlockMode::atomics + ? VK_DESCRIPTOR_TYPE_STORAGE_IMAGE + : VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, + .descriptorCount = 1, + .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT, + }, + }; + static_assert(COLOR_PLANE_IDX == 0); + static_assert(CLIP_PLANE_IDX == 1); + static_assert(SCRATCH_COLOR_PLANE_IDX == 2); + static_assert(COVERAGE_PLANE_IDX == 3); + + VkDescriptorSetLayoutCreateInfo plsLayoutInfo = { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, + }; + if (m_options & DrawPipelineLayoutOptions::fixedFunctionColorOutput) + { + // Drop the COLOR input attachment when using + // fixedFunctionColorOutput. + assert(plsLayoutBindings[0].binding == COLOR_PLANE_IDX); + plsLayoutInfo.bindingCount = std::size(plsLayoutBindings) - 1; + plsLayoutInfo.pBindings = plsLayoutBindings + 1; + } + else + { + plsLayoutInfo.bindingCount = std::size(plsLayoutBindings); + plsLayoutInfo.pBindings = plsLayoutBindings; + } + + VK_CHECK(m_vk->CreateDescriptorSetLayout( + m_vk->device, + &plsLayoutInfo, + nullptr, + &m_plsTextureDescriptorSetLayout)); + } + else + { + // clockwiseAtomic and msaa modes don't use pixel local storage. + m_plsTextureDescriptorSetLayout = VK_NULL_HANDLE; + } + + VkDescriptorSetLayout pipelineDescriptorSetLayouts[] = { + impl->m_perFlushDescriptorSetLayout, + impl->m_perDrawDescriptorSetLayout, + impl->m_immutableSamplerDescriptorSetLayout, + m_plsTextureDescriptorSetLayout, + }; + static_assert(COLOR_PLANE_IDX == 0); + static_assert(CLIP_PLANE_IDX == 1); + static_assert(SCRATCH_COLOR_PLANE_IDX == 2); + static_assert(COVERAGE_PLANE_IDX == 3); + static_assert(BINDINGS_SET_COUNT == 4); + + VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, + .setLayoutCount = m_plsTextureDescriptorSetLayout != VK_NULL_HANDLE + ? BINDINGS_SET_COUNT + : BINDINGS_SET_COUNT - 1u, + .pSetLayouts = pipelineDescriptorSetLayouts, + }; + + VK_CHECK(m_vk->CreatePipelineLayout(m_vk->device, + &pipelineLayoutCreateInfo, + nullptr, + &m_pipelineLayout)); + } + + ~DrawPipelineLayout() + { + m_vk->DestroyDescriptorSetLayout(m_vk->device, + m_plsTextureDescriptorSetLayout, + nullptr); + m_vk->DestroyPipelineLayout(m_vk->device, m_pipelineLayout, nullptr); + } + + gpu::InterlockMode interlockMode() const { return m_interlockMode; } + DrawPipelineLayoutOptions options() const { return m_options; } + + uint32_t attachmentCount(uint32_t subpassIndex) const + { + switch (m_interlockMode) + { + case gpu::InterlockMode::rasterOrdering: + assert(subpassIndex == 0); + return 4; + case gpu::InterlockMode::atomics: + assert(subpassIndex <= 1); + return 2u - subpassIndex; // Subpass 0 -> 2, subpass 1 -> 1. + case gpu::InterlockMode::clockwiseAtomic: + assert(subpassIndex == 0); + return 1; + case gpu::InterlockMode::msaa: + assert(subpassIndex == 0); + return 2; + } + } + + VkDescriptorSetLayout plsLayout() const + { + return m_plsTextureDescriptorSetLayout; + } + + VkPipelineLayout operator*() const { return m_pipelineLayout; } + VkPipelineLayout vkPipelineLayout() const { return m_pipelineLayout; } + +private: + const rcp m_vk; + const gpu::InterlockMode m_interlockMode; + const DrawPipelineLayoutOptions m_options; + + VkDescriptorSetLayout m_plsTextureDescriptorSetLayout; + VkPipelineLayout m_pipelineLayout; +}; + +constexpr static VkAttachmentLoadOp vk_load_op(gpu::LoadAction loadAction) +{ + switch (loadAction) + { + case gpu::LoadAction::preserveRenderTarget: + return VK_ATTACHMENT_LOAD_OP_LOAD; + case gpu::LoadAction::clear: + return VK_ATTACHMENT_LOAD_OP_CLEAR; + case gpu::LoadAction::dontCare: + return VK_ATTACHMENT_LOAD_OP_DONT_CARE; + } + RIVE_UNREACHABLE(); +} + +// VkRenderPass wrapper for Rive flushes. +class RenderContextVulkanImpl::RenderPass +{ +public: + constexpr static uint64_t FORMAT_BIT_COUNT = 19; + constexpr static uint64_t LOAD_OP_BIT_COUNT = 2; + constexpr static uint64_t KEY_BIT_COUNT = + FORMAT_BIT_COUNT + DRAW_PIPELINE_LAYOUT_BIT_COUNT + LOAD_OP_BIT_COUNT; + static_assert(KEY_BIT_COUNT <= 32); + + static uint32_t Key(gpu::InterlockMode interlockMode, + DrawPipelineLayoutOptions layoutOptions, + VkFormat renderTargetFormat, + gpu::LoadAction loadAction) + { + uint32_t formatKey = static_cast(renderTargetFormat); + if (formatKey > VK_FORMAT_ASTC_12x12_SRGB_BLOCK) + { + assert(formatKey >= VK_FORMAT_G8B8G8R8_422_UNORM); + formatKey -= VK_FORMAT_G8B8G8R8_422_UNORM - + VK_FORMAT_ASTC_12x12_SRGB_BLOCK - 1; + } + assert(formatKey <= 1 << FORMAT_BIT_COUNT); + + uint32_t drawPipelineLayoutIdx = + DrawPipelineLayoutIdx(interlockMode, layoutOptions); + assert(drawPipelineLayoutIdx < 1 << DRAW_PIPELINE_LAYOUT_BIT_COUNT); + + assert(static_cast(loadAction) < 1 << LOAD_OP_BIT_COUNT); + + return (formatKey << (DRAW_PIPELINE_LAYOUT_BIT_COUNT + + LOAD_OP_BIT_COUNT)) | + (drawPipelineLayoutIdx << LOAD_OP_BIT_COUNT) | + static_cast(loadAction); + } + + RenderPass(RenderContextVulkanImpl* impl, + gpu::InterlockMode interlockMode, + DrawPipelineLayoutOptions layoutOptions, + VkFormat renderTargetFormat, + gpu::LoadAction loadAction) : + m_vk(ref_rcp(impl->vulkanContext())) + { + uint32_t pipelineLayoutIdx = + DrawPipelineLayoutIdx(interlockMode, layoutOptions); + assert(pipelineLayoutIdx < impl->m_drawPipelineLayouts.size()); + if (impl->m_drawPipelineLayouts[pipelineLayoutIdx] == nullptr) + { + impl->m_drawPipelineLayouts[pipelineLayoutIdx] = + std::make_unique(impl, + interlockMode, + layoutOptions); + } + m_drawPipelineLayout = + impl->m_drawPipelineLayouts[pipelineLayoutIdx].get(); + + // COLOR attachment. + const VkImageLayout colorAttachmentLayout = + (layoutOptions & + DrawPipelineLayoutOptions::fixedFunctionColorOutput) + ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL + : VK_IMAGE_LAYOUT_GENERAL; + StackVector attachments; + StackVector colorAttachments; + StackVector resolveAttachments; + assert(attachments.size() == COLOR_PLANE_IDX); + assert(colorAttachments.size() == COLOR_PLANE_IDX); + attachments.push_back({ + .format = renderTargetFormat, + .samples = VK_SAMPLE_COUNT_1_BIT, + .loadOp = vk_load_op(loadAction), + .storeOp = (layoutOptions & + DrawPipelineLayoutOptions::coalescedResolveAndTransfer) + ? VK_ATTACHMENT_STORE_OP_DONT_CARE + : VK_ATTACHMENT_STORE_OP_STORE, + .initialLayout = loadAction == gpu::LoadAction::preserveRenderTarget + ? colorAttachmentLayout + : VK_IMAGE_LAYOUT_UNDEFINED, + .finalLayout = colorAttachmentLayout, + }); + colorAttachments.push_back({ + .attachment = COLOR_PLANE_IDX, + .layout = colorAttachmentLayout, + }); + + if (interlockMode == gpu::InterlockMode::rasterOrdering || + interlockMode == gpu::InterlockMode::atomics) + { + // CLIP attachment. + assert(attachments.size() == CLIP_PLANE_IDX); + assert(colorAttachments.size() == CLIP_PLANE_IDX); + attachments.push_back({ + // The clip buffer is encoded as RGBA8 in atomic mode so we can + // block writes by emitting alpha=0. + .format = interlockMode == gpu::InterlockMode::atomics + ? VK_FORMAT_R8G8B8A8_UNORM + : VK_FORMAT_R32_UINT, + .samples = VK_SAMPLE_COUNT_1_BIT, + .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, + .storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, + .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, + .finalLayout = VK_IMAGE_LAYOUT_GENERAL, + }); + colorAttachments.push_back({ + .attachment = CLIP_PLANE_IDX, + .layout = VK_IMAGE_LAYOUT_GENERAL, + }); + } + + if (interlockMode == gpu::InterlockMode::rasterOrdering) + { + // SCRATCH_COLOR attachment. + assert(attachments.size() == SCRATCH_COLOR_PLANE_IDX); + assert(colorAttachments.size() == SCRATCH_COLOR_PLANE_IDX); + attachments.push_back({ + .format = renderTargetFormat, + .samples = VK_SAMPLE_COUNT_1_BIT, + .loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, + .storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, + .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, + .finalLayout = VK_IMAGE_LAYOUT_GENERAL, + }); + colorAttachments.push_back({ + .attachment = SCRATCH_COLOR_PLANE_IDX, + .layout = VK_IMAGE_LAYOUT_GENERAL, + }); + + // COVERAGE attachment. + assert(attachments.size() == COVERAGE_PLANE_IDX); + assert(colorAttachments.size() == COVERAGE_PLANE_IDX); + attachments.push_back({ + .format = VK_FORMAT_R32_UINT, + .samples = VK_SAMPLE_COUNT_1_BIT, + .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, + .storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, + .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, + .finalLayout = VK_IMAGE_LAYOUT_GENERAL, + }); + colorAttachments.push_back({ + .attachment = COVERAGE_PLANE_IDX, + .layout = VK_IMAGE_LAYOUT_GENERAL, + }); + } + else if (interlockMode == gpu::InterlockMode::atomics) + { + if (layoutOptions & + DrawPipelineLayoutOptions::coalescedResolveAndTransfer) + { + // COALESCED_ATOMIC_RESOLVE attachment (primary render target). + assert(attachments.size() == COALESCED_ATOMIC_RESOLVE_IDX); + attachments.push_back({ + .format = renderTargetFormat, + .samples = VK_SAMPLE_COUNT_1_BIT, + .loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, + .storeOp = VK_ATTACHMENT_STORE_OP_STORE, + // This could sometimes be VK_IMAGE_LAYOUT_UNDEFINED, but it + // might not preserve the portion outside the renderArea + // when it isn't the full render target. Instead we rely on + // accessTargetImageView() to invalidate the target texture + // when we can. + .initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + .finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + }); + + // The resolve subpass only renders to the resolve texture. + // And the "coalesced" resolve shader outputs to color + // attachment 0, so alias the COALESCED_ATOMIC_RESOLVE + // attachment on output 0 for this subpass. + assert(resolveAttachments.size() == 0); + resolveAttachments.push_back({ + .attachment = COALESCED_ATOMIC_RESOLVE_IDX, + .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + }); + } + else + { + // When not in "coalesced" mode, the resolve texture is the + // same as the COLOR texture. + static_assert(COLOR_PLANE_IDX == 0); + assert(resolveAttachments.size() == 0); + resolveAttachments.push_back(colorAttachments[0]); + } + } + + // Input attachments. + StackVector inputAttachments; + if (interlockMode != gpu::InterlockMode::clockwiseAtomic) + { + inputAttachments.push_back_n(colorAttachments.size(), + colorAttachments.data()); + if (layoutOptions & + DrawPipelineLayoutOptions::fixedFunctionColorOutput) + { + // COLOR is not an input attachment if we're using fixed + // function blending. + inputAttachments[0] = {.attachment = VK_ATTACHMENT_UNUSED}; + } + } + + // Draw subpass. + constexpr uint32_t MAX_SUBPASSES = 2; + const bool rasterOrderedAttachmentAccess = + interlockMode == gpu::InterlockMode::rasterOrdering && + m_vk->features.rasterizationOrderColorAttachmentAccess; + StackVector subpassDescs; + StackVector subpassDeps; + assert(subpassDescs.size() == 0); + assert(subpassDeps.size() == 0); + assert(colorAttachments.size() == + m_drawPipelineLayout->attachmentCount(0)); + subpassDescs.push_back({ + .flags = + rasterOrderedAttachmentAccess + ? VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_COLOR_ACCESS_BIT_EXT + : 0u, + .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, + .inputAttachmentCount = inputAttachments.size(), + .pInputAttachments = inputAttachments.data(), + .colorAttachmentCount = colorAttachments.size(), + .pColorAttachments = colorAttachments.data(), + .pDepthStencilAttachment = nullptr, + }); + + // Draw subpass self-dependencies. + if (interlockMode == gpu::InterlockMode::clockwiseAtomic) + { + // clockwiseAtomic mode has a dependency when we switch from + // borrowed coverage into forward. + subpassDeps.push_back({ + .srcSubpass = 0, + .dstSubpass = 0, + .srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + .dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + .srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT, + .dstAccessMask = VK_ACCESS_SHADER_READ_BIT, + .dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT, + }); + } + else if (!rasterOrderedAttachmentAccess) + { + // Normally our dependencies are input attachments. + // + // In implicit rasterOrdering mode (meaning + // EXT_rasterization_order_attachment_access is not present, but + // we're on ARM hardware and know the hardware is raster ordered + // anyway), we also need to declare this dependency even though + // we won't be issuing any barriers. + subpassDeps.push_back({ + .srcSubpass = 0, + .dstSubpass = 0, + .srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + .dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + // TODO: We should add SHADER_READ/SHADER_WRITE flags for the + // coverage buffer as well, but ironically, adding those causes + // artifacts on Qualcomm. Leave them out for now unless we find + // a case where we don't work without them. + .srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + .dstAccessMask = VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, + .dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT, + }); + } + + // Resolve subpass (atomic mode only). + if (interlockMode == gpu::InterlockMode::atomics) + { + // The resolve happens in a separate subpass. + assert(subpassDescs.size() == 1); + assert(resolveAttachments.size() == + m_drawPipelineLayout->attachmentCount(1)); + subpassDescs.push_back({ + .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, + .inputAttachmentCount = inputAttachments.size(), + .pInputAttachments = inputAttachments.data(), + .colorAttachmentCount = resolveAttachments.size(), + .pColorAttachments = resolveAttachments.data(), + }); + + // The resolve subpass depends on the previous one, but not itself. + subpassDeps.push_back({ + .srcSubpass = 0, + .dstSubpass = 1, + .srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + .dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + // TODO: We should add SHADER_READ/SHADER_WRITE flags for the + // coverage buffer as well, but ironically, adding those causes + // artifacts on Qualcomm. Leave them out for now unless we find + // a case where we don't work without them. + .srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + .dstAccessMask = VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, + .dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT, + }); + } + + VkRenderPassCreateInfo renderPassCreateInfo = { + .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, + .attachmentCount = attachments.size(), + .pAttachments = attachments.data(), + .subpassCount = subpassDescs.size(), + .pSubpasses = subpassDescs.data(), + .dependencyCount = subpassDeps.size(), + .pDependencies = subpassDeps.data(), + }; + + VK_CHECK(m_vk->CreateRenderPass(m_vk->device, + &renderPassCreateInfo, + nullptr, + &m_renderPass)); + } + + ~RenderPass() + { + // Don't touch m_drawPipelineLayout in the destructor since destruction + // order of us vs. impl->m_drawPipelineLayouts is uncertain. + m_vk->DestroyRenderPass(m_vk->device, m_renderPass, nullptr); + } + + const DrawPipelineLayout* drawPipelineLayout() const + { + return m_drawPipelineLayout; + } + + operator VkRenderPass() const { return m_renderPass; } + +private: + const rcp m_vk; + // Raw pointer into impl->m_drawPipelineLayouts. RenderContextVulkanImpl + // ensures the pipline layouts outlive this RenderPass instance. + const DrawPipelineLayout* m_drawPipelineLayout; + VkRenderPass m_renderPass; +}; + +// Pipeline options that don't affect the shader. +enum class DrawPipelineOptions +{ + none = 0, + wireframe = 1 << 0, +}; +constexpr static int DRAW_PIPELINE_OPTION_COUNT = 1; +RIVE_MAKE_ENUM_BITSET(DrawPipelineOptions); + +// VkPipeline wrapper for Rive draw calls. +class RenderContextVulkanImpl::DrawPipeline +{ +public: + static uint64_t Key(DrawType drawType, + ShaderFeatures shaderFeatures, + InterlockMode interlockMode, + ShaderMiscFlags shaderMiscFlags, + DrawPipelineOptions drawPipelineOptions, + uint32_t renderPassKey) + { + uint64_t key = gpu::ShaderUniqueKey(drawType, + shaderFeatures, + interlockMode, + shaderMiscFlags); + + assert(key << DRAW_PIPELINE_OPTION_COUNT >> + DRAW_PIPELINE_OPTION_COUNT == + key); + key = (key << DRAW_PIPELINE_OPTION_COUNT) | + static_cast(drawPipelineOptions); + + assert(key << RenderPass::KEY_BIT_COUNT >> RenderPass::KEY_BIT_COUNT == + key); + key = (key << RenderPass::KEY_BIT_COUNT) | renderPassKey; + + return key; + } + + DrawPipeline(RenderContextVulkanImpl* impl, + gpu::DrawType drawType, + const DrawPipelineLayout& pipelineLayout, + gpu::ShaderFeatures shaderFeatures, + gpu::ShaderMiscFlags shaderMiscFlags, + DrawPipelineOptions drawPipelineOptions, + VkRenderPass vkRenderPass) : + m_vk(ref_rcp(impl->vulkanContext())) + { + gpu::InterlockMode interlockMode = pipelineLayout.interlockMode(); + uint32_t shaderKey = gpu::ShaderUniqueKey(drawType, + shaderFeatures, + interlockMode, + shaderMiscFlags); + const uint32_t subpassIndex = + drawType == gpu::DrawType::atomicResolve ? 1u : 0u; + + std::unique_ptr& drawShader = + impl->m_drawShaders[shaderKey]; + if (drawShader == nullptr) + { + drawShader = std::make_unique(m_vk.get(), + drawType, + interlockMode, + shaderFeatures, + shaderMiscFlags); + } + + uint32_t shaderPermutationFlags[SPECIALIZATION_COUNT] = { + shaderFeatures & gpu::ShaderFeatures::ENABLE_CLIPPING, + shaderFeatures & gpu::ShaderFeatures::ENABLE_CLIP_RECT, + shaderFeatures & gpu::ShaderFeatures::ENABLE_ADVANCED_BLEND, + shaderFeatures & gpu::ShaderFeatures::ENABLE_FEATHER, + shaderFeatures & gpu::ShaderFeatures::ENABLE_EVEN_ODD, + shaderFeatures & gpu::ShaderFeatures::ENABLE_NESTED_CLIPPING, + shaderFeatures & gpu::ShaderFeatures::ENABLE_HSL_BLEND_MODES, + shaderMiscFlags & gpu::ShaderMiscFlags::clockwiseFill, + shaderMiscFlags & gpu::ShaderMiscFlags::borrowedCoveragePrepass, + impl->m_vendorID, + }; + static_assert(CLIPPING_SPECIALIZATION_IDX == 0); + static_assert(CLIP_RECT_SPECIALIZATION_IDX == 1); + static_assert(ADVANCED_BLEND_SPECIALIZATION_IDX == 2); + static_assert(FEATHER_SPECIALIZATION_IDX == 3); + static_assert(EVEN_ODD_SPECIALIZATION_IDX == 4); + static_assert(NESTED_CLIPPING_SPECIALIZATION_IDX == 5); + static_assert(HSL_BLEND_MODES_SPECIALIZATION_IDX == 6); + static_assert(CLOCKWISE_FILL_SPECIALIZATION_IDX == 7); + static_assert(BORROWED_COVERAGE_PREPASS_SPECIALIZATION_IDX == 8); + static_assert(VULKAN_VENDOR_ID_SPECIALIZATION_IDX == 9); + static_assert(SPECIALIZATION_COUNT == 10); + + VkSpecializationMapEntry permutationMapEntries[SPECIALIZATION_COUNT]; + for (uint32_t i = 0; i < SPECIALIZATION_COUNT; ++i) + { + permutationMapEntries[i] = { + .constantID = i, + .offset = i * static_cast(sizeof(uint32_t)), + .size = sizeof(uint32_t), + }; + } + + VkSpecializationInfo specializationInfo = { + .mapEntryCount = SPECIALIZATION_COUNT, + .pMapEntries = permutationMapEntries, + .dataSize = sizeof(shaderPermutationFlags), + .pData = &shaderPermutationFlags, + }; + + VkPipelineShaderStageCreateInfo stages[] = { + { + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + .stage = VK_SHADER_STAGE_VERTEX_BIT, + .module = drawShader->vertexModule(), + .pName = "main", + .pSpecializationInfo = &specializationInfo, + }, + { + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + .stage = VK_SHADER_STAGE_FRAGMENT_BIT, + .module = drawShader->fragmentModule(), + .pName = "main", + .pSpecializationInfo = &specializationInfo, + }, + }; + + VkPipelineRasterizationStateCreateInfo + pipelineRasterizationStateCreateInfo = { + .sType = + VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, + .polygonMode = + (drawPipelineOptions & DrawPipelineOptions::wireframe) + ? VK_POLYGON_MODE_LINE + : VK_POLYGON_MODE_FILL, + .cullMode = static_cast( + DrawTypeIsImageDraw(drawType) ? VK_CULL_MODE_NONE + : VK_CULL_MODE_BACK_BIT), + .frontFace = VK_FRONT_FACE_CLOCKWISE, + .lineWidth = 1.0, + }; + + VkPipelineColorBlendAttachmentState blendState; + if (interlockMode == gpu::InterlockMode::rasterOrdering || + (shaderMiscFlags & + gpu::ShaderMiscFlags::coalescedResolveAndTransfer)) + { + blendState = { + .blendEnable = VK_FALSE, + .colorWriteMask = vkutil::kColorWriteMaskRGBA, + }; + } + else if (shaderMiscFlags & + gpu::ShaderMiscFlags::borrowedCoveragePrepass) + { + // Borrowed coverage draws only update the coverage buffer. + blendState = { + .blendEnable = VK_FALSE, + .colorWriteMask = vkutil::kColorWriteMaskNone, + }; + } + else + { + // Atomic mode blends the color and clip both as independent RGBA8 + // values. + // + // Advanced blend modes are handled by rearranging the math + // such that the correct color isn't reached until *AFTER* this + // blend state is applied. + // + // This allows us to preserve clip and color contents by just + // emitting a=0 instead of loading the current value. It also saves + // flops by offloading the blending work onto the ROP blending + // unit, and serves as a hint to the hardware that it doesn't need + // to read or write anything when a == 0. + blendState = { + .blendEnable = VK_TRUE, + // Image draws use premultiplied src-over so they can blend + // the image with the previous paint together, out of order. + // (Premultiplied src-over is associative.) + // + // Otherwise we save 3 flops and let the ROP multiply alpha + // into the color when it does the blending. + .srcColorBlendFactor = + interlockMode == gpu::InterlockMode::atomics && + gpu::DrawTypeIsImageDraw(drawType) + ? VK_BLEND_FACTOR_ONE + : VK_BLEND_FACTOR_SRC_ALPHA, + .dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, + .colorBlendOp = VK_BLEND_OP_ADD, + .srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE, + .dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, + .alphaBlendOp = VK_BLEND_OP_ADD, + .colorWriteMask = vkutil::kColorWriteMaskRGBA, + }; + } + + StackVector + blendStates; + blendStates.push_back_n(pipelineLayout.attachmentCount(subpassIndex), + blendState); + VkPipelineColorBlendStateCreateInfo pipelineColorBlendStateCreateInfo = + { + .sType = + VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, + .attachmentCount = blendStates.size(), + .pAttachments = blendStates.data(), + }; + + if (interlockMode == gpu::InterlockMode::rasterOrdering && + m_vk->features.rasterizationOrderColorAttachmentAccess) + { + pipelineColorBlendStateCreateInfo.flags |= + VK_PIPELINE_COLOR_BLEND_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_BIT_EXT; + } + + VkPipelineDepthStencilStateCreateInfo depthStencilState = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, + .depthTestEnable = VK_FALSE, + .depthWriteEnable = VK_FALSE, + .depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL, + .depthBoundsTestEnable = VK_FALSE, + .stencilTestEnable = VK_FALSE, + .minDepthBounds = DEPTH_MIN, + .maxDepthBounds = DEPTH_MAX, + }; + + VkGraphicsPipelineCreateInfo pipelineCreateInfo = { + .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, + .stageCount = 2, + .pStages = stages, + .pViewportState = &layout::SINGLE_VIEWPORT, + .pRasterizationState = &pipelineRasterizationStateCreateInfo, + .pMultisampleState = &layout::MSAA_DISABLED, + .pDepthStencilState = interlockMode == gpu::InterlockMode::msaa + ? &depthStencilState + : nullptr, + .pColorBlendState = &pipelineColorBlendStateCreateInfo, + .pDynamicState = &layout::DYNAMIC_VIEWPORT_SCISSOR, + .layout = *pipelineLayout, + .renderPass = vkRenderPass, + .subpass = subpassIndex, + }; + + switch (drawType) + { + case DrawType::midpointFanPatches: + case DrawType::midpointFanCenterAAPatches: + case DrawType::outerCurvePatches: + pipelineCreateInfo.pVertexInputState = + &layout::PATH_VERTEX_INPUT_STATE; + pipelineCreateInfo.pInputAssemblyState = + &layout::INPUT_ASSEMBLY_TRIANGLE_LIST; + break; + + case DrawType::interiorTriangulation: + case DrawType::atlasBlit: + pipelineCreateInfo.pVertexInputState = + &layout::INTERIOR_TRI_VERTEX_INPUT_STATE; + pipelineCreateInfo.pInputAssemblyState = + &layout::INPUT_ASSEMBLY_TRIANGLE_LIST; + break; + + case DrawType::imageRect: + pipelineCreateInfo.pVertexInputState = + &layout::IMAGE_RECT_VERTEX_INPUT_STATE; + pipelineCreateInfo.pInputAssemblyState = + &layout::INPUT_ASSEMBLY_TRIANGLE_LIST; + break; + + case DrawType::imageMesh: + pipelineCreateInfo.pVertexInputState = + &layout::IMAGE_MESH_VERTEX_INPUT_STATE; + pipelineCreateInfo.pInputAssemblyState = + &layout::INPUT_ASSEMBLY_TRIANGLE_LIST; + break; + + case DrawType::atomicResolve: + pipelineCreateInfo.pVertexInputState = + &layout::EMPTY_VERTEX_INPUT_STATE; + pipelineCreateInfo.pInputAssemblyState = + &layout::INPUT_ASSEMBLY_TRIANGLE_STRIP; + break; + + case DrawType::atomicInitialize: + case DrawType::msaaStrokes: + case DrawType::msaaMidpointFans: + case DrawType::msaaMidpointFanBorrowedCoverage: + case DrawType::msaaMidpointFanStencilReset: + case DrawType::msaaMidpointFanPathsStencil: + case DrawType::msaaMidpointFanPathsCover: + case DrawType::msaaOuterCubics: + case DrawType::msaaStencilClipReset: + RIVE_UNREACHABLE(); + } + + VK_CHECK(m_vk->CreateGraphicsPipelines(m_vk->device, + VK_NULL_HANDLE, + 1, + &pipelineCreateInfo, + nullptr, + &m_vkPipeline)); + } + + ~DrawPipeline() + { + m_vk->DestroyPipeline(m_vk->device, m_vkPipeline, nullptr); + } + + operator VkPipeline() const { return m_vkPipeline; } + +private: + const rcp m_vk; + VkPipeline m_vkPipeline; +}; + +RenderContextVulkanImpl::RenderContextVulkanImpl( + rcp vk, + const VkPhysicalDeviceProperties& physicalDeviceProps) : + m_vk(std::move(vk)), + m_vendorID(physicalDeviceProps.vendorID), + m_atlasFormat(m_vk->isFormatSupportedWithFeatureFlags( + VK_FORMAT_R32_SFLOAT, + VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT) + ? VK_FORMAT_R32_SFLOAT + : VK_FORMAT_R16_SFLOAT), + m_flushUniformBufferPool(m_vk, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT), + m_imageDrawUniformBufferPool(m_vk, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT), + m_pathBufferPool(m_vk, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT), + m_paintBufferPool(m_vk, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT), + m_paintAuxBufferPool(m_vk, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT), + m_contourBufferPool(m_vk, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT), + m_gradSpanBufferPool(m_vk, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT), + m_tessSpanBufferPool(m_vk, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT), + m_triangleBufferPool(m_vk, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT), + m_descriptorSetPoolPool(make_rcp(m_vk)) +{ + m_platformFeatures.supportsRasterOrdering = + m_vk->features.rasterizationOrderColorAttachmentAccess; + m_platformFeatures.supportsFragmentShaderAtomics = + m_vk->features.fragmentStoresAndAtomics; + m_platformFeatures.supportsClockwiseAtomicRendering = + m_vk->features.fragmentStoresAndAtomics; + m_platformFeatures.clipSpaceBottomUp = false; + m_platformFeatures.framebufferBottomUp = false; + m_platformFeatures.maxCoverageBufferLength = + std::min(physicalDeviceProps.limits.maxStorageBufferRange, 1u << 28) / + sizeof(uint32_t); + + switch (m_vendorID) + { + case VULKAN_VENDOR_QUALCOMM: + // Qualcomm advertises EXT_rasterization_order_attachment_access, + // but it's slow. Use atomics instead on this platform. + m_platformFeatures.supportsRasterOrdering = false; + // Pixel4 struggles with fine-grained fp16 path IDs. + m_platformFeatures.pathIDGranularity = 2; + break; + + case VULKAN_VENDOR_ARM: + // This is undocumented, but raster ordering always works on ARM + // Mali GPUs if you define a subpass dependency, even without + // EXT_rasterization_order_attachment_access. + m_platformFeatures.supportsRasterOrdering = true; + break; + } +} + +static VkFilter vk_filter(rive::ImageFilter option) +{ + switch (option) + { + case rive::ImageFilter::trilinear: + return VK_FILTER_LINEAR; + case rive::ImageFilter::nearest: + return VK_FILTER_NEAREST; + } + + RIVE_UNREACHABLE(); +} + +static VkSamplerMipmapMode vk_sampler_mipmap_mode(rive::ImageFilter option) +{ + switch (option) + { + case rive::ImageFilter::trilinear: + return VK_SAMPLER_MIPMAP_MODE_LINEAR; + case rive::ImageFilter::nearest: + return VK_SAMPLER_MIPMAP_MODE_NEAREST; + } + + RIVE_UNREACHABLE(); +} + +static VkSamplerAddressMode vk_sampler_address_mode(rive::ImageWrap option) +{ + switch (option) + { + case rive::ImageWrap::clamp: + return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + case rive::ImageWrap::repeat: + return VK_SAMPLER_ADDRESS_MODE_REPEAT; + case rive::ImageWrap::mirror: + return VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT; + } + + RIVE_UNREACHABLE(); +} + +void RenderContextVulkanImpl::initGPUObjects() +{ + // Create the immutable samplers. + VkSamplerCreateInfo linearSamplerCreateInfo = { + .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, + .magFilter = VK_FILTER_LINEAR, + .minFilter = VK_FILTER_LINEAR, + .mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST, + .addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, + .addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, + .minLod = 0, + .maxLod = 0, + }; + + VK_CHECK(m_vk->CreateSampler(m_vk->device, + &linearSamplerCreateInfo, + nullptr, + &m_linearSampler)); + + for (size_t i = 0; i < ImageSampler::MAX_SAMPLER_PERMUTATIONS; ++i) + { + ImageWrap wrapX = ImageSampler::GetWrapXOptionFromKey(i); + ImageWrap wrapY = ImageSampler::GetWrapYOptionFromKey(i); + ImageFilter filter = ImageSampler::GetFilterOptionFromKey(i); + VkFilter minMagFilter = vk_filter(filter); + + VkSamplerCreateInfo samplerCreateInfo = { + .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, + .magFilter = minMagFilter, + .minFilter = minMagFilter, + .mipmapMode = vk_sampler_mipmap_mode(filter), + .addressModeU = vk_sampler_address_mode(wrapX), + .addressModeV = vk_sampler_address_mode(wrapY), + .minLod = 0, + .maxLod = VK_LOD_CLAMP_NONE, + }; + + VK_CHECK(m_vk->CreateSampler(m_vk->device, + &samplerCreateInfo, + nullptr, + m_imageSamplers + i)); + } + + // Bound when there is not an image paint. + constexpr static uint8_t black[] = {0, 0, 0, 1}; + m_nullImageTexture = m_vk->makeTexture2D({ + .format = VK_FORMAT_R8G8B8A8_UNORM, + .extent = {1, 1}, + }); + m_nullImageTexture->stageContentsForUpload(black, sizeof(black)); + + // All pipelines share the same perFlush bindings. + VkDescriptorSetLayoutBinding perFlushLayoutBindings[] = { + { + .binding = FLUSH_UNIFORM_BUFFER_IDX, + .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .descriptorCount = 1, + .stageFlags = + VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, + }, + { + .binding = IMAGE_DRAW_UNIFORM_BUFFER_IDX, + .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, + .descriptorCount = 1, + .stageFlags = + VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, + }, + { + .binding = PATH_BUFFER_IDX, + .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .descriptorCount = 1, + .stageFlags = VK_SHADER_STAGE_VERTEX_BIT, + }, + { + .binding = PAINT_BUFFER_IDX, + .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .descriptorCount = 1, + .stageFlags = + VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, + }, + { + .binding = PAINT_AUX_BUFFER_IDX, + .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .descriptorCount = 1, + .stageFlags = + VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, + }, + { + .binding = CONTOUR_BUFFER_IDX, + .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .descriptorCount = 1, + .stageFlags = VK_SHADER_STAGE_VERTEX_BIT, + }, + { + .binding = COVERAGE_BUFFER_IDX, + .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .descriptorCount = 1, + .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT, + }, + { + .binding = TESS_VERTEX_TEXTURE_IDX, + .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, + .descriptorCount = 1, + .stageFlags = VK_SHADER_STAGE_VERTEX_BIT, + }, + { + .binding = GRAD_TEXTURE_IDX, + .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, + .descriptorCount = 1, + .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT, + }, + { + .binding = FEATHER_TEXTURE_IDX, + .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, + .descriptorCount = 1, + .stageFlags = + VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, + }, + { + .binding = ATLAS_TEXTURE_IDX, + .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, + .descriptorCount = 1, + .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT, + }, + }; + + VkDescriptorSetLayoutCreateInfo perFlushLayoutInfo = { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, + .bindingCount = std::size(perFlushLayoutBindings), + .pBindings = perFlushLayoutBindings, + }; + + VK_CHECK(m_vk->CreateDescriptorSetLayout(m_vk->device, + &perFlushLayoutInfo, + nullptr, + &m_perFlushDescriptorSetLayout)); + + // The imageTexture gets updated with every draw that uses it. + VkDescriptorSetLayoutBinding perDrawLayoutBindings[] = { + { + .binding = IMAGE_TEXTURE_IDX, + .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, + .descriptorCount = 1, + .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT, + }, + { + .binding = IMAGE_SAMPLER_IDX, + .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER, + .descriptorCount = 1, + .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT, + }, + }; + + VkDescriptorSetLayoutCreateInfo perDrawLayoutInfo = { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, + .bindingCount = std::size(perDrawLayoutBindings), + .pBindings = perDrawLayoutBindings, + }; + + VK_CHECK(m_vk->CreateDescriptorSetLayout(m_vk->device, + &perDrawLayoutInfo, + nullptr, + &m_perDrawDescriptorSetLayout)); + + // Every shader uses the same immutable sampler layout. + VkDescriptorSetLayoutBinding immutableSamplerLayoutBindings[] = { + { + .binding = GRAD_TEXTURE_IDX, + .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER, + .descriptorCount = 1, + .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT, + .pImmutableSamplers = &m_linearSampler, + }, + { + .binding = FEATHER_TEXTURE_IDX, + .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER, + .descriptorCount = 1, + .stageFlags = + VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, + .pImmutableSamplers = &m_linearSampler, + }, + { + .binding = ATLAS_TEXTURE_IDX, + .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER, + .descriptorCount = 1, + .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT, + .pImmutableSamplers = &m_linearSampler, + }, + }; + + VkDescriptorSetLayoutCreateInfo immutableSamplerLayoutInfo = { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, + .bindingCount = std::size(immutableSamplerLayoutBindings), + .pBindings = immutableSamplerLayoutBindings, + }; + + VK_CHECK(m_vk->CreateDescriptorSetLayout( + m_vk->device, + &immutableSamplerLayoutInfo, + nullptr, + &m_immutableSamplerDescriptorSetLayout)); + + // For when a set isn't used at all by a shader. + VkDescriptorSetLayoutCreateInfo emptyLayoutInfo = { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, + .bindingCount = 0, + }; + + VK_CHECK(m_vk->CreateDescriptorSetLayout(m_vk->device, + &emptyLayoutInfo, + nullptr, + &m_emptyDescriptorSetLayout)); + + // Create static descriptor sets. + VkDescriptorPoolSize staticDescriptorPoolSizes[] = { + { + .type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, + .descriptorCount = 1, // m_nullImageTexture + }, + { + .type = VK_DESCRIPTOR_TYPE_SAMPLER, + .descriptorCount = 4, // grad, feather, atlas, image samplers + }, + }; + + VkDescriptorPoolCreateInfo staticDescriptorPoolCreateInfo = { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, + .flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, + .maxSets = 2, + .poolSizeCount = std::size(staticDescriptorPoolSizes), + .pPoolSizes = staticDescriptorPoolSizes, + }; + + VK_CHECK(m_vk->CreateDescriptorPool(m_vk->device, + &staticDescriptorPoolCreateInfo, + nullptr, + &m_staticDescriptorPool)); + + // Create a descriptor set to bind m_nullImageTexture when there is no image + // paint. + VkDescriptorSetAllocateInfo nullImageDescriptorSetInfo = { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, + .descriptorPool = m_staticDescriptorPool, + .descriptorSetCount = 1, + .pSetLayouts = &m_perDrawDescriptorSetLayout, + }; + + VK_CHECK(m_vk->AllocateDescriptorSets(m_vk->device, + &nullImageDescriptorSetInfo, + &m_nullImageDescriptorSet)); + + m_vk->updateImageDescriptorSets( + m_nullImageDescriptorSet, + { + .dstBinding = IMAGE_TEXTURE_IDX, + .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, + }, + {{ + .imageView = m_nullImageTexture->vkImageView(), + .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + }}); + + m_vk->updateImageDescriptorSets( + m_nullImageDescriptorSet, + { + .dstBinding = IMAGE_SAMPLER_IDX, + .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER, + }, + {{ + .sampler = m_imageSamplers[ImageSampler::LINEAR_CLAMP_SAMPLER_KEY], + }}); + + // Create an empty descriptor set for IMMUTABLE_SAMPLER_BINDINGS_SET. Vulkan + // requires this even though the samplers are all immutable. + VkDescriptorSetAllocateInfo immutableSamplerDescriptorSetInfo = { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, + .descriptorPool = m_staticDescriptorPool, + .descriptorSetCount = 1, + .pSetLayouts = &m_immutableSamplerDescriptorSetLayout, + }; + + VK_CHECK(m_vk->AllocateDescriptorSets(m_vk->device, + &immutableSamplerDescriptorSetInfo, + &m_immutableSamplerDescriptorSet)); + + // The pipelines reference our vulkan objects. Delete them first. + m_colorRampPipeline = std::make_unique(this); + m_tessellatePipeline = std::make_unique(this); + m_atlasPipeline = std::make_unique(this); + + // Emulate the feather texture1d array as a 2d texture until we add + // texture1d support in Vulkan. + uint16_t featherTextureData[gpu::GAUSSIAN_TABLE_SIZE * + FEATHER_TEXTURE_1D_ARRAY_LENGTH]; + memcpy(featherTextureData, + gpu::g_gaussianIntegralTableF16, + sizeof(gpu::g_gaussianIntegralTableF16)); + memcpy(featherTextureData + gpu::GAUSSIAN_TABLE_SIZE, + gpu::g_inverseGaussianIntegralTableF16, + sizeof(gpu::g_inverseGaussianIntegralTableF16)); + static_assert(FEATHER_FUNCTION_ARRAY_INDEX == 0); + static_assert(FEATHER_INVERSE_FUNCTION_ARRAY_INDEX == 1); + m_featherTexture = m_vk->makeTexture2D({ + .format = VK_FORMAT_R16_SFLOAT, + .extent = + { + .width = gpu::GAUSSIAN_TABLE_SIZE, + .height = FEATHER_TEXTURE_1D_ARRAY_LENGTH, + }, + }); + m_featherTexture->stageContentsForUpload(featherTextureData, + sizeof(featherTextureData)); + + m_tessSpanIndexBuffer = m_vk->makeBuffer( + { + .size = sizeof(gpu::kTessSpanIndices), + .usage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT, + }, + vkutil::Mappability::writeOnly); + memcpy(m_tessSpanIndexBuffer->contents(), + gpu::kTessSpanIndices, + sizeof(gpu::kTessSpanIndices)); + m_tessSpanIndexBuffer->flushContents(); + + m_pathPatchVertexBuffer = m_vk->makeBuffer( + { + .size = kPatchVertexBufferCount * sizeof(gpu::PatchVertex), + .usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, + }, + vkutil::Mappability::writeOnly); + m_pathPatchIndexBuffer = m_vk->makeBuffer( + { + .size = kPatchIndexBufferCount * sizeof(uint16_t), + .usage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT, + }, + vkutil::Mappability::writeOnly); + gpu::GeneratePatchBufferData( + reinterpret_cast(m_pathPatchVertexBuffer->contents()), + reinterpret_cast(m_pathPatchIndexBuffer->contents())); + m_pathPatchVertexBuffer->flushContents(); + m_pathPatchIndexBuffer->flushContents(); + + m_imageRectVertexBuffer = m_vk->makeBuffer( + { + .size = sizeof(gpu::kImageRectVertices), + .usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, + }, + vkutil::Mappability::writeOnly); + memcpy(m_imageRectVertexBuffer->contents(), + gpu::kImageRectVertices, + sizeof(gpu::kImageRectVertices)); + m_imageRectVertexBuffer->flushContents(); + m_imageRectIndexBuffer = m_vk->makeBuffer( + { + .size = sizeof(gpu::kImageRectIndices), + .usage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT, + }, + vkutil::Mappability::writeOnly); + memcpy(m_imageRectIndexBuffer->contents(), + gpu::kImageRectIndices, + sizeof(gpu::kImageRectIndices)); + m_imageRectIndexBuffer->flushContents(); +} + +RenderContextVulkanImpl::~RenderContextVulkanImpl() +{ + // These should all have gotten recycled at the end of the last frame. + assert(m_flushUniformBuffer == nullptr); + assert(m_imageDrawUniformBuffer == nullptr); + assert(m_pathBuffer == nullptr); + assert(m_paintBuffer == nullptr); + assert(m_paintAuxBuffer == nullptr); + assert(m_contourBuffer == nullptr); + assert(m_gradSpanBuffer == nullptr); + assert(m_tessSpanBuffer == nullptr); + assert(m_triangleBuffer == nullptr); + + // Tell the context we are entering our shutdown cycle. After this point, + // all resources will be deleted immediately upon their refCount reaching + // zero, as opposed to being kept alive for in-flight command buffers. + m_vk->shutdown(); + + m_vk->DestroyDescriptorPool(m_vk->device, m_staticDescriptorPool, nullptr); + m_vk->DestroyDescriptorSetLayout(m_vk->device, + m_perFlushDescriptorSetLayout, + nullptr); + m_vk->DestroyDescriptorSetLayout(m_vk->device, + m_perDrawDescriptorSetLayout, + nullptr); + m_vk->DestroyDescriptorSetLayout(m_vk->device, + m_immutableSamplerDescriptorSetLayout, + nullptr); + m_vk->DestroyDescriptorSetLayout(m_vk->device, + m_emptyDescriptorSetLayout, + nullptr); + for (VkSampler sampler : m_imageSamplers) + { + m_vk->DestroySampler(m_vk->device, sampler, nullptr); + } + m_vk->DestroySampler(m_vk->device, m_linearSampler, nullptr); +} + +void RenderContextVulkanImpl::resizeGradientTexture(uint32_t width, + uint32_t height) +{ + width = std::max(width, 1u); + height = std::max(height, 1u); + if (m_gradTexture == nullptr || m_gradTexture->width() != width || + m_gradTexture->height() != height) + { + m_gradTexture = m_vk->makeTexture2D({ + .format = VK_FORMAT_R8G8B8A8_UNORM, + .extent = {width, height}, + .usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | + VK_IMAGE_USAGE_SAMPLED_BIT, + }); + + m_gradTextureFramebuffer = m_vk->makeFramebuffer({ + .renderPass = m_colorRampPipeline->renderPass(), + .attachmentCount = 1, + .pAttachments = m_gradTexture->vkImageViewAddressOf(), + .width = width, + .height = height, + .layers = 1, + }); + } +} + +void RenderContextVulkanImpl::resizeTessellationTexture(uint32_t width, + uint32_t height) +{ + width = std::max(width, 1u); + height = std::max(height, 1u); + if (m_tessTexture == nullptr || m_tessTexture->width() != width || + m_tessTexture->height() != height) + { + m_tessTexture = m_vk->makeTexture2D({ + .format = VK_FORMAT_R32G32B32A32_UINT, + .extent = {width, height}, + .usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | + VK_IMAGE_USAGE_SAMPLED_BIT, + }); + + m_tessTextureFramebuffer = m_vk->makeFramebuffer({ + .renderPass = m_tessellatePipeline->renderPass(), + .attachmentCount = 1, + .pAttachments = m_tessTexture->vkImageViewAddressOf(), + .width = width, + .height = height, + .layers = 1, + }); + } +} + +void RenderContextVulkanImpl::resizeAtlasTexture(uint32_t width, + uint32_t height) +{ + width = std::max(width, 1u); + height = std::max(height, 1u); + if (m_atlasTexture == nullptr || m_atlasTexture->width() != width || + m_atlasTexture->height() != height) + { + m_atlasTexture = m_vk->makeTexture2D({ + .format = m_atlasFormat, + .extent = {width, height}, + .usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | + VK_IMAGE_USAGE_SAMPLED_BIT, + }); + + m_atlasFramebuffer = m_vk->makeFramebuffer({ + .renderPass = m_atlasPipeline->renderPass(), + .attachmentCount = 1, + .pAttachments = m_atlasTexture->vkImageViewAddressOf(), + .width = width, + .height = height, + .layers = 1, + }); + } +} + +void RenderContextVulkanImpl::resizeCoverageBuffer(size_t sizeInBytes) +{ + if (sizeInBytes == 0) + { + m_coverageBuffer = nullptr; + } + else + { + m_coverageBuffer = m_vk->makeBuffer( + { + .size = sizeInBytes, + .usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | + VK_BUFFER_USAGE_TRANSFER_DST_BIT, + }, + vkutil::Mappability::none); + } +} + +void RenderContextVulkanImpl::prepareToFlush(uint64_t nextFrameNumber, + uint64_t safeFrameNumber) +{ + // These should all have gotten recycled at the end of the last frame. + assert(m_flushUniformBuffer == nullptr); + assert(m_imageDrawUniformBuffer == nullptr); + assert(m_pathBuffer == nullptr); + assert(m_paintBuffer == nullptr); + assert(m_paintAuxBuffer == nullptr); + assert(m_contourBuffer == nullptr); + assert(m_gradSpanBuffer == nullptr); + assert(m_tessSpanBuffer == nullptr); + assert(m_triangleBuffer == nullptr); + + // Advance the context frame and delete resources that are no longer + // referenced by in-flight command buffers. + m_vk->advanceFrameNumber(nextFrameNumber, safeFrameNumber); + + // Acquire buffers for the flush. + m_flushUniformBuffer = m_flushUniformBufferPool.acquire(); + m_imageDrawUniformBuffer = m_imageDrawUniformBufferPool.acquire(); + m_pathBuffer = m_pathBufferPool.acquire(); + m_paintBuffer = m_paintBufferPool.acquire(); + m_paintAuxBuffer = m_paintAuxBufferPool.acquire(); + m_contourBuffer = m_contourBufferPool.acquire(); + m_gradSpanBuffer = m_gradSpanBufferPool.acquire(); + m_tessSpanBuffer = m_tessSpanBufferPool.acquire(); + m_triangleBuffer = m_triangleBufferPool.acquire(); +} + +namespace descriptor_pool_limits +{ +constexpr static uint32_t kMaxUniformUpdates = 3; +constexpr static uint32_t kMaxDynamicUniformUpdates = 1; +constexpr static uint32_t kMaxImageTextureUpdates = 256; +constexpr static uint32_t kMaxSampledImageUpdates = + 4 + kMaxImageTextureUpdates; // tess + grad + feather + atlas + images +constexpr static uint32_t kMaxStorageImageUpdates = + 1; // coverageAtomicTexture in atomic mode. +constexpr static uint32_t kMaxStorageBufferUpdates = + 7 + // path/paint/uniform buffers + 1; // coverage buffer in clockwiseAtomic mode +constexpr static uint32_t kMaxDescriptorSets = 3 + kMaxImageTextureUpdates; +} // namespace descriptor_pool_limits + +RenderContextVulkanImpl::DescriptorSetPool::DescriptorSetPool( + rcp vulkanContext) : + vkutil::Resource(std::move(vulkanContext)) +{ + VkDescriptorPoolSize descriptorPoolSizes[] = { + { + .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .descriptorCount = descriptor_pool_limits::kMaxUniformUpdates, + }, + { + .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, + .descriptorCount = + descriptor_pool_limits::kMaxDynamicUniformUpdates, + }, + { + .type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, + .descriptorCount = descriptor_pool_limits::kMaxSampledImageUpdates, + }, + { + .type = VK_DESCRIPTOR_TYPE_SAMPLER, + .descriptorCount = descriptor_pool_limits::kMaxImageTextureUpdates, + }, + { + .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, + .descriptorCount = descriptor_pool_limits::kMaxStorageImageUpdates, + }, + { + .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .descriptorCount = descriptor_pool_limits::kMaxStorageBufferUpdates, + }, + { + .type = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, + .descriptorCount = 4, + }, + }; + + VkDescriptorPoolCreateInfo descriptorPoolCreateInfo = { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, + .flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, + .maxSets = descriptor_pool_limits::kMaxDescriptorSets, + .poolSizeCount = std::size(descriptorPoolSizes), + .pPoolSizes = descriptorPoolSizes, + }; + + VK_CHECK(vk()->CreateDescriptorPool(vk()->device, + &descriptorPoolCreateInfo, + nullptr, + &m_vkDescriptorPool)); +} + +RenderContextVulkanImpl::DescriptorSetPool::~DescriptorSetPool() +{ + vk()->DestroyDescriptorPool(vk()->device, m_vkDescriptorPool, nullptr); +} + +VkDescriptorSet RenderContextVulkanImpl::DescriptorSetPool:: + allocateDescriptorSet(VkDescriptorSetLayout layout) +{ + VkDescriptorSetAllocateInfo descriptorSetAllocateInfo = { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, + .descriptorPool = m_vkDescriptorPool, + .descriptorSetCount = 1, + .pSetLayouts = &layout, + }; + + VkDescriptorSet descriptorSet; + VK_CHECK(vk()->AllocateDescriptorSets(vk()->device, + &descriptorSetAllocateInfo, + &descriptorSet)); + + return descriptorSet; +} + +void RenderContextVulkanImpl::DescriptorSetPool::reset() +{ + vk()->ResetDescriptorPool(vk()->device, m_vkDescriptorPool, 0); +} + +rcp RenderContextVulkanImpl:: + DescriptorSetPoolPool::acquire() +{ + auto descriptorSetPool = + static_rcp_cast(GPUResourcePool::acquire()); + if (descriptorSetPool == nullptr) + { + descriptorSetPool = make_rcp( + static_rcp_cast(m_manager)); + } + else + { + descriptorSetPool->reset(); + } + return descriptorSetPool; +} + +void RenderContextVulkanImpl::flush(const FlushDescriptor& desc) +{ + constexpr static VkDeviceSize ZERO_OFFSET[1] = {0}; + constexpr static uint32_t ZERO_OFFSET_32[1] = {0}; + + if (desc.interlockMode == gpu::InterlockMode::msaa) + { + return; + } + + if (desc.renderTargetUpdateBounds.empty()) + { + return; + } + + auto commandBuffer = + reinterpret_cast(desc.externalCommandBuffer); + rcp descriptorSetPool = + m_descriptorSetPoolPool->acquire(); + + // Apply pending texture updates. + if (m_featherTexture->hasUpdates()) + { + m_featherTexture->synchronize(commandBuffer); + } + if (m_nullImageTexture->hasUpdates()) + { + m_nullImageTexture->synchronize(commandBuffer); + } + for (const DrawBatch& batch : *desc.drawList) + { + if (auto imageTextureVulkan = + static_cast(batch.imageTexture)) + { + if (imageTextureVulkan->hasUpdates()) + { + imageTextureVulkan->synchronize(commandBuffer); + } + } + } + + // Create a per-flush descriptor set. + VkDescriptorSet perFlushDescriptorSet = + descriptorSetPool->allocateDescriptorSet(m_perFlushDescriptorSetLayout); + + m_vk->updateBufferDescriptorSets( + perFlushDescriptorSet, + { + .dstBinding = FLUSH_UNIFORM_BUFFER_IDX, + .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + }, + {{ + .buffer = *m_flushUniformBuffer, + .offset = desc.flushUniformDataOffsetInBytes, + .range = sizeof(gpu::FlushUniforms), + }}); + + m_vk->updateBufferDescriptorSets( + perFlushDescriptorSet, + { + .dstBinding = IMAGE_DRAW_UNIFORM_BUFFER_IDX, + .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, + }, + {{ + .buffer = *m_imageDrawUniformBuffer, + .offset = 0, + .range = sizeof(gpu::ImageDrawUniforms), + }}); + + m_vk->updateBufferDescriptorSets( + perFlushDescriptorSet, + { + .dstBinding = PATH_BUFFER_IDX, + .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + }, + {{ + .buffer = *m_pathBuffer, + .offset = desc.firstPath * sizeof(gpu::PathData), + .range = VK_WHOLE_SIZE, + }}); + + m_vk->updateBufferDescriptorSets( + perFlushDescriptorSet, + { + .dstBinding = PAINT_BUFFER_IDX, + .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + }, + { + { + .buffer = *m_paintBuffer, + .offset = desc.firstPaint * sizeof(gpu::PaintData), + .range = VK_WHOLE_SIZE, + }, + { + .buffer = *m_paintAuxBuffer, + .offset = desc.firstPaintAux * sizeof(gpu::PaintAuxData), + .range = VK_WHOLE_SIZE, + }, + }); + static_assert(PAINT_AUX_BUFFER_IDX == PAINT_BUFFER_IDX + 1); + + m_vk->updateBufferDescriptorSets( + perFlushDescriptorSet, + { + .dstBinding = CONTOUR_BUFFER_IDX, + .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + }, + {{ + .buffer = *m_contourBuffer, + .offset = desc.firstContour * sizeof(gpu::ContourData), + .range = VK_WHOLE_SIZE, + }}); + + if (desc.interlockMode == gpu::InterlockMode::clockwiseAtomic && + m_coverageBuffer != nullptr) + { + m_vk->updateBufferDescriptorSets( + perFlushDescriptorSet, + { + .dstBinding = COVERAGE_BUFFER_IDX, + .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + }, + {{ + .buffer = *m_coverageBuffer, + .offset = 0, + .range = VK_WHOLE_SIZE, + }}); + } + + m_vk->updateImageDescriptorSets( + perFlushDescriptorSet, + { + .dstBinding = TESS_VERTEX_TEXTURE_IDX, + .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, + }, + {{ + .imageView = m_tessTexture->vkImageView(), + .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + }}); + + m_vk->updateImageDescriptorSets( + perFlushDescriptorSet, + { + .dstBinding = GRAD_TEXTURE_IDX, + .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, + }, + {{ + .imageView = m_gradTexture->vkImageView(), + .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + }}); + + m_vk->updateImageDescriptorSets( + perFlushDescriptorSet, + { + .dstBinding = FEATHER_TEXTURE_IDX, + .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, + }, + {{ + .imageView = m_featherTexture->vkImageView(), + .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + }}); + + m_vk->updateImageDescriptorSets( + perFlushDescriptorSet, + { + .dstBinding = ATLAS_TEXTURE_IDX, + .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, + }, + {{ + .imageView = m_atlasTexture->vkImageView(), + .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + }}); + + // Render the complex color ramps to the gradient texture. + if (desc.gradSpanCount > 0) + { + // Wait for previous accesses to finish before rendering to the gradient + // texture. + m_gradTexture->barrier( + commandBuffer, + { + .pipelineStages = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + .accessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + }, + vkutil::ImageAccessAction::invalidateContents); + + VkRect2D renderArea = { + .extent = {gpu::kGradTextureWidth, desc.gradDataHeight}, + }; + + VkRenderPassBeginInfo renderPassBeginInfo = { + .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, + .renderPass = m_colorRampPipeline->renderPass(), + .framebuffer = *m_gradTextureFramebuffer, + .renderArea = renderArea, + }; + + m_vk->CmdBeginRenderPass(commandBuffer, + &renderPassBeginInfo, + VK_SUBPASS_CONTENTS_INLINE); + + m_vk->CmdBindPipeline(commandBuffer, + VK_PIPELINE_BIND_POINT_GRAPHICS, + m_colorRampPipeline->renderPipeline()); + + m_vk->CmdSetViewport(commandBuffer, + 0, + 1, + vkutil::ViewportFromRect2D(renderArea)); + + m_vk->CmdSetScissor(commandBuffer, 0, 1, &renderArea); + + VkBuffer gradSpanBuffer = *m_gradSpanBuffer; + VkDeviceSize gradSpanOffset = + desc.firstGradSpan * sizeof(gpu::GradientSpan); + m_vk->CmdBindVertexBuffers(commandBuffer, + 0, + 1, + &gradSpanBuffer, + &gradSpanOffset); + + m_vk->CmdBindDescriptorSets(commandBuffer, + VK_PIPELINE_BIND_POINT_GRAPHICS, + m_colorRampPipeline->pipelineLayout(), + PER_FLUSH_BINDINGS_SET, + 1, + &perFlushDescriptorSet, + 1, + ZERO_OFFSET_32); + + m_vk->CmdDraw(commandBuffer, + gpu::GRAD_SPAN_TRI_STRIP_VERTEX_COUNT, + desc.gradSpanCount, + 0, + 0); + + m_vk->CmdEndRenderPass(commandBuffer); + + // The render pass transitioned the gradient texture to + // VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL. + m_gradTexture->lastAccess().layout = + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + } + + // Ensure the gradient texture has finished updating before the path + // fragment shaders read it. + m_gradTexture->barrier( + commandBuffer, + { + .pipelineStages = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + .accessMask = VK_ACCESS_SHADER_READ_BIT, + .layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + }); + + // Tessellate all curves into vertices in the tessellation texture. + if (desc.tessVertexSpanCount > 0) + { + // Don't render new vertices until the previous flush has finished using + // the tessellation texture. + m_tessTexture->barrier( + commandBuffer, + { + .pipelineStages = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + .accessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + }, + vkutil::ImageAccessAction::invalidateContents); + + VkRect2D renderArea = { + .extent = {gpu::kTessTextureWidth, desc.tessDataHeight}, + }; + + VkRenderPassBeginInfo renderPassBeginInfo = { + .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, + .renderPass = m_tessellatePipeline->renderPass(), + .framebuffer = *m_tessTextureFramebuffer, + .renderArea = renderArea, + }; + + m_vk->CmdBeginRenderPass(commandBuffer, + &renderPassBeginInfo, + VK_SUBPASS_CONTENTS_INLINE); + + m_vk->CmdBindPipeline(commandBuffer, + VK_PIPELINE_BIND_POINT_GRAPHICS, + m_tessellatePipeline->renderPipeline()); + + m_vk->CmdSetViewport(commandBuffer, + 0, + 1, + vkutil::ViewportFromRect2D(renderArea)); + + m_vk->CmdSetScissor(commandBuffer, 0, 1, &renderArea); + + VkBuffer tessBuffer = *m_tessSpanBuffer; + VkDeviceSize tessOffset = + desc.firstTessVertexSpan * sizeof(gpu::TessVertexSpan); + m_vk->CmdBindVertexBuffers(commandBuffer, + 0, + 1, + &tessBuffer, + &tessOffset); + + m_vk->CmdBindIndexBuffer(commandBuffer, + *m_tessSpanIndexBuffer, + 0, + VK_INDEX_TYPE_UINT16); + + m_vk->CmdBindDescriptorSets(commandBuffer, + VK_PIPELINE_BIND_POINT_GRAPHICS, + m_tessellatePipeline->pipelineLayout(), + PER_FLUSH_BINDINGS_SET, + 1, + &perFlushDescriptorSet, + 1, + ZERO_OFFSET_32); + m_vk->CmdBindDescriptorSets(commandBuffer, + VK_PIPELINE_BIND_POINT_GRAPHICS, + m_tessellatePipeline->pipelineLayout(), + IMMUTABLE_SAMPLER_BINDINGS_SET, + 1, + &m_immutableSamplerDescriptorSet, + 0, + nullptr); + + m_vk->CmdDrawIndexed(commandBuffer, + std::size(gpu::kTessSpanIndices), + desc.tessVertexSpanCount, + 0, + 0, + 0); + + m_vk->CmdEndRenderPass(commandBuffer); + + // The render pass transitioned the tessellation texture to + // VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL. + m_tessTexture->lastAccess().layout = + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + } + + // Ensure the tessellation texture has finished rendering before the path + // vertex shaders read it. + m_tessTexture->barrier( + commandBuffer, + { + .pipelineStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, + .accessMask = VK_ACCESS_SHADER_READ_BIT, + .layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + }); + + // Render the atlas if we have any offscreen feathers. + if ((desc.atlasFillBatchCount | desc.atlasStrokeBatchCount) != 0) + { + // Don't render new vertices until the previous flush has finished using + // the atlas texture. + m_atlasTexture->barrier( + commandBuffer, + { + .pipelineStages = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + .accessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + }, + vkutil::ImageAccessAction::invalidateContents); + + VkRect2D renderArea = { + .extent = {desc.atlasContentWidth, desc.atlasContentHeight}, + }; + + VkClearValue atlasClearValue = {}; + + VkRenderPassBeginInfo renderPassBeginInfo = { + .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, + .renderPass = m_atlasPipeline->renderPass(), + .framebuffer = *m_atlasFramebuffer, + .renderArea = renderArea, + .clearValueCount = 1, + .pClearValues = &atlasClearValue, + }; + + m_vk->CmdBeginRenderPass(commandBuffer, + &renderPassBeginInfo, + VK_SUBPASS_CONTENTS_INLINE); + m_vk->CmdSetViewport(commandBuffer, + 0, + 1, + vkutil::ViewportFromRect2D(renderArea)); + m_vk->CmdBindVertexBuffers(commandBuffer, + 0, + 1, + m_pathPatchVertexBuffer->vkBufferAddressOf(), + ZERO_OFFSET); + m_vk->CmdBindIndexBuffer(commandBuffer, + *m_pathPatchIndexBuffer, + 0, + VK_INDEX_TYPE_UINT16); + m_vk->CmdBindDescriptorSets(commandBuffer, + VK_PIPELINE_BIND_POINT_GRAPHICS, + m_atlasPipeline->pipelineLayout(), + PER_FLUSH_BINDINGS_SET, + 1, + &perFlushDescriptorSet, + 1, + ZERO_OFFSET_32); + m_vk->CmdBindDescriptorSets(commandBuffer, + VK_PIPELINE_BIND_POINT_GRAPHICS, + m_atlasPipeline->pipelineLayout(), + IMMUTABLE_SAMPLER_BINDINGS_SET, + 1, + &m_immutableSamplerDescriptorSet, + 0, + nullptr); + if (desc.atlasFillBatchCount != 0) + { + m_vk->CmdBindPipeline(commandBuffer, + VK_PIPELINE_BIND_POINT_GRAPHICS, + m_atlasPipeline->fillPipeline()); + for (size_t i = 0; i < desc.atlasFillBatchCount; ++i) + { + const gpu::AtlasDrawBatch& fillBatch = desc.atlasFillBatches[i]; + VkRect2D scissor = { + .offset = {fillBatch.scissor.left, fillBatch.scissor.top}, + .extent = {fillBatch.scissor.width(), + fillBatch.scissor.height()}, + }; + m_vk->CmdSetScissor(commandBuffer, 0, 1, &scissor); + m_vk->CmdDrawIndexed(commandBuffer, + gpu::kMidpointFanCenterAAPatchIndexCount, + fillBatch.patchCount, + gpu::kMidpointFanCenterAAPatchBaseIndex, + 0, + fillBatch.basePatch); + } + } + + if (desc.atlasStrokeBatchCount != 0) + { + m_vk->CmdBindPipeline(commandBuffer, + VK_PIPELINE_BIND_POINT_GRAPHICS, + m_atlasPipeline->strokePipeline()); + for (size_t i = 0; i < desc.atlasStrokeBatchCount; ++i) + { + const gpu::AtlasDrawBatch& strokeBatch = + desc.atlasStrokeBatches[i]; + VkRect2D scissor = { + .offset = {strokeBatch.scissor.left, + strokeBatch.scissor.top}, + .extent = {strokeBatch.scissor.width(), + strokeBatch.scissor.height()}, + }; + m_vk->CmdSetScissor(commandBuffer, 0, 1, &scissor); + m_vk->CmdDrawIndexed(commandBuffer, + gpu::kMidpointFanPatchBorderIndexCount, + strokeBatch.patchCount, + gpu::kMidpointFanPatchBaseIndex, + 0, + strokeBatch.basePatch); + } + } + + m_vk->CmdEndRenderPass(commandBuffer); + + // The render pass transitioned the atlas texture to + // VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL. + m_atlasTexture->lastAccess().layout = + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + } + + // Ensure the atlas texture has finished rendering before the fragment + // shaders read it. + m_atlasTexture->barrier( + commandBuffer, + { + .pipelineStages = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + .accessMask = VK_ACCESS_SHADER_READ_BIT, + .layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + }); + + auto* renderTarget = static_cast(desc.renderTarget); + + vkutil::Texture2D *clipTexture, *scratchColorTexture, *coverageTexture; + if (desc.interlockMode == gpu::InterlockMode::rasterOrdering) + { + clipTexture = renderTarget->clipTextureR32UI(); + scratchColorTexture = renderTarget->scratchColorTexture(); + coverageTexture = renderTarget->coverageTexture(); + } + else if (desc.interlockMode == gpu::InterlockMode::atomics) + { + clipTexture = renderTarget->clipTextureRGBA8(); + scratchColorTexture = nullptr; + coverageTexture = renderTarget->coverageAtomicTexture(); + } + + // Ensure any previous accesses to the color texture complete before we + // begin rendering. + const vkutil::ImageAccess colorLoadAccess = { + // "Load" operations always occur in + // VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT. + .pipelineStages = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + .accessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + .layout = desc.atomicFixedFunctionColorOutput + ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL + : VK_IMAGE_LAYOUT_GENERAL, + }; + + const bool renderAreaIsFullTarget = desc.renderTargetUpdateBounds.contains( + IAABB{0, + 0, + static_cast(renderTarget->width()), + static_cast(renderTarget->height())}); + + VkImageView colorImageView; + bool colorAttachmentIsOffscreen; + if (desc.atomicFixedFunctionColorOutput || + (renderTarget->targetUsageFlags() & + VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT)) + { + colorImageView = renderTarget->accessTargetImageView( + commandBuffer, + colorLoadAccess, + renderAreaIsFullTarget && desc.colorLoadAction != + gpu::LoadAction::preserveRenderTarget + ? vkutil::ImageAccessAction::invalidateContents + : vkutil::ImageAccessAction::preserveContents); + colorAttachmentIsOffscreen = false; + } + else if (desc.colorLoadAction != gpu::LoadAction::preserveRenderTarget) + { + colorImageView = renderTarget + ->accessOffscreenColorTexture( + commandBuffer, + colorLoadAccess, + vkutil::ImageAccessAction::invalidateContents) + ->vkImageView(); + colorAttachmentIsOffscreen = true; + } + else + { + // Preserve the target texture by blitting its contents into our + // offscreen color texture. + m_vk->blitSubRect( + commandBuffer, + renderTarget->accessTargetImage( + commandBuffer, + { + .pipelineStages = VK_PIPELINE_STAGE_TRANSFER_BIT, + .accessMask = VK_ACCESS_TRANSFER_READ_BIT, + .layout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + }), + renderTarget + ->accessOffscreenColorTexture( + commandBuffer, + { + .pipelineStages = VK_PIPELINE_STAGE_TRANSFER_BIT, + .accessMask = VK_ACCESS_TRANSFER_WRITE_BIT, + .layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + }, + vkutil::ImageAccessAction::invalidateContents) + ->vkImage(), + desc.renderTargetUpdateBounds); + colorImageView = + renderTarget + ->accessOffscreenColorTexture(commandBuffer, colorLoadAccess) + ->vkImageView(); + colorAttachmentIsOffscreen = true; + } + + auto pipelineLayoutOptions = DrawPipelineLayoutOptions::none; + if (desc.interlockMode == gpu::InterlockMode::atomics) + { + if (desc.atomicFixedFunctionColorOutput) + { + pipelineLayoutOptions |= + DrawPipelineLayoutOptions::fixedFunctionColorOutput; + } + else if (colorAttachmentIsOffscreen) + { + pipelineLayoutOptions |= + DrawPipelineLayoutOptions::coalescedResolveAndTransfer; + } + } + + const uint32_t renderPassKey = + RenderPass::Key(desc.interlockMode, + pipelineLayoutOptions, + renderTarget->framebufferFormat(), + desc.colorLoadAction); + std::unique_ptr& renderPass = m_renderPasses[renderPassKey]; + if (renderPass == nullptr) + { + renderPass = + std::make_unique(this, + desc.interlockMode, + pipelineLayoutOptions, + renderTarget->framebufferFormat(), + desc.colorLoadAction); + } + const DrawPipelineLayout& pipelineLayout = + *renderPass->drawPipelineLayout(); + + // Create the framebuffer. + StackVector framebufferViews; + assert(framebufferViews.size() == COLOR_PLANE_IDX); + framebufferViews.push_back(colorImageView); + if (desc.interlockMode == gpu::InterlockMode::rasterOrdering) + { + assert(framebufferViews.size() == CLIP_PLANE_IDX); + framebufferViews.push_back(clipTexture->vkImageView()); + assert(framebufferViews.size() == SCRATCH_COLOR_PLANE_IDX); + framebufferViews.push_back(scratchColorTexture->vkImageView()); + assert(framebufferViews.size() == COVERAGE_PLANE_IDX); + framebufferViews.push_back(coverageTexture->vkImageView()); + } + else if (desc.interlockMode == gpu::InterlockMode::atomics) + { + assert(framebufferViews.size() == CLIP_PLANE_IDX); + framebufferViews.push_back(clipTexture->vkImageView()); + if (pipelineLayout.options() & + DrawPipelineLayoutOptions::coalescedResolveAndTransfer) + { + assert(framebufferViews.size() == COALESCED_ATOMIC_RESOLVE_IDX); + framebufferViews.push_back(renderTarget->accessTargetImageView( + commandBuffer, + { + .pipelineStages = + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + .accessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + }, + renderAreaIsFullTarget + ? vkutil::ImageAccessAction::invalidateContents + : vkutil::ImageAccessAction::preserveContents)); + } + } + + rcp framebuffer = m_vk->makeFramebuffer({ + .renderPass = *renderPass, + .attachmentCount = framebufferViews.size(), + .pAttachments = framebufferViews.data(), + .width = static_cast(renderTarget->width()), + .height = static_cast(renderTarget->height()), + .layers = 1, + }); + + VkRect2D renderArea = { + .offset = {desc.renderTargetUpdateBounds.left, + desc.renderTargetUpdateBounds.top}, + .extent = {static_cast(desc.renderTargetUpdateBounds.width()), + static_cast( + desc.renderTargetUpdateBounds.height())}, + }; + + VkClearValue clearValues[] = { + {.color = vkutil::color_clear_rgba32f(desc.colorClearValue)}, + {}, + {}, + {.color = vkutil::color_clear_r32ui(desc.coverageClearValue)}, + {.depthStencil = {desc.depthClearValue, desc.stencilClearValue}}, + }; + static_assert(COLOR_PLANE_IDX == 0); + static_assert(CLIP_PLANE_IDX == 1); + static_assert(SCRATCH_COLOR_PLANE_IDX == 2); + static_assert(COVERAGE_PLANE_IDX == 3); + static_assert(DEPTH_STENCIL_IDX == 4); + + if (desc.interlockMode == gpu::InterlockMode::atomics) + { + // Clear the coverage texture, which is not an attachment. + VkImageSubresourceRange clearRange = { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .levelCount = 1, + .layerCount = 1, + }; + + // Don't clear the coverage texture until shaders in the previous flush + // have finished using it. + m_vk->imageMemoryBarrier( + commandBuffer, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + 0, + { + .srcAccessMask = + VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, + .dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, + .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED, + .newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + .image = renderTarget->coverageAtomicTexture()->vkImage(), + }); + + const VkClearColorValue coverageClearValue = + vkutil::color_clear_r32ui(desc.coverageClearValue); + m_vk->CmdClearColorImage( + commandBuffer, + renderTarget->coverageAtomicTexture()->vkImage(), + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + &coverageClearValue, + 1, + &clearRange); + + // Don't use the coverage texture in shaders until the clear finishes. + m_vk->imageMemoryBarrier( + commandBuffer, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + 0, + { + .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, + .dstAccessMask = + VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, + .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + .newLayout = VK_IMAGE_LAYOUT_GENERAL, + .image = renderTarget->coverageAtomicTexture()->vkImage(), + }); + } + else if (desc.interlockMode == gpu::InterlockMode::clockwiseAtomic) + { + VkPipelineStageFlags lastCoverageBufferStage = + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + VkAccessFlags lastCoverageBufferAccess = VK_ACCESS_SHADER_WRITE_BIT; + + if (desc.needsCoverageBufferClear) + { + assert(m_coverageBuffer != nullptr); + + // Don't clear the coverage buffer until shaders in the previous + // flush have finished accessing it. + m_vk->bufferMemoryBarrier( + commandBuffer, + lastCoverageBufferStage, + VK_PIPELINE_STAGE_TRANSFER_BIT, + 0, + { + .srcAccessMask = lastCoverageBufferAccess, + .dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, + .buffer = *m_coverageBuffer, + }); + + m_vk->CmdFillBuffer(commandBuffer, + *m_coverageBuffer, + 0, + m_coverageBuffer->info().size, + 0); + + lastCoverageBufferStage = VK_PIPELINE_STAGE_TRANSFER_BIT; + lastCoverageBufferAccess = VK_ACCESS_TRANSFER_WRITE_BIT; + } + + if (m_coverageBuffer != nullptr) + { + // Don't use the coverage buffer until prior clears/accesses + // have completed. + m_vk->bufferMemoryBarrier( + commandBuffer, + lastCoverageBufferStage, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + 0, + { + .srcAccessMask = lastCoverageBufferAccess, + .dstAccessMask = VK_ACCESS_SHADER_READ_BIT, + .buffer = *m_coverageBuffer, + }); + } + } + + // Ensure all reads to any internal attachments complete before we execute + // the load operations. + m_vk->memoryBarrier( + commandBuffer, + // "Load" operations always occur in + // VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT. + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + 0, + { + .srcAccessMask = VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, + .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + }); + + VkRenderPassBeginInfo renderPassBeginInfo = { + .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, + .renderPass = *renderPass, + .framebuffer = *framebuffer, + .renderArea = renderArea, + .clearValueCount = std::size(clearValues), + .pClearValues = clearValues, + }; + + m_vk->CmdBeginRenderPass(commandBuffer, + &renderPassBeginInfo, + VK_SUBPASS_CONTENTS_INLINE); + + m_vk->CmdSetViewport( + commandBuffer, + 0, + 1, + vkutil::ViewportFromRect2D( + {.extent = {renderTarget->width(), renderTarget->height()}})); + + m_vk->CmdSetScissor(commandBuffer, 0, 1, &renderArea); + + // Update the PLS input attachment descriptor sets. + VkDescriptorSet inputAttachmentDescriptorSet = VK_NULL_HANDLE; + if (desc.interlockMode == gpu::InterlockMode::rasterOrdering || + desc.interlockMode == gpu::InterlockMode::atomics) + { + inputAttachmentDescriptorSet = descriptorSetPool->allocateDescriptorSet( + pipelineLayout.plsLayout()); + + if (!desc.atomicFixedFunctionColorOutput) + { + m_vk->updateImageDescriptorSets( + inputAttachmentDescriptorSet, + { + .dstBinding = COLOR_PLANE_IDX, + .descriptorType = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, + }, + {{ + .imageView = colorImageView, + .imageLayout = VK_IMAGE_LAYOUT_GENERAL, + }}); + } + + m_vk->updateImageDescriptorSets( + inputAttachmentDescriptorSet, + { + .dstBinding = CLIP_PLANE_IDX, + .descriptorType = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, + }, + {{ + .imageView = clipTexture->vkImageView(), + .imageLayout = VK_IMAGE_LAYOUT_GENERAL, + }}); + + if (desc.interlockMode == gpu::InterlockMode::rasterOrdering) + { + m_vk->updateImageDescriptorSets( + inputAttachmentDescriptorSet, + { + .dstBinding = SCRATCH_COLOR_PLANE_IDX, + .descriptorType = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, + }, + {{ + .imageView = scratchColorTexture->vkImageView(), + .imageLayout = VK_IMAGE_LAYOUT_GENERAL, + }}); + } + + assert(coverageTexture != nullptr); + m_vk->updateImageDescriptorSets( + inputAttachmentDescriptorSet, + { + .dstBinding = COVERAGE_PLANE_IDX, + .descriptorType = + desc.interlockMode == gpu::InterlockMode::atomics + ? VK_DESCRIPTOR_TYPE_STORAGE_IMAGE + : VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, + }, + {{ + .imageView = coverageTexture->vkImageView(), + .imageLayout = VK_IMAGE_LAYOUT_GENERAL, + }}); + } + + // Bind the descriptor sets for this draw pass. + // (The imageTexture and imageDraw dynamic uniform offsets might have to + // update between draws, but this is otherwise all we need to bind!) + VkDescriptorSet drawDescriptorSets[] = { + perFlushDescriptorSet, + m_nullImageDescriptorSet, + m_immutableSamplerDescriptorSet, + inputAttachmentDescriptorSet, + }; + static_assert(PER_FLUSH_BINDINGS_SET == 0); + static_assert(PER_DRAW_BINDINGS_SET == 1); + static_assert(IMMUTABLE_SAMPLER_BINDINGS_SET == 2); + static_assert(PLS_TEXTURE_BINDINGS_SET == 3); + static_assert(BINDINGS_SET_COUNT == 4); + + m_vk->CmdBindDescriptorSets(commandBuffer, + VK_PIPELINE_BIND_POINT_GRAPHICS, + *pipelineLayout, + PER_FLUSH_BINDINGS_SET, + drawDescriptorSets[PLS_TEXTURE_BINDINGS_SET] != + VK_NULL_HANDLE + ? BINDINGS_SET_COUNT + : BINDINGS_SET_COUNT - 1, + drawDescriptorSets, + 1, + ZERO_OFFSET_32); + + // Execute the DrawList. + uint32_t imageTextureUpdateCount = 0; + for (const DrawBatch& batch : *desc.drawList) + { + assert(batch.elementCount > 0); + const DrawType drawType = batch.drawType; + + if (batch.imageTexture != nullptr) + { + // Update the imageTexture binding and the dynamic offset into the + // imageDraw uniform buffer. + auto imageTexture = + static_cast(batch.imageTexture); + VkDescriptorSet imageDescriptorSet = + imageTexture->getCachedDescriptorSet(m_vk->currentFrameNumber(), + batch.imageSampler); + if (imageDescriptorSet == VK_NULL_HANDLE) + { + // Update the image's "texture binding" descriptor set. (These + // expire every frame, so we need to make a new one each frame.) + if (imageTextureUpdateCount >= + descriptor_pool_limits::kMaxImageTextureUpdates) + { + // We ran out of room for image texture updates. Allocate a + // new pool. + m_descriptorSetPoolPool->recycle( + std::move(descriptorSetPool)); + descriptorSetPool = m_descriptorSetPoolPool->acquire(); + imageTextureUpdateCount = 0; + } + + imageDescriptorSet = descriptorSetPool->allocateDescriptorSet( + m_perDrawDescriptorSetLayout); + + m_vk->updateImageDescriptorSets( + imageDescriptorSet, + { + .dstBinding = IMAGE_TEXTURE_IDX, + .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, + }, + {{ + .imageView = imageTexture->vkImageView(), + .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + }}); + + m_vk->updateImageDescriptorSets( + imageDescriptorSet, + { + .dstBinding = IMAGE_SAMPLER_IDX, + .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER, + }, + {{ + .sampler = m_imageSamplers[batch.imageSampler.asKey()], + }}); + + ++imageTextureUpdateCount; + imageTexture->updateCachedDescriptorSet( + imageDescriptorSet, + m_vk->currentFrameNumber(), + batch.imageSampler); + } + + VkDescriptorSet imageDescriptorSets[] = { + perFlushDescriptorSet, // Dynamic offset to imageDraw uniforms. + imageDescriptorSet, // imageTexture. + }; + static_assert(PER_DRAW_BINDINGS_SET == PER_FLUSH_BINDINGS_SET + 1); + + m_vk->CmdBindDescriptorSets(commandBuffer, + VK_PIPELINE_BIND_POINT_GRAPHICS, + *pipelineLayout, + PER_FLUSH_BINDINGS_SET, + std::size(imageDescriptorSets), + imageDescriptorSets, + 1, + &batch.imageDrawDataOffset); + } + + // Setup the pipeline for this specific drawType and shaderFeatures. + gpu::ShaderFeatures shaderFeatures = + desc.interlockMode == gpu::InterlockMode::atomics + ? desc.combinedShaderFeatures + : batch.shaderFeatures; + + auto shaderMiscFlags = batch.shaderMiscFlags; + if (desc.atomicFixedFunctionColorOutput) + { + shaderMiscFlags |= gpu::ShaderMiscFlags::fixedFunctionColorOutput; + } + if (desc.interlockMode == gpu::InterlockMode::rasterOrdering && + (batch.drawContents & gpu::DrawContents::clockwiseFill)) + { + shaderMiscFlags |= gpu::ShaderMiscFlags::clockwiseFill; + } + if ((pipelineLayout.options() & + DrawPipelineLayoutOptions::coalescedResolveAndTransfer) && + (drawType == gpu::DrawType::atomicResolve)) + { + shaderMiscFlags |= + gpu::ShaderMiscFlags::coalescedResolveAndTransfer; + } + + auto drawPipelineOptions = DrawPipelineOptions::none; + if (desc.wireframe && m_vk->features.fillModeNonSolid) + { + drawPipelineOptions |= DrawPipelineOptions::wireframe; + } + + std::unique_ptr& drawPipeline = + m_drawPipelines[DrawPipeline::Key(drawType, + shaderFeatures, + desc.interlockMode, + shaderMiscFlags, + drawPipelineOptions, + renderPassKey)]; + if (drawPipeline == nullptr) + { + drawPipeline = std::make_unique(this, + drawType, + pipelineLayout, + shaderFeatures, + shaderMiscFlags, + drawPipelineOptions, + *renderPass); + } + m_vk->CmdBindPipeline(commandBuffer, + VK_PIPELINE_BIND_POINT_GRAPHICS, + *drawPipeline); + + if (batch.barriers & BarrierFlags::plsAtomicPreResolve) + { + // The atomic resolve gets its barrier via vkCmdNextSubpass(). + assert(desc.interlockMode == gpu::InterlockMode::atomics); + assert(drawType == gpu::DrawType::atomicResolve); + m_vk->CmdNextSubpass(commandBuffer, VK_SUBPASS_CONTENTS_INLINE); + } + else if (batch.barriers & + (BarrierFlags::plsAtomicPostInit | BarrierFlags::plsAtomic)) + { + // Wait for color attachment writes to complete before we read the + // input attachments again. (We also checked for "plsAtomicPostInit" + // because this barrier has to occur after the Vulkan load + // operations as well.) + assert(desc.interlockMode == gpu::InterlockMode::atomics); + assert(drawType != gpu::DrawType::atomicResolve); + m_vk->memoryBarrier( + commandBuffer, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + VK_DEPENDENCY_BY_REGION_BIT, + { + // TODO: We should add SHADER_READ/SHADER_WRITE flags for + // the coverage buffer as well, but ironically, adding those + // causes artifacts on Qualcomm. Leave them out for now + // unless we find a case where we don't work without them. + .srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + .dstAccessMask = VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, + }); + } + else if (batch.barriers & BarrierFlags::clockwiseBorrowedCoverage) + { + // Wait for prior fragment shaders to finish updating the coverage + // buffer before we read it again. + assert(desc.interlockMode == gpu::InterlockMode::clockwiseAtomic); + m_vk->memoryBarrier(commandBuffer, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + VK_DEPENDENCY_BY_REGION_BIT, + { + .srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT, + .dstAccessMask = VK_ACCESS_SHADER_READ_BIT, + }); + } + + switch (drawType) + { + case DrawType::midpointFanPatches: + case DrawType::midpointFanCenterAAPatches: + case DrawType::outerCurvePatches: + { + // Draw patches that connect the tessellation vertices. + m_vk->CmdBindVertexBuffers( + commandBuffer, + 0, + 1, + m_pathPatchVertexBuffer->vkBufferAddressOf(), + ZERO_OFFSET); + m_vk->CmdBindIndexBuffer(commandBuffer, + *m_pathPatchIndexBuffer, + 0, + VK_INDEX_TYPE_UINT16); + m_vk->CmdDrawIndexed(commandBuffer, + gpu::PatchIndexCount(drawType), + batch.elementCount, + gpu::PatchBaseIndex(drawType), + 0, + batch.baseElement); + break; + } + + case DrawType::interiorTriangulation: + case DrawType::atlasBlit: + { + VkBuffer buffer = *m_triangleBuffer; + m_vk->CmdBindVertexBuffers(commandBuffer, + 0, + 1, + &buffer, + ZERO_OFFSET); + m_vk->CmdDraw(commandBuffer, + batch.elementCount, + 1, + batch.baseElement, + 0); + break; + } + + case DrawType::imageRect: + { + assert(desc.interlockMode == gpu::InterlockMode::atomics); + m_vk->CmdBindVertexBuffers( + commandBuffer, + 0, + 1, + m_imageRectVertexBuffer->vkBufferAddressOf(), + ZERO_OFFSET); + m_vk->CmdBindIndexBuffer(commandBuffer, + *m_imageRectIndexBuffer, + 0, + VK_INDEX_TYPE_UINT16); + m_vk->CmdDrawIndexed(commandBuffer, + std::size(gpu::kImageRectIndices), + 1, + batch.baseElement, + 0, + 0); + break; + } + + case DrawType::imageMesh: + { + LITE_RTTI_CAST_OR_BREAK(vertexBuffer, + RenderBufferVulkanImpl*, + batch.vertexBuffer); + LITE_RTTI_CAST_OR_BREAK(uvBuffer, + RenderBufferVulkanImpl*, + batch.uvBuffer); + LITE_RTTI_CAST_OR_BREAK(indexBuffer, + RenderBufferVulkanImpl*, + batch.indexBuffer); + m_vk->CmdBindVertexBuffers( + commandBuffer, + 0, + 1, + vertexBuffer->currentBuffer()->vkBufferAddressOf(), + ZERO_OFFSET); + m_vk->CmdBindVertexBuffers( + commandBuffer, + 1, + 1, + uvBuffer->currentBuffer()->vkBufferAddressOf(), + ZERO_OFFSET); + m_vk->CmdBindIndexBuffer(commandBuffer, + *indexBuffer->currentBuffer(), + 0, + VK_INDEX_TYPE_UINT16); + m_vk->CmdDrawIndexed(commandBuffer, + batch.elementCount, + 1, + batch.baseElement, + 0, + 0); + break; + } + + case DrawType::atomicResolve: + { + assert(desc.interlockMode == gpu::InterlockMode::atomics); + m_vk->CmdDraw(commandBuffer, 4, 1, 0, 0); + break; + } + + case DrawType::atomicInitialize: + case DrawType::msaaStrokes: + case DrawType::msaaMidpointFanBorrowedCoverage: + case DrawType::msaaMidpointFans: + case DrawType::msaaMidpointFanStencilReset: + case DrawType::msaaMidpointFanPathsStencil: + case DrawType::msaaMidpointFanPathsCover: + case DrawType::msaaOuterCubics: + case DrawType::msaaStencilClipReset: + RIVE_UNREACHABLE(); + } + } + + m_vk->CmdEndRenderPass(commandBuffer); + + if (colorAttachmentIsOffscreen && + !(pipelineLayout.options() & + DrawPipelineLayoutOptions::coalescedResolveAndTransfer)) + { + // Copy from the offscreen texture back to the target. + m_vk->blitSubRect( + commandBuffer, + renderTarget + ->accessOffscreenColorTexture( + commandBuffer, + { + .pipelineStages = VK_PIPELINE_STAGE_TRANSFER_BIT, + .accessMask = VK_ACCESS_TRANSFER_READ_BIT, + .layout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + }) + ->vkImage(), + renderTarget->accessTargetImage( + commandBuffer, + { + .pipelineStages = VK_PIPELINE_STAGE_TRANSFER_BIT, + .accessMask = VK_ACCESS_TRANSFER_WRITE_BIT, + .layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + }, + vkutil::ImageAccessAction::invalidateContents), + desc.renderTargetUpdateBounds); + } + + m_descriptorSetPoolPool->recycle(std::move(descriptorSetPool)); +} + +void RenderContextVulkanImpl::postFlush(const RenderContext::FlushResources&) +{ + // Recycle buffers. + m_flushUniformBufferPool.recycle(std::move(m_flushUniformBuffer)); + m_imageDrawUniformBufferPool.recycle(std::move(m_imageDrawUniformBuffer)); + m_pathBufferPool.recycle(std::move(m_pathBuffer)); + m_paintBufferPool.recycle(std::move(m_paintBuffer)); + m_paintAuxBufferPool.recycle(std::move(m_paintAuxBuffer)); + m_contourBufferPool.recycle(std::move(m_contourBuffer)); + m_gradSpanBufferPool.recycle(std::move(m_gradSpanBuffer)); + m_tessSpanBufferPool.recycle(std::move(m_tessSpanBuffer)); + m_triangleBufferPool.recycle(std::move(m_triangleBuffer)); +} + +void RenderContextVulkanImpl::hotloadShaders( + rive::Span spirvData) +{ + spirv::hotload_shaders(spirvData); + + // Delete and replace old shaders + m_colorRampPipeline = std::make_unique(this); + m_tessellatePipeline = std::make_unique(this); + m_atlasPipeline = std::make_unique(this); + m_drawShaders.clear(); + m_drawPipelines.clear(); +} + +std::unique_ptr RenderContextVulkanImpl::MakeContext( + VkInstance instance, + VkPhysicalDevice physicalDevice, + VkDevice device, + const VulkanFeatures& features, + PFN_vkGetInstanceProcAddr pfnvkGetInstanceProcAddr) +{ + rcp vk = make_rcp(instance, + physicalDevice, + device, + features, + pfnvkGetInstanceProcAddr); + VkPhysicalDeviceProperties physicalDeviceProps; + vk->GetPhysicalDeviceProperties(vk->physicalDevice, &physicalDeviceProps); + std::unique_ptr impl( + new RenderContextVulkanImpl(std::move(vk), physicalDeviceProps)); + if (!impl->platformFeatures().supportsRasterOrdering && + !impl->platformFeatures().supportsFragmentShaderAtomics) + { + return nullptr; // TODO: implement MSAA. + } + impl->initGPUObjects(); + return std::make_unique(std::move(impl)); +} +} // namespace rive::gpu diff --git a/third_party/rive_renderer/source/vulkan/render_target_vulkan.cpp b/third_party/rive_renderer/source/vulkan/render_target_vulkan.cpp new file mode 100644 index 0000000..088cdb9 --- /dev/null +++ b/third_party/rive_renderer/source/vulkan/render_target_vulkan.cpp @@ -0,0 +1,178 @@ +/* + * Copyright 2023 Rive + */ + +#include "rive/renderer/vulkan/render_target_vulkan.hpp" + +#include "rive/renderer/vulkan/render_context_vulkan_impl.hpp" + +namespace rive::gpu +{ +RenderTargetVulkan::RenderTargetVulkan(rcp vk, + uint32_t width, + uint32_t height, + VkFormat framebufferFormat, + VkImageUsageFlags targetUsageFlags) : + RenderTarget(width, height), + m_vk(std::move(vk)), + m_framebufferFormat(framebufferFormat), + m_targetUsageFlags(targetUsageFlags) +{ +#ifndef NDEBUG + // In order to implement blend modes, the target texture needs to either + // support input attachment usage (ideal), or else transfers. + constexpr static VkImageUsageFlags TRANSFER_SRC_AND_DST = + VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; + assert((m_targetUsageFlags & VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT) || + (m_targetUsageFlags & TRANSFER_SRC_AND_DST) == TRANSFER_SRC_AND_DST); +#endif +} + +VkImage RenderTargetVulkanImpl::accessTargetImage( + VkCommandBuffer commandBuffer, + const vkutil::ImageAccess& dstAccess, + vkutil::ImageAccessAction imageAccessAction) +{ + m_targetLastAccess = m_vk->simpleImageMemoryBarrier(commandBuffer, + m_targetLastAccess, + dstAccess, + m_targetImage, + imageAccessAction); + return m_targetImage; +} + +VkImageView RenderTargetVulkanImpl::accessTargetImageView( + VkCommandBuffer commandBuffer, + const vkutil::ImageAccess& dstAccess, + vkutil::ImageAccessAction imageAccessAction) +{ + accessTargetImage(commandBuffer, dstAccess, imageAccessAction); + return m_targetImageView; +} + +vkutil::Texture2D* RenderTargetVulkan::accessOffscreenColorTexture( + VkCommandBuffer commandBuffer, + const vkutil::ImageAccess& dstAccess, + vkutil::ImageAccessAction imageAccessAction) +{ + if (m_offscreenColorTexture == nullptr) + { + m_offscreenColorTexture = m_vk->makeTexture2D({ + .format = m_framebufferFormat, + .extent = {width(), height()}, + .usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | + VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | + VK_IMAGE_USAGE_TRANSFER_SRC_BIT | + VK_IMAGE_USAGE_TRANSFER_DST_BIT, + }); + } + + m_offscreenColorTexture->barrier(commandBuffer, + dstAccess, + imageAccessAction); + + return m_offscreenColorTexture.get(); +} + +vkutil::Texture2D* RenderTargetVulkan::clipTextureR32UI() +{ + if (m_clipTextureR32UI == nullptr) + { + m_clipTextureR32UI = m_vk->makeTexture2D({ + .format = VK_FORMAT_R32_UINT, + .extent = {width(), height()}, + .usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | + VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT | + VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT, + }); + } + return m_clipTextureR32UI.get(); +} + +vkutil::Texture2D* RenderTargetVulkan::scratchColorTexture() +{ + if (m_scratchColorTexture == nullptr) + { + m_scratchColorTexture = m_vk->makeTexture2D({ + .format = m_framebufferFormat, + .extent = {width(), height()}, + .usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | + VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT | + VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT, + }); + } + return m_scratchColorTexture.get(); +} + +vkutil::Texture2D* RenderTargetVulkan::coverageTexture() +{ + if (m_coverageTexture == nullptr) + { + m_coverageTexture = m_vk->makeTexture2D({ + .format = VK_FORMAT_R32_UINT, + .extent = {width(), height()}, + .usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | + VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT | + VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT, + }); + } + return m_coverageTexture.get(); +} + +vkutil::Texture2D* RenderTargetVulkan::clipTextureRGBA8() +{ + if (m_clipTextureRGBA8 == nullptr) + { + m_clipTextureRGBA8 = m_vk->makeTexture2D({ + .format = VK_FORMAT_R8G8B8A8_UNORM, + .extent = {width(), height()}, + .usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | + VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT | + VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT, + }); + } + return m_clipTextureRGBA8.get(); +} + +vkutil::Texture2D* RenderTargetVulkan::coverageAtomicTexture() +{ + if (m_coverageAtomicTexture == nullptr) + { + m_coverageAtomicTexture = m_vk->makeTexture2D({ + .format = VK_FORMAT_R32_UINT, + .extent = {width(), height()}, + .usage = + VK_IMAGE_USAGE_STORAGE_BIT | + VK_IMAGE_USAGE_TRANSFER_DST_BIT, // For vkCmdClearColorImage + }); + } + return m_coverageAtomicTexture.get(); +} + +vkutil::Texture2D* RenderTargetVulkan::depthStencilTexture() +{ + if (m_depthStencilTexture == nullptr) + { + m_depthStencilTexture = m_vk->makeTexture2D({ + .format = vkutil::get_preferred_depth_stencil_format( + m_vk->supportsD24S8()), + .extent = {width(), height()}, + .usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, + }); + } + return m_depthStencilTexture.get(); +} + +rcp RenderContextVulkanImpl::makeRenderTarget( + uint32_t width, + uint32_t height, + VkFormat framebufferFormat, + VkImageUsageFlags targetUsageFlags) +{ + return rcp(new RenderTargetVulkanImpl(m_vk, + width, + height, + framebufferFormat, + targetUsageFlags)); +} +} // namespace rive::gpu diff --git a/third_party/rive_renderer/source/vulkan/vkutil.cpp b/third_party/rive_renderer/source/vulkan/vkutil.cpp new file mode 100644 index 0000000..ffc8269 --- /dev/null +++ b/third_party/rive_renderer/source/vulkan/vkutil.cpp @@ -0,0 +1,463 @@ +/* + * Copyright 2023 Rive + */ + +#include "rive/renderer/vulkan/vkutil.hpp" + +#include "rive/rive_types.hpp" +#include "rive/renderer/vulkan/vulkan_context.hpp" +#include + +namespace rive::gpu::vkutil +{ +Resource::Resource(rcp vk) : GPUResource(std::move(vk)) {} + +VulkanContext* Resource::vk() const +{ + return static_cast(m_manager.get()); +} + +Buffer::Buffer(rcp vk, + const VkBufferCreateInfo& info, + Mappability mappability) : + Resource(std::move(vk)), m_mappability(mappability), m_info(info) +{ + m_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + init(); +} + +Buffer::~Buffer() { resizeImmediately(0); } + +void Buffer::resizeImmediately(VkDeviceSize sizeInBytes) +{ + if (m_info.size != sizeInBytes) + { + if (m_vmaAllocation != VK_NULL_HANDLE) + { + if (m_mappability != Mappability::none) + { + vmaUnmapMemory(vk()->allocator(), m_vmaAllocation); + } + vmaDestroyBuffer(vk()->allocator(), m_vkBuffer, m_vmaAllocation); + } + m_info.size = sizeInBytes; + init(); + } +} + +VmaAllocationCreateFlags vma_flags_for_mappability(Mappability mappability) +{ + switch (mappability) + { + case Mappability::none: + return 0; + case Mappability::writeOnly: + return VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT; + case Mappability::readWrite: + return VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT; + } + RIVE_UNREACHABLE(); +} + +void Buffer::init() +{ + if (m_info.size > 0) + { + VmaAllocationCreateInfo allocInfo = { + .flags = vma_flags_for_mappability(m_mappability), + .usage = VMA_MEMORY_USAGE_AUTO, + }; + + VK_CHECK(vmaCreateBuffer(vk()->allocator(), + &m_info, + &allocInfo, + &m_vkBuffer, + &m_vmaAllocation, + nullptr)); + + if (m_mappability != Mappability::none) + { + // Leave the buffer constantly mapped and let the OS/drivers handle + // the rest. + VK_CHECK( + vmaMapMemory(vk()->allocator(), m_vmaAllocation, &m_contents)); + } + else + { + m_contents = nullptr; + } + } + else + { + m_vkBuffer = VK_NULL_HANDLE; + m_vmaAllocation = VK_NULL_HANDLE; + m_contents = nullptr; + } +} + +void Buffer::flushContents(VkDeviceSize updatedSizeInBytes) +{ + vmaFlushAllocation(vk()->allocator(), + m_vmaAllocation, + 0, + updatedSizeInBytes); +} + +void Buffer::invalidateContents(VkDeviceSize updatedSizeInBytes) +{ + vmaInvalidateAllocation(vk()->allocator(), + m_vmaAllocation, + 0, + updatedSizeInBytes); +} + +BufferPool::BufferPool(rcp vk, + VkBufferUsageFlags usageFlags, + VkDeviceSize size) : + GPUResourcePool(std::move(vk), MAX_POOL_SIZE), + m_usageFlags(usageFlags), + m_targetSize(size) +{} + +inline VulkanContext* BufferPool::vk() const +{ + return static_cast(m_manager.get()); +} + +void BufferPool::setTargetSize(VkDeviceSize size) +{ + // Buffers always get bound, even if unused, so make sure they aren't empty + // and we get a valid Vulkan handle. + size = std::max(size, 1); + + if (m_usageFlags & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT) + { + // Uniform blocks must be multiples of 256 bytes in size. + size = std::max(size, 256); + assert(size % 256 == 0); + } + + m_targetSize = size; +} + +rcp BufferPool::acquire() +{ + auto buffer = static_rcp_cast(GPUResourcePool::acquire()); + if (buffer == nullptr) + { + buffer = vk()->makeBuffer( + { + .size = m_targetSize, + .usage = m_usageFlags, + }, + Mappability::writeOnly); + } + else if (buffer->info().size != m_targetSize) + { + buffer->resizeImmediately(m_targetSize); + } + return buffer; +} + +Image::Image(rcp vulkanContext, const VkImageCreateInfo& info) : + Resource(std::move(vulkanContext)), m_info(info) +{ + m_info = info; + m_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + + if (m_info.mipLevels == 0) + { + m_info.mipLevels = 1; + } + else if (m_info.mipLevels > 1) + { + // We generate mipmaps internally with image blits. + m_info.usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + } + + if (m_info.arrayLayers == 0) + { + m_info.arrayLayers = 1; + } + + if (m_info.samples == 0) + { + m_info.samples = VK_SAMPLE_COUNT_1_BIT; + } + + if (m_info.usage & VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT) + { + // Attempt to create transient attachments with lazily-allocated memory. + // This should succeed on mobile. Otherwise, use normal memory. + VmaAllocationCreateInfo allocInfo = { + .usage = VMA_MEMORY_USAGE_GPU_LAZILY_ALLOCATED, + }; + + if (vmaCreateImage(vk()->allocator(), + &m_info, + &allocInfo, + &m_vkImage, + &m_vmaAllocation, + nullptr) == VK_SUCCESS) + { + return; + } + } + + VmaAllocationCreateInfo allocInfo = { + .usage = VMA_MEMORY_USAGE_AUTO, + }; + + VK_CHECK(vmaCreateImage(vk()->allocator(), + &m_info, + &allocInfo, + &m_vkImage, + &m_vmaAllocation, + nullptr)); +} + +Image::~Image() +{ + if (m_vmaAllocation != VK_NULL_HANDLE) + { + vmaDestroyImage(vk()->allocator(), m_vkImage, m_vmaAllocation); + } +} + +ImageView::ImageView(rcp vulkanContext, + rcp textureRef, + const VkImageViewCreateInfo& info) : + Resource(std::move(vulkanContext)), + m_textureRefOrNull(std::move(textureRef)), + m_info(info) +{ + assert(m_textureRefOrNull == nullptr || info.image == *m_textureRefOrNull); + m_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + VK_CHECK( + vk()->CreateImageView(vk()->device, &m_info, nullptr, &m_vkImageView)); +} + +ImageView::~ImageView() +{ + vk()->DestroyImageView(vk()->device, m_vkImageView, nullptr); +} + +Texture2D::Texture2D(rcp vk, VkImageCreateInfo info) : + rive::gpu::Texture(info.extent.width, info.extent.height), + m_lastAccess({ + .pipelineStages = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + .accessMask = VK_ACCESS_NONE, + .layout = VK_IMAGE_LAYOUT_UNDEFINED, + }) +{ + assert(info.imageType == 0 || info.imageType == VK_IMAGE_TYPE_2D); + if (info.imageType == 0) + { + info.imageType = VK_IMAGE_TYPE_2D; + } + if (info.extent.depth == 0) + { + info.extent.depth = 1; + } + if (info.usage == 0) + { + info.usage = + VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; + } + m_image = vk->makeImage(info); + m_imageView = vk->makeImageView(m_image); +} + +void Texture2D::stageContentsForUpload(const void* imageData, + size_t imageDataSizeInBytes) +{ + m_imageUploadBuffer = m_image->vk()->makeBuffer( + { + .size = imageDataSizeInBytes, + .usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT, + }, + vkutil::Mappability::writeOnly); + memcpy(m_imageUploadBuffer->contents(), imageData, imageDataSizeInBytes); + m_imageUploadBuffer->flushContents(); +} + +void Texture2D::synchronize(VkCommandBuffer commandBuffer) +{ + assert(hasUpdates()); + assert(m_imageUploadBuffer != nullptr); + + VkBufferImageCopy bufferImageCopy = { + .imageSubresource = + { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .layerCount = 1, + }, + .imageExtent = {width(), height(), 1}, + }; + + barrier(commandBuffer, + { + .pipelineStages = VK_PIPELINE_STAGE_TRANSFER_BIT, + .accessMask = VK_ACCESS_TRANSFER_WRITE_BIT, + .layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + }, + vkutil::ImageAccessAction::invalidateContents); + + m_image->vk()->CmdCopyBufferToImage(commandBuffer, + *m_imageUploadBuffer, + *m_image, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 1, + &bufferImageCopy); + + generateMipmaps(commandBuffer, + { + .pipelineStages = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + .accessMask = VK_ACCESS_SHADER_READ_BIT, + .layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + }); + + m_imageUploadBuffer = nullptr; +} + +void Texture2D::barrier(VkCommandBuffer commandBuffer, + const vkutil::ImageAccess& dstAccess, + vkutil::ImageAccessAction imageAccessAction, + VkDependencyFlags dependencyFlags) +{ + m_lastAccess = m_image->vk()->simpleImageMemoryBarrier(commandBuffer, + m_lastAccess, + dstAccess, + *m_image, + imageAccessAction, + dependencyFlags); +} + +void Texture2D::generateMipmaps(VkCommandBuffer commandBuffer, + const ImageAccess& dstAccess) +{ + VulkanContext* vk = m_image->vk(); + uint32_t mipLevels = m_image->info().mipLevels; + if (mipLevels <= 1) + { + barrier(commandBuffer, dstAccess); + return; + } + + barrier(commandBuffer, + { + .pipelineStages = VK_PIPELINE_STAGE_TRANSFER_BIT, + .accessMask = VK_ACCESS_TRANSFER_WRITE_BIT, + .layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + }); + + int2 dstSize, srcSize = {static_cast(width()), + static_cast(height())}; + for (uint32_t level = 1; level < mipLevels; ++level, srcSize = dstSize) + { + dstSize = simd::max(srcSize >> 1, int2(1)); + + VkImageBlit imageBlit = { + .srcSubresource = + { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .mipLevel = level - 1, + .layerCount = 1, + }, + .dstSubresource = + { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .mipLevel = level, + .layerCount = 1, + }, + }; + + imageBlit.srcOffsets[0] = {0, 0, 0}; + imageBlit.srcOffsets[1] = {srcSize.x, srcSize.y, 1}; + + imageBlit.dstOffsets[0] = {0, 0, 0}; + imageBlit.dstOffsets[1] = {dstSize.x, dstSize.y, 1}; + + vk->imageMemoryBarrier( + commandBuffer, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + 0, + { + .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, + .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT, + .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + .newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + .image = *m_image, + .subresourceRange = + { + .baseMipLevel = level - 1, + .levelCount = 1, + }, + }); + + vk->CmdBlitImage(commandBuffer, + *m_image, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + *m_image, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 1, + &imageBlit, + VK_FILTER_LINEAR); + } + + VkImageMemoryBarrier barriers[] = { + { + // The first N - 1 layers are in TRANSFER_READ. + .srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT, + .dstAccessMask = dstAccess.accessMask, + .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + .newLayout = dstAccess.layout, + .image = *m_image, + .subresourceRange = + { + .baseMipLevel = 0, + .levelCount = mipLevels - 1, + }, + }, + { + // The final layer is still in TRANSFER_WRITE. + .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, + .dstAccessMask = dstAccess.accessMask, + .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + .newLayout = dstAccess.layout, + .image = *m_image, + .subresourceRange = + { + .baseMipLevel = mipLevels - 1, + .levelCount = 1, + }, + }, + }; + + vk->imageMemoryBarriers(commandBuffer, + VK_PIPELINE_STAGE_TRANSFER_BIT, + dstAccess.pipelineStages, + 0, + std::size(barriers), + barriers); + + m_lastAccess = dstAccess; +} + +Framebuffer::Framebuffer(rcp vulkanContext, + const VkFramebufferCreateInfo& info) : + Resource(std::move(vulkanContext)), m_info(info) +{ + m_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + VK_CHECK(vk()->CreateFramebuffer(vk()->device, + &m_info, + nullptr, + &m_vkFramebuffer)); +} + +Framebuffer::~Framebuffer() +{ + vk()->DestroyFramebuffer(vk()->device, m_vkFramebuffer, nullptr); +} +} // namespace rive::gpu::vkutil diff --git a/third_party/rive_renderer/source/vulkan/vulkan_context.cpp b/third_party/rive_renderer/source/vulkan/vulkan_context.cpp new file mode 100644 index 0000000..a6c511a --- /dev/null +++ b/third_party/rive_renderer/source/vulkan/vulkan_context.cpp @@ -0,0 +1,346 @@ +/* + * Copyright 2023 Rive + */ + +#include "rive/renderer/vulkan/vulkan_context.hpp" + +#include "rive/rive_types.hpp" +#include + +namespace rive::gpu +{ +static VmaAllocator make_vma_allocator( + const VulkanContext* vk, + PFN_vkGetInstanceProcAddr pfnvkGetInstanceProcAddr) +{ + VmaAllocator vmaAllocator; + VmaVulkanFunctions vmaVulkanFunctions = { + .vkGetInstanceProcAddr = pfnvkGetInstanceProcAddr, + .vkGetDeviceProcAddr = vk->GetDeviceProcAddr, + .vkGetPhysicalDeviceProperties = vk->GetPhysicalDeviceProperties, + }; + VmaAllocatorCreateInfo vmaCreateInfo = { + // We are single-threaded. + .flags = VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT, + .physicalDevice = vk->physicalDevice, + .device = vk->device, + .pVulkanFunctions = &vmaVulkanFunctions, + .instance = vk->instance, + .vulkanApiVersion = vk->features.apiVersion, + }; + VK_CHECK(vmaCreateAllocator(&vmaCreateInfo, &vmaAllocator)); + return vmaAllocator; +} + +VulkanContext::VulkanContext( + VkInstance instance, + VkPhysicalDevice physicalDevice_, + VkDevice device_, + const VulkanFeatures& features_, + PFN_vkGetInstanceProcAddr pfnvkGetInstanceProcAddr) : + instance(instance), + physicalDevice(physicalDevice_), + device(device_), + features(features_), +#define LOAD_VULKAN_INSTANCE_COMMAND(CMD) \ + CMD(reinterpret_cast( \ + pfnvkGetInstanceProcAddr(instance, "vk" #CMD))), + RIVE_VULKAN_INSTANCE_COMMANDS(LOAD_VULKAN_INSTANCE_COMMAND) +#undef LOAD_VULKAN_INSTANCE_COMMAND +#define LOAD_VULKAN_DEVICE_COMMAND(CMD) \ + CMD(reinterpret_cast(GetDeviceProcAddr(device, "vk" #CMD))), + RIVE_VULKAN_DEVICE_COMMANDS(LOAD_VULKAN_DEVICE_COMMAND) +#undef LOAD_VULKAN_DEVICE_COMMAND + m_vmaAllocator(make_vma_allocator(this, pfnvkGetInstanceProcAddr)) +{ + // VK spec says between D24_S8 and D32_S8, one of them must be supported + m_supportsD24S8 = isFormatSupportedWithFeatureFlags( + VK_FORMAT_D24_UNORM_S8_UINT, + VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT); + + // This assert should never fire unless some hardware is breaking the VK + // spec by reporting that it does not support one of these formats. + assert((m_supportsD24S8 || + isFormatSupportedWithFeatureFlags( + VK_FORMAT_D32_SFLOAT_S8_UINT, + VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)) && + "No suitable depth format supported!"); +} + +VulkanContext::~VulkanContext() { vmaDestroyAllocator(m_vmaAllocator); } + +bool VulkanContext::isFormatSupportedWithFeatureFlags( + VkFormat format, + VkFormatFeatureFlagBits featureFlags) +{ + // Can flesch this out, but currently just checks if format's optimal tiling + // features include the provided bits. + VkFormatProperties properties; + GetPhysicalDeviceFormatProperties(physicalDevice, format, &properties); + return properties.optimalTilingFeatures & featureFlags; +} + +rcp VulkanContext::makeBuffer(const VkBufferCreateInfo& info, + vkutil::Mappability mappability) +{ + return rcp(new vkutil::Buffer(ref_rcp(this), info, mappability)); +} + +rcp VulkanContext::makeImage(const VkImageCreateInfo& info) +{ + return rcp(new vkutil::Image(ref_rcp(this), info)); +} + +rcp VulkanContext::makeFramebuffer( + const VkFramebufferCreateInfo& info) +{ + return rcp(new vkutil::Framebuffer(ref_rcp(this), info)); +} + +static VkImageViewType image_view_type_for_image_type(VkImageType type) +{ + switch (type) + { + case VK_IMAGE_TYPE_2D: + return VK_IMAGE_VIEW_TYPE_2D; + default: + fprintf( + stderr, + "vkutil::image_view_type_for_image_type: VkImageType %u is not " + "supported\n", + type); + } + RIVE_UNREACHABLE(); +} + +static VkImageAspectFlags image_aspect_flags_for_format(VkFormat format) +{ + switch (format) + { + case VK_FORMAT_D24_UNORM_S8_UINT: + case VK_FORMAT_D32_SFLOAT_S8_UINT: + return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; + default: + return VK_IMAGE_ASPECT_COLOR_BIT; + } + RIVE_UNREACHABLE(); +} + +rcp VulkanContext::makeImageView(rcp image) +{ + const VkImageCreateInfo& texInfo = image->info(); + + return makeImageView( + image, + { + .image = *image, + .viewType = image_view_type_for_image_type(texInfo.imageType), + .format = texInfo.format, + .subresourceRange = + { + .aspectMask = image_aspect_flags_for_format(texInfo.format), + .levelCount = texInfo.mipLevels, + .layerCount = 1, + }, + }); +} + +rcp VulkanContext::makeImageView( + rcp image, + const VkImageViewCreateInfo& info) +{ + assert(image); + return rcp(new vkutil::ImageView(ref_rcp(this), std::move(image), info)); +} + +rcp VulkanContext::makeExternalImageView( + const VkImageViewCreateInfo& info) +{ + return rcp( + new vkutil::ImageView(ref_rcp(this), nullptr, info)); +} + +rcp VulkanContext::makeTexture2D( + const VkImageCreateInfo& info) +{ + return rcp(new vkutil::Texture2D(ref_rcp(this), info)); +} + +void VulkanContext::updateImageDescriptorSets( + VkDescriptorSet vkDescriptorSet, + VkWriteDescriptorSet writeSet, + std::initializer_list imageInfos) +{ + writeSet.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + writeSet.dstSet = vkDescriptorSet; + writeSet.descriptorCount = + math::lossless_numeric_cast(imageInfos.size()); + writeSet.pImageInfo = imageInfos.begin(); + UpdateDescriptorSets(device, 1, &writeSet, 0, nullptr); +} + +void VulkanContext::updateBufferDescriptorSets( + VkDescriptorSet vkDescriptorSet, + VkWriteDescriptorSet writeSet, + std::initializer_list bufferInfos) +{ + writeSet.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + writeSet.dstSet = vkDescriptorSet; + writeSet.descriptorCount = + math::lossless_numeric_cast(bufferInfos.size()); + writeSet.pBufferInfo = bufferInfos.begin(); + UpdateDescriptorSets(device, 1, &writeSet, 0, nullptr); +} + +void VulkanContext::memoryBarrier(VkCommandBuffer commandBuffer, + VkPipelineStageFlags srcStageMask, + VkPipelineStageFlags dstStageMask, + VkDependencyFlags dependencyFlags, + VkMemoryBarrier memoryBarrier) +{ + memoryBarrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER; + CmdPipelineBarrier(commandBuffer, + srcStageMask, + dstStageMask, + dependencyFlags, + 1, + &memoryBarrier, + 0, + nullptr, + 0, + nullptr); +} + +void VulkanContext::imageMemoryBarriers( + VkCommandBuffer commandBuffer, + VkPipelineStageFlags srcStageMask, + VkPipelineStageFlags dstStageMask, + VkDependencyFlags dependencyFlags, + uint32_t count, + VkImageMemoryBarrier* imageMemoryBarriers) +{ + for (uint32_t i = 0; i < count; ++i) + { + auto& imageMemoryBarrier = imageMemoryBarriers[i]; + imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + if (imageMemoryBarrier.subresourceRange.aspectMask == 0) + { + imageMemoryBarrier.subresourceRange.aspectMask = + VK_IMAGE_ASPECT_COLOR_BIT; + } + if (imageMemoryBarrier.subresourceRange.levelCount == 0) + { + imageMemoryBarrier.subresourceRange.levelCount = + VK_REMAINING_MIP_LEVELS; + } + if (imageMemoryBarrier.subresourceRange.layerCount == 0) + { + imageMemoryBarrier.subresourceRange.layerCount = + VK_REMAINING_ARRAY_LAYERS; + } + } + CmdPipelineBarrier(commandBuffer, + srcStageMask, + dstStageMask, + dependencyFlags, + 0, + nullptr, + 0, + nullptr, + count, + imageMemoryBarriers); +} + +const vkutil::ImageAccess& VulkanContext::simpleImageMemoryBarrier( + VkCommandBuffer commandBuffer, + const vkutil::ImageAccess& srcAccess, + const vkutil::ImageAccess& dstAccess, + VkImage image, + vkutil::ImageAccessAction imageAccessAction, + VkDependencyFlags dependencyFlags) +{ + assert(image != VK_NULL_HANDLE); + if (srcAccess != dstAccess) + { + imageMemoryBarrier( + commandBuffer, + srcAccess.pipelineStages, + dstAccess.pipelineStages, + dependencyFlags, + { + .srcAccessMask = srcAccess.accessMask, + .dstAccessMask = dstAccess.accessMask, + .oldLayout = imageAccessAction == + vkutil::ImageAccessAction::preserveContents + ? srcAccess.layout + : VK_IMAGE_LAYOUT_UNDEFINED, + .newLayout = dstAccess.layout, + .image = image, + }); + } + return dstAccess; +} + +void VulkanContext::bufferMemoryBarrier( + VkCommandBuffer commandBuffer, + VkPipelineStageFlags srcStageMask, + VkPipelineStageFlags dstStageMask, + VkDependencyFlags dependencyFlags, + VkBufferMemoryBarrier bufferMemoryBarrier) +{ + bufferMemoryBarrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; + if (bufferMemoryBarrier.size == 0) + { + bufferMemoryBarrier.size = VK_WHOLE_SIZE; + } + CmdPipelineBarrier(commandBuffer, + srcStageMask, + dstStageMask, + dependencyFlags, + 0, + nullptr, + 1, + &bufferMemoryBarrier, + 0, + nullptr); +} + +void VulkanContext::blitSubRect(VkCommandBuffer commandBuffer, + VkImage src, + VkImage dst, + const IAABB& blitBounds) +{ + if (blitBounds.empty()) + { + return; + } + + VkImageBlit imageBlit = { + .srcSubresource = + { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .layerCount = 1, + }, + .dstSubresource = + { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .layerCount = 1, + }, + }; + + imageBlit.srcOffsets[0] = {blitBounds.left, blitBounds.top, 0}; + imageBlit.srcOffsets[1] = {blitBounds.right, blitBounds.bottom, 1}; + + imageBlit.dstOffsets[0] = {blitBounds.left, blitBounds.top, 0}; + imageBlit.dstOffsets[1] = {blitBounds.right, blitBounds.bottom, 1}; + + CmdBlitImage(commandBuffer, + src, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + dst, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 1, + &imageBlit, + VK_FILTER_NEAREST); +} +} // namespace rive::gpu diff --git a/third_party/rive_renderer/source/vulkan/vulkan_memory_allocator.cpp b/third_party/rive_renderer/source/vulkan/vulkan_memory_allocator.cpp new file mode 100644 index 0000000..7a6837c --- /dev/null +++ b/third_party/rive_renderer/source/vulkan/vulkan_memory_allocator.cpp @@ -0,0 +1,2 @@ +#define VMA_IMPLEMENTATION +#include diff --git a/third_party/rive_renderer/source/webgpu/em_js_handle.cpp b/third_party/rive_renderer/source/webgpu/em_js_handle.cpp new file mode 100644 index 0000000..5d1f1d0 --- /dev/null +++ b/third_party/rive_renderer/source/webgpu/em_js_handle.cpp @@ -0,0 +1,100 @@ +/* + * Copyright 2023 Rive + */ + +#include "rive/renderer/webgpu/em_js_handle.hpp" + +EmJsHandle& EmJsHandle::operator=(EmJsHandle&& rhs) +{ + int tmp = rhs.m_handle; + rhs.m_handle = this->m_handle; + this->m_handle = tmp; + return *this; +} + +#ifdef RIVE_DAWN +EmJsHandle::~EmJsHandle() { assert(m_handle == 0); } + +wgpu::ShaderModule EmJsHandle::compileShaderModule(wgpu::Device device, + const char* language, + const char* source) +{ + RIVE_UNREACHABLE(); +} + +wgpu::ShaderModule EmJsHandle::compileSPIRVShaderModule(wgpu::Device device, + const uint32_t* code, + uint32_t codeSize) +{ + wgpu::ShaderModuleSPIRVDescriptor spirvDesc; + spirvDesc.code = code; + spirvDesc.codeSize = codeSize; + wgpu::ShaderModuleDescriptor descriptor; + descriptor.nextInChain = &spirvDesc; + return device.CreateShaderModule(&descriptor); +} +#endif + +#ifdef RIVE_WEBGPU +EmJsHandle::~EmJsHandle() +{ + if (m_handle != 0) + { + emscripten_webgpu_release_js_handle(m_handle); + } +} + +EM_JS(int, + compile_glsl_shader_module_js, + (int device, const char* language, const char* source), + { + device = JsValStore.get(device); + language = UTF8ToString(language); + source = UTF8ToString(source); + const shader = device.createShaderModule({ + language : language, + code : source, + }); + return JsValStore.add(shader); + }); + +wgpu::ShaderModule EmJsHandle::compileShaderModule(wgpu::Device device, + const char* language, + const char* source) +{ + m_handle = compile_glsl_shader_module_js( + emscripten_webgpu_export_device(device.Get()), + source, + language); + return wgpu::ShaderModule::Acquire( + emscripten_webgpu_import_shader_module(m_handle)); +} + +EM_JS(int, + compile_spirv_shader_module_js, + (int device, uintptr_t indexU32, uint32_t codeSize), + { + device = JsValStore.get(device); + // Copy data off the WASM heap before sending it to WebGPU bindings. + const code = new Uint32Array(codeSize); + code.set(Module.HEAPU32.subarray(indexU32, indexU32 + codeSize)); + const shader = device.createShaderModule({ + language : "spirv", + code : code, + }); + return JsValStore.add(shader); + }); + +wgpu::ShaderModule EmJsHandle::compileSPIRVShaderModule(wgpu::Device device, + const uint32_t* code, + uint32_t codeSize) +{ + assert(reinterpret_cast(code) % sizeof(uint32_t) == 0); + m_handle = compile_spirv_shader_module_js( + emscripten_webgpu_export_device(device.Get()), + reinterpret_cast(code) / sizeof(uint32_t), + codeSize); + return wgpu::ShaderModule::Acquire( + emscripten_webgpu_import_shader_module(m_handle)); +} +#endif diff --git a/third_party/rive_renderer/source/webgpu/render_context_webgpu_impl.cpp b/third_party/rive_renderer/source/webgpu/render_context_webgpu_impl.cpp new file mode 100644 index 0000000..1787aa4 --- /dev/null +++ b/third_party/rive_renderer/source/webgpu/render_context_webgpu_impl.cpp @@ -0,0 +1,2697 @@ +/* + * Copyright 2023 Rive + */ + +#include "rive/renderer/webgpu/render_context_webgpu_impl.hpp" + +#include "rive/renderer/rive_render_image.hpp" +#include "shaders/constants.glsl" + +#include "generated/shaders/spirv/blit_texture_as_draw.vert.h" +#include "generated/shaders/spirv/blit_texture_as_draw.frag.h" +#include "generated/shaders/spirv/color_ramp.vert.h" +#include "generated/shaders/spirv/color_ramp.frag.h" +#include "generated/shaders/spirv/tessellate.vert.h" +#include "generated/shaders/spirv/tessellate.frag.h" +#include "generated/shaders/spirv/render_atlas.vert.h" +#include "generated/shaders/spirv/render_atlas_fill.frag.h" +#include "generated/shaders/spirv/render_atlas_stroke.frag.h" +#include "generated/shaders/spirv/draw_path.vert.h" +#include "generated/shaders/spirv/draw_path.frag.h" +#include "generated/shaders/spirv/draw_interior_triangles.vert.h" +#include "generated/shaders/spirv/draw_interior_triangles.frag.h" +#include "generated/shaders/spirv/draw_atlas_blit.vert.h" +#include "generated/shaders/spirv/draw_atlas_blit.frag.h" +#include "generated/shaders/spirv/draw_image_mesh.vert.h" +#include "generated/shaders/spirv/draw_image_mesh.frag.h" + +#include "generated/shaders/glsl.glsl.hpp" +#include "generated/shaders/constants.glsl.hpp" +#include "generated/shaders/common.glsl.hpp" +#include "generated/shaders/bezier_utils.glsl.hpp" +#include "generated/shaders/tessellate.glsl.hpp" +#include "generated/shaders/render_atlas.glsl.hpp" +#include "generated/shaders/advanced_blend.glsl.hpp" +#include "generated/shaders/draw_path.glsl.hpp" +#include "generated/shaders/draw_path_common.glsl.hpp" +#include "generated/shaders/draw_image_mesh.glsl.hpp" + +#include +#include + +// When compiling "glsl-raw" shaders, the WebGPU driver will automatically +// search for a uniform with this name and update its value when draw commands +// have a base instance. +constexpr static char BASE_INSTANCE_UNIFORM_NAME[] = "nrdp_BaseInstance"; + +#ifdef RIVE_DAWN +#include + +namespace wgpu +{ +using ImageCopyBuffer = TexelCopyBufferInfo; +using ImageCopyTexture = TexelCopyTextureInfo; +using TextureDataLayout = TexelCopyBufferLayout; +}; // namespace wgpu + +static void enable_shader_pixel_local_storage_ext(wgpu::RenderPassEncoder, + bool enabled) +{ + RIVE_UNREACHABLE(); +} + +static bool generate_mipmaps_builtin(wgpu::CommandEncoder encoder, + wgpu::Texture texture) +{ + return false; +} +#endif + +#ifdef RIVE_WEBGPU +#include "render_context_webgpu_vulkan.hpp" +#include +#include +#include + +EM_JS(void, + enable_shader_pixel_local_storage_ext_js, + (int renderPass, bool enabled), + { + renderPass = JsValStore.get(renderPass); + renderPass.setShaderPixelLocalStorageEnabled(Boolean(enabled)); + }); + +static void enable_shader_pixel_local_storage_ext( + wgpu::RenderPassEncoder renderPass, + bool enabled) +{ + enable_shader_pixel_local_storage_ext_js( + emscripten_webgpu_export_render_pass_encoder(renderPass.Get()), + enabled); +} + +EM_JS(bool, generate_mipmaps_builtin_js, (int encoder, int texture), { + encoder = JsValStore.get(encoder); + texture = JsValStore.get(texture); + if (encoder.generateMipmap) + { + encoder.generateMipmap(texture); + return true; + } + return false; +}); + +static bool generate_mipmaps_builtin(wgpu::CommandEncoder encoder, + wgpu::Texture texture) +{ + return generate_mipmaps_builtin_js( + emscripten_webgpu_export_command_encoder(encoder.Get()), + emscripten_webgpu_export_texture(texture.Get())); +} +#endif + +namespace rive::gpu +{ +// Draws emulated render-pass load/store actions for +// EXT_shader_pixel_local_storage. +class RenderContextWebGPUImpl::LoadStoreEXTPipeline +{ +public: + LoadStoreEXTPipeline(RenderContextWebGPUImpl* context, + LoadStoreActionsEXT actions, + wgpu::TextureFormat framebufferFormat) : + m_framebufferFormat(framebufferFormat) + { + wgpu::PipelineLayoutDescriptor pipelineLayoutDesc; + if (actions & LoadStoreActionsEXT::clearColor) + { + // Create a uniform buffer binding for the clear color. + wgpu::BindGroupLayoutEntry bindingLayouts[] = { + { + .binding = 0, + .visibility = wgpu::ShaderStage::Fragment, + .buffer = + { + .type = wgpu::BufferBindingType::Uniform, + }, + }, + }; + + wgpu::BindGroupLayoutDescriptor bindingsDesc = { + .entryCount = std::size(bindingLayouts), + .entries = bindingLayouts, + }; + + m_bindGroupLayout = + context->m_device.CreateBindGroupLayout(&bindingsDesc); + + pipelineLayoutDesc = { + .bindGroupLayoutCount = 1, + .bindGroupLayouts = &m_bindGroupLayout, + }; + } + else + { + pipelineLayoutDesc = { + .bindGroupLayoutCount = 0, + .bindGroupLayouts = nullptr, + }; + } + + wgpu::PipelineLayout pipelineLayout = + context->m_device.CreatePipelineLayout(&pipelineLayoutDesc); + + wgpu::ShaderModule fragmentShader; + std::ostringstream glsl; + glsl << "#version 310 es\n"; + glsl << "#pragma shader_stage(fragment)\n"; + glsl << "#define " GLSL_FRAGMENT " true\n"; + glsl << "#define " GLSL_ENABLE_CLIPPING " true\n"; + if (context->m_contextOptions.invertRenderTargetY) + { + glsl << "#define " GLSL_POST_INVERT_Y " true\n"; + } + BuildLoadStoreEXTGLSL(glsl, actions); + fragmentShader = + m_fragmentShaderHandle.compileShaderModule(context->m_device, + glsl.str().c_str(), + "glsl-raw"); + + wgpu::ColorTargetState colorTargetState = { + .format = framebufferFormat, + }; + + wgpu::FragmentState fragmentState = { + .module = fragmentShader, + .entryPoint = "main", + .targetCount = 1, + .targets = &colorTargetState, + }; + + wgpu::RenderPipelineDescriptor desc = { + .layout = pipelineLayout, + .vertex = + { + .module = context->m_loadStoreEXTVertexShader, + .entryPoint = "main", + .bufferCount = 0, + .buffers = nullptr, + }, + .primitive = + { + .topology = wgpu::PrimitiveTopology::TriangleStrip, + .frontFace = context->frontFaceForRenderTargetDraws(), + .cullMode = wgpu::CullMode::Back, + }, + .fragment = &fragmentState, + }; + + m_renderPipeline = context->m_device.CreateRenderPipeline(&desc); + } + + const wgpu::BindGroupLayout& bindGroupLayout() const + { + assert(m_bindGroupLayout); // We only have a bind group if there is a + // clear color. + return m_bindGroupLayout; + } + + wgpu::RenderPipeline renderPipeline( + wgpu::TextureFormat framebufferFormat) const + { + assert(framebufferFormat == m_framebufferFormat); + return m_renderPipeline; + } + +private: + const wgpu::TextureFormat m_framebufferFormat RIVE_MAYBE_UNUSED; + wgpu::BindGroupLayout m_bindGroupLayout; + EmJsHandle m_fragmentShaderHandle; + wgpu::RenderPipeline m_renderPipeline; +}; + +// Renders color ramps to the gradient texture. +class RenderContextWebGPUImpl::ColorRampPipeline +{ +public: + ColorRampPipeline(RenderContextWebGPUImpl* impl) + { + const wgpu::Device device = impl->device(); + + wgpu::BindGroupLayoutDescriptor colorRampBindingsDesc = { + .entryCount = COLOR_RAMP_BINDINGS_COUNT, + .entries = impl->m_perFlushBindingLayouts.data(), + }; + + m_bindGroupLayout = + device.CreateBindGroupLayout(&colorRampBindingsDesc); + + wgpu::PipelineLayoutDescriptor pipelineLayoutDesc = { + .bindGroupLayoutCount = 1, + .bindGroupLayouts = &m_bindGroupLayout, + }; + + wgpu::PipelineLayout pipelineLayout = + device.CreatePipelineLayout(&pipelineLayoutDesc); + + wgpu::ShaderModule vertexShader = + m_vertexShaderHandle.compileSPIRVShaderModule( + device, + color_ramp_vert, + std::size(color_ramp_vert)); + + wgpu::VertexAttribute attrs[] = { + { + .format = wgpu::VertexFormat::Uint32x4, + .offset = 0, + .shaderLocation = 0, + }, + }; + + wgpu::VertexBufferLayout vertexBufferLayout = { + .arrayStride = sizeof(gpu::GradientSpan), + .stepMode = wgpu::VertexStepMode::Instance, + .attributeCount = std::size(attrs), + .attributes = attrs, + }; + + wgpu::ShaderModule fragmentShader = + m_fragmentShaderHandle.compileSPIRVShaderModule( + device, + color_ramp_frag, + std::size(color_ramp_frag)); + + wgpu::ColorTargetState colorTargetState = { + .format = wgpu::TextureFormat::RGBA8Unorm, + }; + + wgpu::FragmentState fragmentState = { + .module = fragmentShader, + .entryPoint = "main", + .targetCount = 1, + .targets = &colorTargetState, + }; + + wgpu::RenderPipelineDescriptor desc = { + .layout = pipelineLayout, + .vertex = + { + .module = vertexShader, + .entryPoint = "main", + .bufferCount = 1, + .buffers = &vertexBufferLayout, + }, + .primitive = + { + .topology = wgpu::PrimitiveTopology::TriangleStrip, + .frontFace = kFrontFaceForOffscreenDraws, + .cullMode = wgpu::CullMode::Back, + }, + .fragment = &fragmentState, + }; + + m_renderPipeline = device.CreateRenderPipeline(&desc); + } + + const wgpu::BindGroupLayout& bindGroupLayout() const + { + return m_bindGroupLayout; + } + wgpu::RenderPipeline renderPipeline() const { return m_renderPipeline; } + +private: + wgpu::BindGroupLayout m_bindGroupLayout; + EmJsHandle m_vertexShaderHandle; + EmJsHandle m_fragmentShaderHandle; + wgpu::RenderPipeline m_renderPipeline; +}; + +// Renders tessellated vertices to the tessellation texture. +class RenderContextWebGPUImpl::TessellatePipeline +{ +public: + TessellatePipeline(RenderContextWebGPUImpl* impl) + { + const wgpu::Device device = impl->device(); + + wgpu::BindGroupLayoutDescriptor perFlushBindingsDesc = { + .entryCount = TESS_BINDINGS_COUNT, + .entries = impl->m_perFlushBindingLayouts.data(), + }; + + m_perFlushBindingsLayout = + device.CreateBindGroupLayout(&perFlushBindingsDesc); + + wgpu::BindGroupLayout layouts[] = { + m_perFlushBindingsLayout, + impl->m_emptyBindingsLayout, + impl->m_drawBindGroupLayouts[IMMUTABLE_SAMPLER_BINDINGS_SET], + }; + static_assert(IMMUTABLE_SAMPLER_BINDINGS_SET == 2); + + wgpu::PipelineLayoutDescriptor pipelineLayoutDesc = { + .bindGroupLayoutCount = std::size(layouts), + .bindGroupLayouts = layouts, + }; + + wgpu::PipelineLayout pipelineLayout = + device.CreatePipelineLayout(&pipelineLayoutDesc); + + wgpu::ShaderModule vertexShader; + if (impl->m_contextOptions.disableStorageBuffers) + { + // The built-in SPIRV does not #define + // DISABLE_SHADER_STORAGE_BUFFERS. Recompile the tessellation shader + // with storage buffers disabled. + std::ostringstream vertexGLSL; + vertexGLSL << "#version 460\n"; + vertexGLSL << "#pragma shader_stage(vertex)\n"; + vertexGLSL << "#define " GLSL_VERTEX " true\n"; + vertexGLSL << "#define " GLSL_DISABLE_SHADER_STORAGE_BUFFERS + " true\n"; + vertexGLSL << "#define " GLSL_TARGET_VULKAN " true\n"; + vertexGLSL + << "#extension GL_EXT_samplerless_texture_functions : enable\n"; + vertexGLSL << glsl::glsl << "\n"; + vertexGLSL << glsl::constants << "\n"; + vertexGLSL << glsl::common << "\n"; + vertexGLSL << glsl::bezier_utils << "\n"; + vertexGLSL << glsl::tessellate << "\n"; + vertexShader = m_vertexShaderHandle.compileShaderModule( + device, + vertexGLSL.str().c_str(), + "glsl"); + } + else + { + vertexShader = m_vertexShaderHandle.compileSPIRVShaderModule( + device, + tessellate_vert, + std::size(tessellate_vert)); + } + + wgpu::VertexAttribute attrs[] = { + { + .format = wgpu::VertexFormat::Float32x4, + .offset = 0, + .shaderLocation = 0, + }, + { + .format = wgpu::VertexFormat::Float32x4, + .offset = 4 * sizeof(float), + .shaderLocation = 1, + }, + { + .format = wgpu::VertexFormat::Float32x4, + .offset = 8 * sizeof(float), + .shaderLocation = 2, + }, + { + .format = wgpu::VertexFormat::Uint32x4, + .offset = 12 * sizeof(float), + .shaderLocation = 3, + }, + }; + + wgpu::VertexBufferLayout vertexBufferLayout = { + .arrayStride = sizeof(gpu::TessVertexSpan), + .stepMode = wgpu::VertexStepMode::Instance, + .attributeCount = std::size(attrs), + .attributes = attrs, + }; + + wgpu::ShaderModule fragmentShader = + m_fragmentShaderHandle.compileSPIRVShaderModule( + device, + tessellate_frag, + std::size(tessellate_frag)); + + wgpu::ColorTargetState colorTargetState = { + .format = wgpu::TextureFormat::RGBA32Uint, + }; + + wgpu::FragmentState fragmentState = { + .module = fragmentShader, + .entryPoint = "main", + .targetCount = 1, + .targets = &colorTargetState, + }; + + wgpu::RenderPipelineDescriptor desc = { + .layout = pipelineLayout, + .vertex = + { + .module = vertexShader, + .entryPoint = "main", + .bufferCount = 1, + .buffers = &vertexBufferLayout, + }, + .primitive = + { + .topology = wgpu::PrimitiveTopology::TriangleList, + .frontFace = kFrontFaceForOffscreenDraws, + .cullMode = wgpu::CullMode::Back, + }, + .fragment = &fragmentState, + }; + + m_renderPipeline = device.CreateRenderPipeline(&desc); + } + + wgpu::BindGroupLayout perFlushBindingsLayout() const + { + return m_perFlushBindingsLayout; + } + wgpu::RenderPipeline renderPipeline() const { return m_renderPipeline; } + +private: + wgpu::BindGroupLayout m_perFlushBindingsLayout; + EmJsHandle m_vertexShaderHandle; + EmJsHandle m_fragmentShaderHandle; + wgpu::RenderPipeline m_renderPipeline; +}; + +// Renders tessellated vertices to the tessellation texture. +class RenderContextWebGPUImpl::AtlasPipeline +{ +public: + AtlasPipeline(RenderContextWebGPUImpl* impl) + { + const wgpu::Device device = impl->device(); + + wgpu::BindGroupLayoutDescriptor perFlushBindingsDesc = { + .entryCount = ATLAS_BINDINGS_COUNT, + .entries = impl->m_perFlushBindingLayouts.data(), + }; + + m_perFlushBindingsLayout = + device.CreateBindGroupLayout(&perFlushBindingsDesc); + + wgpu::BindGroupLayout layouts[] = { + m_perFlushBindingsLayout, + impl->m_emptyBindingsLayout, + impl->m_drawBindGroupLayouts[IMMUTABLE_SAMPLER_BINDINGS_SET], + }; + static_assert(IMMUTABLE_SAMPLER_BINDINGS_SET == 2); + + wgpu::PipelineLayoutDescriptor pipelineLayoutDesc = { + .bindGroupLayoutCount = std::size(layouts), + .bindGroupLayouts = layouts, + }; + + wgpu::PipelineLayout pipelineLayout = + device.CreatePipelineLayout(&pipelineLayoutDesc); + + wgpu::ShaderModule vertexShader; + if (impl->m_contextOptions.disableStorageBuffers) + { + // The built-in SPIRV does not #define + // DISABLE_SHADER_STORAGE_BUFFERS. Recompile the tessellation shader + // with storage buffers disabled. + std::ostringstream vertexGLSL; + vertexGLSL << "#version 460\n"; + vertexGLSL + << "#extension GL_EXT_samplerless_texture_functions : enable\n"; + vertexGLSL << "#pragma shader_stage(vertex)\n"; + vertexGLSL << "#define " GLSL_VERTEX " true\n"; + vertexGLSL << "#define " GLSL_DISABLE_SHADER_STORAGE_BUFFERS + " true\n"; + vertexGLSL << "#define " GLSL_TARGET_VULKAN " true\n"; + vertexGLSL << "#define " << GLSL_DRAW_PATH << '\n'; + vertexGLSL << "#define " << GLSL_ENABLE_FEATHER << "true\n"; + vertexGLSL << glsl::glsl << '\n'; + vertexGLSL << glsl::constants << '\n'; + vertexGLSL << glsl::common << '\n'; + vertexGLSL << glsl::draw_path_common << '\n'; + vertexGLSL << glsl::render_atlas << '\n'; + vertexShader = m_vertexShaderHandle.compileShaderModule( + device, + vertexGLSL.str().c_str(), + "glsl"); + } + else + { + vertexShader = m_vertexShaderHandle.compileSPIRVShaderModule( + device, + render_atlas_vert, + std::size(render_atlas_vert)); + } + + wgpu::VertexAttribute attrs[] = { + { + .format = wgpu::VertexFormat::Float32x4, + .offset = 0, + .shaderLocation = 0, + }, + { + .format = wgpu::VertexFormat::Float32x4, + .offset = 4 * sizeof(float), + .shaderLocation = 1, + }, + }; + + wgpu::VertexBufferLayout vertexBufferLayout = { + .arrayStride = sizeof(gpu::PatchVertex), + .stepMode = wgpu::VertexStepMode::Vertex, + .attributeCount = std::size(attrs), + .attributes = attrs, + }; + + wgpu::ShaderModule fillFragmentShader = + m_fragmentShaderHandle.compileSPIRVShaderModule( + device, + render_atlas_fill_frag, + std::size(render_atlas_fill_frag)); + + wgpu::ShaderModule strokeFragmentShader = + m_fragmentShaderHandle.compileSPIRVShaderModule( + device, + render_atlas_stroke_frag, + std::size(render_atlas_stroke_frag)); + + wgpu::BlendState blendState = { + .color = { + .operation = wgpu::BlendOperation::Add, + .srcFactor = wgpu::BlendFactor::One, + .dstFactor = wgpu::BlendFactor::One, + }}; + + wgpu::ColorTargetState colorTargetState = { + .format = wgpu::TextureFormat::R16Float, + .blend = &blendState, + }; + + wgpu::FragmentState fragmentState = { + .module = fillFragmentShader, + .entryPoint = "main", + .targetCount = 1, + .targets = &colorTargetState, + }; + + wgpu::RenderPipelineDescriptor desc = { + .layout = pipelineLayout, + .vertex = + { + .module = vertexShader, + .entryPoint = "main", + .bufferCount = 1, + .buffers = &vertexBufferLayout, + }, + .primitive = + { + .topology = wgpu::PrimitiveTopology::TriangleList, + .frontFace = kFrontFaceForOffscreenDraws, + .cullMode = wgpu::CullMode::Back, + }, + .fragment = &fragmentState, + }; + + m_fillPipeline = device.CreateRenderPipeline(&desc); + + blendState.color.operation = wgpu::BlendOperation::Max; + fragmentState.module = strokeFragmentShader; + m_strokePipeline = device.CreateRenderPipeline(&desc); + } + + wgpu::BindGroupLayout perFlushBindingsLayout() const + { + return m_perFlushBindingsLayout; + } + wgpu::RenderPipeline fillPipeline() const { return m_fillPipeline; } + wgpu::RenderPipeline strokePipeline() const { return m_strokePipeline; } + +private: + wgpu::BindGroupLayout m_perFlushBindingsLayout; + EmJsHandle m_vertexShaderHandle; + EmJsHandle m_fragmentShaderHandle; + wgpu::RenderPipeline m_fillPipeline; + wgpu::RenderPipeline m_strokePipeline; +}; + +// Draw paths and image meshes using the gradient and tessellation textures. +class RenderContextWebGPUImpl::DrawPipeline +{ +public: + DrawPipeline(RenderContextWebGPUImpl* context, + DrawType drawType, + gpu::ShaderFeatures shaderFeatures, + const ContextOptions& contextOptions) + { + PixelLocalStorageType plsType = context->m_contextOptions.plsType; + wgpu::ShaderModule vertexShader, fragmentShader; + if (plsType == PixelLocalStorageType::subpassLoad || + plsType == PixelLocalStorageType::EXT_shader_pixel_local_storage || + contextOptions.disableStorageBuffers) + { + const char* language; + const char* versionString; + std::ostringstream glsl; + auto addDefine = [&glsl](const char* name) { + glsl << "#define " << name << " true\n"; + }; + if (plsType == + PixelLocalStorageType::EXT_shader_pixel_local_storage) + { + language = "glsl-raw"; + versionString = "#version 310 es"; + if (context->m_contextOptions.invertRenderTargetY) + { + addDefine(GLSL_POST_INVERT_Y); + } + glsl << "#define " << GLSL_BASE_INSTANCE_UNIFORM_NAME << ' ' + << BASE_INSTANCE_UNIFORM_NAME << '\n'; + } + else + { + language = "glsl"; + versionString = "#version 460"; + addDefine(GLSL_TARGET_VULKAN); + } + if (plsType == + PixelLocalStorageType::EXT_shader_pixel_local_storage) + { + glsl << "#ifdef GL_EXT_shader_pixel_local_storage\n"; + addDefine(GLSL_PLS_IMPL_EXT_NATIVE); + glsl << "#else\n"; + glsl << "#extension GL_EXT_samplerless_texture_functions : " + "enable\n"; + // If we are being compiled by SPIRV transpiler for + // introspection, GL_EXT_shader_pixel_local_storage will not be + // defined. + addDefine(GLSL_PLS_IMPL_NONE); + glsl << "#endif\n"; + } + else + { + glsl << "#extension GL_EXT_samplerless_texture_functions : " + "enable\n"; + addDefine(plsType == PixelLocalStorageType::subpassLoad + ? GLSL_PLS_IMPL_SUBPASS_LOAD + : GLSL_PLS_IMPL_NONE); + } + if (contextOptions.disableStorageBuffers) + { + addDefine(GLSL_DISABLE_SHADER_STORAGE_BUFFERS); + } + switch (drawType) + { + case DrawType::midpointFanPatches: + case DrawType::midpointFanCenterAAPatches: + case DrawType::outerCurvePatches: + addDefine(GLSL_ENABLE_INSTANCE_INDEX); + break; + case DrawType::atlasBlit: + addDefine(GLSL_ATLAS_BLIT); + [[fallthrough]]; + case DrawType::interiorTriangulation: + addDefine(GLSL_DRAW_INTERIOR_TRIANGLES); + break; + case DrawType::imageRect: + addDefine(GLSL_DRAW_IMAGE); + addDefine(GLSL_DRAW_IMAGE_RECT); + RIVE_UNREACHABLE(); + break; + case DrawType::imageMesh: + addDefine(GLSL_DRAW_IMAGE); + addDefine(GLSL_DRAW_IMAGE_MESH); + break; + case DrawType::atomicInitialize: + addDefine(GLSL_DRAW_RENDER_TARGET_UPDATE_BOUNDS); + addDefine(GLSL_INITIALIZE_PLS); + RIVE_UNREACHABLE(); + break; + case DrawType::atomicResolve: + addDefine(GLSL_DRAW_RENDER_TARGET_UPDATE_BOUNDS); + addDefine(GLSL_RESOLVE_PLS); + RIVE_UNREACHABLE(); + break; + case DrawType::msaaStrokes: + case DrawType::msaaMidpointFanBorrowedCoverage: + case DrawType::msaaMidpointFans: + case DrawType::msaaMidpointFanStencilReset: + case DrawType::msaaMidpointFanPathsStencil: + case DrawType::msaaMidpointFanPathsCover: + case DrawType::msaaOuterCubics: + case DrawType::msaaStencilClipReset: + RIVE_UNREACHABLE(); + break; + } + for (size_t i = 0; i < gpu::kShaderFeatureCount; ++i) + { + ShaderFeatures feature = static_cast(1 << i); + if (shaderFeatures & feature) + { + addDefine(GetShaderFeatureGLSLName(feature)); + } + } + glsl << gpu::glsl::glsl << '\n'; + glsl << gpu::glsl::constants << '\n'; + glsl << gpu::glsl::common << '\n'; + if (shaderFeatures & ShaderFeatures::ENABLE_ADVANCED_BLEND) + { + glsl << gpu::glsl::advanced_blend << '\n'; + } + glsl << "#define " << GLSL_OPTIONALLY_FLAT; + if (!context->platformFeatures().avoidFlatVaryings) + { + glsl << " flat"; + } + glsl << '\n'; + switch (drawType) + { + case DrawType::midpointFanPatches: + case DrawType::midpointFanCenterAAPatches: + case DrawType::outerCurvePatches: + addDefine(GLSL_DRAW_PATH); + glsl << gpu::glsl::draw_path_common << '\n'; + glsl << gpu::glsl::draw_path << '\n'; + break; + case DrawType::interiorTriangulation: + case DrawType::atlasBlit: + glsl << gpu::glsl::draw_path_common << '\n'; + glsl << gpu::glsl::draw_path << '\n'; + break; + case DrawType::imageMesh: + glsl << gpu::glsl::draw_image_mesh << '\n'; + break; + case DrawType::imageRect: + case DrawType::atomicInitialize: + case DrawType::atomicResolve: + case DrawType::msaaStrokes: + case DrawType::msaaMidpointFanBorrowedCoverage: + case DrawType::msaaMidpointFans: + case DrawType::msaaMidpointFanStencilReset: + case DrawType::msaaMidpointFanPathsStencil: + case DrawType::msaaMidpointFanPathsCover: + case DrawType::msaaOuterCubics: + case DrawType::msaaStencilClipReset: + RIVE_UNREACHABLE(); + break; + } + + std::ostringstream vertexGLSL; + vertexGLSL << versionString << "\n"; + vertexGLSL << "#pragma shader_stage(vertex)\n"; + vertexGLSL << "#define " GLSL_VERTEX " true\n"; + vertexGLSL << glsl.str(); + vertexShader = m_vertexShaderHandle.compileShaderModule( + context->m_device, + vertexGLSL.str().c_str(), + language); + + std::ostringstream fragmentGLSL; + fragmentGLSL << versionString << "\n"; + fragmentGLSL << "#pragma shader_stage(fragment)\n"; + fragmentGLSL << "#define " GLSL_FRAGMENT " true\n"; + fragmentGLSL << glsl.str(); + fragmentShader = m_fragmentShaderHandle.compileShaderModule( + context->m_device, + fragmentGLSL.str().c_str(), + language); + } + else + { + switch (drawType) + { + case DrawType::midpointFanPatches: + case DrawType::midpointFanCenterAAPatches: + case DrawType::outerCurvePatches: + vertexShader = + m_vertexShaderHandle.compileSPIRVShaderModule( + context->m_device, + draw_path_vert, + std::size(draw_path_vert)); + fragmentShader = + m_fragmentShaderHandle.compileSPIRVShaderModule( + context->m_device, + draw_path_frag, + std::size(draw_path_frag)); + break; + case DrawType::interiorTriangulation: + vertexShader = + m_vertexShaderHandle.compileSPIRVShaderModule( + context->m_device, + draw_interior_triangles_vert, + std::size(draw_interior_triangles_vert)); + fragmentShader = + m_fragmentShaderHandle.compileSPIRVShaderModule( + context->m_device, + draw_interior_triangles_frag, + std::size(draw_interior_triangles_frag)); + break; + case DrawType::atlasBlit: + vertexShader = + m_vertexShaderHandle.compileSPIRVShaderModule( + context->m_device, + draw_atlas_blit_vert, + std::size(draw_atlas_blit_vert)); + fragmentShader = + m_fragmentShaderHandle.compileSPIRVShaderModule( + context->m_device, + draw_atlas_blit_frag, + std::size(draw_atlas_blit_frag)); + break; + case DrawType::imageRect: + RIVE_UNREACHABLE(); + case DrawType::imageMesh: + vertexShader = + m_vertexShaderHandle.compileSPIRVShaderModule( + context->m_device, + draw_image_mesh_vert, + std::size(draw_image_mesh_vert)); + fragmentShader = + m_fragmentShaderHandle.compileSPIRVShaderModule( + context->m_device, + draw_image_mesh_frag, + std::size(draw_image_mesh_frag)); + break; + case DrawType::atomicInitialize: + case DrawType::atomicResolve: + case DrawType::msaaStrokes: + case DrawType::msaaMidpointFanBorrowedCoverage: + case DrawType::msaaMidpointFans: + case DrawType::msaaMidpointFanStencilReset: + case DrawType::msaaMidpointFanPathsStencil: + case DrawType::msaaMidpointFanPathsCover: + case DrawType::msaaOuterCubics: + case DrawType::msaaStencilClipReset: + RIVE_UNREACHABLE(); + } + } + + for (auto framebufferFormat : + {wgpu::TextureFormat::BGRA8Unorm, wgpu::TextureFormat::RGBA8Unorm}) + { + int pipelineIdx = RenderPipelineIdx(framebufferFormat); + m_renderPipelines[pipelineIdx] = context->makeDrawPipeline( + drawType, + framebufferFormat, + vertexShader, + fragmentShader, + &m_renderPipelineHandles[pipelineIdx]); + } + } + + wgpu::RenderPipeline renderPipeline( + wgpu::TextureFormat framebufferFormat) const + { + return m_renderPipelines[RenderPipelineIdx(framebufferFormat)]; + } + +private: + static int RenderPipelineIdx(wgpu::TextureFormat framebufferFormat) + { + assert(framebufferFormat == wgpu::TextureFormat::BGRA8Unorm || + framebufferFormat == wgpu::TextureFormat::RGBA8Unorm); + return framebufferFormat == wgpu::TextureFormat::BGRA8Unorm ? 1 : 0; + } + + EmJsHandle m_vertexShaderHandle; + EmJsHandle m_fragmentShaderHandle; + wgpu::RenderPipeline m_renderPipelines[2]; + EmJsHandle m_renderPipelineHandles[2]; +}; + +RenderContextWebGPUImpl::RenderContextWebGPUImpl( + wgpu::Device device, + wgpu::Queue queue, + const ContextOptions& contextOptions) : + m_device(device), m_queue(queue), m_contextOptions(contextOptions) +{ + // All backends currently use raster ordered shaders. + // TODO: update this flag once we have msaa and atomic modes. + m_platformFeatures.supportsRasterOrdering = true; + m_platformFeatures.clipSpaceBottomUp = true; + m_platformFeatures.framebufferBottomUp = false; +} + +void RenderContextWebGPUImpl::initGPUObjects() +{ + m_perFlushBindingLayouts = {{ + { + .binding = FLUSH_UNIFORM_BUFFER_IDX, + .visibility = + wgpu::ShaderStage::Vertex | wgpu::ShaderStage::Fragment, + .buffer = + { + .type = wgpu::BufferBindingType::Uniform, + }, + }, + m_contextOptions.disableStorageBuffers ? + wgpu::BindGroupLayoutEntry{ + .binding = PATH_BUFFER_IDX, + .visibility = wgpu::ShaderStage::Vertex, + .texture = + { + .sampleType = wgpu::TextureSampleType::Uint, + .viewDimension = wgpu::TextureViewDimension::e2D, + }, + } : + wgpu::BindGroupLayoutEntry{ + .binding = PATH_BUFFER_IDX, + .visibility = wgpu::ShaderStage::Vertex, + .buffer = + { + .type = wgpu::BufferBindingType::ReadOnlyStorage, + }, + }, + m_contextOptions.disableStorageBuffers ? + wgpu::BindGroupLayoutEntry{ + .binding = PAINT_BUFFER_IDX, + .visibility = wgpu::ShaderStage::Vertex, + .texture = + { + .sampleType = wgpu::TextureSampleType::Uint, + .viewDimension = wgpu::TextureViewDimension::e2D, + }, + } : + wgpu::BindGroupLayoutEntry{ + .binding = PAINT_BUFFER_IDX, + .visibility = wgpu::ShaderStage::Vertex, + .buffer = + { + .type = wgpu::BufferBindingType::ReadOnlyStorage, + }, + }, + m_contextOptions.disableStorageBuffers ? + wgpu::BindGroupLayoutEntry{ + .binding = PAINT_AUX_BUFFER_IDX, + .visibility = wgpu::ShaderStage::Vertex, + .texture = + { + .sampleType = wgpu::TextureSampleType::UnfilterableFloat, + .viewDimension = wgpu::TextureViewDimension::e2D, + }, + } : + wgpu::BindGroupLayoutEntry{ + .binding = PAINT_AUX_BUFFER_IDX, + .visibility = wgpu::ShaderStage::Vertex, + .buffer = + { + .type = wgpu::BufferBindingType::ReadOnlyStorage, + }, + }, + m_contextOptions.disableStorageBuffers ? + wgpu::BindGroupLayoutEntry{ + .binding = CONTOUR_BUFFER_IDX, + .visibility = wgpu::ShaderStage::Vertex, + .texture = + { + .sampleType = wgpu::TextureSampleType::Uint, + .viewDimension = wgpu::TextureViewDimension::e2D, + }, + } : + wgpu::BindGroupLayoutEntry{ + .binding = CONTOUR_BUFFER_IDX, + .visibility = wgpu::ShaderStage::Vertex, + .buffer = + { + .type = wgpu::BufferBindingType::ReadOnlyStorage, + }, + }, + { + .binding = FEATHER_TEXTURE_IDX, + .visibility = + wgpu::ShaderStage::Vertex | wgpu::ShaderStage::Fragment, + .texture = + { + .sampleType = wgpu::TextureSampleType::Float, + .viewDimension = wgpu::TextureViewDimension::e2D, + }, + }, + { + .binding = TESS_VERTEX_TEXTURE_IDX, + .visibility = wgpu::ShaderStage::Vertex, + .texture = + { + .sampleType = wgpu::TextureSampleType::Uint, + .viewDimension = wgpu::TextureViewDimension::e2D, + }, + }, + { + .binding = ATLAS_TEXTURE_IDX, + .visibility = wgpu::ShaderStage::Fragment, + .texture = + { + .sampleType = wgpu::TextureSampleType::Float, + .viewDimension = wgpu::TextureViewDimension::e2D, + }, + }, + { + .binding = GRAD_TEXTURE_IDX, + .visibility = wgpu::ShaderStage::Fragment, + .texture = + { + .sampleType = wgpu::TextureSampleType::Float, + .viewDimension = wgpu::TextureViewDimension::e2D, + }, + }, + { + .binding = IMAGE_DRAW_UNIFORM_BUFFER_IDX, + .visibility = + wgpu::ShaderStage::Vertex | wgpu::ShaderStage::Fragment, + .buffer = + { + .type = wgpu::BufferBindingType::Uniform, + .hasDynamicOffset = true, + .minBindingSize = sizeof(gpu::ImageDrawUniforms), + }, + }, + }}; + static_assert(DRAW_BINDINGS_COUNT == 10); + static_assert(sizeof(m_perFlushBindingLayouts) == + DRAW_BINDINGS_COUNT * sizeof(wgpu::BindGroupLayoutEntry)); + + wgpu::BindGroupLayoutDescriptor perFlushBindingsDesc = { + .entryCount = DRAW_BINDINGS_COUNT, + .entries = m_perFlushBindingLayouts.data(), + }; + + m_drawBindGroupLayouts[PER_FLUSH_BINDINGS_SET] = + m_device.CreateBindGroupLayout(&perFlushBindingsDesc); + + wgpu::BindGroupLayoutEntry perDrawBindingLayouts[] = { + { + .binding = IMAGE_TEXTURE_IDX, + .visibility = wgpu::ShaderStage::Fragment, + .texture = + { + .sampleType = wgpu::TextureSampleType::Float, + .viewDimension = wgpu::TextureViewDimension::e2D, + }, + }, + }; + + wgpu::BindGroupLayoutDescriptor perDrawBindingsDesc = { + .entryCount = std::size(perDrawBindingLayouts), + .entries = perDrawBindingLayouts, + }; + + m_drawBindGroupLayouts[PER_DRAW_BINDINGS_SET] = + m_device.CreateBindGroupLayout(&perDrawBindingsDesc); + + wgpu::BindGroupLayoutEntry drawBindingSamplerLayouts[] = { + { + .binding = GRAD_TEXTURE_IDX, + .visibility = wgpu::ShaderStage::Fragment, + .sampler = + { + .type = wgpu::SamplerBindingType::Filtering, + }, + }, + { + .binding = FEATHER_TEXTURE_IDX, + .visibility = + wgpu::ShaderStage::Vertex | wgpu::ShaderStage::Fragment, + .sampler = + { + .type = wgpu::SamplerBindingType::Filtering, + }, + }, + { + .binding = ATLAS_TEXTURE_IDX, + .visibility = wgpu::ShaderStage::Fragment, + .sampler = + { + .type = wgpu::SamplerBindingType::Filtering, + }, + }, + { + .binding = IMAGE_TEXTURE_IDX, + .visibility = wgpu::ShaderStage::Fragment, + .sampler = + { + .type = wgpu::SamplerBindingType::Filtering, + }, + }, + }; + + wgpu::BindGroupLayoutDescriptor samplerBindingsDesc = { + .entryCount = std::size(drawBindingSamplerLayouts), + .entries = drawBindingSamplerLayouts, + }; + + m_drawBindGroupLayouts[IMMUTABLE_SAMPLER_BINDINGS_SET] = + m_device.CreateBindGroupLayout(&samplerBindingsDesc); + + wgpu::SamplerDescriptor linearSamplerDesc = { + .addressModeU = wgpu::AddressMode::ClampToEdge, + .addressModeV = wgpu::AddressMode::ClampToEdge, + .magFilter = wgpu::FilterMode::Linear, + .minFilter = wgpu::FilterMode::Linear, + .mipmapFilter = wgpu::MipmapFilterMode::Nearest, + }; + + m_linearSampler = m_device.CreateSampler(&linearSamplerDesc); + + wgpu::SamplerDescriptor mipmapSamplerDesc = { + .addressModeU = wgpu::AddressMode::ClampToEdge, + .addressModeV = wgpu::AddressMode::ClampToEdge, + .magFilter = wgpu::FilterMode::Linear, + .minFilter = wgpu::FilterMode::Linear, + .mipmapFilter = wgpu::MipmapFilterMode::Nearest, + }; + + m_mipmapSampler = m_device.CreateSampler(&mipmapSamplerDesc); + + wgpu::BindGroupEntry samplerBindingEntries[] = { + { + .binding = GRAD_TEXTURE_IDX, + .sampler = m_linearSampler, + }, + { + .binding = FEATHER_TEXTURE_IDX, + .sampler = m_linearSampler, + }, + { + .binding = ATLAS_TEXTURE_IDX, + .sampler = m_linearSampler, + }, + { + .binding = IMAGE_TEXTURE_IDX, + .sampler = m_mipmapSampler, + }, + }; + + wgpu::BindGroupDescriptor samplerBindGroupDesc = { + .layout = m_drawBindGroupLayouts[IMMUTABLE_SAMPLER_BINDINGS_SET], + .entryCount = std::size(samplerBindingEntries), + .entries = samplerBindingEntries, + }; + + m_samplerBindings = m_device.CreateBindGroup(&samplerBindGroupDesc); + + bool needsTextureBindings = + m_contextOptions.plsType == PixelLocalStorageType::subpassLoad; + if (needsTextureBindings) + { + m_drawBindGroupLayouts[PLS_TEXTURE_BINDINGS_SET] = + initTextureBindGroup(); + } + + wgpu::PipelineLayoutDescriptor drawPipelineLayoutDesc = { + .bindGroupLayoutCount = static_cast( + needsTextureBindings ? BINDINGS_SET_COUNT : BINDINGS_SET_COUNT - 1), + .bindGroupLayouts = m_drawBindGroupLayouts, + }; + + m_drawPipelineLayout = + m_device.CreatePipelineLayout(&drawPipelineLayoutDesc); + + wgpu::BindGroupLayoutDescriptor emptyBindingsDesc = {}; + m_emptyBindingsLayout = m_device.CreateBindGroupLayout(&emptyBindingsDesc); + + if (m_contextOptions.plsType == + PixelLocalStorageType::EXT_shader_pixel_local_storage) + { + // We have to manually implement load/store operations from a shader + // when using EXT_shader_pixel_local_storage. + std::ostringstream glsl; + glsl << "#version 310 es\n"; + glsl << "#pragma shader_stage(vertex)\n"; + glsl << "#define " GLSL_VERTEX " true\n"; + // If we are being compiled by SPIRV transpiler for introspection, use + // gl_VertexIndex instead of gl_VertexID. + glsl << "#ifndef GL_EXT_shader_pixel_local_storage\n"; + glsl << "#define gl_VertexID gl_VertexIndex\n"; + glsl << "#endif\n"; + glsl << "#define " GLSL_ENABLE_CLIPPING " true\n"; + if (m_contextOptions.invertRenderTargetY) + { + glsl << "#define " GLSL_POST_INVERT_Y " true\n"; + } + BuildLoadStoreEXTGLSL(glsl, LoadStoreActionsEXT::none); + m_loadStoreEXTVertexShader = + m_loadStoreEXTVertexShaderHandle.compileShaderModule( + m_device, + glsl.str().c_str(), + "glsl-raw"); + m_loadStoreEXTUniforms = makeUniformBufferRing(sizeof(float) * 4); + } + + wgpu::BufferDescriptor tessSpanIndexBufferDesc = { + .usage = wgpu::BufferUsage::Index, + .size = sizeof(gpu::kTessSpanIndices), + .mappedAtCreation = true, + }; + m_tessSpanIndexBuffer = m_device.CreateBuffer(&tessSpanIndexBufferDesc); + memcpy(m_tessSpanIndexBuffer.GetMappedRange(), + gpu::kTessSpanIndices, + sizeof(gpu::kTessSpanIndices)); + m_tessSpanIndexBuffer.Unmap(); + + wgpu::BufferDescriptor patchBufferDesc = { + .usage = wgpu::BufferUsage::Vertex, + .size = kPatchVertexBufferCount * sizeof(PatchVertex), + .mappedAtCreation = true, + }; + m_pathPatchVertexBuffer = m_device.CreateBuffer(&patchBufferDesc); + + patchBufferDesc.size = (kPatchIndexBufferCount * sizeof(uint16_t)); + // WebGPU buffer sizes must be multiples of 4. + patchBufferDesc.size = + math::round_up_to_multiple_of<4>(patchBufferDesc.size); + patchBufferDesc.usage = wgpu::BufferUsage::Index; + m_pathPatchIndexBuffer = m_device.CreateBuffer(&patchBufferDesc); + + GeneratePatchBufferData( + reinterpret_cast( + m_pathPatchVertexBuffer.GetMappedRange()), + reinterpret_cast(m_pathPatchIndexBuffer.GetMappedRange())); + + m_pathPatchVertexBuffer.Unmap(); + m_pathPatchIndexBuffer.Unmap(); + + wgpu::TextureDescriptor featherTextureDesc = { + .usage = + wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::CopyDst, + .dimension = wgpu::TextureDimension::e2D, + .size = {gpu::GAUSSIAN_TABLE_SIZE, FEATHER_TEXTURE_1D_ARRAY_LENGTH}, + .format = wgpu::TextureFormat::R16Float, + }; + + m_featherTexture = m_device.CreateTexture(&featherTextureDesc); + wgpu::ImageCopyTexture dest = {.texture = m_featherTexture}; + wgpu::TextureDataLayout layout = { + .bytesPerRow = sizeof(gpu::g_gaussianIntegralTableF16), + }; + wgpu::Extent3D extent = { + .width = gpu::GAUSSIAN_TABLE_SIZE, + .height = 1, + }; + m_queue.WriteTexture(&dest, + gpu::g_gaussianIntegralTableF16, + sizeof(gpu::g_gaussianIntegralTableF16), + &layout, + &extent); + dest.origin.y = 1; + m_queue.WriteTexture(&dest, + gpu::g_inverseGaussianIntegralTableF16, + sizeof(gpu::g_inverseGaussianIntegralTableF16), + &layout, + &extent); + m_featherTextureView = m_featherTexture.CreateView(); + + wgpu::TextureDescriptor nullImagePaintTextureDesc = { + .usage = wgpu::TextureUsage::TextureBinding, + .dimension = wgpu::TextureDimension::e2D, + .size = {1, 1}, + .format = wgpu::TextureFormat::RGBA8Unorm, + }; + + m_nullImagePaintTexture = + m_device.CreateTexture(&nullImagePaintTextureDesc); + m_nullImagePaintTextureView = m_nullImagePaintTexture.CreateView(); + + m_colorRampPipeline = std::make_unique(this); + m_tessellatePipeline = std::make_unique(this); + m_atlasPipeline = std::make_unique(this); +} + +RenderContextWebGPUImpl::~RenderContextWebGPUImpl() {} + +RenderTargetWebGPU::RenderTargetWebGPU( + wgpu::Device device, + wgpu::TextureFormat framebufferFormat, + uint32_t width, + uint32_t height, + wgpu::TextureUsage additionalTextureFlags) : + RenderTarget(width, height), m_framebufferFormat(framebufferFormat) +{ + wgpu::TextureDescriptor desc = { + .usage = wgpu::TextureUsage::RenderAttachment | additionalTextureFlags, + .size = {static_cast(width), static_cast(height)}, + }; + + desc.format = wgpu::TextureFormat::R32Uint; + m_coverageTexture = device.CreateTexture(&desc); + m_clipTexture = device.CreateTexture(&desc); + + desc.format = m_framebufferFormat; + m_scratchColorTexture = device.CreateTexture(&desc); + + m_targetTextureView = {}; // Will be configured later by setTargetTexture(). + m_coverageTextureView = m_coverageTexture.CreateView(); + m_clipTextureView = m_clipTexture.CreateView(); + m_scratchColorTextureView = m_scratchColorTexture.CreateView(); +} + +void RenderTargetWebGPU::setTargetTextureView(wgpu::TextureView textureView) +{ + m_targetTextureView = textureView; +} + +rcp RenderContextWebGPUImpl::makeRenderTarget( + wgpu::TextureFormat framebufferFormat, + uint32_t width, + uint32_t height) +{ + return rcp(new RenderTargetWebGPU(m_device, + framebufferFormat, + width, + height, + wgpu::TextureUsage::None)); +} + +class RenderBufferWebGPUImpl : public RenderBuffer +{ +public: + RenderBufferWebGPUImpl(wgpu::Device device, + wgpu::Queue queue, + RenderBufferType renderBufferType, + RenderBufferFlags renderBufferFlags, + size_t sizeInBytes) : + RenderBuffer(renderBufferType, renderBufferFlags, sizeInBytes), + m_device(device), + m_queue(queue) + { + bool mappedOnceAtInitialization = + flags() & RenderBufferFlags::mappedOnceAtInitialization; + int bufferCount = mappedOnceAtInitialization ? 1 : gpu::kBufferRingSize; + wgpu::BufferDescriptor desc = { + .usage = type() == RenderBufferType::index + ? wgpu::BufferUsage::Index + : wgpu::BufferUsage::Vertex, + // WebGPU buffer sizes must be multiples of 4. + .size = math::round_up_to_multiple_of<4>(sizeInBytes), + .mappedAtCreation = mappedOnceAtInitialization, + }; + if (!mappedOnceAtInitialization) + { + desc.usage |= wgpu::BufferUsage::CopyDst; + } + for (int i = 0; i < bufferCount; ++i) + { + m_buffers[i] = device.CreateBuffer(&desc); + } + } + + wgpu::Buffer submittedBuffer() const + { + return m_buffers[m_submittedBufferIdx]; + } + +protected: + void* onMap() override + { + m_submittedBufferIdx = + (m_submittedBufferIdx + 1) % gpu::kBufferRingSize; + assert(m_buffers[m_submittedBufferIdx] != nullptr); + if (flags() & RenderBufferFlags::mappedOnceAtInitialization) + { + return m_buffers[m_submittedBufferIdx].GetMappedRange(); + } + else + { + if (m_stagingBuffer == nullptr) + { + m_stagingBuffer.reset(new uint8_t[sizeInBytes()]); + } + return m_stagingBuffer.get(); + } + } + + void onUnmap() override + { + if (flags() & RenderBufferFlags::mappedOnceAtInitialization) + { + m_buffers[m_submittedBufferIdx].Unmap(); + } + else + { + m_queue.WriteBuffer(m_buffers[m_submittedBufferIdx], + 0, + m_stagingBuffer.get(), + sizeInBytes()); + } + } + +private: + const wgpu::Device m_device; + const wgpu::Queue m_queue; + wgpu::Buffer m_buffers[gpu::kBufferRingSize]; + int m_submittedBufferIdx = -1; + std::unique_ptr m_stagingBuffer; +}; + +rcp RenderContextWebGPUImpl::makeRenderBuffer( + RenderBufferType type, + RenderBufferFlags flags, + size_t sizeInBytes) +{ + return make_rcp(m_device, + m_queue, + type, + flags, + sizeInBytes); +} + +class TextureWebGPUImpl : public Texture +{ +public: + TextureWebGPUImpl(uint32_t width, uint32_t height, wgpu::Texture texture) : + Texture(width, height), + m_texture(std::move(texture)), + m_textureView(m_texture.CreateView()) + {} + + wgpu::TextureView textureView() const { return m_textureView; } + +private: + wgpu::Texture m_texture; + wgpu::TextureView m_textureView; +}; + +// Blits texture-to-texture using a draw command. +class RenderContextWebGPUImpl::BlitTextureAsDrawPipeline +{ +public: + BlitTextureAsDrawPipeline(RenderContextWebGPUImpl* impl) + { + const wgpu::Device device = impl->device(); + + wgpu::BindGroupLayoutEntry bindingEntries[] = { + { + .binding = 0, + .visibility = wgpu::ShaderStage::Fragment, + .texture = + { + .sampleType = wgpu::TextureSampleType::Float, + .viewDimension = wgpu::TextureViewDimension::e2D, + }, + }, + { + .binding = 1, + .visibility = wgpu::ShaderStage::Fragment, + .sampler = + { + .type = wgpu::SamplerBindingType::Filtering, + }, + }, + }; + + wgpu::BindGroupLayoutDescriptor bindingsDesc = { + .entryCount = std::size(bindingEntries), + .entries = bindingEntries, + }; + + m_bindGroupLayout = device.CreateBindGroupLayout(&bindingsDesc); + + wgpu::PipelineLayoutDescriptor pipelineLayoutDesc = { + .bindGroupLayoutCount = 1, + .bindGroupLayouts = &m_bindGroupLayout, + }; + + wgpu::PipelineLayout pipelineLayout = + device.CreatePipelineLayout(&pipelineLayoutDesc); + + wgpu::ShaderModule vertexShader = + m_vertexShaderHandle.compileSPIRVShaderModule( + device, + blit_texture_as_draw_vert, + std::size(blit_texture_as_draw_vert)); + + wgpu::ShaderModule fragmentShader = + m_fragmentShaderHandle.compileSPIRVShaderModule( + device, + blit_texture_as_draw_frag, + std::size(blit_texture_as_draw_frag)); + + wgpu::ColorTargetState colorTargetState = { + .format = wgpu::TextureFormat::RGBA8Unorm, + }; + + wgpu::FragmentState fragmentState = { + .module = fragmentShader, + .entryPoint = "main", + .targetCount = 1, + .targets = &colorTargetState, + }; + + wgpu::RenderPipelineDescriptor desc = { + .layout = pipelineLayout, + .vertex = + { + .module = vertexShader, + .entryPoint = "main", + }, + .primitive = + { + .topology = wgpu::PrimitiveTopology::TriangleStrip, + }, + .fragment = &fragmentState, + }; + + m_renderPipeline = device.CreateRenderPipeline(&desc); + } + + const wgpu::BindGroupLayout& bindGroupLayout() const + { + return m_bindGroupLayout; + } + wgpu::RenderPipeline renderPipeline() const { return m_renderPipeline; } + +private: + wgpu::BindGroupLayout m_bindGroupLayout; + EmJsHandle m_vertexShaderHandle; + EmJsHandle m_fragmentShaderHandle; + wgpu::RenderPipeline m_renderPipeline; +}; + +void RenderContextWebGPUImpl::generateMipmaps(wgpu::Texture texture) +{ + wgpu::CommandEncoder mipEncoder = m_device.CreateCommandEncoder(); + + if (!generate_mipmaps_builtin(mipEncoder, texture)) + { + // Generate the mipmaps manually by drawing each layer. + if (m_blitTextureAsDrawPipeline == nullptr) + { + m_blitTextureAsDrawPipeline = + std::make_unique(this); + } + + wgpu::TextureViewDescriptor textureViewDesc = { + .baseMipLevel = 0, + .mipLevelCount = 1, + }; + + wgpu::TextureView dstView, + srcView = texture.CreateView(&textureViewDesc); + + for (uint32_t level = 1; level < texture.GetMipLevelCount(); + ++level, srcView = std::move(dstView)) + { + textureViewDesc.baseMipLevel = level; + dstView = texture.CreateView(&textureViewDesc); + + wgpu::RenderPassColorAttachment attachment = { + .view = dstView, + .loadOp = wgpu::LoadOp::Clear, + .storeOp = wgpu::StoreOp::Store, + .clearValue = {}, + }; + + wgpu::RenderPassDescriptor mipPassDesc = { + .colorAttachmentCount = 1, + .colorAttachments = &attachment, + }; + + wgpu::RenderPassEncoder mipPass = + mipEncoder.BeginRenderPass(&mipPassDesc); + + wgpu::BindGroupEntry bindingEntries[] = { + { + .binding = 0, + .textureView = srcView, + }, + { + .binding = 1, + .sampler = m_linearSampler, + }, + }; + + wgpu::BindGroupDescriptor bindGroupDesc = { + .layout = m_blitTextureAsDrawPipeline->bindGroupLayout(), + .entryCount = std::size(bindingEntries), + .entries = bindingEntries, + }; + + wgpu::BindGroup bindings = m_device.CreateBindGroup(&bindGroupDesc); + mipPass.SetBindGroup(0, bindings); + + mipPass.SetPipeline(m_blitTextureAsDrawPipeline->renderPipeline()); + mipPass.Draw(4); + mipPass.End(); + } + } + + wgpu::CommandBuffer commands = mipEncoder.Finish(); + m_queue.Submit(1, &commands); +} + +rcp RenderContextWebGPUImpl::makeImageTexture( + uint32_t width, + uint32_t height, + uint32_t mipLevelCount, + const uint8_t imageDataRGBAPremul[]) +{ + wgpu::TextureDescriptor textureDesc = { + .usage = + wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::CopyDst, + .dimension = wgpu::TextureDimension::e2D, + .size = {width, height}, + .format = wgpu::TextureFormat::RGBA8Unorm, + .mipLevelCount = mipLevelCount, + }; + if (mipLevelCount > 1) + { + textureDesc.usage |= wgpu::TextureUsage::RenderAttachment; + } + + wgpu::Texture texture = m_device.CreateTexture(&textureDesc); + + wgpu::ImageCopyTexture dest = {.texture = texture}; + wgpu::TextureDataLayout layout = {.bytesPerRow = width * 4}; + wgpu::Extent3D extent = {width, height}; + m_queue.WriteTexture(&dest, + imageDataRGBAPremul, + height * width * 4, + &layout, + &extent); + + if (mipLevelCount > 1) + { + generateMipmaps(texture); + } + + return make_rcp(width, height, std::move(texture)); +} + +class BufferWebGPU : public BufferRing +{ +public: + static std::unique_ptr Make(wgpu::Device device, + wgpu::Queue queue, + size_t capacityInBytes, + wgpu::BufferUsage usage) + { + return std::make_unique(device, + queue, + capacityInBytes, + usage); + } + + BufferWebGPU(wgpu::Device device, + wgpu::Queue queue, + size_t capacityInBytesUnRounded, + wgpu::BufferUsage usage) : + // Storage buffers must be multiples of 4 in size. + BufferRing(math::round_up_to_multiple_of<4>( + std::max(capacityInBytesUnRounded, 1))), + m_queue(queue) + { + wgpu::BufferDescriptor desc = { + .usage = wgpu::BufferUsage::CopyDst | usage, + .size = capacityInBytes(), + }; + for (int i = 0; i < gpu::kBufferRingSize; ++i) + { + m_buffers[i] = device.CreateBuffer(&desc); + } + } + + wgpu::Buffer submittedBuffer() const + { + return m_buffers[submittedBufferIdx()]; + } + +protected: + void* onMapBuffer(int bufferIdx, size_t mapSizeInBytes) override + { + return shadowBuffer(); + } + + void onUnmapAndSubmitBuffer(int bufferIdx, size_t mapSizeInBytes) override + { + m_queue.WriteBuffer(m_buffers[bufferIdx], + 0, + shadowBuffer(), + mapSizeInBytes); + } + + const wgpu::Queue m_queue; + wgpu::Buffer m_buffers[kBufferRingSize]; +}; + +// GL TextureFormat to use for a texture that polyfills a storage buffer. +static wgpu::TextureFormat storage_texture_format( + gpu::StorageBufferStructure bufferStructure) +{ + switch (bufferStructure) + { + case gpu::StorageBufferStructure::uint32x4: + return wgpu::TextureFormat::RGBA32Uint; + case gpu::StorageBufferStructure::uint32x2: + return wgpu::TextureFormat::RG32Uint; + case gpu::StorageBufferStructure::float32x4: + return wgpu::TextureFormat::RGBA32Float; + } + RIVE_UNREACHABLE(); +} + +// Buffer ring with a texture used to polyfill storage buffers when they are +// disabled. +class StorageTextureBufferWebGPU : public BufferWebGPU +{ +public: + StorageTextureBufferWebGPU(wgpu::Device device, + wgpu::Queue queue, + size_t capacityInBytes, + gpu::StorageBufferStructure bufferStructure) : + BufferWebGPU( + device, + queue, + gpu::StorageTextureBufferSize(capacityInBytes, bufferStructure), + wgpu::BufferUsage::CopySrc), + m_bufferStructure(bufferStructure) + { + // Create a texture to mirror the buffer contents. + auto [textureWidth, textureHeight] = + gpu::StorageTextureSize(this->capacityInBytes(), bufferStructure); + + wgpu::TextureDescriptor desc{ + .usage = wgpu::TextureUsage::TextureBinding | + wgpu::TextureUsage::CopyDst, + .size = {textureWidth, textureHeight}, + .format = storage_texture_format(bufferStructure), + }; + + m_texture = device.CreateTexture(&desc); + m_textureView = m_texture.CreateView(); + } + + void updateTextureFromBuffer(size_t bindingSizeInBytes, + size_t offsetSizeInBytes, + wgpu::CommandEncoder encoder) const + { + auto [updateWidth, updateHeight] = + gpu::StorageTextureSize(bindingSizeInBytes, m_bufferStructure); + wgpu::ImageCopyBuffer srcBuffer = { + .layout = + { + .offset = offsetSizeInBytes, + .bytesPerRow = (STORAGE_TEXTURE_WIDTH * + gpu::StorageBufferElementSizeInBytes( + m_bufferStructure)), + }, + .buffer = submittedBuffer(), + }; + wgpu::ImageCopyTexture dstTexture = { + .texture = m_texture, + .origin = {0, 0, 0}, + }; + wgpu::Extent3D copySize = { + .width = updateWidth, + .height = updateHeight, + }; + encoder.CopyBufferToTexture(&srcBuffer, &dstTexture, ©Size); + } + + wgpu::TextureView textureView() const { return m_textureView; } + +private: + const StorageBufferStructure m_bufferStructure; + wgpu::Texture m_texture; + wgpu::TextureView m_textureView; +}; + +std::unique_ptr RenderContextWebGPUImpl::makeUniformBufferRing( + size_t capacityInBytes) +{ + // Uniform blocks must be multiples of 256 bytes in size. + capacityInBytes = std::max(capacityInBytes, 256); + assert(capacityInBytes % 256 == 0); + return std::make_unique(m_device, + m_queue, + capacityInBytes, + wgpu::BufferUsage::Uniform); +} + +std::unique_ptr RenderContextWebGPUImpl::makeStorageBufferRing( + size_t capacityInBytes, + gpu::StorageBufferStructure bufferStructure) +{ + if (m_contextOptions.disableStorageBuffers) + { + return std::make_unique(m_device, + m_queue, + capacityInBytes, + bufferStructure); + } + else + { + return std::make_unique(m_device, + m_queue, + capacityInBytes, + wgpu::BufferUsage::Storage); + } +} + +std::unique_ptr RenderContextWebGPUImpl::makeVertexBufferRing( + size_t capacityInBytes) +{ + return std::make_unique(m_device, + m_queue, + capacityInBytes, + wgpu::BufferUsage::Vertex); +} + +void RenderContextWebGPUImpl::resizeGradientTexture(uint32_t width, + uint32_t height) +{ + width = std::max(width, 1u); + height = std::max(height, 1u); + + wgpu::TextureDescriptor desc{ + .usage = wgpu::TextureUsage::RenderAttachment | + wgpu::TextureUsage::TextureBinding, + .size = {static_cast(width), static_cast(height)}, + .format = wgpu::TextureFormat::RGBA8Unorm, + }; + + m_gradientTexture = m_device.CreateTexture(&desc); + m_gradientTextureView = m_gradientTexture.CreateView(); +} + +void RenderContextWebGPUImpl::resizeTessellationTexture(uint32_t width, + uint32_t height) +{ + width = std::max(width, 1u); + height = std::max(height, 1u); + + wgpu::TextureDescriptor desc{ + .usage = wgpu::TextureUsage::RenderAttachment | + wgpu::TextureUsage::TextureBinding, + .size = {static_cast(width), static_cast(height)}, + .format = wgpu::TextureFormat::RGBA32Uint, + }; + + m_tessVertexTexture = m_device.CreateTexture(&desc); + m_tessVertexTextureView = m_tessVertexTexture.CreateView(); +} + +void RenderContextWebGPUImpl::resizeAtlasTexture(uint32_t width, + uint32_t height) +{ + width = std::max(width, 1u); + height = std::max(height, 1u); + + wgpu::TextureDescriptor desc{ + .usage = wgpu::TextureUsage::RenderAttachment | + wgpu::TextureUsage::TextureBinding, + .size = {static_cast(width), static_cast(height)}, + .format = wgpu::TextureFormat::R16Float, + }; + + m_atlasTexture = m_device.CreateTexture(&desc); + m_atlasTextureView = m_atlasTexture.CreateView(); +} + +wgpu::RenderPipeline RenderContextWebGPUImpl::makeDrawPipeline( + rive::gpu::DrawType drawType, + wgpu::TextureFormat framebufferFormat, + wgpu::ShaderModule vertexShader, + wgpu::ShaderModule fragmentShader, + EmJsHandle* pipelineJSHandleIfNeeded) +{ + std::vector attrs; + std::vector vertexBufferLayouts; + switch (drawType) + { + case DrawType::midpointFanPatches: + case DrawType::midpointFanCenterAAPatches: + case DrawType::outerCurvePatches: + { + attrs = { + { + .format = wgpu::VertexFormat::Float32x4, + .offset = 0, + .shaderLocation = 0, + }, + { + .format = wgpu::VertexFormat::Float32x4, + .offset = 4 * sizeof(float), + .shaderLocation = 1, + }, + }; + + vertexBufferLayouts = { + { + .arrayStride = sizeof(gpu::PatchVertex), + .stepMode = wgpu::VertexStepMode::Vertex, + .attributeCount = std::size(attrs), + .attributes = attrs.data(), + }, + }; + break; + } + case DrawType::interiorTriangulation: + case DrawType::atlasBlit: + { + attrs = { + { + .format = wgpu::VertexFormat::Float32x3, + .offset = 0, + .shaderLocation = 0, + }, + }; + + vertexBufferLayouts = { + { + .arrayStride = sizeof(gpu::TriangleVertex), + .stepMode = wgpu::VertexStepMode::Vertex, + .attributeCount = std::size(attrs), + .attributes = attrs.data(), + }, + }; + break; + } + case DrawType::imageRect: + RIVE_UNREACHABLE(); + case DrawType::imageMesh: + attrs = { + { + .format = wgpu::VertexFormat::Float32x2, + .offset = 0, + .shaderLocation = 0, + }, + { + .format = wgpu::VertexFormat::Float32x2, + .offset = 0, + .shaderLocation = 1, + }, + }; + + vertexBufferLayouts = { + { + .arrayStride = sizeof(float) * 2, + .stepMode = wgpu::VertexStepMode::Vertex, + .attributeCount = 1, + .attributes = &attrs[0], + }, + { + .arrayStride = sizeof(float) * 2, + .stepMode = wgpu::VertexStepMode::Vertex, + .attributeCount = 1, + .attributes = &attrs[1], + }, + }; + break; + case DrawType::atomicInitialize: + case DrawType::atomicResolve: + case DrawType::msaaStrokes: + case DrawType::msaaMidpointFanBorrowedCoverage: + case DrawType::msaaMidpointFans: + case DrawType::msaaMidpointFanStencilReset: + case DrawType::msaaMidpointFanPathsStencil: + case DrawType::msaaMidpointFanPathsCover: + case DrawType::msaaOuterCubics: + case DrawType::msaaStencilClipReset: + RIVE_UNREACHABLE(); + } + + wgpu::BlendState srcOverBlend = { + .color = {.dstFactor = wgpu::BlendFactor::OneMinusSrcAlpha}, + .alpha = {.dstFactor = wgpu::BlendFactor::OneMinusSrcAlpha}, + }; + + wgpu::ColorTargetState colorTargets[] = { + { + .format = framebufferFormat, + .blend = (m_contextOptions.plsType == PixelLocalStorageType::none) + ? &srcOverBlend + : nullptr, + }, + {.format = wgpu::TextureFormat::R32Uint}, + {.format = framebufferFormat}, + {.format = wgpu::TextureFormat::R32Uint}, + }; + static_assert(COLOR_PLANE_IDX == 0); + static_assert(CLIP_PLANE_IDX == 1); + static_assert(SCRATCH_COLOR_PLANE_IDX == 2); + static_assert(COVERAGE_PLANE_IDX == 3); + + wgpu::FragmentState fragmentState = { + .module = fragmentShader, + .entryPoint = "main", + .targetCount = static_cast( + m_contextOptions.plsType == + PixelLocalStorageType::EXT_shader_pixel_local_storage + ? 1 + : 4), + .targets = colorTargets, + }; + + wgpu::RenderPipelineDescriptor desc = { + .layout = m_drawPipelineLayout, + .vertex = + { + .module = vertexShader, + .entryPoint = "main", + .bufferCount = std::size(vertexBufferLayouts), + .buffers = vertexBufferLayouts.data(), + }, + .primitive = + { + .topology = wgpu::PrimitiveTopology::TriangleList, + .frontFace = frontFaceForRenderTargetDraws(), + .cullMode = DrawTypeIsImageDraw(drawType) + ? wgpu::CullMode::None + : wgpu::CullMode::Back, + }, + .fragment = &fragmentState, + }; + + return m_device.CreateRenderPipeline(&desc); +} + +wgpu::RenderPassEncoder RenderContextWebGPUImpl::makePLSRenderPass( + wgpu::CommandEncoder encoder, + const RenderTargetWebGPU* renderTarget, + wgpu::LoadOp loadOp, + const wgpu::Color& clearColor, + EmJsHandle* renderPassJSHandleIfNeeded) +{ + wgpu::RenderPassColorAttachment plsAttachments[4] = { + { + // framebuffer + .view = renderTarget->m_targetTextureView, + .loadOp = loadOp, + .storeOp = wgpu::StoreOp::Store, + .clearValue = clearColor, + }, + { + // clip + .view = renderTarget->m_clipTextureView, + .loadOp = wgpu::LoadOp::Clear, + .storeOp = wgpu::StoreOp::Discard, + .clearValue = {}, + }, + { + // scratchColor + .view = renderTarget->m_scratchColorTextureView, + .loadOp = wgpu::LoadOp::Clear, + .storeOp = wgpu::StoreOp::Discard, + .clearValue = {}, + }, + { + // coverage + .view = renderTarget->m_coverageTextureView, + .loadOp = wgpu::LoadOp::Clear, + .storeOp = wgpu::StoreOp::Discard, + .clearValue = {}, + }, + }; + static_assert(COLOR_PLANE_IDX == 0); + static_assert(CLIP_PLANE_IDX == 1); + static_assert(SCRATCH_COLOR_PLANE_IDX == 2); + static_assert(COVERAGE_PLANE_IDX == 3); + + wgpu::RenderPassDescriptor passDesc = { + .colorAttachmentCount = static_cast( + m_contextOptions.plsType == + PixelLocalStorageType::EXT_shader_pixel_local_storage + ? 1 + : 4), + .colorAttachments = plsAttachments, + }; + + return encoder.BeginRenderPass(&passDesc); +} + +static wgpu::Buffer webgpu_buffer(const BufferRing* bufferRing) +{ + assert(bufferRing != nullptr); + return static_cast(bufferRing)->submittedBuffer(); +} + +template +void update_webgpu_storage_texture(const BufferRing* bufferRing, + size_t bindingCount, + size_t firstElement, + wgpu::CommandEncoder encoder) +{ + assert(bufferRing != nullptr); + auto storageTextureBuffer = + static_cast(bufferRing); + storageTextureBuffer->updateTextureFromBuffer( + bindingCount * sizeof(HighLevelStruct), + firstElement * sizeof(HighLevelStruct), + encoder); +} + +wgpu::TextureView webgpu_storage_texture_view(const BufferRing* bufferRing) +{ + assert(bufferRing != nullptr); + return static_cast(bufferRing) + ->textureView(); +} + +void RenderContextWebGPUImpl::flush(const FlushDescriptor& desc) +{ + auto* renderTarget = + static_cast(desc.renderTarget); + wgpu::CommandEncoder encoder = m_device.CreateCommandEncoder(); + + // If storage buffers are disabled, copy their contents to textures. + if (m_contextOptions.disableStorageBuffers) + { + if (desc.pathCount > 0) + { + update_webgpu_storage_texture(pathBufferRing(), + desc.pathCount, + desc.firstPath, + encoder); + update_webgpu_storage_texture(paintBufferRing(), + desc.pathCount, + desc.firstPaint, + encoder); + update_webgpu_storage_texture( + paintAuxBufferRing(), + desc.pathCount, + desc.firstPaintAux, + encoder); + } + if (desc.contourCount > 0) + { + update_webgpu_storage_texture(contourBufferRing(), + desc.contourCount, + desc.firstContour, + encoder); + } + } + + wgpu::BindGroupEntry perFlushBindingEntries[DRAW_BINDINGS_COUNT] = { + { + .binding = FLUSH_UNIFORM_BUFFER_IDX, + .buffer = webgpu_buffer(flushUniformBufferRing()), + .offset = desc.flushUniformDataOffsetInBytes, + }, + m_contextOptions.disableStorageBuffers ? + wgpu::BindGroupEntry{ + .binding = PATH_BUFFER_IDX, + .textureView = webgpu_storage_texture_view(pathBufferRing()) + } : + wgpu::BindGroupEntry{ + .binding = PATH_BUFFER_IDX, + .buffer = webgpu_buffer(pathBufferRing()), + .offset = desc.firstPath * sizeof(gpu::PathData), + }, + m_contextOptions.disableStorageBuffers ? + wgpu::BindGroupEntry{ + .binding = PAINT_BUFFER_IDX, + .textureView = webgpu_storage_texture_view(paintBufferRing()), + } : + wgpu::BindGroupEntry{ + .binding = PAINT_BUFFER_IDX, + .buffer = webgpu_buffer(paintBufferRing()), + .offset = desc.firstPaint * sizeof(gpu::PaintData), + }, + m_contextOptions.disableStorageBuffers ? + wgpu::BindGroupEntry{ + .binding = PAINT_AUX_BUFFER_IDX, + .textureView = webgpu_storage_texture_view(paintAuxBufferRing()), + } : + wgpu::BindGroupEntry{ + .binding = PAINT_AUX_BUFFER_IDX, + .buffer = webgpu_buffer(paintAuxBufferRing()), + .offset = desc.firstPaintAux * sizeof(gpu::PaintAuxData), + }, + m_contextOptions.disableStorageBuffers ? + wgpu::BindGroupEntry{ + .binding = CONTOUR_BUFFER_IDX, + .textureView = webgpu_storage_texture_view(contourBufferRing()), + } : + wgpu::BindGroupEntry{ + .binding = CONTOUR_BUFFER_IDX, + .buffer = webgpu_buffer(contourBufferRing()), + .offset = desc.firstContour * sizeof(gpu::ContourData), + }, + { + .binding = FEATHER_TEXTURE_IDX, + .textureView = m_featherTextureView, + }, + { + .binding = TESS_VERTEX_TEXTURE_IDX, + .textureView = m_tessVertexTextureView, + }, + { + .binding = ATLAS_TEXTURE_IDX, + .textureView = m_atlasTextureView, + }, + { + .binding = GRAD_TEXTURE_IDX, + .textureView = m_gradientTextureView, + }, + { + .binding = IMAGE_DRAW_UNIFORM_BUFFER_IDX, + .buffer = webgpu_buffer(imageDrawUniformBufferRing()), + .size = sizeof(gpu::ImageDrawUniforms), + }, + }; + + // Render the complex color ramps to the gradient texture. + if (desc.gradDataHeight > 0) + { + wgpu::BindGroupDescriptor colorRampBindGroupDesc = { + .layout = m_colorRampPipeline->bindGroupLayout(), + .entryCount = COLOR_RAMP_BINDINGS_COUNT, + .entries = perFlushBindingEntries, + }; + + wgpu::RenderPassColorAttachment attachment = { + .view = m_gradientTextureView, + .loadOp = wgpu::LoadOp::Clear, + .storeOp = wgpu::StoreOp::Store, + .clearValue = {}, + }; + + wgpu::RenderPassDescriptor gradPassDesc = { + .colorAttachmentCount = 1, + .colorAttachments = &attachment, + }; + + wgpu::RenderPassEncoder gradPass = + encoder.BeginRenderPass(&gradPassDesc); + gradPass.SetViewport(0.f, + 0.f, + gpu::kGradTextureWidth, + static_cast(desc.gradDataHeight), + 0.0, + 1.0); + gradPass.SetPipeline(m_colorRampPipeline->renderPipeline()); + gradPass.SetVertexBuffer(0, + webgpu_buffer(gradSpanBufferRing()), + desc.firstGradSpan * + sizeof(gpu::GradientSpan)); + gradPass.SetBindGroup( + 0, + m_device.CreateBindGroup(&colorRampBindGroupDesc)); + gradPass.Draw(gpu::GRAD_SPAN_TRI_STRIP_VERTEX_COUNT, + desc.gradSpanCount, + 0, + 0); + gradPass.End(); + } + + // Tessellate all curves into vertices in the tessellation texture. + if (desc.tessVertexSpanCount > 0) + { + wgpu::BindGroupDescriptor tessBindGroupDesc = { + .layout = m_tessellatePipeline->perFlushBindingsLayout(), + .entryCount = TESS_BINDINGS_COUNT, + .entries = perFlushBindingEntries, + }; + + wgpu::RenderPassColorAttachment attachment{ + .view = m_tessVertexTextureView, + .loadOp = wgpu::LoadOp::Clear, + .storeOp = wgpu::StoreOp::Store, + .clearValue = {}, + }; + + wgpu::RenderPassDescriptor tessPassDesc = { + .colorAttachmentCount = 1, + .colorAttachments = &attachment, + }; + + wgpu::RenderPassEncoder tessPass = + encoder.BeginRenderPass(&tessPassDesc); + tessPass.SetViewport(0.f, + 0.f, + gpu::kTessTextureWidth, + static_cast(desc.tessDataHeight), + 0.0, + 1.0); + tessPass.SetPipeline(m_tessellatePipeline->renderPipeline()); + tessPass.SetVertexBuffer(0, + webgpu_buffer(tessSpanBufferRing()), + desc.firstTessVertexSpan * + sizeof(gpu::TessVertexSpan)); + tessPass.SetIndexBuffer(m_tessSpanIndexBuffer, + wgpu::IndexFormat::Uint16); + tessPass.SetBindGroup(PER_FLUSH_BINDINGS_SET, + m_device.CreateBindGroup(&tessBindGroupDesc)); + tessPass.SetBindGroup(IMMUTABLE_SAMPLER_BINDINGS_SET, + m_samplerBindings); + tessPass.DrawIndexed(std::size(gpu::kTessSpanIndices), + desc.tessVertexSpanCount, + 0, + 0, + 0); + tessPass.End(); + } + + // Render the atlas if we have any offscreen feathers. + if ((desc.atlasFillBatchCount | desc.atlasStrokeBatchCount) != 0) + { + wgpu::BindGroupDescriptor atlasBindGroupDesc = { + .layout = m_atlasPipeline->perFlushBindingsLayout(), + .entryCount = ATLAS_BINDINGS_COUNT, + .entries = perFlushBindingEntries, + }; + + wgpu::RenderPassColorAttachment attachment{ + .view = m_atlasTextureView, + .loadOp = wgpu::LoadOp::Clear, + .storeOp = wgpu::StoreOp::Store, + .clearValue = {0, 0, 0, 0}, + }; + + wgpu::RenderPassDescriptor atlasPassDesc = { + .colorAttachmentCount = 1, + .colorAttachments = &attachment, + }; + + wgpu::RenderPassEncoder atlasPass = + encoder.BeginRenderPass(&atlasPassDesc); + atlasPass.SetViewport(0.f, + 0.f, + desc.atlasContentWidth, + desc.atlasContentHeight, + 0.0, + 1.0); + atlasPass.SetVertexBuffer(0, m_pathPatchVertexBuffer); + atlasPass.SetIndexBuffer(m_pathPatchIndexBuffer, + wgpu::IndexFormat::Uint16); + atlasPass.SetBindGroup(PER_FLUSH_BINDINGS_SET, + m_device.CreateBindGroup(&atlasBindGroupDesc)); + atlasPass.SetBindGroup(IMMUTABLE_SAMPLER_BINDINGS_SET, + m_samplerBindings); + + if (desc.atlasFillBatchCount != 0) + { + atlasPass.SetPipeline(m_atlasPipeline->fillPipeline()); + for (size_t i = 0; i < desc.atlasFillBatchCount; ++i) + { + const gpu::AtlasDrawBatch& fillBatch = desc.atlasFillBatches[i]; + atlasPass.SetScissorRect(fillBatch.scissor.left, + fillBatch.scissor.top, + fillBatch.scissor.width(), + fillBatch.scissor.height()); + atlasPass.DrawIndexed(gpu::kMidpointFanCenterAAPatchIndexCount, + fillBatch.patchCount, + gpu::kMidpointFanCenterAAPatchBaseIndex, + 0, + fillBatch.basePatch); + } + } + + if (desc.atlasStrokeBatchCount != 0) + { + atlasPass.SetPipeline(m_atlasPipeline->strokePipeline()); + for (size_t i = 0; i < desc.atlasStrokeBatchCount; ++i) + { + const gpu::AtlasDrawBatch& strokeBatch = + desc.atlasStrokeBatches[i]; + atlasPass.SetScissorRect(strokeBatch.scissor.left, + strokeBatch.scissor.top, + strokeBatch.scissor.width(), + strokeBatch.scissor.height()); + atlasPass.DrawIndexed(gpu::kMidpointFanPatchBorderIndexCount, + strokeBatch.patchCount, + gpu::kMidpointFanPatchBaseIndex, + 0, + strokeBatch.basePatch); + } + } + + atlasPass.End(); + } + + wgpu::LoadOp loadOp; + wgpu::Color clearColor; + if (desc.colorLoadAction == LoadAction::clear) + { + loadOp = wgpu::LoadOp::Clear; + float cc[4]; + UnpackColorToRGBA32FPremul(desc.colorClearValue, cc); + clearColor = {cc[0], cc[1], cc[2], cc[3]}; + } + else + { + loadOp = wgpu::LoadOp::Load; + } + + EmJsHandle drawPassJSHandle; + wgpu::RenderPassEncoder drawPass = makePLSRenderPass(encoder, + renderTarget, + loadOp, + clearColor, + &drawPassJSHandle); + drawPass.SetViewport(0.f, + 0.f, + renderTarget->width(), + renderTarget->height(), + 0.0, + 1.0); + + bool needsTextureBindings = + m_contextOptions.plsType == PixelLocalStorageType::subpassLoad; + if (needsTextureBindings) + { + wgpu::BindGroupEntry plsTextureBindingEntries[] = { + { + .binding = COLOR_PLANE_IDX, + .textureView = renderTarget->m_targetTextureView, + }, + { + .binding = CLIP_PLANE_IDX, + .textureView = renderTarget->m_clipTextureView, + }, + { + .binding = SCRATCH_COLOR_PLANE_IDX, + .textureView = renderTarget->m_scratchColorTextureView, + }, + { + .binding = COVERAGE_PLANE_IDX, + .textureView = renderTarget->m_coverageTextureView, + }, + }; + + wgpu::BindGroupDescriptor plsTextureBindingsGroupDesc = { + .layout = m_drawBindGroupLayouts[PLS_TEXTURE_BINDINGS_SET], + .entryCount = std::size(plsTextureBindingEntries), + .entries = plsTextureBindingEntries, + }; + + wgpu::BindGroup plsTextureBindings = + m_device.CreateBindGroup(&plsTextureBindingsGroupDesc); + drawPass.SetBindGroup(PLS_TEXTURE_BINDINGS_SET, plsTextureBindings); + } + + if (m_contextOptions.plsType == + PixelLocalStorageType::EXT_shader_pixel_local_storage) + { + enable_shader_pixel_local_storage_ext(drawPass, true); + + // Draw the load action for EXT_shader_pixel_local_storage. + std::array clearColor; + LoadStoreActionsEXT loadActions = + gpu::BuildLoadActionsEXT(desc, &clearColor); + const LoadStoreEXTPipeline& loadPipeline = + m_loadStoreEXTPipelines + .try_emplace(loadActions, + this, + loadActions, + renderTarget->framebufferFormat()) + .first->second; + + if (loadActions & LoadStoreActionsEXT::clearColor) + { + void* uniformData = + m_loadStoreEXTUniforms->mapBuffer(sizeof(clearColor)); + memcpy(uniformData, clearColor.data(), sizeof(clearColor)); + m_loadStoreEXTUniforms->unmapAndSubmitBuffer(); + + wgpu::BindGroupEntry uniformBindingEntries[] = { + { + .binding = 0, + .buffer = webgpu_buffer(m_loadStoreEXTUniforms.get()), + }, + }; + + wgpu::BindGroupDescriptor uniformBindGroupDesc = { + .layout = loadPipeline.bindGroupLayout(), + .entryCount = std::size(uniformBindingEntries), + .entries = uniformBindingEntries, + }; + + wgpu::BindGroup uniformBindings = + m_device.CreateBindGroup(&uniformBindGroupDesc); + drawPass.SetBindGroup(0, uniformBindings); + } + + drawPass.SetPipeline( + loadPipeline.renderPipeline(renderTarget->framebufferFormat())); + drawPass.Draw(4); + } + + drawPass.SetBindGroup(IMMUTABLE_SAMPLER_BINDINGS_SET, m_samplerBindings); + + wgpu::BindGroupDescriptor perFlushBindGroupDesc = { + .layout = m_drawBindGroupLayouts[PER_FLUSH_BINDINGS_SET], + .entryCount = std::size(perFlushBindingEntries), + .entries = perFlushBindingEntries, + }; + + wgpu::BindGroup perFlushBindings = + m_device.CreateBindGroup(&perFlushBindGroupDesc); + + // Execute the DrawList. + bool needsNewBindings = true; + for (const DrawBatch& batch : *desc.drawList) + { + DrawType drawType = batch.drawType; + + // Bind the appropriate image texture, if any. + wgpu::TextureView imageTextureView = m_nullImagePaintTextureView; + if (auto imageTexture = + static_cast(batch.imageTexture)) + { + imageTextureView = imageTexture->textureView(); + needsNewBindings = true; + } + + if (needsNewBindings || + // Image draws always re-bind because they update the dynamic offset + // to their uniforms. + drawType == DrawType::imageRect || drawType == DrawType::imageMesh) + { + drawPass.SetBindGroup(PER_FLUSH_BINDINGS_SET, + perFlushBindings, + 1, + &batch.imageDrawDataOffset); + + wgpu::BindGroupEntry perDrawBindingEntries[] = { + { + .binding = IMAGE_TEXTURE_IDX, + .textureView = imageTextureView, + }, + }; + + wgpu::BindGroupDescriptor perDrawBindGroupDesc = { + .layout = m_drawBindGroupLayouts[PER_DRAW_BINDINGS_SET], + .entryCount = std::size(perDrawBindingEntries), + .entries = perDrawBindingEntries, + }; + + wgpu::BindGroup perDrawBindings = + m_device.CreateBindGroup(&perDrawBindGroupDesc); + drawPass.SetBindGroup(PER_DRAW_BINDINGS_SET, + perDrawBindings, + 0, + nullptr); + } + + // Setup the pipeline for this specific drawType and shaderFeatures. + const DrawPipeline& drawPipeline = + m_drawPipelines + .try_emplace( + gpu::ShaderUniqueKey(drawType, + batch.shaderFeatures, + gpu::InterlockMode::rasterOrdering, + gpu::ShaderMiscFlags::none), + this, + drawType, + batch.shaderFeatures, + m_contextOptions) + .first->second; + drawPass.SetPipeline( + drawPipeline.renderPipeline(renderTarget->framebufferFormat())); + + switch (drawType) + { + case DrawType::midpointFanPatches: + case DrawType::midpointFanCenterAAPatches: + case DrawType::outerCurvePatches: + { + // Draw PLS patches that connect the tessellation vertices. + drawPass.SetVertexBuffer(0, m_pathPatchVertexBuffer); + drawPass.SetIndexBuffer(m_pathPatchIndexBuffer, + wgpu::IndexFormat::Uint16); + drawPass.DrawIndexed(gpu::PatchIndexCount(drawType), + batch.elementCount, + gpu::PatchBaseIndex(drawType), + 0, + batch.baseElement); + break; + } + case DrawType::interiorTriangulation: + case DrawType::atlasBlit: + { + drawPass.SetVertexBuffer(0, + webgpu_buffer(triangleBufferRing())); + drawPass.Draw(batch.elementCount, 1, batch.baseElement); + break; + } + case DrawType::imageRect: + RIVE_UNREACHABLE(); + case DrawType::imageMesh: + { + auto vertexBuffer = static_cast( + batch.vertexBuffer); + auto uvBuffer = + static_cast(batch.uvBuffer); + auto indexBuffer = static_cast( + batch.indexBuffer); + drawPass.SetVertexBuffer(0, vertexBuffer->submittedBuffer()); + drawPass.SetVertexBuffer(1, uvBuffer->submittedBuffer()); + drawPass.SetIndexBuffer(indexBuffer->submittedBuffer(), + wgpu::IndexFormat::Uint16); + drawPass.DrawIndexed(batch.elementCount, 1, batch.baseElement); + break; + } + case DrawType::atomicInitialize: + case DrawType::atomicResolve: + case DrawType::msaaStrokes: + case DrawType::msaaMidpointFanBorrowedCoverage: + case DrawType::msaaMidpointFans: + case DrawType::msaaMidpointFanStencilReset: + case DrawType::msaaMidpointFanPathsStencil: + case DrawType::msaaMidpointFanPathsCover: + case DrawType::msaaOuterCubics: + case DrawType::msaaStencilClipReset: + RIVE_UNREACHABLE(); + } + } + + if (m_contextOptions.plsType == + PixelLocalStorageType::EXT_shader_pixel_local_storage) + { + // Draw the store action for EXT_shader_pixel_local_storage. + LoadStoreActionsEXT actions = LoadStoreActionsEXT::storeColor; + auto it = m_loadStoreEXTPipelines.try_emplace( + actions, + this, + actions, + renderTarget->framebufferFormat()); + LoadStoreEXTPipeline* storePipeline = &it.first->second; + drawPass.SetPipeline( + storePipeline->renderPipeline(renderTarget->framebufferFormat())); + drawPass.Draw(4); + + enable_shader_pixel_local_storage_ext(drawPass, false); + } + + drawPass.End(); + + wgpu::CommandBuffer commands = encoder.Finish(); + m_queue.Submit(1, &commands); +} + +std::unique_ptr RenderContextWebGPUImpl::MakeContext( + wgpu::Device device, + wgpu::Queue queue, + const ContextOptions& contextOptions) +{ + std::unique_ptr impl; + switch (contextOptions.plsType) + { + case PixelLocalStorageType::subpassLoad: +#ifdef RIVE_WEBGPU + impl = std::unique_ptr( + new RenderContextWebGPUVulkan(device, queue, contextOptions)); + break; +#endif + case PixelLocalStorageType::EXT_shader_pixel_local_storage: + case PixelLocalStorageType::none: + impl = std::unique_ptr( + new RenderContextWebGPUImpl(device, queue, contextOptions)); + break; + } + impl->initGPUObjects(); + return std::make_unique(std::move(impl)); +} +} // namespace rive::gpu diff --git a/third_party/rive_renderer/source/webgpu/render_context_webgpu_vulkan.cpp b/third_party/rive_renderer/source/webgpu/render_context_webgpu_vulkan.cpp new file mode 100644 index 0000000..8ed5027 --- /dev/null +++ b/third_party/rive_renderer/source/webgpu/render_context_webgpu_vulkan.cpp @@ -0,0 +1,343 @@ +/* + * Copyright 2023 Rive + */ + +#ifdef RIVE_WEBGPU + +#include "render_context_webgpu_vulkan.hpp" + +#include "shaders/constants.glsl" + +#include +#include +#include + +namespace rive::gpu +{ +// Create a group for binding PLS textures as Vulkan input attachments. The +// "inputTexture" property is nonstandard WebGPU. +EM_JS(int, make_pls_input_attachment_texture_bind_group, (int device), { + device = JsValStore.get(device); + const plsBindBroupLayout = device.createBindGroupLayout({ + entries : [ + { + binding : 0, + visibility : GPUShaderStage.FRAGMENT, + inputTexture : {viewDimension : "2d"}, + }, + { + binding : 1, + visibility : GPUShaderStage.FRAGMENT, + inputTexture : {viewDimension : "2d"}, + }, + { + binding : 2, + visibility : GPUShaderStage.FRAGMENT, + inputTexture : {viewDimension : "2d"}, + }, + { + binding : 3, + visibility : GPUShaderStage.FRAGMENT, + inputTexture : {viewDimension : "2d"}, + }, + ] + }); + return JsValStore.add(plsBindBroupLayout); +}); + +wgpu::BindGroupLayout RenderContextWebGPUVulkan::initTextureBindGroup() +{ + m_plsTextureBindGroupJSHandle = + EmJsHandle(make_pls_input_attachment_texture_bind_group( + emscripten_webgpu_export_device(device().Get()))); + return wgpu::BindGroupLayout::Acquire( + emscripten_webgpu_import_bind_group_layout( + m_plsTextureBindGroupJSHandle.get())); +} + +// The "TRANSIENT_ATTACHMENT" and "INPUT_ATTACHMENT" flags are nonstandard +// WebGPU. +EM_JS(int, texture_usage_transient_input_attachment, (), { + return GPUTextureUsage.TRANSIENT_ATTACHMENT | + GPUTextureUsage.INPUT_ATTACHMENT; +}); + +rcp RenderContextWebGPUVulkan::makeRenderTarget( + wgpu::TextureFormat framebufferFormat, + uint32_t width, + uint32_t height) +{ + return rcp(new RenderTargetWebGPU( + device(), + framebufferFormat, + width, + height, + static_cast( + texture_usage_transient_input_attachment()))); +} + +// Create a standard PLS "draw" pipeline that uses Vulkan input attachments and +// VK_EXT_rasterization_order_attachment_access for pixel local storage. The +// "inputs" and "features" properties on GPUFragmentState, and the "usedAsInput" +// property on GPUColorTargetState are nonstandard WebGPU. +EM_JS(int, + make_pls_draw_pipeline, + (int device, + rive::gpu::DrawType drawType, + wgpu::TextureFormat framebufferFormat, + int vertexShader, + int fragmentShader, + int pipelineLayout, + bool clockwiseFrontFace), + { + device = JsValStore.get(device); + vertexShader = JsValStore.get(vertexShader); + fragmentShader = JsValStore.get(fragmentShader); + pipelineLayout = JsValStore.get(pipelineLayout); + + const RGBA8_UNORM = 0x00000012; + const BGRA8_UNORM = 0x00000017; + switch (framebufferFormat) + { + case RGBA8_UNORM: + framebufferFormat = "rgba8unorm"; + break; + case BGRA8_UNORM: + framebufferFormat = "bgra8unorm"; + break; + default: + throw "unsupported framebuffer format " + framebufferFormat; + } + + let vertexBufferLayout; + switch (drawType) + { + case 0: + case 1: + attrs = [ + { + format : "float32x4", + offset : 0, + shaderLocation : 0, + }, + { + format : "float32x4", + offset : 4 * 4, + shaderLocation : 1, + }, + ]; + vertexBufferLayouts = [ + { + arrayStride : 4 * 8, + stepMode : "vertex", + attributes : attrs, + }, + ]; + break; + case 2: + attrs = [ + { + format : "float32x3", + offset : 0, + shaderLocation : 0, + }, + ]; + + vertexBufferLayouts = [ + { + arrayStride : 4 * 3, + stepMode : "vertex", + attributes : attrs, + }, + ]; + break; + case 3: + attrs = [ + { + format : "float32x2", + offset : 0, + shaderLocation : 0, + }, + { + format : "float32x2", + offset : 0, + shaderLocation : 1, + }, + ]; + + vertexBufferLayouts = [ + { + arrayStride : 4 * 2, + stepMode : "vertex", + attributes : [attrs[0]], + }, + { + arrayStride : 4 * 2, + stepMode : "vertex", + attributes : [attrs[1]], + }, + ]; + break; + } + + const pipelineDesc = { + vertex : { + module : vertexShader, + entryPoint : "main", + buffers : vertexBufferLayouts, + }, + fragment : { + module : fragmentShader, + entryPoint : "main", + inputs : [ + {format : framebufferFormat, usedAsColor : true}, + {format : "r32uint", usedAsColor : true}, + {format : framebufferFormat, usedAsColor : true}, + {format : "r32uint", usedAsColor : true}, + ], + targets : [ + {format : framebufferFormat, usedAsInput : true}, + {format : "r32uint", usedAsInput : true}, + {format : framebufferFormat, usedAsInput : true}, + {format : "r32uint", usedAsInput : true}, + ], + features : GPUFragmentStateFeatures + .RASTERIZATION_ORDER_ATTACHMENT_ACCESS, + }, + primitive : { + topology : "triangle-list", + frontFace : clockwiseFrontFace ? "cw" : "ccw", + cullMode : drawType != 3 ? "back" : "none" + }, + layout : pipelineLayout + }; + + const pipeline = device.createRenderPipeline(pipelineDesc); + return JsValStore.add(pipeline); + }); + +wgpu::RenderPipeline RenderContextWebGPUVulkan::makeDrawPipeline( + rive::gpu::DrawType drawType, + wgpu::TextureFormat framebufferFormat, + wgpu::ShaderModule vertexShader, + wgpu::ShaderModule fragmentShader, + EmJsHandle* pipelineJSHandleIfNeeded) +{ + *pipelineJSHandleIfNeeded = EmJsHandle(make_pls_draw_pipeline( + emscripten_webgpu_export_device(device().Get()), + drawType, + framebufferFormat, + emscripten_webgpu_export_shader_module(vertexShader.Get()), + emscripten_webgpu_export_shader_module(fragmentShader.Get()), + emscripten_webgpu_export_pipeline_layout(drawPipelineLayout().Get()), + frontFaceForRenderTargetDraws() == wgpu::FrontFace::CW)); + static_assert(COLOR_PLANE_IDX == 0); + static_assert(CLIP_PLANE_IDX == 1); + static_assert(SCRATCH_COLOR_PLANE_IDX == 2); + static_assert(COVERAGE_PLANE_IDX == 3); + return wgpu::RenderPipeline::Acquire( + emscripten_webgpu_import_render_pipeline( + pipelineJSHandleIfNeeded->get())); +} + +// Create a standard PLS "draw" render pass that uses Vulkan input attachments +// for pixel local storage. The "inputAttachments" property on +// GPURenderPassDescriptor is nonstandard WebGPU. +EM_JS(int, + make_pls_render_pass, + (int encoder, + int tex0, + int tex1, + int tex2, + int tex3, + wgpu::LoadOp loadOp, + double r, + double g, + double b, + double a), + { + encoder = JsValStore.get(encoder); + tex0 = JsValStore.get(tex0); + tex1 = JsValStore.get(tex1); + tex2 = JsValStore.get(tex2); + tex3 = JsValStore.get(tex3); + + const CLEAR = 1; + const LOAD = 2; + switch (loadOp) + { + case CLEAR: + loadOp = "clear"; + break; + case LOAD: + loadOp = "load"; + break; + default: + throw "unsupported framebuffer format " + framebufferFormat; + } + + const zero = {r : 0, g : 0, b : 0, a : 0}; + const plsAttachments = [ + { + view : tex0, + loadOp : loadOp, + storeOp : "store", + clearValue : {r : r, g : g, b : b, a : a}, + }, + { + view : tex1, + loadOp : "clear", + storeOp : "discard", + clearValue : zero, + }, + { + view : tex2, + loadOp : "clear", + storeOp : "discard", + clearValue : zero, + }, + { + view : tex3, + loadOp : "clear", + storeOp : "discard", + clearValue : zero, + }, + ]; + + const renderPass = encoder.beginRenderPass({ + inputAttachments : plsAttachments, + colorAttachments : plsAttachments, + }); + + return JsValStore.add(renderPass); + }); + +wgpu::RenderPassEncoder RenderContextWebGPUVulkan::makePLSRenderPass( + wgpu::CommandEncoder encoder, + const RenderTargetWebGPU* renderTarget, + wgpu::LoadOp loadOp, + const wgpu::Color& clearColor, + EmJsHandle* renderPassJSHandleIfNeeded) +{ + *renderPassJSHandleIfNeeded = EmJsHandle(make_pls_render_pass( + emscripten_webgpu_export_command_encoder(encoder.Get()), + emscripten_webgpu_export_texture_view( + renderTarget->m_targetTextureView.Get()), + emscripten_webgpu_export_texture_view( + renderTarget->m_coverageTextureView.Get()), + emscripten_webgpu_export_texture_view( + renderTarget->m_clipTextureView.Get()), + emscripten_webgpu_export_texture_view( + renderTarget->m_scratchColorTextureView.Get()), + loadOp, + clearColor.r, + clearColor.g, + clearColor.b, + clearColor.a)); + return wgpu::RenderPassEncoder::Acquire( + emscripten_webgpu_import_render_pass_encoder( + renderPassJSHandleIfNeeded->get())); +} +} // namespace rive::gpu + +#endif diff --git a/third_party/rive_renderer/source/webgpu/render_context_webgpu_vulkan.hpp b/third_party/rive_renderer/source/webgpu/render_context_webgpu_vulkan.hpp new file mode 100644 index 0000000..f91557e --- /dev/null +++ b/third_party/rive_renderer/source/webgpu/render_context_webgpu_vulkan.hpp @@ -0,0 +1,57 @@ +/* + * Copyright 2023 Rive + */ + +#pragma once + +#ifdef RIVE_WEBGPU + +#include "rive/renderer/webgpu/render_context_webgpu_impl.hpp" + +namespace rive::gpu +{ +// WebGPU implementation that uses Vulkan input attachments, +// VK_EXT_rasterization_order_attachment_access, and subpassLoad() for pixel +// local storage. These Vulkan features are accessed via nonstandard WebGPU +// APIs. +class RenderContextWebGPUVulkan : public RenderContextWebGPUImpl +{ +public: + rcp makeRenderTarget(wgpu::TextureFormat, + uint32_t width, + uint32_t height) override; + +protected: + wgpu::BindGroupLayout initTextureBindGroup() override; + + wgpu::RenderPipeline makeDrawPipeline( + rive::gpu::DrawType drawType, + wgpu::TextureFormat framebufferFormat, + wgpu::ShaderModule vertexShader, + wgpu::ShaderModule fragmentShader, + EmJsHandle* pipelineJSHandleIfNeeded) override; + + wgpu::RenderPassEncoder makePLSRenderPass( + wgpu::CommandEncoder, + const RenderTargetWebGPU*, + wgpu::LoadOp, + const wgpu::Color& clearColor, + EmJsHandle* renderPassJSHandleIfNeeded) override; + +private: + friend class RenderContextWebGPUImpl; + + RenderContextWebGPUVulkan(wgpu::Device device, + wgpu::Queue queue, + const ContextOptions& contextOptions) : + RenderContextWebGPUImpl(device, queue, contextOptions) + { + assert(contextOptions.plsType == PixelLocalStorageType::subpassLoad); + m_platformFeatures.supportsRasterOrdering = true; + } + + EmJsHandle m_plsTextureBindGroupJSHandle; +}; +} // namespace rive::gpu + +#endif diff --git a/third_party/sheenbidi/include/SBAlgorithm.h b/third_party/sheenbidi/include/SBAlgorithm.h new file mode 100644 index 0000000..15758de --- /dev/null +++ b/third_party/sheenbidi/include/SBAlgorithm.h @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2016-2018 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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 _SB_PUBLIC_ALGORITHM_H +#define _SB_PUBLIC_ALGORITHM_H + +#include "SBBase.h" +#include "SBBidiType.h" +#include "SBCodepointSequence.h" +#include "SBParagraph.h" + +typedef struct _SBAlgorithm *SBAlgorithmRef; + +/** + * Creates an algorithm object for the specified code point sequence. The source string inside the + * code point sequence should not be freed until the algorithm object is in use. + * + * @param codepointSequence + * The code point sequence to apply bidirectional algorithm on. + * @return + * A reference to an algorithm object if the call was successful, NULL otherwise. + */ +SBAlgorithmRef SBAlgorithmCreate(const SBCodepointSequence *codepointSequence); + +/** + * Returns a direct pointer to the bidirectional types of code units, stored in the algorithm + * object. + * + * @param algorithm + * The algorithm object from which to access the bidirectional types of code units. + * @return + * A valid pointer to an array of SBBidiType structures, whose length will be equal to that of + * string buffer. + */ +const SBBidiType *SBAlgorithmGetBidiTypesPtr(SBAlgorithmRef algorithm); + +/** + * Determines the boundary of first paragraph within the specified range. + * + * The boundary of the paragraph occurs after a code point whose bidirectional type is Paragraph + * Separator (B), or at the suggestedLength if no such code point exists before it. The exception to + * this rule is when a Carriage Return (CR) is followed by a Line Feed (LF). Both CR and LF are + * paragraph separators, but in that case, the boundary of the paragraph is considered after LF code + * point. + * + * @param algorithm + * The algorithm object to use for determining paragraph boundary. + * @param paragraphOffset + * The index to the first code unit of the paragraph in source string. + * @param suggestedLength + * The number of code units covering the suggested length of the paragraph. + * @param acutalLength + * The actual length of the first paragraph, including the paragraph separator, within the + * given range. + * @param separatorLength + * On output, the length of paragraph separator. This parameter can be set to NULL if not + * needed. + */ +void SBAlgorithmGetParagraphBoundary(SBAlgorithmRef algorithm, + SBUInteger paragraphOffset, SBUInteger suggestedLength, + SBUInteger *acutalLength, SBUInteger *separatorLength); + +/** + * Creates a paragraph object processed with Unicode Bidirectional Algorithm. + * + * This function processes only first paragraph starting at paragraphOffset with length less than or + * equal to suggestedLength, in accordance with Rule P1 of Unicode Bidirectional Algorithm. + * + * The paragraph level is determined by applying Rules P2-P3 and embedding levels are resolved by + * applying Rules X1-I2. + * + * @param algorithm + * The algorithm object to use for creating the desired paragraph. + * @param paragraphOffset + * The index to the first code unit of the paragraph in source string. + * @param suggestedLength + * The number of code units covering the suggested length of the paragraph. + * @param baseLevel + * The desired base level of the paragraph. Rules P2-P3 would be ignored if it is neither + * SBLevelDefaultLTR nor SBLevelDefaultRTL. + * @return + * A reference to a paragraph object if the call was successful, NULL otherwise. + */ +SBParagraphRef SBAlgorithmCreateParagraph(SBAlgorithmRef algorithm, + SBUInteger paragraphOffset, SBUInteger suggestedLength, SBLevel baseLevel); + +/** + * Increments the reference count of an algorithm object. + * + * @param algorithm + * The algorithm object whose reference count will be incremented. + * @return + * The same algorithm object passed in as the parameter. + */ +SBAlgorithmRef SBAlgorithmRetain(SBAlgorithmRef algorithm); + +/** + * Decrements the reference count of an algorithm object. The object will be deallocated when its + * reference count reaches zero. + * + * @param algorithm + * The algorithm object whose reference count will be decremented. + */ +void SBAlgorithmRelease(SBAlgorithmRef algorithm); + +#endif diff --git a/third_party/sheenbidi/include/SBBase.h b/third_party/sheenbidi/include/SBBase.h new file mode 100644 index 0000000..dfadf1c --- /dev/null +++ b/third_party/sheenbidi/include/SBBase.h @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2014-2018 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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 _SB_PUBLIC_BASE_H +#define _SB_PUBLIC_BASE_H + +#include +#include + +/** + * A type to represent an 8-bit signed integer. + */ +typedef int8_t SBInt8; + +/** + * A type to represent a 16-bit signed integer. + */ +typedef int16_t SBInt16; + +/** + * A type to represent a 32-bit signed integer. + */ +typedef int32_t SBInt32; + +/** + * A type to represent an 8-bit unsigned integer. + */ +typedef uint8_t SBUInt8; + +/** + * A type to represent a 16-bit unsigned integer. + */ +typedef uint16_t SBUInt16; + +/** + * A type to represent a 32-bit unsigned integer. + */ +typedef uint32_t SBUInt32; + +/** + * A signed integer type whose width is equal to the width of the machine word. + */ +typedef intptr_t SBInteger; + +/** + * An unsigned integer type whose width is equal to the width of the machine word. + */ +typedef uintptr_t SBUInteger; + +/** + * Constants that specify the states of a boolean. + */ +enum { + SBFalse = 0, /**< A value representing the false state. */ + SBTrue = 1 /**< A value representing the true state. */ +}; +/** + * A type to represent a boolean value. + */ +typedef SBUInt8 SBBoolean; + +#define SBUInt8InRange(v, s, e) \ +( \ + (SBUInt8)((v) - (s)) \ + <= (SBUInt8)((e) - (s)) \ +) + +#define SBUInt16InRange(v, s, e) \ +( \ + (SBUInt16)((v) - (s)) \ + <= (SBUInt16)((e) - (s)) \ +) + +#define SBUInt32InRange(v, s, e) \ +( \ + (SBUInt32)((v) - (s)) \ + <= (SBUInt32)((e) - (s)) \ +) + + +/** + * A type to represent a bidi level. + */ +typedef SBUInt8 SBLevel; + +/** + * A value representing an invalid bidi level. + */ +#define SBLevelInvalid 0xFF + +/** + * A value representing maximum explicit embedding level. + */ +#define SBLevelMax 125 + +/** + * A value specifying to set base level to zero (left-to-right) if there is no strong character. + */ +#define SBLevelDefaultLTR 0xFE + +/** + * A value specifying to set base level to one (right-to-left) if there is no strong character. + */ +#define SBLevelDefaultRTL 0xFD + +#endif diff --git a/third_party/sheenbidi/include/SBBidiType.h b/third_party/sheenbidi/include/SBBidiType.h new file mode 100644 index 0000000..0aaaad1 --- /dev/null +++ b/third_party/sheenbidi/include/SBBidiType.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2018 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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 _SB_PUBLIC_BIDI_TYPE_H +#define _SB_PUBLIC_BIDI_TYPE_H + +#include "SBBase.h" + +/** + * Constants that specify the bidirectional types of a character. + */ +enum { + SBBidiTypeNil = 0x00, + + SBBidiTypeL = 0x01, /**< Strong: Left-to-Right */ + SBBidiTypeR = 0x02, /**< Strong: Right-to-Left */ + SBBidiTypeAL = 0x03, /**< Strong: Right-to-Left Arabic */ + + SBBidiTypeBN = 0x04, /**< Weak: Boundary Neutral */ + SBBidiTypeNSM = 0x05, /**< Weak: Non-Spacing Mark */ + SBBidiTypeAN = 0x06, /**< Weak: Arabic Number */ + SBBidiTypeEN = 0x07, /**< Weak: European Number */ + SBBidiTypeET = 0x08, /**< Weak: European Number Terminator */ + SBBidiTypeES = 0x09, /**< Weak: European Number Separator */ + SBBidiTypeCS = 0x0A, /**< Weak: Common Number Separator */ + + SBBidiTypeWS = 0x0B, /**< Neutral: White Space */ + SBBidiTypeS = 0x0C, /**< Neutral: Segment Separator */ + SBBidiTypeB = 0x0D, /**< Neutral: Paragraph Separator */ + SBBidiTypeON = 0x0E, /**< Neutral: Other Neutral */ + + SBBidiTypeLRI = 0x0F, /**< Format: Left-to-Right Isolate */ + SBBidiTypeRLI = 0x10, /**< Format: Right-to-Left Isolate */ + SBBidiTypeFSI = 0x11, /**< Format: First Strong Isolate */ + SBBidiTypePDI = 0x12, /**< Format: Pop Directional Isolate */ + SBBidiTypeLRE = 0x13, /**< Format: Left-to-Right Embedding */ + SBBidiTypeRLE = 0x14, /**< Format: Right-to-Left Embedding */ + SBBidiTypeLRO = 0x15, /**< Format: Left-to-Right Override */ + SBBidiTypeRLO = 0x16, /**< Format: Right-to-Left Override */ + SBBidiTypePDF = 0x17 /**< Format: Pop Directional Formatting */ +}; + +/** + * A type to represent the bidirectional type of a character. + */ +typedef SBUInt8 SBBidiType; + +/** + * Checks whether specified bidirectional type is strong. + */ +#define SBBidiTypeIsStrong(t) SBUInt8InRange(t, SBBidiTypeL, SBBidiTypeAL) + +/** + * Checks whether specified bidirectional type is weak. + */ +#define SBBidiTypeIsWeak(t) SBUInt8InRange(t, SBBidiTypeBN, SBBidiTypeCS) + +/** + * Checks whether specified bidirectional type is neutral. + */ +#define SBBidiTypeIsNeutral(t) SBUInt8InRange(t, SBBidiTypeWS, SBBidiTypeON) + +/** + * Checks whether specified bidirectional type is format. + */ +#define SBBidiTypeIsFormat(t) SBUInt8InRange(t, SBBidiTypeLRI, SBBidiTypePDF) + +#endif diff --git a/third_party/sheenbidi/include/SBCodepoint.h b/third_party/sheenbidi/include/SBCodepoint.h new file mode 100644 index 0000000..b22e07b --- /dev/null +++ b/third_party/sheenbidi/include/SBCodepoint.h @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2018 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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 _SB_PUBLIC_CODEPOINT_H +#define _SB_PUBLIC_CODEPOINT_H + +#include "SBBase.h" +#include "SBBidiType.h" +#include "SBGeneralCategory.h" +#include "SBScript.h" + +/** + * A type to represent a unicode code point. + */ +typedef SBUInt32 SBCodepoint; + +/** + * A value representing an invalid code point. + */ +#define SBCodepointInvalid UINT32_MAX + +/** + * A value representing a faulty code point, used as a replacement by the decoder. + */ +#define SBCodepointFaulty 0xFFFD + +/** + * Returns the bidirectional type of a code point. + * + * @param codepoint + * The code point whose bidirectional type is returned. + * @return + * The bidirectional type of specified code point. + */ +SBBidiType SBCodepointGetBidiType(SBCodepoint codepoint); + +/** + * Returns the general category of a code point. + * + * @param codepoint + * The code point whose general category is returned. + * @return + * The general category of specified code point. + */ +SBGeneralCategory SBCodepointGetGeneralCategory(SBCodepoint codepoint); + +/** + * Returns the mirror of a code point. + * + * @param codepoint + * The code point whose mirror is returned. + * @return + * The mirror of specified code point if available, 0 otherwise. + */ +SBCodepoint SBCodepointGetMirror(SBCodepoint codepoint); + +/** + * Returns the script of a code point. + * + * @param codepoint + * The code point whose script is returned. + * @return + * The script of specified code point. + */ +SBScript SBCodepointGetScript(SBCodepoint codepoint); + +#endif diff --git a/third_party/sheenbidi/include/SBCodepointSequence.h b/third_party/sheenbidi/include/SBCodepointSequence.h new file mode 100644 index 0000000..f1f8a5c --- /dev/null +++ b/third_party/sheenbidi/include/SBCodepointSequence.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2016-2018 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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 _SB_PUBLIC_CODEPOINT_SEQUENCE_H +#define _SB_PUBLIC_CODEPOINT_SEQUENCE_H + +#include "SBBase.h" +#include "SBCodepoint.h" + +enum { + SBStringEncodingUTF8 = 0, /**< An 8-bit representation of Unicode code points. */ + SBStringEncodingUTF16 = 1, /**< 16-bit UTF encoding in native endianness. */ + SBStringEncodingUTF32 = 2 /**< 32-bit UTF encoding in native endianness. */ +}; +typedef SBUInt32 SBStringEncoding; + +typedef struct _SBCodepointSequence { + SBStringEncoding stringEncoding; /**< The encoding of the string. */ + void *stringBuffer; /**< The source string containing the code units. */ + SBUInteger stringLength; /**< The length of the string in terms of code units. */ +} SBCodepointSequence; + +/** + * Returns the code point before the given string index. + * + * @param codepointSequence + * The object holding the information of the string. + * @param stringIndex + * The index of code unit before which to get the code point. On output, it is set to point to + * the first code unit of returned code point. + * @return + * The code point before the given string index, or SBCodepointInvalid if stringIndex is equal + * to zero or larger than actual length of source string. + */ +SBCodepoint SBCodepointSequenceGetCodepointBefore(const SBCodepointSequence *codepointSequence, + SBUInteger *stringIndex); + +/** + * Returns the code point at the given string index. + * + * @param codepointSequence + * The object holding the information of the string. + * @param stringIndex + * The index of code unit at which to get the code point. On output, it is set to point to the + * first code unit of next code point. + * @return + * The code point at the given string index, or SBCodepointInvalid if stringIndex is larger + * than or equal to actual length of source string. + */ +SBCodepoint SBCodepointSequenceGetCodepointAt(const SBCodepointSequence *codepointSequence, + SBUInteger *stringIndex); + +#endif diff --git a/third_party/sheenbidi/include/SBConfig.h b/third_party/sheenbidi/include/SBConfig.h new file mode 100644 index 0000000..801e91a --- /dev/null +++ b/third_party/sheenbidi/include/SBConfig.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2014 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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 _SB_PUBLIC_CONFIG_H +#define _SB_PUBLIC_CONFIG_H + +/* #define SB_CONFIG_LOG */ +/* #define SB_CONFIG_UNITY */ + +#ifdef SB_CONFIG_UNITY +#define SB_INTERNAL static +#else +#define SB_INTERNAL +#endif + +#endif diff --git a/third_party/sheenbidi/include/SBGeneralCategory.h b/third_party/sheenbidi/include/SBGeneralCategory.h new file mode 100644 index 0000000..ce15284 --- /dev/null +++ b/third_party/sheenbidi/include/SBGeneralCategory.h @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2018 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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 _SB_PUBLIC_GENERAL_CATEGORY_H +#define _SB_PUBLIC_GENERAL_CATEGORY_H + +#include "SBBase.h" + +/** + * Constants that specify the general category of a character. + */ +enum { + SBGeneralCategoryNil = 0x00, + + SBGeneralCategoryLU = 0x01, /**< Letter: Uppercase Letter */ + SBGeneralCategoryLL = 0x02, /**< Letter: Lowercase Letter */ + SBGeneralCategoryLT = 0x03, /**< Letter: Titlecase Letter */ + SBGeneralCategoryLM = 0x04, /**< Letter: Modifier Letter */ + SBGeneralCategoryLO = 0x05, /**< Letter: Other Letter */ + + SBGeneralCategoryMN = 0x06, /**< Mark: Nonspacing Mark */ + SBGeneralCategoryMC = 0x07, /**< Mark: Spacing Mark */ + SBGeneralCategoryME = 0x08, /**< Mark: Enclosing Mark */ + + SBGeneralCategoryND = 0x09, /**< Number: Decimal Number */ + SBGeneralCategoryNL = 0x0A, /**< Number: Letter Number */ + SBGeneralCategoryNO = 0x0B, /**< Number: Other Number */ + + SBGeneralCategoryPC = 0x0C, /**< Punctuation: Connector Punctuation */ + SBGeneralCategoryPD = 0x0D, /**< Punctuation: Dash Punctuation */ + SBGeneralCategoryPS = 0x0E, /**< Punctuation: Open Punctuation */ + SBGeneralCategoryPE = 0x0F, /**< Punctuation: Close Punctuation */ + SBGeneralCategoryPI = 0x10, /**< Punctuation: Initial Punctuation */ + SBGeneralCategoryPF = 0x11, /**< Punctuation: Final Punctuation */ + SBGeneralCategoryPO = 0x12, /**< Punctuation: Other Punctuation */ + + SBGeneralCategorySM = 0x13, /**< Symbol: Math Symbol */ + SBGeneralCategorySC = 0x14, /**< Symbol: Currency Symbol */ + SBGeneralCategorySK = 0x15, /**< Symbol: Modifier Symbol */ + SBGeneralCategorySO = 0x16, /**< Symbol: Other Symbol */ + + SBGeneralCategoryZS = 0x17, /**< Separator: Space Separator */ + SBGeneralCategoryZL = 0x18, /**< Separator: Line Separator */ + SBGeneralCategoryZP = 0x19, /**< Separator: Paragraph Separator */ + + SBGeneralCategoryCC = 0x1A, /**< Other: Control */ + SBGeneralCategoryCF = 0x1B, /**< Other: Format */ + SBGeneralCategoryCS = 0x1C, /**< Other: Surrogate */ + SBGeneralCategoryCO = 0x1D, /**< Other: Private_Use */ + SBGeneralCategoryCN = 0x1E /**< Other: Unassigned */ +}; + +/** + * A type to represent the general category of a character. + */ +typedef SBUInt8 SBGeneralCategory; + +/** + * Checks whether specified general category is letter. + */ +#define SBGeneralCategoryIsLetter(gc) SBUInt8InRange(gc, SBGeneralCategoryLU, SBGeneralCategoryLO) + +/** + * Checks whether specified general category is mark. + */ +#define SBGeneralCategoryIsMark(gc) SBUInt8InRange(gc, SBGeneralCategoryMN, SBGeneralCategoryME) + +/** + * Checks whether specified general category is number. + */ +#define SBGeneralCategoryIsNumber(gc) SBUInt8InRange(gc, SBGeneralCategoryND, SBGeneralCategoryNO) + +/** + * Checks whether specified general category is punctuation. + */ +#define SBGeneralCategoryIsPunctuation(gc) SBUInt8InRange(gc, SBGeneralCategoryPC, SBGeneralCategoryPO) + +/** + * Checks whether specified general category is symbol. + */ +#define SBGeneralCategoryIsSymbol(gc) SBUInt8InRange(gc, SBGeneralCategorySM, SBGeneralCategorySO) + +/** + * Checks whether specified general category is separator. + */ +#define SBGeneralCategoryIsSeparator(gc) SBUInt8InRange(gc, SBGeneralCategoryZS, SBGeneralCategoryZP) + +/** + * Checks whether specified general category is other. + */ +#define SBGeneralCategoryIsOther(gc) SBUInt8InRange(gc, SBGeneralCategoryCC, SBGeneralCategoryCN) + +#endif diff --git a/third_party/sheenbidi/include/SBLine.h b/third_party/sheenbidi/include/SBLine.h new file mode 100644 index 0000000..b3f6123 --- /dev/null +++ b/third_party/sheenbidi/include/SBLine.h @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2014-2018 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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 _SB_PUBLIC_LINE_H +#define _SB_PUBLIC_LINE_H + +#include "SBBase.h" +#include "SBRun.h" + +typedef struct _SBLine *SBLineRef; + +/** + * Returns the index to the first code unit of the line in source string. + * + * @param line + * The line whose offset is returned. + * @return + * The offset of the line passed in. + */ +SBUInteger SBLineGetOffset(SBLineRef line); + +/** + * Returns the number of code units coverting the length of the line. + * + * @param line + * The line whose length is returned. + * @return + * The length of the line passed in. + */ +SBUInteger SBLineGetLength(SBLineRef line); + +/** + * Returns the number of runs in the line. + * + * @param line + * The line whose run count is returned. + * @return + * The number of runs in the line passed in. + */ +SBUInteger SBLineGetRunCount(SBLineRef line); + +/** + * Returns a direct pointer to the run array, stored in the line. + * + * @param line + * The line from which to access the runs. + * @return + * A valid pointer to an array of SBRun structures. + */ +const SBRun *SBLineGetRunsPtr(SBLineRef line); + +/** + * Increments the reference count of a line object. + * + * @param line + * The line object whose reference count will be incremented. + * @return + * The same line object passed in as the parameter. + */ +SBLineRef SBLineRetain(SBLineRef line); + +/** + * Decrements the reference count of a line object. The object will be deallocated when its + * reference count reaches zero. + * + * @param line + * The line object whose reference count will be decremented. + */ +void SBLineRelease(SBLineRef line); + +#endif diff --git a/third_party/sheenbidi/include/SBMirrorLocator.h b/third_party/sheenbidi/include/SBMirrorLocator.h new file mode 100644 index 0000000..dc3effe --- /dev/null +++ b/third_party/sheenbidi/include/SBMirrorLocator.h @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2014-2018 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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 _SB_PUBLIC_MIRROR_LOCATOR_H +#define _SB_PUBLIC_MIRROR_LOCATOR_H + +#include "SBBase.h" +#include "SBCodepoint.h" +#include "SBLine.h" + +typedef struct _SBMirrorLocator *SBMirrorLocatorRef; + +/** + * A structure containing the information about a code point having Bidi_Mirrored property. + */ +typedef struct _SBMirrorAgent { + SBUInteger index; /**< The absolute index of the code point. */ + SBCodepoint mirror; /**< The mirrored code point. */ + SBCodepoint codepoint; /**< The actual code point. */ +} SBMirrorAgent; + +/** + * Creates a mirror locator object which can be used to find mirrors in a line. + * + * @return + * A reference to a mirror locator object. + */ +SBMirrorLocatorRef SBMirrorLocatorCreate(void); + +/** + * Loads a line in the locator so that its mirror can be located. + * + * @param locator + * The locator in which the line will be loaded. + * @param line + * The line which will be loaded in the locator. + * @param stringBuffer + * The string buffer from which the line's algorithm was created. + */ +void SBMirrorLocatorLoadLine(SBMirrorLocatorRef locator, SBLineRef line, void *stringBuffer); + +/** + * Returns the agent containing the information of current located mirror. + * + * @param locator + * The locator whose agent is returned. + */ +const SBMirrorAgent *SBMirrorLocatorGetAgent(SBMirrorLocatorRef locator); + +/** + * Instructs the locator to find next mirror in the loaded line. + * + * @param locator + * The locator whom you want to instruct. + * @return + * SBTrue if another mirror is available, SBFalse otherwise. + * @note + * The locator will be reset after locating last mirror. + */ +SBBoolean SBMirrorLocatorMoveNext(SBMirrorLocatorRef locator); + +/** + * Instructs the locator to reset itself so that mirrors of the loaded line can be obatained from + * the beginning. + * + * @param locator + * The locator whom you want to reset. + */ +void SBMirrorLocatorReset(SBMirrorLocatorRef locator); + +/** + * Increments the reference count of a mirror locator object. + * + * @param locator + * The mirror locator object whose reference count will be incremented. + * @return + * The same mirror locator object passed in as the parameter. + */ +SBMirrorLocatorRef SBMirrorLocatorRetain(SBMirrorLocatorRef locator); + +/** + * Decrements the reference count of a mirror locator object. The object will be deallocated when + * its reference count reaches zero. + * + * @param locator + * The mirror locator object whose reference count will be decremented. + */ +void SBMirrorLocatorRelease(SBMirrorLocatorRef locator); + +#endif diff --git a/third_party/sheenbidi/include/SBParagraph.h b/third_party/sheenbidi/include/SBParagraph.h new file mode 100644 index 0000000..07fe59d --- /dev/null +++ b/third_party/sheenbidi/include/SBParagraph.h @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2014-2018 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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 _SB_PUBLIC_PARAGRAPH_H +#define _SB_PUBLIC_PARAGRAPH_H + +#include "SBBase.h" +#include "SBLine.h" + +typedef struct _SBParagraph *SBParagraphRef; + +/** + * Returns the index to the first code unit of the paragraph in source string. + * + * @param paragraph + * The paragraph whose offset is returned. + * @return + * The offset of the paragraph passed in. + */ +SBUInteger SBParagraphGetOffset(SBParagraphRef paragraph); + +/** + * Returns the number of code units covering the length of the paragraph. + * + * @param paragraph + * The paragraph whose length is returned. + * @return + * The length of the paragraph passed in. + */ +SBUInteger SBParagraphGetLength(SBParagraphRef paragraph); + +/** + * Returns the base level of the paragraph. + * + * @param paragraph + * The paragraph whose base level is returned. + * @return + * The base level of the paragraph passed in. + */ +SBLevel SBParagraphGetBaseLevel(SBParagraphRef paragraph); + +/** + * Returns a direct pointer to the embedding levels, stored in the paragraph. + * + * @param paragraph + * The paragraph from which to access the embedding levels. + * @return + * A valid pointer to an array of SBLevel structures. + */ +const SBLevel *SBParagraphGetLevelsPtr(SBParagraphRef paragraph); + +/** + * Creates a line object of specified range by applying rules L1-L2 of Unicode Bidirectional + * Algorithm. + * + * @param paragraph + * The paragraph that creates the line. + * @param lineOffset + * The index to the first code unit of the line in source string. It should occur within the + * range of paragraph. + * @param lineLength + * The number of code units covering the length of the line. + * @return + * A reference to a line object if the call was successful, NULL otherwise. + */ +SBLineRef SBParagraphCreateLine(SBParagraphRef paragraph, SBUInteger lineOffset, SBUInteger lineLength); + +/** + * Increments the reference count of a paragraph object. + * + * @param paragraph + * The paragraph object whose reference count will be incremented. + * @return + * The same paragraph object passed in as the parameter. + */ +SBParagraphRef SBParagraphRetain(SBParagraphRef paragraph); + +/** + * Decrements the reference count of a paragraph object. The object will be deallocated when its + * reference count reaches zero. + * + * @param paragraph + * The paragraph object whose reference count will be decremented. + */ +void SBParagraphRelease(SBParagraphRef paragraph); + +#endif diff --git a/third_party/sheenbidi/include/SBRun.h b/third_party/sheenbidi/include/SBRun.h new file mode 100644 index 0000000..71cbe14 --- /dev/null +++ b/third_party/sheenbidi/include/SBRun.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2016-2018 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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 _SB_PUBLIC_RUN_H +#define _SB_PUBLIC_RUN_H + +#include "SBBase.h" + +/** + * A structure containing the information of a sequence of characters having the same embedding + * level. + */ +typedef struct _SBRun { + SBUInteger offset; /**< The index to the first code unit of the run in source string. */ + SBUInteger length; /**< The number of code units covering the length of the run. */ + SBLevel level; /**< The embedding level of the run. */ +} SBRun; + +#endif diff --git a/third_party/sheenbidi/include/SBScript.h b/third_party/sheenbidi/include/SBScript.h new file mode 100644 index 0000000..6d46868 --- /dev/null +++ b/third_party/sheenbidi/include/SBScript.h @@ -0,0 +1,254 @@ +/* + * Copyright (C) 2018-2021 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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 _SB_PUBLIC_SCRIPT_H +#define _SB_PUBLIC_SCRIPT_H + +#include "SBBase.h" + +/** + * Constants that specify the script of a character. + */ +enum { + SBScriptNil = 0x00, + + SBScriptZINH = 0x01, /**< Inherited */ + SBScriptZYYY = 0x02, /**< Common */ + SBScriptZZZZ = 0x03, /**< Unknown */ + + /* Unicode 1.1 */ + SBScriptARAB = 0x04, /**< Arabic */ + SBScriptARMN = 0x05, /**< Armenian */ + SBScriptBENG = 0x06, /**< Bengali */ + SBScriptBOPO = 0x07, /**< Bopomofo */ + SBScriptCYRL = 0x08, /**< Cyrillic */ + SBScriptDEVA = 0x09, /**< Devanagari */ + SBScriptGEOR = 0x0A, /**< Georgian */ + SBScriptGREK = 0x0B, /**< Greek */ + SBScriptGUJR = 0x0C, /**< Gujarati */ + SBScriptGURU = 0x0D, /**< Gurmukhi */ + SBScriptHANG = 0x0E, /**< Hangul */ + SBScriptHANI = 0x0F, /**< Han */ + SBScriptHEBR = 0x10, /**< Hebrew */ + SBScriptHIRA = 0x11, /**< Hiragana */ + SBScriptKANA = 0x12, /**< Katakana */ + SBScriptKNDA = 0x13, /**< Kannada */ + SBScriptLAOO = 0x14, /**< Lao */ + SBScriptLATN = 0x15, /**< Latin */ + SBScriptMLYM = 0x16, /**< Malayalam */ + SBScriptORYA = 0x17, /**< Oriya */ + SBScriptTAML = 0x18, /**< Tamil */ + SBScriptTELU = 0x19, /**< Telugu */ + SBScriptTHAI = 0x1A, /**< Thai */ + + /* Unicode 2.0 */ + SBScriptTIBT = 0x1B, /**< Tibetan */ + + /* Unicode 3.0 */ + SBScriptBRAI = 0x1C, /**< Braille */ + SBScriptCANS = 0x1D, /**< Canadian_Aboriginal */ + SBScriptCHER = 0x1E, /**< Cherokee */ + SBScriptETHI = 0x1F, /**< Ethiopic */ + SBScriptKHMR = 0x20, /**< Khmer */ + SBScriptMONG = 0x21, /**< Mongolian */ + SBScriptMYMR = 0x22, /**< Myanmar */ + SBScriptOGAM = 0x23, /**< Ogham */ + SBScriptRUNR = 0x24, /**< Runic */ + SBScriptSINH = 0x25, /**< Sinhala */ + SBScriptSYRC = 0x26, /**< Syriac */ + SBScriptTHAA = 0x27, /**< Thaana */ + SBScriptYIII = 0x28, /**< Yi */ + + /* Unicode 3.1 */ + SBScriptDSRT = 0x29, /**< Deseret */ + SBScriptGOTH = 0x2A, /**< Gothic */ + SBScriptITAL = 0x2B, /**< Old_Italic */ + + /* Unicode 3.2 */ + SBScriptBUHD = 0x2C, /**< Buhid */ + SBScriptHANO = 0x2D, /**< Hanunoo */ + SBScriptTAGB = 0x2E, /**< Tagbanwa */ + SBScriptTGLG = 0x2F, /**< Tagalog */ + + /* Unicode 4.0 */ + SBScriptCPRT = 0x30, /**< Cypriot */ + SBScriptLIMB = 0x31, /**< Limbu */ + SBScriptLINB = 0x32, /**< Linear_B */ + SBScriptOSMA = 0x33, /**< Osmanya */ + SBScriptSHAW = 0x34, /**< Shavian */ + SBScriptTALE = 0x35, /**< Tai_Le */ + SBScriptUGAR = 0x36, /**< Ugaritic */ + + /* Unicode 4.1 */ + SBScriptBUGI = 0x37, /**< Buginese */ + SBScriptCOPT = 0x38, /**< Coptic */ + SBScriptGLAG = 0x39, /**< Glagolitic */ + SBScriptKHAR = 0x3A, /**< Kharoshthi */ + SBScriptSYLO = 0x3B, /**< Syloti_Nagri */ + SBScriptTALU = 0x3C, /**< New_Tai_Lue */ + SBScriptTFNG = 0x3D, /**< Tifinagh */ + SBScriptXPEO = 0x3E, /**< Old_Persian */ + + /* Unicode 5.0 */ + SBScriptBALI = 0x3F, /**< Balinese */ + SBScriptNKOO = 0x40, /**< Nko */ + SBScriptPHAG = 0x41, /**< Phags_Pa */ + SBScriptPHNX = 0x42, /**< Phoenician */ + SBScriptXSUX = 0x43, /**< Cuneiform */ + + /* Unicode 5.1 */ + SBScriptCARI = 0x44, /**< Carian */ + SBScriptCHAM = 0x45, /**< Cham */ + SBScriptKALI = 0x46, /**< Kayah_Li */ + SBScriptLEPC = 0x47, /**< Lepcha */ + SBScriptLYCI = 0x48, /**< Lycian */ + SBScriptLYDI = 0x49, /**< Lydian */ + SBScriptOLCK = 0x4A, /**< Ol_Chiki */ + SBScriptRJNG = 0x4B, /**< Rejang */ + SBScriptSAUR = 0x4C, /**< Saurashtra */ + SBScriptSUND = 0x4D, /**< Sundanese */ + SBScriptVAII = 0x4E, /**< Vai */ + + /* Unicode 5.2 */ + SBScriptARMI = 0x4F, /**< Imperial_Aramaic */ + SBScriptAVST = 0x50, /**< Avestan */ + SBScriptBAMU = 0x51, /**< Bamum */ + SBScriptEGYP = 0x52, /**< Egyptian_Hieroglyphs */ + SBScriptJAVA = 0x53, /**< Javanese */ + SBScriptKTHI = 0x54, /**< Kaithi */ + SBScriptLANA = 0x55, /**< Tai_Tham */ + SBScriptLISU = 0x56, /**< Lisu */ + SBScriptMTEI = 0x57, /**< Meetei_Mayek */ + SBScriptORKH = 0x58, /**< Old_Turkic */ + SBScriptPHLI = 0x59, /**< Inscriptional_Pahlavi */ + SBScriptPRTI = 0x5A, /**< Inscriptional_Parthian */ + SBScriptSAMR = 0x5B, /**< Samaritan */ + SBScriptSARB = 0x5C, /**< Old_South_Arabian */ + SBScriptTAVT = 0x5D, /**< Tai_Viet */ + + /* Unicode 6.0 */ + SBScriptBATK = 0x5E, /**< Batak */ + SBScriptBRAH = 0x5F, /**< Brahmi */ + SBScriptMAND = 0x60, /**< Mandaic */ + + /* Unicode 6.1 */ + SBScriptCAKM = 0x61, /**< Chakma */ + SBScriptMERC = 0x62, /**< Meroitic_Cursive */ + SBScriptMERO = 0x63, /**< Meroitic_Hieroglyphs */ + SBScriptPLRD = 0x64, /**< Miao */ + SBScriptSHRD = 0x65, /**< Sharada */ + SBScriptSORA = 0x66, /**< Sora_Sompeng */ + SBScriptTAKR = 0x67, /**< Takri */ + + /* Unicode 7.0 */ + SBScriptAGHB = 0x68, /**< Caucasian_Albanian */ + SBScriptBASS = 0x69, /**< Bassa_Vah */ + SBScriptDUPL = 0x6A, /**< Duployan */ + SBScriptELBA = 0x6B, /**< Elbasan */ + SBScriptGRAN = 0x6C, /**< Grantha */ + SBScriptHMNG = 0x6D, /**< Pahawh_Hmong */ + SBScriptKHOJ = 0x6E, /**< Khojki */ + SBScriptLINA = 0x6F, /**< Linear_A */ + SBScriptMAHJ = 0x70, /**< Mahajani */ + SBScriptMANI = 0x71, /**< Manichaean */ + SBScriptMEND = 0x72, /**< Mende_Kikakui */ + SBScriptMODI = 0x73, /**< Modi */ + SBScriptMROO = 0x74, /**< Mro */ + SBScriptNARB = 0x75, /**< Old_North_Arabian */ + SBScriptNBAT = 0x76, /**< Nabataean */ + SBScriptPALM = 0x77, /**< Palmyrene */ + SBScriptPAUC = 0x78, /**< Pau_Cin_Hau */ + SBScriptPERM = 0x79, /**< Old_Permic */ + SBScriptPHLP = 0x7A, /**< Psalter_Pahlavi */ + SBScriptSIDD = 0x7B, /**< Siddham */ + SBScriptSIND = 0x7C, /**< Khudawadi */ + SBScriptTIRH = 0x7D, /**< Tirhuta */ + SBScriptWARA = 0x7E, /**< Warang_Citi */ + + /* Unicode 8.0 */ + SBScriptAHOM = 0x7F, /**< Ahom */ + SBScriptHATR = 0x80, /**< Hatran */ + SBScriptHLUW = 0x81, /**< Anatolian_Hieroglyphs */ + SBScriptHUNG = 0x82, /**< Old_Hungarian */ + SBScriptMULT = 0x83, /**< Multani */ + SBScriptSGNW = 0x84, /**< SignWriting */ + + /* Unicode 9.0 */ + SBScriptADLM = 0x85, /**< Adlam */ + SBScriptBHKS = 0x86, /**< Bhaiksuki */ + SBScriptMARC = 0x87, /**< Marchen */ + SBScriptNEWA = 0x88, /**< Newa */ + SBScriptOSGE = 0x89, /**< Osage */ + SBScriptTANG = 0x8A, /**< Tangut */ + + /* Unicode 10.0 */ + SBScriptGONM = 0x8B, /**< Masaram_Gondi */ + SBScriptNSHU = 0x8C, /**< Nushu */ + SBScriptSOYO = 0x8D, /**< Soyombo */ + SBScriptZANB = 0x8E, /**< Zanabazar_Square */ + + /* Unicode 11.0 */ + SBScriptDOGR = 0x8F, /**< Dogra */ + SBScriptGONG = 0x90, /**< Gunjala_Gondi */ + SBScriptMAKA = 0x91, /**< Makasar */ + SBScriptMEDF = 0x92, /**< Medefaidrin */ + SBScriptROHG = 0x93, /**< Hanifi_Rohingya */ + SBScriptSOGD = 0x94, /**< Sogdian */ + SBScriptSOGO = 0x95, /**< Old_Sogdian */ + + /* Unicode 12.0 */ + SBScriptELYM = 0x96, /**< Elymaic */ + SBScriptHMNP = 0x97, /**< Nyiakeng_Puachue_Hmong */ + SBScriptNAND = 0x98, /**< Nandinagari */ + SBScriptWCHO = 0x99, /**< Wancho */ + + /* Unicde 13.0 */ + SBScriptCHRS = 0x9A, /**< Chorasmian */ + SBScriptDIAK = 0x9B, /**< Dives_Akuru */ + SBScriptKITS = 0x9C, /**< Khitan_Small_Script */ + SBScriptYEZI = 0x9D, /**< Yezidi */ + + /* Unicde 14.0 */ + SBScriptCPMN = 0x9E, /**< Cypro_Minoan */ + SBScriptOUGR = 0x9F, /**< Old_Uyghur */ + SBScriptTNSA = 0xA0, /**< Tangsa */ + SBScriptTOTO = 0xA1, /**< Toto */ + SBScriptVITH = 0xA2 /**< Vithkuqi */ +}; + +/** + * A type to represent the script of a character. + */ +typedef SBUInt8 SBScript; + +/** + * Returns the OpenType tag of a script as UInt32 in big endian byte order. The association between + * Unicode Script property and OpenType script tags is taken from the specification: + * https://docs.microsoft.com/en-us/typography/opentype/spec/scripttags. + * + * If more than one tag is associated with a script, then the latest one is retured. For example, + * Devanagari script has two tags, `deva` and `dev2`. So in this case, `dev2` will be returned. + * + * If no tag is associated with a script, then `DFLT` is returned. + * + * @param script + * The script whose OpenType tag is returned. + * @return + * The OpenType tag of specified script as UInt32 in big endian byte order. + */ +SBUInt32 SBScriptGetOpenTypeTag(SBScript script); + +#endif diff --git a/third_party/sheenbidi/include/SBScriptLocator.h b/third_party/sheenbidi/include/SBScriptLocator.h new file mode 100644 index 0000000..cad4afb --- /dev/null +++ b/third_party/sheenbidi/include/SBScriptLocator.h @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2018 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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 _SB_PUBLIC_SCRIPT_LOCATOR_H +#define _SB_PUBLIC_SCRIPT_LOCATOR_H + +#include "SBBase.h" +#include "SBCodepointSequence.h" +#include "SBScript.h" + +typedef struct _SBScriptLocator *SBScriptLocatorRef; + +/** + * A structure containing the information about a run of code points having same script. + */ +typedef struct _SBScriptAgent { + SBUInteger offset; /**< The index to the first code unit of the run in source string. */ + SBUInteger length; /**< The number of code units covering the length of the run. */ + SBScript script; /**< The script of the run. */ +} SBScriptAgent; + +/** + * Creates a script locator object which can be used to find script runs in a string. + * + * @return + * A reference to a script locator object. + */ +SBScriptLocatorRef SBScriptLocatorCreate(void); + +/** + * Loads a code point sequence in the locator so that its script runs can be located. + * + * @param locator + * The locator in which the code point sequence will be loaded. + * @param codepointSequence + * The code point sequence which will be loaded in the locator. + */ +void SBScriptLocatorLoadCodepoints(SBScriptLocatorRef locator, const SBCodepointSequence *codepointSequence); + +/** + * Returns the agent containing the information of current located script run. + * + * @param locator + * The locator whose agent is returned. + */ +const SBScriptAgent *SBScriptLocatorGetAgent(SBScriptLocatorRef locator); + +/** + * Instructs the locator to find next script run in the loaded code point sequence. + * + * @param locator + * The locator whom you want to instruct. + * @return + * SBTrue if another script run is available, SBFalse otherwise. + * @note + * The locator will be reset after locating last script run. + */ +SBBoolean SBScriptLocatorMoveNext(SBScriptLocatorRef locator); + +/** + * Instructs the locator to reset itself so that script runs of the loaded line can be obatained + * from the beginning. + * + * @param locator + * The locator whom you want to reset. + */ +void SBScriptLocatorReset(SBScriptLocatorRef locator); + +/** + * Increments the reference count of a script locator object. + * + * @param locator + * The script locator object whose reference count will be incremented. + * @return + * The same script locator object passed in as the parameter. + */ +SBScriptLocatorRef SBScriptLocatorRetain(SBScriptLocatorRef locator); + +/** + * Decrements the reference count of a script locator object. The object will be deallocated when + * its reference count reaches zero. + * + * @param locator + * The script locator object whose reference count will be decremented. + */ +void SBScriptLocatorRelease(SBScriptLocatorRef locator); + +#endif diff --git a/third_party/sheenbidi/include/SheenBidi.h b/third_party/sheenbidi/include/SheenBidi.h new file mode 100644 index 0000000..96cdd9f --- /dev/null +++ b/third_party/sheenbidi/include/SheenBidi.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2014-2018 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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 _SHEEN_BIDI_H +#define _SHEEN_BIDI_H + +#include "SBAlgorithm.h" +#include "SBBase.h" +#include "SBBidiType.h" +#include "SBCodepoint.h" +#include "SBCodepointSequence.h" +#include "SBGeneralCategory.h" +#include "SBLine.h" +#include "SBMirrorLocator.h" +#include "SBParagraph.h" +#include "SBRun.h" +#include "SBScript.h" +#include "SBScriptLocator.h" + +#endif diff --git a/third_party/sheenbidi/sheenbidi.c b/third_party/sheenbidi/sheenbidi.c new file mode 100644 index 0000000..9247f2f --- /dev/null +++ b/third_party/sheenbidi/sheenbidi.c @@ -0,0 +1,52 @@ +/* + ============================================================================== + + This file is part of the YUP library. + Copyright (c) 2024 - kunitoki@gmail.com + + YUP is an open source library subject to open-source licensing. + + The code included in this file is provided under the terms of the ISC license + http://www.isc.org/downloads/software-support-policy/isc-license. Permission + to use, copy, modify, and/or distribute this software for any purpose with or + without fee is hereby granted provided that the above copyright notice and + this permission notice appear in all copies. + + YUP IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +#include "sheenbidi.h" + +#if defined(__GNUC__) && !defined(__clang__) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wstringop-overflow" +#endif + +#include "source/SBBase.c" +#include "source/RunQueue.c" +#include "source/BidiTypeLookup.c" +#include "source/SBLog.c" +#include "source/SBLine.c" +#include "source/PairingLookup.c" +#include "source/BidiChain.c" +#include "source/SBCodepointSequence.c" +#include "source/ScriptStack.c" +#include "source/SBMirrorLocator.c" +#include "source/StatusStack.c" +#include "source/SheenBidi.c" +#include "source/SBScriptLocator.c" +#include "source/GeneralCategoryLookup.c" +#include "source/LevelRun.c" +#include "source/BracketQueue.c" +#include "source/ScriptLookup.c" +#include "source/SBParagraph.c" +#include "source/IsolatingRun.c" +#include "source/SBAlgorithm.c" + +#if defined(__GNUC__) && !defined(__clang__) + #pragma GCC diagnostic pop +#endif diff --git a/third_party/sheenbidi/sheenbidi.h b/third_party/sheenbidi/sheenbidi.h new file mode 100644 index 0000000..224c7e8 --- /dev/null +++ b/third_party/sheenbidi/sheenbidi.h @@ -0,0 +1,44 @@ +/* + ============================================================================== + + This file is part of the YUP library. + Copyright (c) 2024 - kunitoki@gmail.com + + YUP is an open source library subject to open-source licensing. + + The code included in this file is provided under the terms of the ISC license + http://www.isc.org/downloads/software-support-policy/isc-license. Permission + to use, copy, modify, and/or distribute this software for any purpose with or + without fee is hereby granted provided that the above copyright notice and + this permission notice appear in all copies. + + YUP IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +/* + ============================================================================== + + BEGIN_YUP_MODULE_DECLARATION + + ID: sheenbidi + vendor: sheenbidi + version: 2.6 + name: SheenBidi implements Unicode Bidirectional Algorithm + description: It is a sophisticated implementation which provides the developers an easy way to use UBA in their applications. + website: https://github.com/Tehreer/SheenBidi + license: Apache-2.0 + + searchpaths: include + + END_YUP_MODULE_DECLARATION + + ============================================================================== +*/ + +#pragma once + +#include "include/SheenBidi.h" diff --git a/third_party/sheenbidi/source/BidiChain.c b/third_party/sheenbidi/source/BidiChain.c new file mode 100644 index 0000000..0f80d6b --- /dev/null +++ b/third_party/sheenbidi/source/BidiChain.c @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2014-2019 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ + +#include + +#include "SBBase.h" +#include "BidiChain.h" + +SB_INTERNAL void BidiChainInitialize(BidiChainRef chain, + SBBidiType *types, SBLevel *levels, BidiLink *links) +{ + chain->types = types; + chain->levels = levels; + chain->links = links; + chain->roller = 0; + chain->last = 0; + + /* Make first link empty. */ + chain->types[0] = SBBidiTypeNil; + chain->levels[0] = SBLevelInvalid; + chain->links[0] = BidiLinkNone; +} + +SB_INTERNAL void BidiChainAdd(BidiChainRef chain, SBBidiType type, SBUInteger length) +{ + BidiLink last = chain->last; + BidiLink current = last + (SBUInt32)length; + + chain->types[current] = type; + chain->links[current] = chain->roller; + + chain->links[last] = current; + chain->last = current; +} + +SB_INTERNAL SBBoolean BidiChainIsSingle(BidiChainRef chain, BidiLink link) +{ + BidiLink next = chain->links[link]; + + /* Check the type of in between code units. */ + while (++link != next) { + if (chain->types[link] != SBBidiTypeBN) { + return SBFalse; + } + } + + return SBTrue; +} + +SB_INTERNAL SBBidiType BidiChainGetType(BidiChainRef chain, BidiLink link) +{ + return chain->types[link]; +} + +SB_INTERNAL void BidiChainSetType(BidiChainRef chain, BidiLink link, SBBidiType type) +{ + chain->types[link] = type; +} + +SB_INTERNAL SBLevel BidiChainGetLevel(BidiChainRef chain, BidiLink link) +{ + return chain->levels[link]; +} + +SB_INTERNAL void BidiChainSetLevel(BidiChainRef chain, BidiLink link, SBLevel level) +{ + chain->levels[link] = level; +} + +SB_INTERNAL BidiLink BidiChainGetNext(BidiChainRef chain, BidiLink link) +{ + return chain->links[link]; +} + +SB_INTERNAL void BidiChainSetNext(BidiChainRef chain, BidiLink link, BidiLink next) +{ + chain->links[link] = next; +} + +SB_INTERNAL void BidiChainAbandonNext(BidiChainRef chain, BidiLink link) +{ + BidiLink next = chain->links[link]; + BidiLink limit = chain->links[next]; + + chain->links[link] = limit; +} + +SB_INTERNAL SBBoolean BidiChainMergeIfEqual(BidiChainRef chain, BidiLink first, BidiLink second) +{ + if (chain->types[first] == chain->types[second] + && chain->levels[first] == chain->levels[second]) { + chain->links[first] = chain->links[second]; + return SBTrue; + } + + return SBFalse; +} diff --git a/third_party/sheenbidi/source/BidiChain.h b/third_party/sheenbidi/source/BidiChain.h new file mode 100644 index 0000000..4b378c3 --- /dev/null +++ b/third_party/sheenbidi/source/BidiChain.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2014-2019 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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 _SB_INTERNAL_BIDI_CHAIN_H +#define _SB_INTERNAL_BIDI_CHAIN_H + +#include +#include "SBBase.h" + +typedef SBUInt32 BidiLink; + +#define BidiLinkNone (SBUInt32)(-1) + +typedef struct _BidiChain { + SBBidiType *types; + SBLevel *levels; + BidiLink *links; + BidiLink roller; + BidiLink last; +} BidiChain, *BidiChainRef; + +SB_INTERNAL void BidiChainInitialize(BidiChainRef chain, + SBBidiType *types, SBLevel *levels, BidiLink *links); +SB_INTERNAL void BidiChainAdd(BidiChainRef chain, SBBidiType type, SBUInteger length); + +#define BidiChainGetOffset(chain, link) \ +( \ + (link) - 1 \ +) + +SB_INTERNAL SBBoolean BidiChainIsSingle(BidiChainRef chain, BidiLink link); + +SB_INTERNAL SBBidiType BidiChainGetType(BidiChainRef chain, BidiLink link); +SB_INTERNAL void BidiChainSetType(BidiChainRef chain, BidiLink link, SBBidiType type); + +SB_INTERNAL SBLevel BidiChainGetLevel(BidiChainRef chain, BidiLink link); +SB_INTERNAL void BidiChainSetLevel(BidiChainRef chain, BidiLink link, SBLevel level); + +SB_INTERNAL BidiLink BidiChainGetNext(BidiChainRef chain, BidiLink link); +SB_INTERNAL void BidiChainSetNext(BidiChainRef chain, BidiLink link, BidiLink next); +SB_INTERNAL void BidiChainAbandonNext(BidiChainRef chain, BidiLink link); +SB_INTERNAL SBBoolean BidiChainMergeIfEqual(BidiChainRef chain, BidiLink first, BidiLink second); + +#define BidiChainForEach(chain, roller, link) \ + for (link = chain->links[roller]; link != roller; link = chain->links[link]) + +#endif diff --git a/third_party/sheenbidi/source/BidiTypeLookup.c b/third_party/sheenbidi/source/BidiTypeLookup.c new file mode 100644 index 0000000..c2b4200 --- /dev/null +++ b/third_party/sheenbidi/source/BidiTypeLookup.c @@ -0,0 +1,1031 @@ +/* + * Automatically generated by SheenBidiGenerator tool. + * DO NOT EDIT!! + * + * REQUIRED MEMORY: 4528+(2688*2)+(1088*2) = 12080 Bytes + */ + +#include "BidiTypeLookup.h" + +#define AL SBBidiTypeAL +#define AN SBBidiTypeAN +#define B SBBidiTypeB +#define BN SBBidiTypeBN +#define CS SBBidiTypeCS +#define EN SBBidiTypeEN +#define ES SBBidiTypeES +#define ET SBBidiTypeET +#define FSI SBBidiTypeFSI +#define L SBBidiTypeL +#define LRE SBBidiTypeLRE +#define LRI SBBidiTypeLRI +#define LRO SBBidiTypeLRO +#define NSM SBBidiTypeNSM +#define ON SBBidiTypeON +#define PDF SBBidiTypePDF +#define PDI SBBidiTypePDI +#define R SBBidiTypeR +#define RLE SBBidiTypeRLE +#define RLI SBBidiTypeRLI +#define RLO SBBidiTypeRLO +#define S SBBidiTypeS +#define WS SBBidiTypeWS + +static const SBUInt8 PrimaryBidiTypeData[4528] = { +/* DATA_BLOCK: -- 0x0000..0x000F -- */ + BN, BN, BN, BN, BN, BN, BN, BN, BN, S, B, S, WS, B, BN, BN, +/* DATA_BLOCK: -- 0x0010..0x001F -- */ + BN, BN, BN, BN, BN, BN, BN, BN, BN, BN, BN, BN, B, B, B, S, +/* DATA_BLOCK: -- 0x0020..0x002F -- */ + WS, ON, ON, ET, ET, ET, ON, ON, ON, ON, ON, ES, CS, ES, CS, CS, +/* DATA_BLOCK: -- 0x0030..0x003F -- */ + EN, EN, EN, EN, EN, EN, EN, EN, EN, EN, CS, ON, ON, ON, ON, ON, +/* DATA_BLOCK: -- 0x0040..0x004F -- */ + ON, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0050..0x005F -- */ + L, L, L, L, L, L, L, L, L, L, L, ON, ON, ON, ON, ON, +/* DATA_BLOCK: -- 0x0060..0x006F -- */ + L, L, L, L, L, L, L, L, L, L, L, ON, ON, ON, ON, BN, +/* DATA_BLOCK: -- 0x0070..0x007F -- */ + BN, BN, BN, BN, BN, B, BN, BN, BN, BN, BN, BN, BN, BN, BN, BN, +/* DATA_BLOCK: -- 0x0080..0x008F -- */ + BN, BN, BN, BN, BN, BN, BN, BN, BN, BN, BN, BN, BN, BN, BN, BN, +/* DATA_BLOCK: -- 0x0090..0x009F -- */ + CS, ON, ET, ET, ET, ET, ON, ON, ON, ON, L, ON, ON, BN, ON, ON, +/* DATA_BLOCK: -- 0x00A0..0x00AF -- */ + ET, ET, EN, EN, ON, L, ON, ON, ON, EN, L, ON, ON, ON, ON, ON, +/* DATA_BLOCK: -- 0x00B0..0x00BF -- */ + L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x00C0..0x00CF -- */ + L, L, L, L, L, L, L, ON, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x00D0..0x00DF -- */ + L, L, L, L, L, L, L, L, L, ON, ON, L, L, L, L, L, +/* DATA_BLOCK: -- 0x00E0..0x00EF -- */ + L, L, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, +/* DATA_BLOCK: -- 0x00F0..0x00FF -- */ + L, L, L, L, L, ON, ON, ON, ON, ON, ON, ON, ON, ON, L, ON, +/* DATA_BLOCK: -- 0x0100..0x010F -- */ + ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, +/* DATA_BLOCK: -- 0x0110..0x011F -- */ + NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, +/* DATA_BLOCK: -- 0x0120..0x012F -- */ + L, L, L, L, ON, ON, L, L, L, L, L, L, L, L, ON, L, +/* DATA_BLOCK: -- 0x0130..0x013F -- */ + L, L, L, L, ON, ON, L, ON, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0140..0x014F -- */ + L, L, L, L, L, L, ON, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0150..0x015F -- */ + L, L, L, NSM, NSM, NSM, NSM, NSM, NSM, NSM, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0160..0x016F -- */ + L, L, L, L, L, L, L, L, L, L, ON, L, L, ON, ON, ET, +/* DATA_BLOCK: -- 0x0170..0x017F -- */ + R, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, +/* DATA_BLOCK: -- 0x0180..0x018F -- */ + NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, R, NSM, +/* DATA_BLOCK: -- 0x0190..0x019F -- */ + R, NSM, NSM, R, NSM, NSM, R, NSM, R, R, R, R, R, R, R, R, +/* DATA_BLOCK: -- 0x01A0..0x01AF -- */ + R, R, R, R, R, R, R, R, R, R, R, R, R, R, R, R, +/* DATA_BLOCK: -- 0x01B0..0x01BF -- */ + AN, AN, AN, AN, AN, AN, ON, ON, AL, ET, ET, AL, CS, AL, ON, ON, +/* DATA_BLOCK: -- 0x01C0..0x01CF -- */ + NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, AL, AL, AL, AL, AL, +/* DATA_BLOCK: -- 0x01D0..0x01DF -- */ + AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, +/* DATA_BLOCK: -- 0x01E0..0x01EF -- */ + AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, NSM, NSM, NSM, NSM, NSM, +/* DATA_BLOCK: -- 0x01F0..0x01FF -- */ + AN, AN, AN, AN, AN, AN, AN, AN, AN, AN, ET, AN, AN, AL, AL, AL, +/* DATA_BLOCK: -- 0x0200..0x020F -- */ + NSM, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, +/* DATA_BLOCK: -- 0x0210..0x021F -- */ + AL, AL, AL, AL, AL, AL, NSM, NSM, NSM, NSM, NSM, NSM, NSM, AN, ON, NSM, +/* DATA_BLOCK: -- 0x0220..0x022F -- */ + NSM, NSM, NSM, NSM, NSM, AL, AL, NSM, NSM, ON, NSM, NSM, NSM, NSM, AL, AL, +/* DATA_BLOCK: -- 0x0230..0x023F -- */ + EN, EN, EN, EN, EN, EN, EN, EN, EN, EN, AL, AL, AL, AL, AL, AL, +/* DATA_BLOCK: -- 0x0240..0x024F -- */ + AL, NSM, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, +/* DATA_BLOCK: -- 0x0250..0x025F -- */ + AL, AL, AL, AL, AL, AL, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, +/* DATA_BLOCK: -- 0x0260..0x026F -- */ + R, R, R, R, R, R, R, R, R, R, R, NSM, NSM, NSM, NSM, NSM, +/* DATA_BLOCK: -- 0x0270..0x027F -- */ + NSM, NSM, NSM, NSM, R, R, ON, ON, ON, ON, R, R, R, NSM, R, R, +/* DATA_BLOCK: -- 0x0280..0x028F -- */ + R, R, R, R, R, R, NSM, NSM, NSM, NSM, R, NSM, NSM, NSM, NSM, NSM, +/* DATA_BLOCK: -- 0x0290..0x029F -- */ + NSM, NSM, NSM, NSM, R, NSM, NSM, NSM, R, NSM, NSM, NSM, NSM, NSM, R, R, +/* DATA_BLOCK: -- 0x02A0..0x02AF -- */ + R, R, R, R, R, R, R, R, R, NSM, NSM, NSM, R, R, R, R, +/* DATA_BLOCK: -- 0x02B0..0x02BF -- */ + AN, AN, AL, AL, AL, AL, AL, AL, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, +/* DATA_BLOCK: -- 0x02C0..0x02CF -- */ + AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, NSM, NSM, NSM, NSM, NSM, NSM, +/* DATA_BLOCK: -- 0x02D0..0x02DF -- */ + NSM, NSM, AN, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, +/* DATA_BLOCK: -- 0x02E0..0x02EF -- */ + NSM, NSM, NSM, L, L, L, L, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x02F0..0x02FF -- */ + L, L, L, L, L, L, L, L, L, L, NSM, L, NSM, L, L, L, +/* DATA_BLOCK: -- 0x0300..0x030F -- */ + L, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, L, L, L, L, NSM, L, L, +/* DATA_BLOCK: -- 0x0310..0x031F -- */ + L, NSM, NSM, NSM, NSM, NSM, NSM, NSM, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0320..0x032F -- */ + L, L, NSM, NSM, L, L, L, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0330..0x033F -- */ + L, NSM, L, L, L, L, L, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0340..0x034F -- */ + L, L, L, L, L, L, L, L, L, L, L, L, NSM, L, L, L, +/* DATA_BLOCK: -- 0x0350..0x035F -- */ + L, NSM, NSM, NSM, NSM, L, L, L, L, L, L, L, L, NSM, L, L, +/* DATA_BLOCK: -- 0x0360..0x036F -- */ + L, L, ET, ET, L, L, L, L, L, L, L, ET, L, L, NSM, L, +/* DATA_BLOCK: -- 0x0370..0x037F -- */ + L, NSM, NSM, L, L, L, L, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0380..0x038F -- */ + L, NSM, NSM, L, L, L, L, NSM, NSM, L, L, NSM, NSM, NSM, L, L, +/* DATA_BLOCK: -- 0x0390..0x039F -- */ + NSM, NSM, L, L, L, NSM, L, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x03A0..0x03AF -- */ + L, NSM, NSM, NSM, NSM, NSM, L, NSM, NSM, L, L, L, L, NSM, L, L, +/* DATA_BLOCK: -- 0x03B0..0x03BF -- */ + L, ET, L, L, L, L, L, L, L, L, NSM, NSM, NSM, NSM, NSM, NSM, +/* DATA_BLOCK: -- 0x03C0..0x03CF -- */ + L, L, L, L, L, L, L, L, L, L, L, L, NSM, L, L, NSM, +/* DATA_BLOCK: -- 0x03D0..0x03DF -- */ + L, L, L, L, L, NSM, NSM, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x03E0..0x03EF -- */ + L, L, NSM, L, L, L, L, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x03F0..0x03FF -- */ + NSM, L, L, L, L, L, L, L, L, L, L, L, L, NSM, L, L, +/* DATA_BLOCK: -- 0x0400..0x040F -- */ + L, L, L, ON, ON, ON, ON, ON, ON, ET, ON, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0410..0x041F -- */ + NSM, L, L, L, NSM, L, L, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0420..0x042F -- */ + L, L, L, L, L, L, L, L, L, L, L, L, NSM, L, NSM, NSM, +/* DATA_BLOCK: -- 0x0430..0x043F -- */ + NSM, L, L, L, L, L, NSM, NSM, NSM, L, NSM, NSM, NSM, NSM, L, L, +/* DATA_BLOCK: -- 0x0440..0x044F -- */ + L, L, L, L, L, L, L, L, ON, ON, ON, ON, ON, ON, ON, L, +/* DATA_BLOCK: -- 0x0450..0x045F -- */ + L, L, L, L, L, L, L, L, L, L, L, L, NSM, NSM, L, L, +/* DATA_BLOCK: -- 0x0460..0x046F -- */ + NSM, NSM, L, L, L, L, L, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0470..0x047F -- */ + L, L, L, L, L, L, L, L, L, L, L, NSM, NSM, L, L, L, +/* DATA_BLOCK: -- 0x0480..0x048F -- */ + L, L, L, L, L, L, L, L, L, L, NSM, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0490..0x049F -- */ + L, L, NSM, NSM, NSM, L, NSM, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x04A0..0x04AF -- */ + L, NSM, L, L, NSM, NSM, NSM, NSM, NSM, NSM, NSM, L, L, L, L, ET, +/* DATA_BLOCK: -- 0x04B0..0x04BF -- */ + L, L, L, L, L, L, L, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, L, +/* DATA_BLOCK: -- 0x04C0..0x04CF -- */ + L, NSM, L, L, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, L, L, L, +/* DATA_BLOCK: -- 0x04D0..0x04DF -- */ + L, L, L, L, L, L, L, L, NSM, NSM, NSM, NSM, NSM, NSM, L, L, +/* DATA_BLOCK: -- 0x04E0..0x04EF -- */ + L, L, L, L, L, L, L, L, NSM, NSM, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x04F0..0x04FF -- */ + L, L, L, L, L, NSM, L, NSM, L, NSM, ON, ON, ON, ON, L, L, +/* DATA_BLOCK: -- 0x0500..0x050F -- */ + L, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, L, +/* DATA_BLOCK: -- 0x0510..0x051F -- */ + NSM, NSM, NSM, NSM, NSM, L, NSM, NSM, L, L, L, L, L, NSM, NSM, NSM, +/* DATA_BLOCK: -- 0x0520..0x052F -- */ + NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, L, NSM, NSM, NSM, NSM, NSM, NSM, NSM, +/* DATA_BLOCK: -- 0x0530..0x053F -- */ + NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, L, L, L, +/* DATA_BLOCK: -- 0x0540..0x054F -- */ + L, L, L, L, L, L, NSM, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0550..0x055F -- */ + L, L, L, L, L, L, L, L, L, L, L, L, L, NSM, NSM, NSM, +/* DATA_BLOCK: -- 0x0560..0x056F -- */ + NSM, L, NSM, NSM, NSM, NSM, NSM, NSM, L, NSM, NSM, L, L, NSM, NSM, L, +/* DATA_BLOCK: -- 0x0570..0x057F -- */ + L, L, L, L, L, L, L, L, NSM, NSM, L, L, L, L, NSM, NSM, +/* DATA_BLOCK: -- 0x0580..0x058F -- */ + NSM, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0590..0x059F -- */ + L, NSM, NSM, NSM, NSM, L, L, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x05A0..0x05AF -- */ + L, L, NSM, L, L, NSM, NSM, L, L, L, L, L, L, NSM, L, L, +/* DATA_BLOCK: -- 0x05B0..0x05BF -- */ + L, L, L, L, L, L, L, L, L, L, L, L, L, NSM, L, L, +/* DATA_BLOCK: -- 0x05C0..0x05CF -- */ + ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x05D0..0x05DF -- */ + WS, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x05E0..0x05EF -- */ + L, L, L, L, L, L, L, L, L, L, L, ON, ON, L, L, L, +/* DATA_BLOCK: -- 0x05F0..0x05FF -- */ + L, L, NSM, NSM, NSM, L, L, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0600..0x060F -- */ + L, L, L, L, NSM, NSM, L, NSM, NSM, NSM, NSM, NSM, NSM, NSM, L, L, +/* DATA_BLOCK: -- 0x0610..0x061F -- */ + L, L, L, L, L, L, NSM, L, L, NSM, NSM, NSM, NSM, NSM, NSM, NSM, +/* DATA_BLOCK: -- 0x0620..0x062F -- */ + NSM, NSM, NSM, NSM, L, L, L, L, L, L, L, ET, L, NSM, L, L, +/* DATA_BLOCK: -- 0x0630..0x063F -- */ + ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, NSM, NSM, NSM, BN, NSM, +/* DATA_BLOCK: -- 0x0640..0x064F -- */ + L, L, L, L, L, L, L, L, L, NSM, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0650..0x065F -- */ + NSM, NSM, NSM, L, L, L, L, NSM, NSM, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0660..0x066F -- */ + L, L, NSM, L, L, L, L, L, L, NSM, NSM, NSM, L, L, L, L, +/* DATA_BLOCK: -- 0x0670..0x067F -- */ + ON, L, L, L, ON, ON, L, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0680..0x068F -- */ + L, L, L, L, L, L, L, L, L, L, L, L, L, L, ON, ON, +/* DATA_BLOCK: -- 0x0690..0x069F -- */ + L, L, L, L, L, L, L, NSM, NSM, L, L, NSM, L, L, L, L, +/* DATA_BLOCK: -- 0x06A0..0x06AF -- */ + L, L, L, L, L, L, NSM, L, NSM, NSM, NSM, NSM, NSM, NSM, NSM, L, +/* DATA_BLOCK: -- 0x06B0..0x06BF -- */ + NSM, L, NSM, L, L, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, L, L, L, +/* DATA_BLOCK: -- 0x06C0..0x06CF -- */ + L, L, L, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, L, L, NSM, +/* DATA_BLOCK: -- 0x06D0..0x06DF -- */ + NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, L, +/* DATA_BLOCK: -- 0x06E0..0x06EF -- */ + NSM, NSM, NSM, NSM, L, L, L, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x06F0..0x06FF -- */ + L, L, L, L, NSM, L, NSM, NSM, NSM, NSM, NSM, L, NSM, L, L, L, +/* DATA_BLOCK: -- 0x0700..0x070F -- */ + L, L, L, L, L, L, L, L, L, L, L, NSM, NSM, NSM, NSM, NSM, +/* DATA_BLOCK: -- 0x0710..0x071F -- */ + L, L, NSM, NSM, NSM, NSM, L, L, NSM, NSM, L, NSM, NSM, NSM, L, L, +/* DATA_BLOCK: -- 0x0720..0x072F -- */ + L, L, L, L, L, L, NSM, L, NSM, NSM, L, L, L, NSM, L, NSM, +/* DATA_BLOCK: -- 0x0730..0x073F -- */ + L, L, L, L, L, L, L, L, L, L, L, L, NSM, NSM, NSM, NSM, +/* DATA_BLOCK: -- 0x0740..0x074F -- */ + NSM, NSM, NSM, NSM, L, L, NSM, NSM, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0750..0x075F -- */ + NSM, NSM, NSM, L, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, +/* DATA_BLOCK: -- 0x0760..0x076F -- */ + NSM, L, NSM, NSM, NSM, NSM, NSM, NSM, NSM, L, L, L, L, NSM, L, L, +/* DATA_BLOCK: -- 0x0770..0x077F -- */ + L, L, L, L, NSM, L, L, L, NSM, NSM, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0780..0x078F -- */ + L, L, L, L, L, L, L, L, L, L, L, L, L, ON, L, ON, +/* DATA_BLOCK: -- 0x0790..0x079F -- */ + ON, ON, L, L, L, L, L, L, L, L, L, L, L, ON, ON, ON, +/* DATA_BLOCK: -- 0x07A0..0x07AF -- */ + L, L, L, L, L, L, L, L, L, L, L, L, L, ON, ON, ON, +/* DATA_BLOCK: -- 0x07B0..0x07BF -- */ + L, L, L, L, L, L, L, L, L, L, L, L, L, ON, ON, L, +/* DATA_BLOCK: -- 0x07C0..0x07CF -- */ + WS, WS, WS, WS, WS, WS, WS, WS, WS, WS, WS, BN, BN, BN, L, R, +/* DATA_BLOCK: -- 0x07D0..0x07DF -- */ + ON, ON, ON, ON, ON, ON, ON, ON, WS, B, LRE, RLE, PDF, LRO, RLO, CS, +/* DATA_BLOCK: -- 0x07E0..0x07EF -- */ + ET, ET, ET, ET, ET, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, +/* DATA_BLOCK: -- 0x07F0..0x07FF -- */ + ON, ON, ON, ON, CS, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, +/* DATA_BLOCK: -- 0x0800..0x080F -- */ + ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, WS, +/* DATA_BLOCK: -- 0x0810..0x081F -- */ + BN, BN, BN, BN, BN, BN, LRI, RLI, FSI, PDI, BN, BN, BN, BN, BN, BN, +/* DATA_BLOCK: -- 0x0820..0x082F -- */ + EN, L, L, L, EN, EN, EN, EN, EN, EN, ES, ES, ON, ON, ON, L, +/* DATA_BLOCK: -- 0x0830..0x083F -- */ + EN, EN, EN, EN, EN, EN, EN, EN, EN, EN, ES, ES, ON, ON, ON, L, +/* DATA_BLOCK: -- 0x0840..0x084F -- */ + ET, ET, ET, ET, ET, ET, ET, ET, ET, ET, ET, ET, ET, ET, ET, ET, +/* DATA_BLOCK: -- 0x0850..0x085F -- */ + ON, ON, L, ON, ON, ON, ON, L, ON, ON, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0860..0x086F -- */ + L, L, L, L, ON, L, ON, ON, ON, L, L, L, L, L, ON, ON, +/* DATA_BLOCK: -- 0x0870..0x087F -- */ + ON, ON, ON, ON, L, ON, L, ON, L, ON, L, L, L, L, ET, L, +/* DATA_BLOCK: -- 0x0880..0x088F -- */ + L, L, L, L, L, L, L, L, L, L, ON, ON, L, L, L, L, +/* DATA_BLOCK: -- 0x0890..0x089F -- */ + ON, ON, ON, ON, ON, L, L, L, L, L, ON, ON, ON, ON, L, L, +/* DATA_BLOCK: -- 0x08A0..0x08AF -- */ + L, L, L, L, L, L, L, L, L, ON, ON, ON, L, L, L, L, +/* DATA_BLOCK: -- 0x08B0..0x08BF -- */ + ON, ON, ES, ET, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, +/* DATA_BLOCK: -- 0x08C0..0x08CF -- */ + ON, ON, ON, ON, ON, ON, L, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x08D0..0x08DF -- */ + ON, ON, ON, ON, ON, L, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, +/* DATA_BLOCK: -- 0x08E0..0x08EF -- */ + ON, ON, ON, ON, ON, ON, ON, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x08F0..0x08FF -- */ + ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0900..0x090F -- */ + ON, ON, ON, ON, ON, ON, ON, ON, EN, EN, EN, EN, EN, EN, EN, EN, +/* DATA_BLOCK: -- 0x0910..0x091F -- */ + EN, EN, EN, EN, EN, EN, EN, EN, EN, EN, EN, EN, L, L, L, L, +/* DATA_BLOCK: -- 0x0920..0x092F -- */ + L, L, L, L, L, L, L, L, L, L, ON, ON, ON, ON, ON, ON, +/* DATA_BLOCK: -- 0x0930..0x093F -- */ + ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, L, ON, ON, ON, +/* DATA_BLOCK: -- 0x0940..0x094F -- */ + ON, ON, ON, ON, L, L, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, +/* DATA_BLOCK: -- 0x0950..0x095F -- */ + ON, ON, ON, ON, ON, ON, L, ON, ON, ON, ON, ON, ON, ON, ON, ON, +/* DATA_BLOCK: -- 0x0960..0x096F -- */ + L, L, L, L, L, ON, ON, ON, ON, ON, ON, L, L, L, L, NSM, +/* DATA_BLOCK: -- 0x0970..0x097F -- */ + NSM, NSM, L, L, L, L, L, L, L, ON, ON, ON, ON, ON, ON, ON, +/* DATA_BLOCK: -- 0x0980..0x098F -- */ + L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, NSM, +/* DATA_BLOCK: -- 0x0990..0x099F -- */ + ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, L, L, +/* DATA_BLOCK: -- 0x09A0..0x09AF -- */ + ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, L, ON, ON, ON, ON, ON, +/* DATA_BLOCK: -- 0x09B0..0x09BF -- */ + ON, ON, ON, ON, L, L, L, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x09C0..0x09CF -- */ + ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, L, L, L, L, +/* DATA_BLOCK: -- 0x09D0..0x09DF -- */ + WS, ON, ON, ON, ON, L, L, L, ON, ON, ON, ON, ON, ON, ON, ON, +/* DATA_BLOCK: -- 0x09E0..0x09EF -- */ + ON, L, L, L, L, L, L, L, L, L, NSM, NSM, NSM, NSM, L, L, +/* DATA_BLOCK: -- 0x09F0..0x09FF -- */ + ON, L, L, L, L, L, ON, ON, L, L, L, L, L, ON, ON, ON, +/* DATA_BLOCK: -- 0x0A00..0x0A0F -- */ + L, L, L, L, L, L, L, L, L, NSM, NSM, ON, ON, L, L, L, +/* DATA_BLOCK: -- 0x0A10..0x0A1F -- */ + L, L, L, L, L, L, L, L, L, L, L, ON, L, L, L, L, +/* DATA_BLOCK: -- 0x0A20..0x0A2F -- */ + L, L, L, L, L, L, L, L, L, L, L, L, ON, ON, ON, L, +/* DATA_BLOCK: -- 0x0A30..0x0A3F -- */ + L, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, +/* DATA_BLOCK: -- 0x0A40..0x0A4F -- */ + L, L, L, L, L, L, L, L, L, L, L, L, ON, ON, ON, ON, +/* DATA_BLOCK: -- 0x0A50..0x0A5F -- */ + L, L, L, L, L, L, L, ON, ON, ON, ON, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0A60..0x0A6F -- */ + L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, ON, +/* DATA_BLOCK: -- 0x0A70..0x0A7F -- */ + NSM, NSM, NSM, ON, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, ON, ON, +/* DATA_BLOCK: -- 0x0A80..0x0A8F -- */ + L, L, L, L, L, L, L, L, L, L, L, L, L, L, NSM, NSM, +/* DATA_BLOCK: -- 0x0A90..0x0A9F -- */ + ON, ON, L, L, L, L, L, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0AA0..0x0AAF -- */ + L, L, L, L, L, L, L, L, ON, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0AB0..0x0ABF -- */ + L, L, NSM, L, L, L, NSM, L, L, L, L, NSM, L, L, L, L, +/* DATA_BLOCK: -- 0x0AC0..0x0ACF -- */ + L, L, L, L, L, NSM, NSM, L, ON, ON, ON, ON, NSM, L, L, L, +/* DATA_BLOCK: -- 0x0AD0..0x0ADF -- */ + L, L, L, L, L, L, L, L, ET, ET, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0AE0..0x0AEF -- */ + L, L, L, L, ON, ON, ON, ON, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0AF0..0x0AFF -- */ + L, L, L, L, NSM, NSM, L, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0B00..0x0B0F -- */ + NSM, NSM, L, L, L, L, L, L, L, L, L, L, L, L, L, NSM, +/* DATA_BLOCK: -- 0x0B10..0x0B1F -- */ + L, L, L, L, L, L, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, L, L, +/* DATA_BLOCK: -- 0x0B20..0x0B2F -- */ + L, L, L, L, L, L, L, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, +/* DATA_BLOCK: -- 0x0B30..0x0B3F -- */ + L, L, L, NSM, L, L, NSM, NSM, NSM, NSM, L, L, NSM, NSM, L, L, +/* DATA_BLOCK: -- 0x0B40..0x0B4F -- */ + L, L, L, L, L, NSM, L, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0B50..0x0B5F -- */ + L, L, L, L, L, L, L, L, L, NSM, NSM, NSM, NSM, NSM, NSM, L, +/* DATA_BLOCK: -- 0x0B60..0x0B6F -- */ + L, NSM, NSM, L, L, NSM, NSM, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0B70..0x0B7F -- */ + L, L, L, NSM, L, L, L, L, L, L, L, L, NSM, L, L, L, +/* DATA_BLOCK: -- 0x0B80..0x0B8F -- */ + NSM, L, NSM, NSM, NSM, L, L, NSM, NSM, L, L, L, L, L, NSM, NSM, +/* DATA_BLOCK: -- 0x0B90..0x0B9F -- */ + L, L, L, L, L, NSM, L, L, NSM, L, L, L, L, NSM, L, L, +/* DATA_BLOCK: -- 0x0BA0..0x0BAF -- */ + L, L, L, L, L, L, L, L, L, L, L, L, L, R, NSM, R, +/* DATA_BLOCK: -- 0x0BB0..0x0BBF -- */ + R, R, R, R, R, R, R, R, R, ES, R, R, R, R, R, R, +/* DATA_BLOCK: -- 0x0BC0..0x0BCF -- */ + AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, ON, ON, +/* DATA_BLOCK: -- 0x0BD0..0x0BDF -- */ + AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, ON, +/* DATA_BLOCK: -- 0x0BE0..0x0BEF -- */ + AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, ON, ON, ON, +/* DATA_BLOCK: -- 0x0BF0..0x0BFF -- */ + CS, ON, CS, L, ON, CS, ON, ON, ON, ON, ON, ON, ON, ON, ON, ET, +/* DATA_BLOCK: -- 0x0C00..0x0C0F -- */ + ON, ON, ES, ES, ON, ON, ON, L, ON, ET, ET, ON, L, L, L, L, +/* DATA_BLOCK: -- 0x0C10..0x0C1F -- */ + AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, BN, +/* DATA_BLOCK: -- 0x0C20..0x0C2F -- */ + L, ON, ON, ET, ET, ET, ON, ON, ON, ON, ON, ES, CS, ES, CS, CS, +/* DATA_BLOCK: -- 0x0C30..0x0C3F -- */ + ET, ET, ON, ON, ON, ET, ET, L, ON, ON, ON, ON, ON, ON, ON, L, +/* DATA_BLOCK: -- 0x0C40..0x0C4F -- */ + BN, BN, BN, BN, BN, BN, BN, BN, BN, ON, ON, ON, ON, ON, BN, BN, +/* DATA_BLOCK: -- 0x0C50..0x0C5F -- */ + L, ON, L, L, L, L, L, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0C60..0x0C6F -- */ + ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, L, L, L, +/* DATA_BLOCK: -- 0x0C70..0x0C7F -- */ + NSM, EN, EN, EN, EN, EN, EN, EN, EN, EN, EN, EN, EN, EN, EN, EN, +/* DATA_BLOCK: -- 0x0C80..0x0C8F -- */ + L, L, L, L, L, L, NSM, NSM, NSM, NSM, NSM, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0C90..0x0C9F -- */ + R, R, R, R, R, R, R, R, R, R, R, R, R, R, R, ON, +/* DATA_BLOCK: -- 0x0CA0..0x0CAF -- */ + R, NSM, NSM, NSM, R, NSM, NSM, R, R, R, R, R, NSM, NSM, NSM, NSM, +/* DATA_BLOCK: -- 0x0CB0..0x0CBF -- */ + R, R, R, R, R, R, R, R, NSM, NSM, NSM, R, R, R, R, NSM, +/* DATA_BLOCK: -- 0x0CC0..0x0CCF -- */ + R, R, R, R, R, NSM, NSM, R, R, R, R, R, R, R, R, R, +/* DATA_BLOCK: -- 0x0CD0..0x0CDF -- */ + R, R, R, R, R, R, R, R, R, ON, ON, ON, ON, ON, ON, ON, +/* DATA_BLOCK: -- 0x0CE0..0x0CEF -- */ + AL, AL, AL, AL, NSM, NSM, NSM, NSM, AL, AL, AL, AL, AL, AL, AL, AL, +/* DATA_BLOCK: -- 0x0CF0..0x0CFF -- */ + AN, AN, AN, AN, AN, AN, AN, AN, AN, AN, AL, AL, AL, AL, AL, AL, +/* DATA_BLOCK: -- 0x0D00..0x0D0F -- */ + AN, AN, AN, AN, AN, AN, AN, AN, AN, AN, AN, AN, AN, AN, AN, AN, +/* DATA_BLOCK: -- 0x0D10..0x0D1F -- */ + AN, AN, AN, AN, AN, AN, AN, AN, AN, AN, AN, AN, AN, AN, AN, R, +/* DATA_BLOCK: -- 0x0D20..0x0D2F -- */ + R, R, R, R, R, R, R, R, R, R, R, NSM, NSM, R, R, R, +/* DATA_BLOCK: -- 0x0D30..0x0D3F -- */ + R, R, NSM, NSM, NSM, NSM, R, R, R, R, R, R, R, R, R, R, +/* DATA_BLOCK: -- 0x0D40..0x0D4F -- */ + L, L, L, L, L, L, L, L, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, +/* DATA_BLOCK: -- 0x0D50..0x0D5F -- */ + NSM, NSM, NSM, NSM, NSM, NSM, NSM, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0D60..0x0D6F -- */ + NSM, L, L, NSM, NSM, L, L, L, L, L, L, L, L, L, L, NSM, +/* DATA_BLOCK: -- 0x0D70..0x0D7F -- */ + L, L, L, NSM, NSM, NSM, NSM, L, L, NSM, NSM, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0D80..0x0D8F -- */ + L, L, L, L, L, L, L, NSM, NSM, NSM, NSM, NSM, L, NSM, NSM, NSM, +/* DATA_BLOCK: -- 0x0D90..0x0D9F -- */ + NSM, NSM, NSM, NSM, NSM, L, L, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0DA0..0x0DAF -- */ + L, L, L, NSM, L, L, L, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0DB0..0x0DBF -- */ + L, L, L, L, L, L, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, L, +/* DATA_BLOCK: -- 0x0DC0..0x0DCF -- */ + L, L, L, L, L, L, L, L, L, NSM, NSM, NSM, NSM, L, L, NSM, +/* DATA_BLOCK: -- 0x0DD0..0x0DDF -- */ + NSM, NSM, L, L, NSM, L, NSM, NSM, L, L, L, L, L, L, NSM, L, +/* DATA_BLOCK: -- 0x0DE0..0x0DEF -- */ + L, L, L, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0DF0..0x0DFF -- */ + L, L, L, L, L, L, NSM, NSM, NSM, NSM, NSM, NSM, NSM, L, L, L, +/* DATA_BLOCK: -- 0x0E00..0x0E0F -- */ + L, L, L, L, L, L, L, L, L, L, L, L, L, L, NSM, L, +/* DATA_BLOCK: -- 0x0E10..0x0E1F -- */ + L, L, L, NSM, NSM, NSM, NSM, NSM, NSM, L, NSM, L, L, L, L, NSM, +/* DATA_BLOCK: -- 0x0E20..0x0E2F -- */ + NSM, L, NSM, NSM, L, L, L, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0E30..0x0E3F -- */ + L, L, NSM, NSM, NSM, NSM, L, L, L, L, L, L, NSM, NSM, L, NSM, +/* DATA_BLOCK: -- 0x0E40..0x0E4F -- */ + L, L, L, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, L, L, NSM, L, NSM, +/* DATA_BLOCK: -- 0x0E50..0x0E5F -- */ + L, L, L, L, L, L, L, L, L, L, L, NSM, L, NSM, L, L, +/* DATA_BLOCK: -- 0x0E60..0x0E6F -- */ + NSM, NSM, NSM, NSM, NSM, NSM, L, NSM, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0E70..0x0E7F -- */ + L, L, NSM, NSM, NSM, NSM, L, NSM, NSM, NSM, NSM, NSM, L, L, L, L, +/* DATA_BLOCK: -- 0x0E80..0x0E8F -- */ + NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, L, NSM, NSM, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0E90..0x0E9F -- */ + L, L, L, L, L, L, L, L, L, L, L, NSM, NSM, L, NSM, L, +/* DATA_BLOCK: -- 0x0EA0..0x0EAF -- */ + L, L, L, L, NSM, NSM, NSM, NSM, L, L, NSM, NSM, L, L, L, L, +/* DATA_BLOCK: -- 0x0EB0..0x0EBF -- */ + L, NSM, NSM, NSM, NSM, NSM, NSM, L, L, NSM, NSM, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0EC0..0x0ECF -- */ + L, L, L, NSM, NSM, NSM, NSM, NSM, NSM, L, L, NSM, NSM, NSM, NSM, L, +/* DATA_BLOCK: -- 0x0ED0..0x0EDF -- */ + L, L, L, L, L, L, L, NSM, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0EE0..0x0EEF -- */ + L, NSM, NSM, NSM, NSM, NSM, NSM, L, L, NSM, NSM, NSM, L, L, L, L, +/* DATA_BLOCK: -- 0x0EF0..0x0EFF -- */ + L, L, L, L, L, L, L, L, L, L, NSM, NSM, NSM, NSM, NSM, NSM, +/* DATA_BLOCK: -- 0x0F00..0x0F0F -- */ + NSM, NSM, NSM, NSM, NSM, NSM, NSM, L, NSM, NSM, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0F10..0x0F1F -- */ + NSM, NSM, NSM, NSM, NSM, NSM, NSM, L, NSM, NSM, NSM, NSM, NSM, NSM, L, L, +/* DATA_BLOCK: -- 0x0F20..0x0F2F -- */ + L, L, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, +/* DATA_BLOCK: -- 0x0F30..0x0F3F -- */ + NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, L, L, NSM, NSM, NSM, NSM, NSM, NSM, +/* DATA_BLOCK: -- 0x0F40..0x0F4F -- */ + NSM, L, NSM, NSM, L, NSM, NSM, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0F50..0x0F5F -- */ + L, NSM, NSM, NSM, NSM, NSM, NSM, L, L, L, NSM, L, NSM, NSM, L, NSM, +/* DATA_BLOCK: -- 0x0F60..0x0F6F -- */ + NSM, NSM, L, L, L, NSM, L, NSM, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0F70..0x0F7F -- */ + L, L, L, NSM, NSM, L, L, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0F80..0x0F8F -- */ + L, L, L, L, L, ON, ON, ON, ON, ON, ON, ON, ON, ET, ET, ET, +/* DATA_BLOCK: -- 0x0F90..0x0F9F -- */ + ET, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, +/* DATA_BLOCK: -- 0x0FA0..0x0FAF -- */ + L, L, ON, L, NSM, L, L, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0FB0..0x0FBF -- */ + L, L, L, L, L, L, L, L, L, L, L, L, L, NSM, NSM, L, +/* DATA_BLOCK: -- 0x0FC0..0x0FCF -- */ + BN, BN, BN, BN, L, L, L, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0FD0..0x0FDF -- */ + NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, L, L, +/* DATA_BLOCK: -- 0x0FE0..0x0FEF -- */ + L, L, L, L, L, L, L, NSM, NSM, NSM, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0FF0..0x0FFF -- */ + L, L, L, BN, BN, BN, BN, BN, BN, BN, BN, NSM, NSM, NSM, NSM, NSM, +/* DATA_BLOCK: -- 0x1000..0x100F -- */ + NSM, NSM, NSM, L, L, NSM, NSM, NSM, NSM, NSM, NSM, NSM, L, L, L, L, +/* DATA_BLOCK: -- 0x1010..0x101F -- */ + L, L, L, L, L, L, L, L, L, L, NSM, NSM, NSM, NSM, L, L, +/* DATA_BLOCK: -- 0x1020..0x102F -- */ + ON, ON, NSM, NSM, NSM, ON, L, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x1030..0x103F -- */ + L, L, L, L, L, ON, L, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x1040..0x104F -- */ + L, L, L, L, L, L, L, L, L, ON, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x1050..0x105F -- */ + L, L, L, ON, L, L, L, L, L, L, L, L, L, L, EN, EN, +/* DATA_BLOCK: -- 0x1060..0x106F -- */ + EN, EN, EN, EN, EN, EN, EN, EN, EN, EN, EN, EN, EN, EN, EN, EN, +/* DATA_BLOCK: -- 0x1070..0x107F -- */ + NSM, NSM, NSM, NSM, NSM, NSM, NSM, L, L, L, L, NSM, NSM, NSM, NSM, NSM, +/* DATA_BLOCK: -- 0x1080..0x108F -- */ + L, L, L, L, NSM, L, L, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x1090..0x109F -- */ + L, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, +/* DATA_BLOCK: -- 0x10A0..0x10AF -- */ + NSM, NSM, NSM, NSM, NSM, NSM, NSM, L, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, +/* DATA_BLOCK: -- 0x10B0..0x10BF -- */ + NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, L, L, NSM, NSM, NSM, NSM, NSM, +/* DATA_BLOCK: -- 0x10C0..0x10CF -- */ + NSM, NSM, L, NSM, NSM, L, NSM, NSM, NSM, NSM, NSM, L, L, L, L, L, +/* DATA_BLOCK: -- 0x10D0..0x10DF -- */ + L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, ET, +/* DATA_BLOCK: -- 0x10E0..0x10EF -- */ + NSM, NSM, NSM, NSM, NSM, NSM, NSM, R, R, R, R, R, R, R, R, R, +/* DATA_BLOCK: -- 0x10F0..0x10FF -- */ + R, R, R, R, NSM, NSM, NSM, NSM, NSM, NSM, NSM, R, R, R, R, R, +/* DATA_BLOCK: -- 0x1100..0x110F -- */ + ON, ON, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, +/* DATA_BLOCK: -- 0x1110..0x111F -- */ + ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, L, +/* DATA_BLOCK: -- 0x1120..0x112F -- */ + EN, EN, EN, EN, EN, EN, EN, EN, EN, EN, EN, ON, ON, ON, ON, ON, +/* DATA_BLOCK: -- 0x1130..0x113F -- */ + L, L, L, L, L, L, L, L, L, L, L, L, L, ON, L, L, +/* DATA_BLOCK: -- 0x1140..0x114F -- */ + ON, ON, ON, ON, ON, ON, ON, ON, L, L, L, L, L, ON, ON, ON, +/* DATA_BLOCK: -- 0x1150..0x115F -- */ + ON, ON, ON, ON, ON, ON, ON, ON, ON, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x1160..0x116F -- */ + ON, ON, ON, ON, ON, ON, ON, ON, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x1170..0x117F -- */ + ON, ON, ON, ON, ON, L, L, L, ON, ON, ON, ON, ON, L, L, L, +/* DATA_BLOCK: -- 0x1180..0x118F -- */ + ON, ON, ON, L, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, +/* DATA_BLOCK: -- 0x1190..0x119F -- */ + EN, EN, EN, EN, EN, EN, EN, EN, EN, EN, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x11A0..0x11AF -- */ + L, L, L, L, L, L, L, L, L, L, L, L, L, L, BN, BN +}; + +static const SBUInt16 MainBidiTypeIndexes[2688] = { +/* INDEX_BLOCK: -- 0x0000..0x003F -- */ + 0x0000, 0x0010, 0x0020, 0x0030, 0x0040, 0x0050, 0x0040, 0x0060, 0x0070, 0x0080, 0x0090, 0x00A0, + 0x00B0, 0x00C0, 0x00B0, 0x00C0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00D0, 0x00E0, 0x00E0, 0x00F0, 0x0100, + 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0120, 0x0130, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x0140, +/* INDEX_BLOCK: -- 0x0040..0x007F -- */ + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0150, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x0160, 0x0170, 0x0110, 0x0180, 0x0190, 0x01A0, 0x01A0, 0x01A0, 0x01B0, 0x01C0, 0x01D0, 0x01D0, + 0x01E0, 0x0110, 0x01F0, 0x0200, 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x0210, 0x0220, 0x0230, + 0x01D0, 0x0240, 0x01D0, 0x0110, 0x01C0, 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x0250, 0x0200, + 0x01A0, 0x01A0, 0x0260, 0x0270, +/* INDEX_BLOCK: -- 0x0080..0x00BF -- */ + 0x01A0, 0x0280, 0x0290, 0x01A0, 0x01A0, 0x02A0, 0x01D0, 0x01D0, 0x01D0, 0x02B0, 0x01D0, 0x01D0, + 0x02C0, 0x0110, 0x02D0, 0x0110, 0x02E0, 0x00B0, 0x00B0, 0x02F0, 0x0300, 0x0310, 0x0320, 0x00B0, + 0x0330, 0x00B0, 0x00B0, 0x0340, 0x0350, 0x00B0, 0x0320, 0x0360, 0x0370, 0x00B0, 0x00B0, 0x0340, + 0x0380, 0x0330, 0x00B0, 0x0390, 0x0370, 0x00B0, 0x00B0, 0x0340, 0x03A0, 0x00B0, 0x0320, 0x03B0, + 0x0330, 0x00B0, 0x00B0, 0x03C0, 0x0350, 0x03D0, 0x0320, 0x00B0, 0x03E0, 0x00B0, 0x00B0, 0x00B0, + 0x03F0, 0x00B0, 0x00B0, 0x0400, +/* INDEX_BLOCK: -- 0x00C0..0x00FF -- */ + 0x0410, 0x00B0, 0x00B0, 0x0420, 0x0430, 0x03D0, 0x0320, 0x0440, 0x0330, 0x00B0, 0x00B0, 0x0340, + 0x0450, 0x00B0, 0x0320, 0x00B0, 0x0460, 0x00B0, 0x00B0, 0x0470, 0x0350, 0x00B0, 0x0320, 0x00B0, + 0x0330, 0x00B0, 0x00B0, 0x00B0, 0x0480, 0x0490, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x04A0, + 0x04B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x04C0, 0x04D0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x04E0, 0x00B0, 0x04F0, 0x00B0, 0x00B0, 0x00B0, 0x0500, 0x0510, 0x0520, 0x0110, 0x0530, + 0x0540, 0x00B0, 0x00B0, 0x00B0, +/* INDEX_BLOCK: -- 0x0100..0x013F -- */ + 0x00B0, 0x00B0, 0x0550, 0x0560, 0x00B0, 0x0570, 0x0580, 0x0590, 0x05A0, 0x05B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0550, 0x00B0, 0x00B0, 0x00B0, 0x05C0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, +/* INDEX_BLOCK: -- 0x0140..0x017F -- */ + 0x0040, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x05D0, 0x05E0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x05F0, 0x00B0, 0x0320, 0x00B0, 0x0320, 0x00B0, 0x0320, 0x00B0, 0x00B0, 0x00B0, 0x0600, + 0x0610, 0x0620, 0x00B0, 0x05C0, +/* INDEX_BLOCK: -- 0x0180..0x01BF -- */ + 0x0630, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x03D0, 0x00B0, 0x0640, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0650, 0x0660, 0x0670, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0680, 0x0100, 0x0100, 0x00B0, 0x0690, 0x00B0, 0x00B0, + 0x00B0, 0x06A0, 0x06B0, 0x06C0, 0x00B0, 0x00B0, 0x00B0, 0x0110, 0x06D0, 0x00B0, 0x00B0, 0x00B0, + 0x06E0, 0x00B0, 0x00B0, 0x06F0, 0x03E0, 0x00B0, 0x0700, 0x06E0, 0x0460, 0x00B0, 0x0710, 0x00B0, + 0x00B0, 0x00B0, 0x0720, 0x0460, +/* INDEX_BLOCK: -- 0x01C0..0x01FF -- */ + 0x00B0, 0x00B0, 0x0730, 0x0740, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x0750, 0x0760, 0x0770, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0110, 0x0110, 0x0110, 0x0110, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0780, + 0x0790, 0x07A0, 0x07A0, 0x07B0, +/* INDEX_BLOCK: -- 0x0200..0x023F -- */ + 0x07C0, 0x0100, 0x07D0, 0x07E0, 0x07F0, 0x0800, 0x0810, 0x0820, 0x0830, 0x00B0, 0x0840, 0x0840, + 0x0840, 0x0110, 0x0110, 0x0580, 0x0850, 0x0860, 0x0870, 0x0880, 0x0890, 0x0100, 0x00B0, 0x00B0, + 0x08A0, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x08B0, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x08C0, 0x00B0, 0x00B0, 0x00B0, 0x0050, 0x0100, 0x08D0, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, +/* INDEX_BLOCK: -- 0x0240..0x027F -- */ + 0x0100, 0x0100, 0x08E0, 0x00B0, 0x08F0, 0x00B0, 0x0100, 0x0100, 0x0900, 0x0910, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x0920, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0930, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, +/* INDEX_BLOCK: -- 0x0280..0x02BF -- */ + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0940, 0x0100, 0x0950, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, +/* INDEX_BLOCK: -- 0x02C0..0x02FF -- */ + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x0960, 0x0970, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0980, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0110, 0x0110, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0990, 0x00B0, 0x00B0, 0x0100, 0x09A0, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x09B0, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x08C0, 0x00B0, 0x09C0, +/* INDEX_BLOCK: -- 0x0300..0x033F -- */ + 0x09D0, 0x0100, 0x09E0, 0x09F0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0A00, 0x0040, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x0A10, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0100, 0x0100, 0x09B0, 0x00B0, 0x00B0, 0x07B0, 0x00B0, 0x00B0, + 0x00B0, 0x0100, 0x00B0, 0x0A20, 0x00B0, 0x00B0, 0x00B0, 0x0A30, 0x0A40, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0A50, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x0680, 0x00B0, 0x0A60, +/* INDEX_BLOCK: -- 0x0340..0x037F -- */ + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, +/* INDEX_BLOCK: -- 0x0380..0x03BF -- */ + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0100, 0x0100, 0x0100, 0x0100, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, +/* INDEX_BLOCK: -- 0x03C0..0x03FF -- */ + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0100, 0x0100, 0x0100, + 0x08E0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x07A0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x0980, 0x0A70, 0x00B0, 0x0A80, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0460, + 0x0100, 0x0100, 0x0A90, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0AA0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, +/* INDEX_BLOCK: -- 0x0400..0x043F -- */ + 0x0AB0, 0x00B0, 0x0AC0, 0x0AD0, 0x00B0, 0x00B0, 0x00B0, 0x0AE0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x0AF0, 0x00B0, 0x0110, 0x0B00, 0x00B0, 0x00B0, 0x0B10, 0x00B0, 0x0B20, 0x0460, 0x00B0, 0x00B0, + 0x02E0, 0x00B0, 0x00B0, 0x0B30, 0x00B0, 0x00B0, 0x0B40, 0x00B0, 0x00B0, 0x00B0, 0x0B50, 0x0B60, + 0x0B70, 0x00B0, 0x00B0, 0x0340, 0x00B0, 0x00B0, 0x00B0, 0x0B80, 0x0330, 0x00B0, 0x0450, 0x0540, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0880, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x0B90, 0x00B0, +/* INDEX_BLOCK: -- 0x0440..0x047F -- */ + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x0BA0, 0x0BB0, 0x01A0, 0x01A0, 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x01D0, + 0x01D0, 0x01D0, 0x01D0, 0x01D0, +/* INDEX_BLOCK: -- 0x0480..0x04BF -- */ + 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x01D0, + 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x0BC0, 0x0100, 0x01D0, 0x01D0, 0x01D0, + 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x0BD0, 0x0080, 0x0080, 0x0BE0, 0x0110, 0x05C0, 0x0110, 0x0100, + 0x0100, 0x0BF0, 0x0C00, 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x0C10, + 0x0C20, 0x0030, 0x0040, 0x0050, 0x0040, 0x0050, 0x08C0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x0C30, 0x0C40, +/* INDEX_BLOCK: -- 0x04C0..0x04FF -- */ + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0C50, 0x00B0, 0x00B0, 0x00B0, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0C60, 0x0C60, 0x0040, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x05B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0C70, 0x0910, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0C80, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, +/* INDEX_BLOCK: -- 0x0500..0x053F -- */ + 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, + 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x0C90, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, + 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x0CA0, 0x01A0, 0x01A0, 0x0CB0, + 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x0CC0, 0x01A0, + 0x01A0, 0x01A0, 0x01A0, 0x0CD0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, + 0x01A0, 0x01A0, 0x01A0, 0x01A0, +/* INDEX_BLOCK: -- 0x0540..0x057F -- */ + 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, + 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01D0, 0x01D0, 0x0CE0, 0x0CF0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, + 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, + 0x01A0, 0x01A0, 0x0D00, 0x0D10, 0x01A0, 0x01A0, 0x0D20, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, + 0x01A0, 0x01A0, 0x01A0, 0x01D0, 0x0250, 0x0200, 0x01D0, 0x01A0, 0x0D30, 0x01A0, 0x01A0, 0x01A0, + 0x01A0, 0x01A0, 0x01A0, 0x01A0, +/* INDEX_BLOCK: -- 0x0580..0x05BF -- */ + 0x0330, 0x00B0, 0x00B0, 0x0D40, 0x0D50, 0x00E0, 0x08C0, 0x0D60, 0x0460, 0x00B0, 0x00B0, 0x0D70, + 0x03E0, 0x00B0, 0x00B0, 0x00B0, 0x02E0, 0x00B0, 0x0D80, 0x0D90, 0x00B0, 0x00B0, 0x00B0, 0x0DA0, + 0x0460, 0x00B0, 0x00B0, 0x0DB0, 0x0DC0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0980, 0x0DD0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0980, 0x0DE0, 0x00B0, + 0x0460, 0x00B0, 0x00B0, 0x0470, 0x0580, 0x00B0, 0x0DF0, 0x0D90, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, +/* INDEX_BLOCK: -- 0x05C0..0x05FF -- */ + 0x00B0, 0x00B0, 0x00B0, 0x0D40, 0x0490, 0x0E00, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0E10, + 0x0E20, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x0E30, 0x0580, 0x0450, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0E40, + 0x0580, 0x00B0, 0x0C60, 0x00B0, 0x00B0, 0x00B0, 0x0E50, 0x0E60, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x0550, 0x0E70, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, +/* INDEX_BLOCK: -- 0x0600..0x063F -- */ + 0x00B0, 0x00B0, 0x0980, 0x0E80, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0E90, 0x0DA0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0EA0, 0x0580, 0x00B0, 0x0EB0, 0x00B0, 0x00B0, 0x0EC0, + 0x0ED0, 0x0EE0, 0x00B0, 0x00B0, 0x0EF0, 0x0F00, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, +/* INDEX_BLOCK: -- 0x0640..0x067F -- */ + 0x00B0, 0x00B0, 0x00B0, 0x0F10, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0F20, 0x0F30, 0x0F40, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0F50, 0x0E60, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x0F60, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0F70, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x0F80, 0x0F90, 0x0A90, +/* INDEX_BLOCK: -- 0x0680..0x06BF -- */ + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0D90, + 0x00B0, 0x00B0, 0x00B0, 0x0D50, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, +/* INDEX_BLOCK: -- 0x06C0..0x06FF -- */ + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0980, 0x00B0, 0x00B0, 0x00B0, 0x0980, 0x02E0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x0FA0, 0x00B0, +/* INDEX_BLOCK: -- 0x0700..0x073F -- */ + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0FB0, 0x0FC0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, +/* INDEX_BLOCK: -- 0x0740..0x077F -- */ + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x0110, 0x0110, 0x0FD0, 0x0110, 0x0D50, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, +/* INDEX_BLOCK: -- 0x0780..0x07BF -- */ + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0FE0, 0x0FF0, + 0x1000, 0x00B0, 0x1010, 0x00B0, 0x00B0, 0x00B0, 0x00D0, 0x00B0, 0x0100, 0x0100, 0x0100, 0x0100, + 0x1020, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x08E0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, +/* INDEX_BLOCK: -- 0x07C0..0x07FF -- */ + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0A10, 0x00B0, 0x00B0, + 0x00B0, 0x1030, 0x00B0, 0x00B0, 0x0A60, 0x00B0, 0x00B0, 0x00B0, 0x1040, 0x00B0, 0x00B0, 0x00B0, + 0x1050, 0x1060, 0x1060, 0x1060, +/* INDEX_BLOCK: -- 0x0800..0x083F -- */ + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0110, 0x0110, 0x0110, 0x1070, + 0x0110, 0x0110, 0x0530, 0x0B40, 0x1080, 0x0700, 0x1090, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, +/* INDEX_BLOCK: -- 0x0840..0x087F -- */ + 0x10A0, 0x10B0, 0x10C0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0D50, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0E00, 0x00B0, 0x00B0, 0x00B0, 0x0730, 0x10D0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, +/* INDEX_BLOCK: -- 0x0880..0x08BF -- */ + 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, + 0x01A0, 0x10E0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x10F0, 0x01A0, 0x01A0, 0x01A0, + 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, + 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, + 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, + 0x01A0, 0x01A0, 0x01A0, 0x01A0, +/* INDEX_BLOCK: -- 0x08C0..0x08FF -- */ + 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x01D0, + 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x01A0, 0x01A0, 0x01A0, + 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01D0, 0x01D0, 0x01D0, 0x01D0, + 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x1100, + 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, + 0x01A0, 0x01A0, 0x01A0, 0x01A0, +/* INDEX_BLOCK: -- 0x0900..0x093F -- */ + 0x0100, 0x0100, 0x09C0, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x09B0, 0x1110, 0x0A30, + 0x0A30, 0x0A30, 0x0100, 0x08C0, 0x1120, 0x00B0, 0x0A60, 0x00B0, 0x00B0, 0x00B0, 0x0920, 0x00B0, + 0x00B0, 0x00B0, 0x1130, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x08C0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, +/* INDEX_BLOCK: -- 0x0940..0x097F -- */ + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x1140, 0x0C60, 0x0C60, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x09B0, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x1150, 0x09C0, 0x0040, +/* INDEX_BLOCK: -- 0x0980..0x09BF -- */ + 0x09C0, 0x0100, 0x0100, 0x0100, 0x1160, 0x05C0, 0x0100, 0x0100, 0x1160, 0x0100, 0x0990, 0x0A90, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x09B0, 0x0990, 0x1170, 0x08E0, 0x0100, 0x0C60, 0x08F0, 0x08C0, 0x05C0, 0x1160, 0x08E0, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x1180, 0x0100, 0x0100, + 0x08F0, 0x00B0, 0x00B0, 0x1190, +/* INDEX_BLOCK: -- 0x09C0..0x09FF -- */ + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x11A0, +/* INDEX_BLOCK: -- 0x0A00..0x0A3F -- */ + 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, + 0x0080, 0x0080, 0x0080, 0x0080, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, + 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, + 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, + 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, + 0x0080, 0x0080, 0x0080, 0x0080, +/* INDEX_BLOCK: -- 0x0A40..0x0A7F -- */ + 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, + 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, + 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, + 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, + 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, + 0x0080, 0x0080, 0x0080, 0x0080 +}; + +static const SBUInt16 BranchBidiTypeIndexes[1088] = { + 0x0000, 0x0040, 0x0080, 0x00C0, 0x0100, 0x0140, 0x0180, 0x01C0, 0x0200, 0x0240, 0x0280, 0x02C0, + 0x0300, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0380, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x03C0, 0x0400, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0440, 0x0480, 0x04C0, 0x0340, 0x0500, 0x0540, 0x0580, 0x05C0, 0x0600, 0x0640, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0680, 0x06C0, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0700, 0x0340, 0x0340, 0x0340, 0x0740, 0x0780, 0x07C0, 0x0800, 0x0340, + 0x0840, 0x0340, 0x0880, 0x08C0, 0x0900, 0x0940, 0x0980, 0x09C0, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x09C0, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x09C0, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x09C0, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x09C0, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x09C0, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x09C0, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x09C0, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x09C0, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x09C0, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x09C0, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x09C0, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x09C0, 0x0A00, 0x0A40, 0x0A40, 0x0A40, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x09C0, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x09C0, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x09C0 +}; + +SB_INTERNAL SBBidiType LookupBidiType(SBCodepoint codepoint) +{ + if (codepoint <= 0x10FFFF) { + return PrimaryBidiTypeData[ + MainBidiTypeIndexes[ + BranchBidiTypeIndexes[ + codepoint / 0x0400 + ] + (codepoint % 0x0400) / 0x0010 + ] + codepoint % 0x0010 + ]; + } + + return ON; +} + +#undef AL +#undef AN +#undef B +#undef BN +#undef CS +#undef EN +#undef ES +#undef ET +#undef FSI +#undef L +#undef LRE +#undef LRI +#undef LRO +#undef NSM +#undef ON +#undef PDF +#undef PDI +#undef R +#undef RLE +#undef RLI +#undef RLO +#undef S +#undef WS diff --git a/third_party/sheenbidi/source/BidiTypeLookup.h b/third_party/sheenbidi/source/BidiTypeLookup.h new file mode 100644 index 0000000..dc39b32 --- /dev/null +++ b/third_party/sheenbidi/source/BidiTypeLookup.h @@ -0,0 +1,16 @@ +/* + * Automatically generated by SheenBidiGenerator tool. + * DO NOT EDIT!! + */ + +#ifndef _SB_INTERNAL_BIDI_TYPE_LOOKUP_H +#define _SB_INTERNAL_BIDI_TYPE_LOOKUP_H + +#include +#include + +#include "SBBase.h" + +SB_INTERNAL SBBidiType LookupBidiType(SBCodepoint codepoint); + +#endif diff --git a/third_party/sheenbidi/source/BracketQueue.c b/third_party/sheenbidi/source/BracketQueue.c new file mode 100644 index 0000000..33f76c0 --- /dev/null +++ b/third_party/sheenbidi/source/BracketQueue.c @@ -0,0 +1,242 @@ +/* + * Copyright (C) 2014-2022 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ + +#include +#include +#include + +#include "BidiChain.h" +#include "SBAssert.h" +#include "SBBase.h" +#include "BracketQueue.h" + +static SBBoolean BracketQueueInsertElement(BracketQueueRef queue) +{ + if (queue->_rearTop != BracketQueueList_MaxIndex) { + queue->_rearTop += 1; + } else { + BracketQueueListRef previousList = queue->_rearList; + BracketQueueListRef rearList = previousList->next; + + if (!rearList) { + rearList = malloc(sizeof(BracketQueueList)); + if (!rearList) { + return SBFalse; + } + + rearList->previous = previousList; + rearList->next = NULL; + + previousList->next = rearList; + } + + queue->_rearList = rearList; + queue->_rearTop = 0; + } + queue->count += 1; + + return SBTrue; +} + +static void BracketQueueFinalizePairs(BracketQueueRef queue, BracketQueueListRef list, SBInteger top) +{ + do { + SBInteger limit = (list == queue->_rearList ? queue->_rearTop : BracketQueueList_MaxIndex); + + while (++top <= limit) { + if (list->openingLink[top] != BidiLinkNone + && list->closingLink[top] == BidiLinkNone) { + list->openingLink[top] = BidiLinkNone; + } + } + + list = list->next; + top = 0; + } while (list); +} + +SB_INTERNAL void BracketQueueInitialize(BracketQueueRef queue) +{ + queue->_firstList.previous = NULL; + queue->_firstList.next = NULL; + queue->_frontList = NULL; + queue->_rearList = NULL; + queue->count = 0; + queue->shouldDequeue = SBFalse; +} + +SB_INTERNAL void BracketQueueReset(BracketQueueRef queue, SBBidiType direction) +{ + queue->_frontList = &queue->_firstList; + queue->_rearList = &queue->_firstList; + queue->_frontTop = 0; + queue->_rearTop = -1; + queue->count = 0; + queue->shouldDequeue = SBFalse; + queue->_direction = direction; +} + +SB_INTERNAL SBBoolean BracketQueueEnqueue(BracketQueueRef queue, + BidiLink priorStrongLink, BidiLink openingLink, SBCodepoint bracket) +{ + /* The queue can only take a maximum of 63 elements. */ + SBAssert(queue->count < BracketQueueGetMaxCapacity()); + + if (BracketQueueInsertElement(queue)) { + BracketQueueListRef list = queue->_rearList; + SBInteger top = queue->_rearTop; + + list->priorStrongLink[top] = priorStrongLink; + list->openingLink[top] = openingLink; + list->closingLink[top] = BidiLinkNone; + list->bracket[top] = bracket; + list->strongType[top] = SBBidiTypeNil; + + return SBTrue; + } + + return SBFalse; +} + +SB_INTERNAL void BracketQueueDequeue(BracketQueueRef queue) +{ + /* The queue must NOT be empty. */ + SBAssert(queue->count != 0); + + if (queue->_frontTop != BracketQueueList_MaxIndex) { + queue->_frontTop += 1; + } else { + BracketQueueListRef frontList = queue->_frontList; + + if (frontList == queue->_rearList) { + queue->_rearTop = -1; + } else { + queue->_frontList = frontList->next; + } + + queue->_frontTop = 0; + } + + queue->count -= 1; +} + +SB_INTERNAL void BracketQueueSetStrongType(BracketQueueRef queue, SBBidiType strongType) +{ + BracketQueueListRef list = queue->_rearList; + SBInteger top = queue->_rearTop; + + while (1) { + SBInteger limit = (list == queue->_frontList ? queue->_frontTop : 0); + + do { + if (list->closingLink[top] == BidiLinkNone + && list->strongType[top] != queue->_direction) { + list->strongType[top] = strongType; + } + } while (top-- > limit); + + if (list == queue->_frontList) { + break; + } + + list = list->previous; + top = BracketQueueList_MaxIndex; + } +} + +SB_INTERNAL void BracketQueueClosePair(BracketQueueRef queue, BidiLink closingLink, SBCodepoint bracket) +{ + BracketQueueListRef list = queue->_rearList; + SBInteger top = queue->_rearTop; + SBCodepoint canonical; + + switch (bracket) { + case 0x232A: + canonical = 0x3009; + break; + + case 0x3009: + canonical = 0x232A; + break; + + default: + canonical = bracket; + break; + } + + while (1) { + SBBoolean isFrontList = (list == queue->_frontList); + SBInteger limit = (isFrontList ? queue->_frontTop : 0); + + do { + if (list->openingLink[top] != BidiLinkNone + && list->closingLink[top] == BidiLinkNone + && (list->bracket[top] == bracket || list->bracket[top] == canonical)) { + list->closingLink[top] = closingLink; + BracketQueueFinalizePairs(queue, list, top); + + if (isFrontList && top == queue->_frontTop) { + queue->shouldDequeue = SBTrue; + } + + return; + } + } while (top-- > limit); + + if (isFrontList) { + break; + } + + list = list->previous; + top = BracketQueueList_MaxIndex; + } +} + +SB_INTERNAL SBBoolean BracketQueueShouldDequeue(BracketQueueRef queue) +{ + return queue->shouldDequeue; +} + +SB_INTERNAL BidiLink BracketQueueGetPriorStrongLink(BracketQueueRef queue) +{ + return queue->_frontList->priorStrongLink[queue->_frontTop]; +} + +SB_INTERNAL BidiLink BracketQueueGetOpeningLink(BracketQueueRef queue) +{ + return queue->_frontList->openingLink[queue->_frontTop]; +} + +SB_INTERNAL BidiLink BracketQueueGetClosingLink(BracketQueueRef queue) +{ + return queue->_frontList->closingLink[queue->_frontTop]; +} + +SB_INTERNAL SBBidiType BracketQueueGetStrongType(BracketQueueRef queue) +{ + return queue->_frontList->strongType[queue->_frontTop]; +} + +SB_INTERNAL void BracketQueueFinalize(BracketQueueRef queue) +{ + BracketQueueListRef list = queue->_firstList.next; + + while (list) { + BracketQueueListRef next = list->next; + free(list); + list = next; + } +} diff --git a/third_party/sheenbidi/source/BracketQueue.h b/third_party/sheenbidi/source/BracketQueue.h new file mode 100644 index 0000000..89a5713 --- /dev/null +++ b/third_party/sheenbidi/source/BracketQueue.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2014-2022 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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 _SB_INTERNAL_BRACKET_QUEUE_H +#define _SB_INTERNAL_BRACKET_QUEUE_H + +#include + +#include "BidiChain.h" +#include "SBBase.h" + +#define BracketQueueList_Length 8 +#define BracketQueueList_MaxIndex (BracketQueueList_Length - 1) + +typedef struct _BracketQueueList { + SBCodepoint bracket[BracketQueueList_Length]; + BidiLink priorStrongLink[BracketQueueList_Length]; + BidiLink openingLink[BracketQueueList_Length]; + BidiLink closingLink[BracketQueueList_Length]; + SBBidiType strongType[BracketQueueList_Length]; + + struct _BracketQueueList *previous; + struct _BracketQueueList *next; +} BracketQueueList, *BracketQueueListRef; + +typedef struct _BracketQueue { + BracketQueueList _firstList; + BracketQueueListRef _frontList; + BracketQueueListRef _rearList; + SBInteger _frontTop; + SBInteger _rearTop; + SBUInteger count; + SBBoolean shouldDequeue; + SBBidiType _direction; +} BracketQueue, *BracketQueueRef; + +#define BracketQueueGetMaxCapacity() 63 + +SB_INTERNAL void BracketQueueInitialize(BracketQueueRef queue); +SB_INTERNAL void BracketQueueReset(BracketQueueRef queue, SBBidiType direction); + +SB_INTERNAL SBBoolean BracketQueueEnqueue(BracketQueueRef queue, + BidiLink priorStrongLink, BidiLink openingLink, SBCodepoint bracket); +SB_INTERNAL void BracketQueueDequeue(BracketQueueRef queue); + +SB_INTERNAL void BracketQueueSetStrongType(BracketQueueRef queue, SBBidiType strongType); +SB_INTERNAL void BracketQueueClosePair(BracketQueueRef queue, + BidiLink closingLink, SBCodepoint bracket); + +SB_INTERNAL SBBoolean BracketQueueShouldDequeue(BracketQueueRef queue); + +SB_INTERNAL BidiLink BracketQueueGetPriorStrongLink(BracketQueueRef queue); +SB_INTERNAL BidiLink BracketQueueGetOpeningLink(BracketQueueRef queue); +SB_INTERNAL BidiLink BracketQueueGetClosingLink(BracketQueueRef queue); +SB_INTERNAL SBBidiType BracketQueueGetStrongType(BracketQueueRef queue); + +SB_INTERNAL void BracketQueueFinalize(BracketQueueRef queue); + +#endif diff --git a/third_party/sheenbidi/source/BracketType.h b/third_party/sheenbidi/source/BracketType.h new file mode 100644 index 0000000..5f44e34 --- /dev/null +++ b/third_party/sheenbidi/source/BracketType.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2014-2019 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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 _SB_INTERNAL_BRACKET_TYPE_H +#define _SB_INTERNAL_BRACKET_TYPE_H + +#include "SBBase.h" + +enum { + BracketTypeNone = 0x00, + BracketTypeOpen = 0x40, /**< Opening paired bracket. */ + BracketTypeClose = 0x80, /**< Closing paired bracket. */ + + BracketTypePrimaryMask = BracketTypeOpen | BracketTypeClose, + BracketTypeInverseMask = ~BracketTypePrimaryMask +}; +typedef SBUInt8 BracketType; + +#endif diff --git a/third_party/sheenbidi/source/GeneralCategoryLookup.c b/third_party/sheenbidi/source/GeneralCategoryLookup.c new file mode 100644 index 0000000..067225a --- /dev/null +++ b/third_party/sheenbidi/source/GeneralCategoryLookup.c @@ -0,0 +1,2062 @@ +/* + * Automatically generated by SheenBidiGenerator tool. + * DO NOT EDIT!! + * + * REQUIRED MEMORY: 10894+(3972*2)+(1422*2) = 21682 Bytes + */ + +#include "GeneralCategoryLookup.h" + +#define Cc SBGeneralCategoryCC +#define Cf SBGeneralCategoryCF +#define Cn SBGeneralCategoryCN +#define Co SBGeneralCategoryCO +#define Cs SBGeneralCategoryCS +#define Ll SBGeneralCategoryLL +#define Lm SBGeneralCategoryLM +#define Lo SBGeneralCategoryLO +#define Lt SBGeneralCategoryLT +#define Lu SBGeneralCategoryLU +#define Mc SBGeneralCategoryMC +#define Me SBGeneralCategoryME +#define Mn SBGeneralCategoryMN +#define Nd SBGeneralCategoryND +#define Nl SBGeneralCategoryNL +#define No SBGeneralCategoryNO +#define Pc SBGeneralCategoryPC +#define Pd SBGeneralCategoryPD +#define Pe SBGeneralCategoryPE +#define Pf SBGeneralCategoryPF +#define Pi SBGeneralCategoryPI +#define Po SBGeneralCategoryPO +#define Ps SBGeneralCategoryPS +#define Sc SBGeneralCategorySC +#define Sk SBGeneralCategorySK +#define Sm SBGeneralCategorySM +#define So SBGeneralCategorySO +#define Zl SBGeneralCategoryZL +#define Zp SBGeneralCategoryZP +#define Zs SBGeneralCategoryZS + +static const SBUInt8 PrimaryGeneralCategoryData[10894] = { +/* DATA_BLOCK: -- 0x0000..0x000F -- */ + Cc, Cc, Cc, Cc, Cc, Cc, Cc, Cc, Cc, Cc, Cc, Cc, Cc, Cc, Cc, Cc, +/* DATA_BLOCK: -- 0x0010..0x001F -- */ + Zs, Po, Po, Po, Sc, Po, Po, Po, Ps, Pe, Po, Sm, Po, Pd, Po, Po, +/* DATA_BLOCK: -- 0x0020..0x002F -- */ + Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Po, Po, Sm, Sm, Sm, Po, +/* DATA_BLOCK: -- 0x0030..0x003F -- */ + Po, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, +/* DATA_BLOCK: -- 0x0040..0x004F -- */ + Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Ps, Po, Pe, Sk, Pc, +/* DATA_BLOCK: -- 0x0050..0x005F -- */ + Sk, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, +/* DATA_BLOCK: -- 0x0060..0x006F -- */ + Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ps, Sm, Pe, Sm, Cc, +/* DATA_BLOCK: -- 0x0070..0x007F -- */ + Zs, Po, Sc, Sc, Sc, Sc, So, Po, Sk, So, Lo, Pi, Sm, Cf, So, Sk, +/* DATA_BLOCK: -- 0x0080..0x008F -- */ + So, Sm, No, No, Sk, Ll, Po, Po, Sk, No, Lo, Pf, No, No, No, Po, +/* DATA_BLOCK: -- 0x0090..0x009F -- */ + Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, +/* DATA_BLOCK: -- 0x00A0..0x00AF -- */ + Lu, Lu, Lu, Lu, Lu, Lu, Lu, Sm, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Ll, +/* DATA_BLOCK: -- 0x00B0..0x00BF -- */ + Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, +/* DATA_BLOCK: -- 0x00C0..0x00CF -- */ + Ll, Ll, Ll, Ll, Ll, Ll, Ll, Sm, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, +/* DATA_BLOCK: -- 0x00D0..0x00DF -- */ + Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, +/* DATA_BLOCK: -- 0x00E0..0x00EF -- */ + Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, +/* DATA_BLOCK: -- 0x00F0..0x00FF -- */ + Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Ll, Lu, Ll, Lu, Ll, Lu, Ll, +/* DATA_BLOCK: -- 0x0100..0x010F -- */ + Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Lu, Ll, Lu, Ll, Lu, Ll, Ll, +/* DATA_BLOCK: -- 0x0110..0x011F -- */ + Ll, Lu, Lu, Ll, Lu, Ll, Lu, Lu, Ll, Lu, Lu, Lu, Ll, Ll, Lu, Lu, +/* DATA_BLOCK: -- 0x0120..0x012F -- */ + Lu, Lu, Ll, Lu, Lu, Ll, Lu, Lu, Lu, Ll, Ll, Ll, Lu, Lu, Ll, Lu, +/* DATA_BLOCK: -- 0x0130..0x013F -- */ + Lu, Ll, Lu, Ll, Lu, Ll, Lu, Lu, Ll, Lu, Ll, Ll, Lu, Ll, Lu, Lu, +/* DATA_BLOCK: -- 0x0140..0x014F -- */ + Ll, Lu, Lu, Lu, Ll, Lu, Ll, Lu, Lu, Ll, Ll, Lo, Lu, Ll, Ll, Ll, +/* DATA_BLOCK: -- 0x0150..0x015F -- */ + Lo, Lo, Lo, Lo, Lu, Lt, Ll, Lu, Lt, Ll, Lu, Lt, Ll, Lu, Ll, Lu, +/* DATA_BLOCK: -- 0x0160..0x016F -- */ + Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Ll, Lu, Ll, +/* DATA_BLOCK: -- 0x0170..0x017F -- */ + Ll, Lu, Lt, Ll, Lu, Ll, Lu, Lu, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, +/* DATA_BLOCK: -- 0x0180..0x018F -- */ + Lu, Ll, Lu, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Lu, Lu, Ll, Lu, Lu, Ll, +/* DATA_BLOCK: -- 0x0190..0x019F -- */ + Ll, Lu, Ll, Lu, Lu, Lu, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, +/* DATA_BLOCK: -- 0x01A0..0x01AF -- */ + Ll, Ll, Ll, Ll, Lo, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, +/* DATA_BLOCK: -- 0x01B0..0x01BF -- */ + Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, +/* DATA_BLOCK: -- 0x01C0..0x01CF -- */ + Lm, Lm, Sk, Sk, Sk, Sk, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, +/* DATA_BLOCK: -- 0x01D0..0x01DF -- */ + Lm, Lm, Sk, Sk, Sk, Sk, Sk, Sk, Sk, Sk, Sk, Sk, Sk, Sk, Sk, Sk, +/* DATA_BLOCK: -- 0x01E0..0x01EF -- */ + Lm, Lm, Lm, Lm, Lm, Sk, Sk, Sk, Sk, Sk, Sk, Sk, Lm, Sk, Lm, Sk, +/* DATA_BLOCK: -- 0x01F0..0x01FF -- */ + Sk, Sk, Sk, Sk, Sk, Sk, Sk, Sk, Sk, Sk, Sk, Sk, Sk, Sk, Sk, Sk, +/* DATA_BLOCK: -- 0x0200..0x020F -- */ + Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x0210..0x021F -- */ + Lu, Ll, Lu, Ll, Lm, Sk, Lu, Ll, Cn, Cn, Lm, Ll, Ll, Ll, Po, Lu, +/* DATA_BLOCK: -- 0x0220..0x022F -- */ + Cn, Cn, Cn, Cn, Sk, Sk, Lu, Po, Lu, Lu, Lu, Cn, Lu, Cn, Lu, Lu, +/* DATA_BLOCK: -- 0x0230..0x023F -- */ + Ll, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, +/* DATA_BLOCK: -- 0x0240..0x024F -- */ + Lu, Lu, Cn, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Ll, Ll, Ll, Ll, +/* DATA_BLOCK: -- 0x0250..0x025F -- */ + Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Lu, +/* DATA_BLOCK: -- 0x0260..0x026F -- */ + Ll, Ll, Lu, Lu, Lu, Ll, Ll, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, +/* DATA_BLOCK: -- 0x0270..0x027F -- */ + Ll, Ll, Ll, Ll, Lu, Ll, Sm, Lu, Ll, Lu, Lu, Ll, Ll, Lu, Lu, Lu, +/* DATA_BLOCK: -- 0x0280..0x028F -- */ + Lu, Ll, So, Mn, Mn, Mn, Mn, Mn, Me, Me, Lu, Ll, Lu, Ll, Lu, Ll, +/* DATA_BLOCK: -- 0x0290..0x029F -- */ + Lu, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Ll, +/* DATA_BLOCK: -- 0x02A0..0x02AF -- */ + Cn, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, +/* DATA_BLOCK: -- 0x02B0..0x02BF -- */ + Lu, Lu, Lu, Lu, Lu, Lu, Lu, Cn, Cn, Lm, Po, Po, Po, Po, Po, Po, +/* DATA_BLOCK: -- 0x02C0..0x02CF -- */ + Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Po, Pd, Cn, Cn, So, So, Sc, +/* DATA_BLOCK: -- 0x02D0..0x02DF -- */ + Cn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x02E0..0x02EF -- */ + Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Pd, Mn, +/* DATA_BLOCK: -- 0x02F0..0x02FF -- */ + Po, Mn, Mn, Po, Mn, Mn, Po, Mn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x0300..0x030F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x0310..0x031F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Cn, Cn, Lo, +/* DATA_BLOCK: -- 0x0320..0x032F -- */ + Lo, Lo, Lo, Po, Po, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x0330..0x033F -- */ + Cf, Cf, Cf, Cf, Cf, Cf, Sm, Sm, Sm, Po, Po, Sc, Po, Po, So, So, +/* DATA_BLOCK: -- 0x0340..0x034F -- */ + Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Po, Cf, Po, Po, Po, +/* DATA_BLOCK: -- 0x0350..0x035F -- */ + Lm, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Mn, Mn, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x0360..0x036F -- */ + Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Po, Po, Po, Po, Lo, Lo, +/* DATA_BLOCK: -- 0x0370..0x037F -- */ + Mn, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x0380..0x038F -- */ + Lo, Lo, Lo, Lo, Po, Lo, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Cf, So, Mn, +/* DATA_BLOCK: -- 0x0390..0x039F -- */ + Mn, Mn, Mn, Mn, Mn, Lm, Lm, Mn, Mn, So, Mn, Mn, Mn, Mn, Lo, Lo, +/* DATA_BLOCK: -- 0x03A0..0x03AF -- */ + Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Lo, Lo, Lo, So, So, Lo, +/* DATA_BLOCK: -- 0x03B0..0x03BF -- */ + Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, Cn, Cf, +/* DATA_BLOCK: -- 0x03C0..0x03CF -- */ + Lo, Mn, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x03D0..0x03DF -- */ + Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Cn, Cn, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x03E0..0x03EF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x03F0..0x03FF -- */ + Mn, Lo, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x0400..0x040F -- */ + Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x0410..0x041F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Mn, Mn, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x0420..0x042F -- */ + Mn, Mn, Mn, Mn, Lm, Lm, So, Po, Po, Po, Lm, Cn, Cn, Mn, Sc, Sc, +/* DATA_BLOCK: -- 0x0430..0x043F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Mn, Mn, Mn, Mn, Lm, Mn, Mn, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x0440..0x044F -- */ + Mn, Mn, Mn, Mn, Lm, Mn, Mn, Mn, Lm, Mn, Mn, Mn, Mn, Mn, Cn, Cn, +/* DATA_BLOCK: -- 0x0450..0x045F -- */ + Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, Cn, +/* DATA_BLOCK: -- 0x0460..0x046F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Mn, Mn, Mn, Cn, Cn, Po, Cn, +/* DATA_BLOCK: -- 0x0470..0x047F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x0480..0x048F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Sk, Lo, Lo, Lo, Lo, Lo, Lo, Cn, +/* DATA_BLOCK: -- 0x0490..0x049F -- */ + Cf, Cf, Cn, Cn, Cn, Cn, Cn, Cn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x04A0..0x04AF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lm, Mn, Mn, Mn, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x04B0..0x04BF -- */ + Mn, Mn, Cf, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x04C0..0x04CF -- */ + Mn, Mn, Mn, Mc, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x04D0..0x04DF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Mn, Mc, Mn, Lo, Mc, Mc, +/* DATA_BLOCK: -- 0x04E0..0x04EF -- */ + Mc, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mc, Mc, Mc, Mc, Mn, Mc, Mc, +/* DATA_BLOCK: -- 0x04F0..0x04FF -- */ + Lo, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x0500..0x050F -- */ + Lo, Lo, Mn, Mn, Po, Po, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, +/* DATA_BLOCK: -- 0x0510..0x051F -- */ + Po, Lm, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x0520..0x052F -- */ + Lo, Mn, Mc, Mc, Cn, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Lo, +/* DATA_BLOCK: -- 0x0530..0x053F -- */ + Lo, Cn, Cn, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x0540..0x054F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x0550..0x055F -- */ + Lo, Cn, Lo, Cn, Cn, Cn, Lo, Lo, Lo, Lo, Cn, Cn, Mn, Lo, Mc, Mc, +/* DATA_BLOCK: -- 0x0560..0x056F -- */ + Mc, Mn, Mn, Mn, Mn, Cn, Cn, Mc, Mc, Cn, Cn, Mc, Mc, Mn, Lo, Cn, +/* DATA_BLOCK: -- 0x0570..0x057F -- */ + Cn, Cn, Cn, Cn, Cn, Cn, Cn, Mc, Cn, Cn, Cn, Cn, Lo, Lo, Cn, Lo, +/* DATA_BLOCK: -- 0x0580..0x058F -- */ + Lo, Lo, Mn, Mn, Cn, Cn, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, +/* DATA_BLOCK: -- 0x0590..0x059F -- */ + Lo, Lo, Sc, Sc, No, No, No, No, No, No, So, Sc, Lo, Po, Mn, Cn, +/* DATA_BLOCK: -- 0x05A0..0x05AF -- */ + Cn, Mn, Mn, Mc, Cn, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Cn, Cn, Lo, +/* DATA_BLOCK: -- 0x05B0..0x05BF -- */ + Lo, Cn, Lo, Lo, Cn, Lo, Lo, Cn, Lo, Lo, Cn, Cn, Mn, Cn, Mc, Mc, +/* DATA_BLOCK: -- 0x05C0..0x05CF -- */ + Mc, Mn, Mn, Cn, Cn, Cn, Cn, Mn, Mn, Cn, Cn, Mn, Mn, Mn, Cn, Cn, +/* DATA_BLOCK: -- 0x05D0..0x05DF -- */ + Cn, Mn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Lo, Lo, Lo, Lo, Cn, Lo, Cn, +/* DATA_BLOCK: -- 0x05E0..0x05EF -- */ + Cn, Cn, Cn, Cn, Cn, Cn, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, +/* DATA_BLOCK: -- 0x05F0..0x05FF -- */ + Mn, Mn, Lo, Lo, Lo, Mn, Po, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x0600..0x060F -- */ + Cn, Mn, Mn, Mc, Cn, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Lo, +/* DATA_BLOCK: -- 0x0610..0x061F -- */ + Lo, Lo, Cn, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x0620..0x062F -- */ + Lo, Cn, Lo, Lo, Cn, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Mn, Lo, Mc, Mc, +/* DATA_BLOCK: -- 0x0630..0x063F -- */ + Mc, Mn, Mn, Mn, Mn, Mn, Cn, Mn, Mn, Mc, Cn, Mc, Mc, Mn, Cn, Cn, +/* DATA_BLOCK: -- 0x0640..0x064F -- */ + Lo, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x0650..0x065F -- */ + Po, Sc, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Lo, Mn, Mn, Mn, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x0660..0x066F -- */ + Cn, Mn, Mc, Mc, Cn, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Lo, +/* DATA_BLOCK: -- 0x0670..0x067F -- */ + Lo, Cn, Lo, Lo, Cn, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Mn, Lo, Mc, Mn, +/* DATA_BLOCK: -- 0x0680..0x068F -- */ + Mc, Mn, Mn, Mn, Mn, Cn, Cn, Mc, Mc, Cn, Cn, Mc, Mc, Mn, Cn, Cn, +/* DATA_BLOCK: -- 0x0690..0x069F -- */ + Cn, Cn, Cn, Cn, Cn, Mn, Mn, Mc, Cn, Cn, Cn, Cn, Lo, Lo, Cn, Lo, +/* DATA_BLOCK: -- 0x06A0..0x06AF -- */ + So, Lo, No, No, No, No, No, No, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x06B0..0x06BF -- */ + Cn, Cn, Mn, Lo, Cn, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Cn, Lo, Lo, +/* DATA_BLOCK: -- 0x06C0..0x06CF -- */ + Lo, Cn, Lo, Lo, Lo, Lo, Cn, Cn, Cn, Lo, Lo, Cn, Lo, Cn, Lo, Lo, +/* DATA_BLOCK: -- 0x06D0..0x06DF -- */ + Cn, Cn, Cn, Lo, Lo, Cn, Cn, Cn, Lo, Lo, Lo, Cn, Cn, Cn, Lo, Lo, +/* DATA_BLOCK: -- 0x06E0..0x06EF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Cn, Cn, Mc, Mc, +/* DATA_BLOCK: -- 0x06F0..0x06FF -- */ + Mn, Mc, Mc, Cn, Cn, Cn, Mc, Mc, Mc, Cn, Mc, Mc, Mc, Mn, Cn, Cn, +/* DATA_BLOCK: -- 0x0700..0x070F -- */ + Lo, Cn, Cn, Cn, Cn, Cn, Cn, Mc, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x0710..0x071F -- */ + No, No, No, So, So, So, So, So, So, Sc, So, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x0720..0x072F -- */ + Mn, Mc, Mc, Mc, Mn, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Lo, Lo, +/* DATA_BLOCK: -- 0x0730..0x073F -- */ + Lo, Cn, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x0740..0x074F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Mn, Lo, Mn, Mn, +/* DATA_BLOCK: -- 0x0750..0x075F -- */ + Mn, Mc, Mc, Mc, Mc, Cn, Mn, Mn, Mn, Cn, Mn, Mn, Mn, Mn, Cn, Cn, +/* DATA_BLOCK: -- 0x0760..0x076F -- */ + Cn, Cn, Cn, Cn, Cn, Mn, Mn, Cn, Lo, Lo, Lo, Cn, Cn, Lo, Cn, Cn, +/* DATA_BLOCK: -- 0x0770..0x077F -- */ + Cn, Cn, Cn, Cn, Cn, Cn, Cn, Po, No, No, No, No, No, No, No, So, +/* DATA_BLOCK: -- 0x0780..0x078F -- */ + Lo, Mn, Mc, Mc, Po, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Lo, Lo, +/* DATA_BLOCK: -- 0x0790..0x079F -- */ + Lo, Lo, Lo, Lo, Cn, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Mn, Lo, Mc, Mn, +/* DATA_BLOCK: -- 0x07A0..0x07AF -- */ + Mc, Mc, Mc, Mc, Mc, Cn, Mn, Mc, Mc, Cn, Mc, Mc, Mn, Mn, Cn, Cn, +/* DATA_BLOCK: -- 0x07B0..0x07BF -- */ + Cn, Cn, Cn, Cn, Cn, Mc, Mc, Cn, Cn, Cn, Cn, Cn, Cn, Lo, Lo, Cn, +/* DATA_BLOCK: -- 0x07C0..0x07CF -- */ + Cn, Lo, Lo, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x07D0..0x07DF -- */ + Mn, Mn, Mc, Mc, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Lo, Lo, +/* DATA_BLOCK: -- 0x07E0..0x07EF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Mn, Mn, Lo, Mc, Mc, +/* DATA_BLOCK: -- 0x07F0..0x07FF -- */ + Mc, Mn, Mn, Mn, Mn, Cn, Mc, Mc, Mc, Cn, Mc, Mc, Mc, Mn, Lo, So, +/* DATA_BLOCK: -- 0x0800..0x080F -- */ + Cn, Cn, Cn, Cn, Lo, Lo, Lo, Mc, No, No, No, No, No, No, No, Lo, +/* DATA_BLOCK: -- 0x0810..0x081F -- */ + No, No, No, No, No, No, No, No, No, So, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x0820..0x082F -- */ + Cn, Mn, Mc, Mc, Cn, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x0830..0x083F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Cn, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x0840..0x084F -- */ + Lo, Lo, Cn, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Lo, Cn, Cn, +/* DATA_BLOCK: -- 0x0850..0x085F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Cn, Mn, Cn, Cn, Cn, Cn, Mc, +/* DATA_BLOCK: -- 0x0860..0x086F -- */ + Mc, Mc, Mn, Mn, Mn, Cn, Mn, Cn, Mc, Mc, Mc, Mc, Mc, Mc, Mc, Mc, +/* DATA_BLOCK: -- 0x0870..0x087F -- */ + Cn, Cn, Mc, Mc, Po, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x0880..0x088F -- */ + Cn, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x0890..0x089F -- */ + Lo, Mn, Lo, Lo, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Cn, Cn, Cn, Cn, Sc, +/* DATA_BLOCK: -- 0x08A0..0x08AF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lm, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Po, +/* DATA_BLOCK: -- 0x08B0..0x08BF -- */ + Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Po, Po, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x08C0..0x08CF -- */ + Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x08D0..0x08DF -- */ + Cn, Lo, Lo, Cn, Lo, Cn, Lo, Lo, Lo, Lo, Lo, Cn, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x08E0..0x08EF -- */ + Lo, Lo, Lo, Lo, Cn, Lo, Cn, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x08F0..0x08FF -- */ + Lo, Mn, Lo, Lo, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Lo, Cn, Cn, +/* DATA_BLOCK: -- 0x0900..0x090F -- */ + Lo, Lo, Lo, Lo, Lo, Cn, Lm, Cn, Mn, Mn, Mn, Mn, Mn, Mn, Cn, Cn, +/* DATA_BLOCK: -- 0x0910..0x091F -- */ + Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Cn, Cn, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x0920..0x092F -- */ + Lo, So, So, So, Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, +/* DATA_BLOCK: -- 0x0930..0x093F -- */ + Po, Po, Po, So, Po, So, So, So, Mn, Mn, So, So, So, So, So, So, +/* DATA_BLOCK: -- 0x0940..0x094F -- */ + Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, No, No, No, No, No, No, +/* DATA_BLOCK: -- 0x0950..0x095F -- */ + No, No, No, No, So, Mn, So, Mn, So, Mn, Ps, Pe, Ps, Pe, Mc, Mc, +/* DATA_BLOCK: -- 0x0960..0x096F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x0970..0x097F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x0980..0x098F -- */ + Cn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mc, +/* DATA_BLOCK: -- 0x0990..0x099F -- */ + Mn, Mn, Mn, Mn, Mn, Po, Mn, Mn, Lo, Lo, Lo, Lo, Lo, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x09A0..0x09AF -- */ + Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Cn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x09B0..0x09BF -- */ + Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Cn, So, So, +/* DATA_BLOCK: -- 0x09C0..0x09CF -- */ + So, So, So, So, So, So, Mn, So, So, So, So, So, So, Cn, So, So, +/* DATA_BLOCK: -- 0x09D0..0x09DF -- */ + Po, Po, Po, Po, Po, So, So, So, So, Po, Po, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x09E0..0x09EF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Mc, Mc, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x09F0..0x09FF -- */ + Mn, Mc, Mn, Mn, Mn, Mn, Mn, Mn, Mc, Mn, Mn, Mc, Mc, Mn, Mn, Lo, +/* DATA_BLOCK: -- 0x0A00..0x0A0F -- */ + Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Po, Po, Po, Po, Po, Po, +/* DATA_BLOCK: -- 0x0A10..0x0A1F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Mc, Mc, Mn, Mn, Lo, Lo, Lo, Lo, Mn, Mn, +/* DATA_BLOCK: -- 0x0A20..0x0A2F -- */ + Mn, Lo, Mc, Mc, Mc, Lo, Lo, Mc, Mc, Mc, Mc, Mc, Mc, Mc, Lo, Lo, +/* DATA_BLOCK: -- 0x0A30..0x0A3F -- */ + Lo, Mn, Mn, Mn, Mn, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x0A40..0x0A4F -- */ + Lo, Lo, Mn, Mc, Mc, Mn, Mn, Mc, Mc, Mc, Mc, Mc, Mc, Mn, Lo, Mc, +/* DATA_BLOCK: -- 0x0A50..0x0A5F -- */ + Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Mc, Mc, Mc, Mn, So, So, +/* DATA_BLOCK: -- 0x0A60..0x0A6F -- */ + Lu, Lu, Lu, Lu, Lu, Lu, Cn, Lu, Cn, Cn, Cn, Cn, Cn, Lu, Cn, Cn, +/* DATA_BLOCK: -- 0x0A70..0x0A7F -- */ + Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Po, Lm, Ll, Ll, Ll, +/* DATA_BLOCK: -- 0x0A80..0x0A8F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Lo, Lo, Lo, Lo, Cn, Cn, +/* DATA_BLOCK: -- 0x0A90..0x0A9F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Lo, Cn, Lo, Lo, Lo, Lo, Cn, Cn, +/* DATA_BLOCK: -- 0x0AA0..0x0AAF -- */ + Lo, Cn, Lo, Lo, Lo, Lo, Cn, Cn, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, +/* DATA_BLOCK: -- 0x0AB0..0x0ABF -- */ + Lo, Cn, Lo, Lo, Lo, Lo, Cn, Cn, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x0AC0..0x0ACF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x0AD0..0x0ADF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x0AE0..0x0AEF -- */ + Po, Po, Po, Po, Po, Po, Po, Po, Po, No, No, No, No, No, No, No, +/* DATA_BLOCK: -- 0x0AF0..0x0AFF -- */ + No, No, No, No, No, No, No, No, No, No, No, No, No, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x0B00..0x0B0F -- */ + So, So, So, So, So, So, So, So, So, So, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x0B10..0x0B1F -- */ + Lu, Lu, Lu, Lu, Lu, Lu, Cn, Cn, Ll, Ll, Ll, Ll, Ll, Ll, Cn, Cn, +/* DATA_BLOCK: -- 0x0B20..0x0B2F -- */ + Pd, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x0B30..0x0B3F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, So, Po, Lo, +/* DATA_BLOCK: -- 0x0B40..0x0B4F -- */ + Zs, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x0B50..0x0B5F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Ps, Pe, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x0B60..0x0B6F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Po, Po, Po, Nl, Nl, +/* DATA_BLOCK: -- 0x0B70..0x0B7F -- */ + Nl, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x0B80..0x0B8F -- */ + Lo, Lo, Mn, Mn, Mn, Mc, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Lo, +/* DATA_BLOCK: -- 0x0B90..0x0B9F -- */ + Lo, Lo, Mn, Mn, Mc, Po, Po, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x0BA0..0x0BAF -- */ + Lo, Lo, Mn, Mn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x0BB0..0x0BBF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Lo, Lo, +/* DATA_BLOCK: -- 0x0BC0..0x0BCF -- */ + Lo, Cn, Mn, Mn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x0BD0..0x0BDF -- */ + Lo, Lo, Lo, Lo, Mn, Mn, Mc, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mc, Mc, +/* DATA_BLOCK: -- 0x0BE0..0x0BEF -- */ + Mc, Mc, Mc, Mc, Mc, Mc, Mn, Mc, Mc, Mn, Mn, Mn, Mn, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x0BF0..0x0BFF -- */ + Mn, Mn, Mn, Mn, Po, Po, Po, Lm, Po, Po, Po, Sc, Lo, Mn, Cn, Cn, +/* DATA_BLOCK: -- 0x0C00..0x0C0F -- */ + Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x0C10..0x0C1F -- */ + No, No, No, No, No, No, No, No, No, No, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x0C20..0x0C2F -- */ + Po, Po, Po, Po, Po, Po, Pd, Po, Po, Po, Po, Mn, Mn, Mn, Cf, Mn, +/* DATA_BLOCK: -- 0x0C30..0x0C3F -- */ + Lo, Lo, Lo, Lm, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x0C40..0x0C4F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x0C50..0x0C5F -- */ + Lo, Lo, Lo, Lo, Lo, Mn, Mn, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x0C60..0x0C6F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Mn, Lo, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x0C70..0x0C7F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x0C80..0x0C8F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, +/* DATA_BLOCK: -- 0x0C90..0x0C9F -- */ + Mn, Mn, Mn, Mc, Mc, Mc, Mc, Mn, Mn, Mc, Mc, Mc, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x0CA0..0x0CAF -- */ + Mc, Mc, Mn, Mc, Mc, Mc, Mc, Mc, Mc, Mn, Mn, Mn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x0CB0..0x0CBF -- */ + So, Cn, Cn, Cn, Po, Po, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, +/* DATA_BLOCK: -- 0x0CC0..0x0CCF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, +/* DATA_BLOCK: -- 0x0CD0..0x0CDF -- */ + Lo, Lo, Lo, Lo, Lo, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x0CE0..0x0CEF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x0CF0..0x0CFF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x0D00..0x0D0F -- */ + Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, No, Cn, Cn, Cn, So, So, +/* DATA_BLOCK: -- 0x0D10..0x0D1F -- */ + So, So, So, So, So, So, So, So, So, So, So, So, So, So, So, So, +/* DATA_BLOCK: -- 0x0D20..0x0D2F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Mn, Mn, Mc, Mc, Mn, Cn, Cn, Po, Po, +/* DATA_BLOCK: -- 0x0D30..0x0D3F -- */ + Lo, Lo, Lo, Lo, Lo, Mc, Mn, Mc, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Cn, +/* DATA_BLOCK: -- 0x0D40..0x0D4F -- */ + Mn, Mc, Mn, Mc, Mc, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mc, Mc, Mc, +/* DATA_BLOCK: -- 0x0D50..0x0D5F -- */ + Mc, Mc, Mc, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Cn, Cn, Mn, +/* DATA_BLOCK: -- 0x0D60..0x0D6F -- */ + Po, Po, Po, Po, Po, Po, Po, Lm, Po, Po, Po, Po, Po, Po, Cn, Cn, +/* DATA_BLOCK: -- 0x0D70..0x0D7F -- */ + Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Me, Mn, +/* DATA_BLOCK: -- 0x0D80..0x0D8F -- */ + Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Cn, +/* DATA_BLOCK: -- 0x0D90..0x0D9F -- */ + Mn, Mn, Mn, Mn, Mc, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x0DA0..0x0DAF -- */ + Lo, Lo, Lo, Lo, Mn, Mc, Mn, Mn, Mn, Mn, Mn, Mc, Mn, Mc, Mc, Mc, +/* DATA_BLOCK: -- 0x0DB0..0x0DBF -- */ + Mc, Mc, Mn, Mc, Mc, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x0DC0..0x0DCF -- */ + Po, So, So, So, So, So, So, So, So, So, So, Mn, Mn, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x0DD0..0x0DDF -- */ + Mn, Mn, Mn, Mn, So, So, So, So, So, So, So, So, So, Po, Po, Cn, +/* DATA_BLOCK: -- 0x0DE0..0x0DEF -- */ + Mn, Mn, Mc, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x0DF0..0x0DFF -- */ + Lo, Mc, Mn, Mn, Mn, Mn, Mc, Mc, Mn, Mn, Mc, Mn, Mn, Mn, Lo, Lo, +/* DATA_BLOCK: -- 0x0E00..0x0E0F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Mn, Mc, Mn, Mn, Mc, Mc, Mc, Mn, Mc, Mn, +/* DATA_BLOCK: -- 0x0E10..0x0E1F -- */ + Mn, Mn, Mc, Mc, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Po, Po, Po, Po, +/* DATA_BLOCK: -- 0x0E20..0x0E2F -- */ + Lo, Lo, Lo, Lo, Mc, Mc, Mc, Mc, Mc, Mc, Mc, Mc, Mn, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x0E30..0x0E3F -- */ + Mn, Mn, Mn, Mn, Mc, Mc, Mn, Mn, Cn, Cn, Cn, Po, Po, Po, Po, Po, +/* DATA_BLOCK: -- 0x0E40..0x0E4F -- */ + Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Cn, Cn, Cn, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x0E50..0x0E5F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lm, Lm, Lm, Lm, Lm, Lm, Po, Po, +/* DATA_BLOCK: -- 0x0E60..0x0E6F -- */ + Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x0E70..0x0E7F -- */ + Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Cn, Cn, Lu, Lu, Lu, +/* DATA_BLOCK: -- 0x0E80..0x0E8F -- */ + Po, Po, Po, Po, Po, Po, Po, Po, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x0E90..0x0E9F -- */ + Mn, Mn, Mn, Po, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x0EA0..0x0EAF -- */ + Mn, Mc, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Lo, Lo, Lo, Lo, Mn, Lo, Lo, +/* DATA_BLOCK: -- 0x0EB0..0x0EBF -- */ + Lo, Lo, Lo, Lo, Mn, Lo, Lo, Mc, Mn, Mn, Lo, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x0EC0..0x0ECF -- */ + Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Lm, Lm, Lm, Lm, +/* DATA_BLOCK: -- 0x0ED0..0x0EDF -- */ + Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Ll, Ll, Ll, Ll, Ll, +/* DATA_BLOCK: -- 0x0EE0..0x0EEF -- */ + Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Lm, Ll, Ll, Ll, Ll, Ll, Ll, Ll, +/* DATA_BLOCK: -- 0x0EF0..0x0EFF -- */ + Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Lm, Lm, Lm, Lm, Lm, +/* DATA_BLOCK: -- 0x0F00..0x0F0F -- */ + Lu, Ll, Lu, Ll, Lu, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Lu, Ll, +/* DATA_BLOCK: -- 0x0F10..0x0F1F -- */ + Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, +/* DATA_BLOCK: -- 0x0F20..0x0F2F -- */ + Ll, Ll, Ll, Ll, Ll, Ll, Cn, Cn, Lu, Lu, Lu, Lu, Lu, Lu, Cn, Cn, +/* DATA_BLOCK: -- 0x0F30..0x0F3F -- */ + Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Cn, Lu, Cn, Lu, Cn, Lu, Cn, Lu, +/* DATA_BLOCK: -- 0x0F40..0x0F4F -- */ + Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Cn, Cn, +/* DATA_BLOCK: -- 0x0F50..0x0F5F -- */ + Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Lt, Lt, Lt, Lt, Lt, Lt, Lt, Lt, +/* DATA_BLOCK: -- 0x0F60..0x0F6F -- */ + Ll, Ll, Ll, Ll, Ll, Cn, Ll, Ll, Lu, Lu, Lu, Lu, Lt, Sk, Ll, Sk, +/* DATA_BLOCK: -- 0x0F70..0x0F7F -- */ + Sk, Sk, Ll, Ll, Ll, Cn, Ll, Ll, Lu, Lu, Lu, Lu, Lt, Sk, Sk, Sk, +/* DATA_BLOCK: -- 0x0F80..0x0F8F -- */ + Ll, Ll, Ll, Ll, Cn, Cn, Ll, Ll, Lu, Lu, Lu, Lu, Cn, Sk, Sk, Sk, +/* DATA_BLOCK: -- 0x0F90..0x0F9F -- */ + Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Lu, Lu, Lu, Lu, Lu, Sk, Sk, Sk, +/* DATA_BLOCK: -- 0x0FA0..0x0FAF -- */ + Cn, Cn, Ll, Ll, Ll, Cn, Ll, Ll, Lu, Lu, Lu, Lu, Lt, Sk, Sk, Cn, +/* DATA_BLOCK: -- 0x0FB0..0x0FBF -- */ + Zs, Zs, Zs, Zs, Zs, Zs, Zs, Zs, Zs, Zs, Zs, Cf, Cf, Cf, Cf, Cf, +/* DATA_BLOCK: -- 0x0FC0..0x0FCF -- */ + Pd, Pd, Pd, Pd, Pd, Pd, Po, Po, Pi, Pf, Ps, Pi, Pi, Pf, Ps, Pi, +/* DATA_BLOCK: -- 0x0FD0..0x0FDF -- */ + Po, Po, Po, Po, Po, Po, Po, Po, Zl, Zp, Cf, Cf, Cf, Cf, Cf, Zs, +/* DATA_BLOCK: -- 0x0FE0..0x0FEF -- */ + Po, Po, Po, Po, Po, Po, Po, Po, Po, Pi, Pf, Po, Po, Po, Po, Pc, +/* DATA_BLOCK: -- 0x0FF0..0x0FFF -- */ + Pc, Po, Po, Po, Sm, Ps, Pe, Po, Po, Po, Po, Po, Po, Po, Po, Po, +/* DATA_BLOCK: -- 0x1000..0x100F -- */ + Po, Po, Sm, Po, Pc, Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, Zs, +/* DATA_BLOCK: -- 0x1010..0x101F -- */ + Cf, Cf, Cf, Cf, Cf, Cn, Cf, Cf, Cf, Cf, Cf, Cf, Cf, Cf, Cf, Cf, +/* DATA_BLOCK: -- 0x1020..0x102F -- */ + No, Lm, Cn, Cn, No, No, No, No, No, No, Sm, Sm, Sm, Ps, Pe, Lm, +/* DATA_BLOCK: -- 0x1030..0x103F -- */ + No, No, No, No, No, No, No, No, No, No, Sm, Sm, Sm, Ps, Pe, Cn, +/* DATA_BLOCK: -- 0x1040..0x104F -- */ + Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1050..0x105F -- */ + Sc, Sc, Sc, Sc, Sc, Sc, Sc, Sc, Sc, Sc, Sc, Sc, Sc, Sc, Sc, Sc, +/* DATA_BLOCK: -- 0x1060..0x106F -- */ + Sc, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1070..0x107F -- */ + Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Me, Me, Me, +/* DATA_BLOCK: -- 0x1080..0x108F -- */ + Me, Mn, Me, Me, Me, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x1090..0x109F -- */ + Mn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x10A0..0x10AF -- */ + So, So, Lu, So, So, So, So, Lu, So, So, Ll, Lu, Lu, Lu, Ll, Ll, +/* DATA_BLOCK: -- 0x10B0..0x10BF -- */ + Lu, Lu, Lu, Ll, So, Lu, So, So, Sm, Lu, Lu, Lu, Lu, Lu, So, So, +/* DATA_BLOCK: -- 0x10C0..0x10CF -- */ + So, So, So, So, Lu, So, Lu, So, Lu, So, Lu, Lu, Lu, Lu, So, Ll, +/* DATA_BLOCK: -- 0x10D0..0x10DF -- */ + Lu, Lu, Lu, Lu, Ll, Lo, Lo, Lo, Lo, Ll, So, So, Ll, Ll, Lu, Lu, +/* DATA_BLOCK: -- 0x10E0..0x10EF -- */ + Sm, Sm, Sm, Sm, Sm, Lu, Ll, Ll, Ll, Ll, So, Sm, So, So, Ll, So, +/* DATA_BLOCK: -- 0x10F0..0x10FF -- */ + No, No, No, No, No, No, No, No, No, No, No, No, No, No, No, No, +/* DATA_BLOCK: -- 0x1100..0x110F -- */ + Nl, Nl, Nl, Nl, Nl, Nl, Nl, Nl, Nl, Nl, Nl, Nl, Nl, Nl, Nl, Nl, +/* DATA_BLOCK: -- 0x1110..0x111F -- */ + Nl, Nl, Nl, Lu, Ll, Nl, Nl, Nl, Nl, No, So, So, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1120..0x112F -- */ + Sm, Sm, Sm, Sm, Sm, So, So, So, So, So, Sm, Sm, So, So, So, So, +/* DATA_BLOCK: -- 0x1130..0x113F -- */ + Sm, So, So, Sm, So, So, Sm, So, So, So, So, So, So, So, Sm, So, +/* DATA_BLOCK: -- 0x1140..0x114F -- */ + So, So, So, So, So, So, So, So, So, So, So, So, So, So, Sm, Sm, +/* DATA_BLOCK: -- 0x1150..0x115F -- */ + So, So, Sm, So, Sm, So, So, So, So, So, So, So, So, So, So, So, +/* DATA_BLOCK: -- 0x1160..0x116F -- */ + So, So, So, So, Sm, Sm, Sm, Sm, Sm, Sm, Sm, Sm, Sm, Sm, Sm, Sm, +/* DATA_BLOCK: -- 0x1170..0x117F -- */ + Sm, Sm, Sm, Sm, Sm, Sm, Sm, Sm, Sm, Sm, Sm, Sm, Sm, Sm, Sm, Sm, +/* DATA_BLOCK: -- 0x1180..0x118F -- */ + So, So, So, So, So, So, So, So, Ps, Pe, Ps, Pe, So, So, So, So, +/* DATA_BLOCK: -- 0x1190..0x119F -- */ + Sm, Sm, So, So, So, So, So, So, So, Ps, Pe, So, So, So, So, So, +/* DATA_BLOCK: -- 0x11A0..0x11AF -- */ + So, So, So, So, So, So, So, So, So, So, So, So, Sm, So, So, So, +/* DATA_BLOCK: -- 0x11B0..0x11BF -- */ + So, So, So, So, So, So, So, So, So, So, So, Sm, Sm, Sm, Sm, Sm, +/* DATA_BLOCK: -- 0x11C0..0x11CF -- */ + Sm, Sm, Sm, Sm, So, So, So, So, So, So, So, So, So, So, So, So, +/* DATA_BLOCK: -- 0x11D0..0x11DF -- */ + So, So, So, So, So, So, So, So, So, So, So, So, Sm, Sm, Sm, Sm, +/* DATA_BLOCK: -- 0x11E0..0x11EF -- */ + Sm, Sm, So, So, So, So, So, So, So, So, So, So, So, So, So, So, +/* DATA_BLOCK: -- 0x11F0..0x11FF -- */ + So, So, So, So, So, So, So, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1200..0x120F -- */ + So, So, So, So, So, So, So, So, So, So, So, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1210..0x121F -- */ + No, No, No, No, No, No, No, No, No, No, No, No, So, So, So, So, +/* DATA_BLOCK: -- 0x1220..0x122F -- */ + So, So, So, So, So, So, So, So, So, So, No, No, No, No, No, No, +/* DATA_BLOCK: -- 0x1230..0x123F -- */ + So, So, So, So, So, So, So, Sm, So, So, So, So, So, So, So, So, +/* DATA_BLOCK: -- 0x1240..0x124F -- */ + So, Sm, So, So, So, So, So, So, So, So, So, So, So, So, So, So, +/* DATA_BLOCK: -- 0x1250..0x125F -- */ + So, So, So, So, So, So, So, So, Sm, Sm, Sm, Sm, Sm, Sm, Sm, Sm, +/* DATA_BLOCK: -- 0x1260..0x126F -- */ + So, So, So, So, So, So, So, So, So, So, So, So, So, So, So, Sm, +/* DATA_BLOCK: -- 0x1270..0x127F -- */ + So, So, So, So, So, So, So, So, Ps, Pe, Ps, Pe, Ps, Pe, Ps, Pe, +/* DATA_BLOCK: -- 0x1280..0x128F -- */ + Ps, Pe, Ps, Pe, Ps, Pe, No, No, No, No, No, No, No, No, No, No, +/* DATA_BLOCK: -- 0x1290..0x129F -- */ + No, No, No, No, So, So, So, So, So, So, So, So, So, So, So, So, +/* DATA_BLOCK: -- 0x12A0..0x12AF -- */ + Sm, Sm, Sm, Sm, Sm, Ps, Pe, Sm, Sm, Sm, Sm, Sm, Sm, Sm, Sm, Sm, +/* DATA_BLOCK: -- 0x12B0..0x12BF -- */ + Sm, Sm, Sm, Sm, Sm, Sm, Ps, Pe, Ps, Pe, Ps, Pe, Ps, Pe, Ps, Pe, +/* DATA_BLOCK: -- 0x12C0..0x12CF -- */ + Sm, Sm, Sm, Ps, Pe, Ps, Pe, Ps, Pe, Ps, Pe, Ps, Pe, Ps, Pe, Ps, +/* DATA_BLOCK: -- 0x12D0..0x12DF -- */ + Pe, Ps, Pe, Ps, Pe, Ps, Pe, Ps, Pe, Sm, Sm, Sm, Sm, Sm, Sm, Sm, +/* DATA_BLOCK: -- 0x12E0..0x12EF -- */ + Sm, Sm, Sm, Sm, Sm, Sm, Sm, Sm, Ps, Pe, Ps, Pe, Sm, Sm, Sm, Sm, +/* DATA_BLOCK: -- 0x12F0..0x12FF -- */ + Sm, Sm, Sm, Sm, Sm, Sm, Sm, Sm, Sm, Sm, Sm, Sm, Ps, Pe, Sm, Sm, +/* DATA_BLOCK: -- 0x1300..0x130F -- */ + Sm, Sm, Sm, Sm, Sm, So, So, Sm, Sm, Sm, Sm, Sm, Sm, So, So, So, +/* DATA_BLOCK: -- 0x1310..0x131F -- */ + So, So, So, So, Cn, Cn, So, So, So, So, So, So, So, So, So, So, +/* DATA_BLOCK: -- 0x1320..0x132F -- */ + So, So, So, So, So, So, Cn, So, So, So, So, So, So, So, So, So, +/* DATA_BLOCK: -- 0x1330..0x133F -- */ + Lu, Ll, Lu, Lu, Lu, Ll, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Lu, Lu, +/* DATA_BLOCK: -- 0x1340..0x134F -- */ + Lu, Ll, Lu, Ll, Ll, Lu, Ll, Ll, Ll, Ll, Ll, Ll, Lm, Lm, Lu, Lu, +/* DATA_BLOCK: -- 0x1350..0x135F -- */ + Lu, Ll, Lu, Ll, Ll, So, So, So, So, So, So, Lu, Ll, Lu, Ll, Mn, +/* DATA_BLOCK: -- 0x1360..0x136F -- */ + Mn, Mn, Lu, Ll, Cn, Cn, Cn, Cn, Cn, Po, Po, Po, Po, No, Po, Po, +/* DATA_BLOCK: -- 0x1370..0x137F -- */ + Ll, Ll, Ll, Ll, Ll, Ll, Cn, Ll, Cn, Cn, Cn, Cn, Cn, Ll, Cn, Cn, +/* DATA_BLOCK: -- 0x1380..0x138F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Lm, +/* DATA_BLOCK: -- 0x1390..0x139F -- */ + Po, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Mn, +/* DATA_BLOCK: -- 0x13A0..0x13AF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x13B0..0x13BF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, +/* DATA_BLOCK: -- 0x13C0..0x13CF -- */ + Po, Po, Pi, Pf, Pi, Pf, Po, Po, Po, Pi, Pf, Po, Pi, Pf, Po, Po, +/* DATA_BLOCK: -- 0x13D0..0x13DF -- */ + Po, Po, Po, Po, Po, Po, Po, Pd, Po, Po, Pd, Po, Pi, Pf, Po, Po, +/* DATA_BLOCK: -- 0x13E0..0x13EF -- */ + Pi, Pf, Ps, Pe, Ps, Pe, Ps, Pe, Ps, Pe, Po, Po, Po, Po, Po, Lm, +/* DATA_BLOCK: -- 0x13F0..0x13FF -- */ + Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, Pd, Pd, Po, Po, Po, Po, +/* DATA_BLOCK: -- 0x1400..0x140F -- */ + Pd, Po, Ps, Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, +/* DATA_BLOCK: -- 0x1410..0x141F -- */ + So, So, Po, Po, Po, Ps, Pe, Ps, Pe, Ps, Pe, Ps, Pe, Pd, Cn, Cn, +/* DATA_BLOCK: -- 0x1420..0x142F -- */ + So, So, So, So, So, So, So, So, So, So, Cn, So, So, So, So, So, +/* DATA_BLOCK: -- 0x1430..0x143F -- */ + So, So, So, So, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1440..0x144F -- */ + So, So, So, So, So, So, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1450..0x145F -- */ + So, So, So, So, So, So, So, So, So, So, So, So, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1460..0x146F -- */ + Zs, Po, Po, Po, So, Lm, Lo, Nl, Ps, Pe, Ps, Pe, Ps, Pe, Ps, Pe, +/* DATA_BLOCK: -- 0x1470..0x147F -- */ + Ps, Pe, So, So, Ps, Pe, Ps, Pe, Ps, Pe, Ps, Pe, Pd, Ps, Pe, Pe, +/* DATA_BLOCK: -- 0x1480..0x148F -- */ + So, Nl, Nl, Nl, Nl, Nl, Nl, Nl, Nl, Nl, Mn, Mn, Mn, Mn, Mc, Mc, +/* DATA_BLOCK: -- 0x1490..0x149F -- */ + Pd, Lm, Lm, Lm, Lm, Lm, So, So, Nl, Nl, Nl, Lm, Lo, Po, So, So, +/* DATA_BLOCK: -- 0x14A0..0x14AF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Mn, Mn, Sk, Sk, Lm, Lm, Lo, +/* DATA_BLOCK: -- 0x14B0..0x14BF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Po, Lm, Lm, Lm, Lo, +/* DATA_BLOCK: -- 0x14C0..0x14CF -- */ + Cn, Cn, Cn, Cn, Cn, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x14D0..0x14DF -- */ + So, So, No, No, No, No, So, So, So, So, So, So, So, So, So, So, +/* DATA_BLOCK: -- 0x14E0..0x14EF -- */ + So, So, So, So, So, So, So, So, So, So, So, So, So, So, So, Cn, +/* DATA_BLOCK: -- 0x14F0..0x14FF -- */ + No, No, No, No, No, No, No, No, No, No, So, So, So, So, So, So, +/* DATA_BLOCK: -- 0x1500..0x150F -- */ + So, So, So, So, So, So, So, So, No, No, No, No, No, No, No, No, +/* DATA_BLOCK: -- 0x1510..0x151F -- */ + So, No, No, No, No, No, No, No, No, No, No, No, No, No, No, No, +/* DATA_BLOCK: -- 0x1520..0x152F -- */ + Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Lo, +/* DATA_BLOCK: -- 0x1530..0x153F -- */ + Lo, Lo, Lo, Lo, Lo, Lm, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x1540..0x154F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lm, Po, Po, Po, +/* DATA_BLOCK: -- 0x1550..0x155F -- */ + Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Lo, Lo, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1560..0x156F -- */ + Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lo, Mn, +/* DATA_BLOCK: -- 0x1570..0x157F -- */ + Me, Me, Me, Po, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Po, Lm, +/* DATA_BLOCK: -- 0x1580..0x158F -- */ + Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lm, Lm, Mn, Mn, +/* DATA_BLOCK: -- 0x1590..0x159F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Nl, Nl, Nl, Nl, Nl, Nl, Nl, Nl, Nl, Nl, +/* DATA_BLOCK: -- 0x15A0..0x15AF -- */ + Mn, Mn, Po, Po, Po, Po, Po, Po, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x15B0..0x15BF -- */ + Sk, Sk, Sk, Sk, Sk, Sk, Sk, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, +/* DATA_BLOCK: -- 0x15C0..0x15CF -- */ + Sk, Sk, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, +/* DATA_BLOCK: -- 0x15D0..0x15DF -- */ + Ll, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, +/* DATA_BLOCK: -- 0x15E0..0x15EF -- */ + Lm, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Lu, Ll, Lu, Ll, Lu, Lu, Ll, +/* DATA_BLOCK: -- 0x15F0..0x15FF -- */ + Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lm, Sk, Sk, Lu, Ll, Lu, Ll, Lo, +/* DATA_BLOCK: -- 0x1600..0x160F -- */ + Lu, Ll, Lu, Ll, Ll, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, +/* DATA_BLOCK: -- 0x1610..0x161F -- */ + Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Lu, Lu, Lu, Lu, Ll, +/* DATA_BLOCK: -- 0x1620..0x162F -- */ + Lu, Lu, Lu, Lu, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, +/* DATA_BLOCK: -- 0x1630..0x163F -- */ + Lu, Ll, Lu, Ll, Lu, Lu, Lu, Lu, Ll, Lu, Ll, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1640..0x164F -- */ + Lu, Ll, Cn, Ll, Cn, Ll, Lu, Ll, Lu, Ll, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1650..0x165F -- */ + Cn, Cn, Lm, Lm, Lm, Lu, Ll, Lo, Lm, Lm, Ll, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x1660..0x166F -- */ + Lo, Lo, Mn, Lo, Lo, Lo, Mn, Lo, Lo, Lo, Lo, Mn, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x1670..0x167F -- */ + Lo, Lo, Lo, Mc, Mc, Mn, Mn, Mc, So, So, So, So, Mn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1680..0x168F -- */ + No, No, No, No, No, No, So, So, Sc, So, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1690..0x169F -- */ + Lo, Lo, Lo, Lo, Po, Po, Po, Po, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x16A0..0x16AF -- */ + Mc, Mc, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x16B0..0x16BF -- */ + Lo, Lo, Lo, Lo, Mc, Mc, Mc, Mc, Mc, Mc, Mc, Mc, Mc, Mc, Mc, Mc, +/* DATA_BLOCK: -- 0x16C0..0x16CF -- */ + Mc, Mc, Mc, Mc, Mn, Mn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Po, Po, +/* DATA_BLOCK: -- 0x16D0..0x16DF -- */ + Mn, Mn, Lo, Lo, Lo, Lo, Lo, Lo, Po, Po, Po, Lo, Po, Lo, Lo, Mn, +/* DATA_BLOCK: -- 0x16E0..0x16EF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Po, Po, +/* DATA_BLOCK: -- 0x16F0..0x16FF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x1700..0x170F -- */ + Mn, Mn, Mc, Mc, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Po, +/* DATA_BLOCK: -- 0x1710..0x171F -- */ + Lo, Lo, Lo, Mn, Mc, Mc, Mn, Mn, Mn, Mn, Mc, Mc, Mn, Mn, Mc, Mc, +/* DATA_BLOCK: -- 0x1720..0x172F -- */ + Mc, Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, Cn, Lm, +/* DATA_BLOCK: -- 0x1730..0x173F -- */ + Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Cn, Cn, Cn, Cn, Po, Po, +/* DATA_BLOCK: -- 0x1740..0x174F -- */ + Lo, Lo, Lo, Lo, Lo, Mn, Lm, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x1750..0x175F -- */ + Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Lo, Lo, Lo, Lo, Lo, Cn, +/* DATA_BLOCK: -- 0x1760..0x176F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Mn, Mn, Mn, Mn, Mn, Mn, Mc, +/* DATA_BLOCK: -- 0x1770..0x177F -- */ + Mc, Mn, Mn, Mc, Mc, Mn, Mn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1780..0x178F -- */ + Lo, Lo, Lo, Mn, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Mn, Mc, Cn, Cn, +/* DATA_BLOCK: -- 0x1790..0x179F -- */ + Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Cn, Cn, Po, Po, Po, Po, +/* DATA_BLOCK: -- 0x17A0..0x17AF -- */ + Lm, Lo, Lo, Lo, Lo, Lo, Lo, So, So, So, Lo, Mc, Mn, Mc, Lo, Lo, +/* DATA_BLOCK: -- 0x17B0..0x17BF -- */ + Mn, Lo, Mn, Mn, Mn, Lo, Lo, Mn, Mn, Lo, Lo, Lo, Lo, Lo, Mn, Mn, +/* DATA_BLOCK: -- 0x17C0..0x17CF -- */ + Lo, Mn, Lo, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x17D0..0x17DF -- */ + Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Lo, Lo, Lm, Po, Po, +/* DATA_BLOCK: -- 0x17E0..0x17EF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Mc, Mn, Mn, Mc, Mc, +/* DATA_BLOCK: -- 0x17F0..0x17FF -- */ + Po, Po, Lo, Lm, Lm, Mc, Mn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1800..0x180F -- */ + Cn, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Lo, Lo, Lo, Lo, Lo, Lo, Cn, +/* DATA_BLOCK: -- 0x1810..0x181F -- */ + Cn, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1820..0x182F -- */ + Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Sk, Lm, Lm, Lm, Lm, +/* DATA_BLOCK: -- 0x1830..0x183F -- */ + Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Lm, Sk, Sk, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1840..0x184F -- */ + Lo, Lo, Lo, Mc, Mc, Mn, Mc, Mc, Mn, Mc, Mc, Po, Mc, Mn, Cn, Cn, +/* DATA_BLOCK: -- 0x1850..0x185F -- */ + Cn, Cn, Cn, Lo, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1860..0x186F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Cn, Cn, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x1870..0x187F -- */ + Cs, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1880..0x188F -- */ + Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cs, +/* DATA_BLOCK: -- 0x1890..0x189F -- */ + Co, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x18A0..0x18AF -- */ + Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Co, +/* DATA_BLOCK: -- 0x18B0..0x18BF -- */ + Ll, Ll, Ll, Ll, Ll, Ll, Ll, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x18C0..0x18CF -- */ + Cn, Cn, Cn, Ll, Ll, Ll, Ll, Ll, Cn, Cn, Cn, Cn, Cn, Lo, Mn, Lo, +/* DATA_BLOCK: -- 0x18D0..0x18DF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Sm, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x18E0..0x18EF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Lo, Lo, Lo, Lo, Lo, Cn, Lo, Cn, +/* DATA_BLOCK: -- 0x18F0..0x18FF -- */ + Lo, Lo, Cn, Lo, Lo, Cn, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x1900..0x190F -- */ + Lo, Lo, Sk, Sk, Sk, Sk, Sk, Sk, Sk, Sk, Sk, Sk, Sk, Sk, Sk, Sk, +/* DATA_BLOCK: -- 0x1910..0x191F -- */ + Sk, Sk, Sk, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1920..0x192F -- */ + Cn, Cn, Cn, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x1930..0x193F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Pe, Ps, +/* DATA_BLOCK: -- 0x1940..0x194F -- */ + Cn, Cn, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x1950..0x195F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Cn, Cn, Cn, Cn, Cn, So, +/* DATA_BLOCK: -- 0x1960..0x196F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Sc, So, So, So, +/* DATA_BLOCK: -- 0x1970..0x197F -- */ + Po, Po, Po, Po, Po, Po, Po, Ps, Pe, Po, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1980..0x198F -- */ + Po, Pd, Pd, Pc, Pc, Ps, Pe, Ps, Pe, Ps, Pe, Ps, Pe, Ps, Pe, Ps, +/* DATA_BLOCK: -- 0x1990..0x199F -- */ + Pe, Ps, Pe, Ps, Pe, Po, Po, Ps, Pe, Po, Po, Po, Po, Pc, Pc, Pc, +/* DATA_BLOCK: -- 0x19A0..0x19AF -- */ + Po, Po, Po, Cn, Po, Po, Po, Po, Pd, Ps, Pe, Ps, Pe, Ps, Pe, Po, +/* DATA_BLOCK: -- 0x19B0..0x19BF -- */ + Po, Po, Sm, Pd, Sm, Sm, Sm, Cn, Po, Sc, Po, Po, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x19C0..0x19CF -- */ + Lo, Lo, Lo, Lo, Lo, Cn, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x19D0..0x19DF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Cf, +/* DATA_BLOCK: -- 0x19E0..0x19EF -- */ + Cn, Po, Po, Po, Sc, Po, Po, Po, Ps, Pe, Po, Sm, Po, Pd, Po, Po, +/* DATA_BLOCK: -- 0x19F0..0x19FF -- */ + Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ps, Sm, Pe, Sm, Ps, +/* DATA_BLOCK: -- 0x1A00..0x1A0F -- */ + Pe, Po, Ps, Pe, Po, Po, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x1A10..0x1A1F -- */ + Lm, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x1A20..0x1A2F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lm, Lm, +/* DATA_BLOCK: -- 0x1A30..0x1A3F -- */ + Cn, Cn, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x1A40..0x1A4F -- */ + Cn, Cn, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Lo, Lo, Lo, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1A50..0x1A5F -- */ + Sc, Sc, Sm, Sk, So, Sc, Sc, Cn, So, Sm, Sm, Sm, Sm, So, So, Cn, +/* DATA_BLOCK: -- 0x1A60..0x1A6F -- */ + Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cf, Cf, Cf, So, So, Cn, Cn, +/* DATA_BLOCK: -- 0x1A70..0x1A7F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x1A80..0x1A8F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Lo, Lo, Cn, Lo, +/* DATA_BLOCK: -- 0x1A90..0x1A9F -- */ + Po, Po, Po, Cn, Cn, Cn, Cn, No, No, No, No, No, No, No, No, No, +/* DATA_BLOCK: -- 0x1AA0..0x1AAF -- */ + No, No, No, No, Cn, Cn, Cn, So, So, So, So, So, So, So, So, So, +/* DATA_BLOCK: -- 0x1AB0..0x1ABF -- */ + Nl, Nl, Nl, Nl, Nl, No, No, No, No, So, So, So, So, So, So, So, +/* DATA_BLOCK: -- 0x1AC0..0x1ACF -- */ + So, So, So, So, So, So, So, So, So, So, No, No, So, So, So, Cn, +/* DATA_BLOCK: -- 0x1AD0..0x1ADF -- */ + So, So, So, So, So, So, So, So, So, So, So, So, So, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1AE0..0x1AEF -- */ + So, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1AF0..0x1AFF -- */ + So, So, So, So, So, So, So, So, So, So, So, So, So, Mn, Cn, Cn, +/* DATA_BLOCK: -- 0x1B00..0x1B0F -- */ + Mn, No, No, No, No, No, No, No, No, No, No, No, No, No, No, No, +/* DATA_BLOCK: -- 0x1B10..0x1B1F -- */ + No, No, No, No, No, No, No, No, No, No, No, No, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1B20..0x1B2F -- */ + No, No, No, No, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x1B30..0x1B3F -- */ + Lo, Nl, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Nl, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1B40..0x1B4F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Mn, Mn, Mn, Mn, Mn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1B50..0x1B5F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Po, +/* DATA_BLOCK: -- 0x1B60..0x1B6F -- */ + Lo, Lo, Lo, Lo, Cn, Cn, Cn, Cn, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x1B70..0x1B7F -- */ + Po, Nl, Nl, Nl, Nl, Nl, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1B80..0x1B8F -- */ + Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, +/* DATA_BLOCK: -- 0x1B90..0x1B9F -- */ + Lu, Lu, Lu, Lu, Cn, Cn, Cn, Cn, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, +/* DATA_BLOCK: -- 0x1BA0..0x1BAF -- */ + Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1BB0..0x1BBF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1BC0..0x1BCF -- */ + Lo, Lo, Lo, Lo, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Po, +/* DATA_BLOCK: -- 0x1BD0..0x1BDF -- */ + Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Cn, Lu, Lu, Lu, Lu, +/* DATA_BLOCK: -- 0x1BE0..0x1BEF -- */ + Lu, Lu, Lu, Cn, Lu, Lu, Cn, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, +/* DATA_BLOCK: -- 0x1BF0..0x1BFF -- */ + Ll, Ll, Cn, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, +/* DATA_BLOCK: -- 0x1C00..0x1C0F -- */ + Ll, Ll, Cn, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Cn, Ll, Ll, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1C10..0x1C1F -- */ + Lm, Lm, Lm, Lm, Lm, Lm, Cn, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, +/* DATA_BLOCK: -- 0x1C20..0x1C2F -- */ + Lm, Cn, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1C30..0x1C3F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Lo, Cn, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x1C40..0x1C4F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Cn, Lo, Lo, Cn, Cn, Cn, Lo, Cn, Cn, Lo, +/* DATA_BLOCK: -- 0x1C50..0x1C5F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Cn, Po, No, No, No, No, No, No, No, No, +/* DATA_BLOCK: -- 0x1C60..0x1C6F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, So, So, No, No, No, No, No, No, No, +/* DATA_BLOCK: -- 0x1C70..0x1C7F -- */ + Cn, Cn, Cn, Cn, Cn, Cn, Cn, No, No, No, No, No, No, No, No, No, +/* DATA_BLOCK: -- 0x1C80..0x1C8F -- */ + Lo, Lo, Lo, Cn, Lo, Lo, Cn, Cn, Cn, Cn, Cn, No, No, No, No, No, +/* DATA_BLOCK: -- 0x1C90..0x1C9F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, No, No, No, No, No, No, Cn, Cn, Cn, Po, +/* DATA_BLOCK: -- 0x1CA0..0x1CAF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Cn, Cn, Cn, Po, +/* DATA_BLOCK: -- 0x1CB0..0x1CBF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Cn, Cn, No, No, Lo, Lo, +/* DATA_BLOCK: -- 0x1CC0..0x1CCF -- */ + Cn, Cn, No, No, No, No, No, No, No, No, No, No, No, No, No, No, +/* DATA_BLOCK: -- 0x1CD0..0x1CDF -- */ + Lo, Mn, Mn, Mn, Cn, Mn, Mn, Cn, Cn, Cn, Cn, Cn, Mn, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x1CE0..0x1CEF -- */ + Lo, Lo, Lo, Lo, Cn, Lo, Lo, Lo, Cn, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x1CF0..0x1CFF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Mn, Mn, Mn, Cn, Cn, Cn, Cn, Mn, +/* DATA_BLOCK: -- 0x1D00..0x1D0F -- */ + No, No, No, No, No, No, No, No, No, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1D10..0x1D1F -- */ + Po, Po, Po, Po, Po, Po, Po, Po, Po, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1D20..0x1D2F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, No, No, Po, +/* DATA_BLOCK: -- 0x1D30..0x1D3F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, No, No, No, +/* DATA_BLOCK: -- 0x1D40..0x1D4F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, So, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x1D50..0x1D5F -- */ + Lo, Lo, Lo, Lo, Lo, Mn, Mn, Cn, Cn, Cn, Cn, No, No, No, No, No, +/* DATA_BLOCK: -- 0x1D60..0x1D6F -- */ + Po, Po, Po, Po, Po, Po, Po, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1D70..0x1D7F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Cn, Po, Po, Po, Po, Po, Po, Po, +/* DATA_BLOCK: -- 0x1D80..0x1D8F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, No, No, No, No, No, No, No, No, +/* DATA_BLOCK: -- 0x1D90..0x1D9F -- */ + Lo, Lo, Lo, Cn, Cn, Cn, Cn, Cn, No, No, No, No, No, No, No, No, +/* DATA_BLOCK: -- 0x1DA0..0x1DAF -- */ + Lo, Lo, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Po, Po, Po, Po, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1DB0..0x1DBF -- */ + Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, No, No, No, No, No, No, No, +/* DATA_BLOCK: -- 0x1DC0..0x1DCF -- */ + Lu, Lu, Lu, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1DD0..0x1DDF -- */ + Ll, Ll, Ll, Cn, Cn, Cn, Cn, Cn, Cn, Cn, No, No, No, No, No, No, +/* DATA_BLOCK: -- 0x1DE0..0x1DEF -- */ + Lo, Lo, Lo, Lo, Mn, Mn, Mn, Mn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1DF0..0x1DFF -- */ + No, No, No, No, No, No, No, No, No, No, No, No, No, No, No, Cn, +/* DATA_BLOCK: -- 0x1E00..0x1E0F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Mn, Mn, Pd, Cn, Cn, +/* DATA_BLOCK: -- 0x1E10..0x1E1F -- */ + Lo, Lo, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1E20..0x1E2F -- */ + No, No, No, No, No, No, No, Lo, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1E30..0x1E3F -- */ + Mn, No, No, No, No, Po, Po, Po, Po, Po, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1E40..0x1E4F -- */ + Lo, Lo, Mn, Mn, Mn, Mn, Po, Po, Po, Po, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1E50..0x1E5F -- */ + Lo, Lo, Lo, Lo, Lo, No, No, No, No, No, No, No, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1E60..0x1E6F -- */ + Mc, Mn, Mc, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x1E70..0x1E7F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x1E80..0x1E8F -- */ + Mn, Mn, Mn, Mn, Mn, Mn, Mn, Po, Po, Po, Po, Po, Po, Po, Cn, Cn, +/* DATA_BLOCK: -- 0x1E90..0x1E9F -- */ + No, No, No, No, No, No, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, +/* DATA_BLOCK: -- 0x1EA0..0x1EAF -- */ + Mn, Lo, Lo, Mn, Mn, Lo, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Mn, +/* DATA_BLOCK: -- 0x1EB0..0x1EBF -- */ + Mc, Mc, Mc, Mn, Mn, Mn, Mn, Mc, Mc, Mn, Mn, Po, Po, Cf, Po, Po, +/* DATA_BLOCK: -- 0x1EC0..0x1ECF -- */ + Po, Po, Mn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cf, Cn, Cn, +/* DATA_BLOCK: -- 0x1ED0..0x1EDF -- */ + Mn, Mn, Mn, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x1EE0..0x1EEF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Mn, Mn, Mn, Mn, Mn, Mc, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x1EF0..0x1EFF -- */ + Mn, Mn, Mn, Mn, Mn, Cn, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, +/* DATA_BLOCK: -- 0x1F00..0x1F0F -- */ + Po, Po, Po, Po, Lo, Mc, Mc, Lo, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1F10..0x1F1F -- */ + Lo, Lo, Lo, Mn, Po, Po, Lo, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1F20..0x1F2F -- */ + Lo, Lo, Lo, Mc, Mc, Mc, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mc, +/* DATA_BLOCK: -- 0x1F30..0x1F3F -- */ + Mc, Lo, Lo, Lo, Lo, Po, Po, Po, Po, Mn, Mn, Mn, Mn, Po, Mc, Mn, +/* DATA_BLOCK: -- 0x1F40..0x1F4F -- */ + Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Lo, Po, Lo, Po, Po, Po, +/* DATA_BLOCK: -- 0x1F50..0x1F5F -- */ + Cn, No, No, No, No, No, No, No, No, No, No, No, No, No, No, No, +/* DATA_BLOCK: -- 0x1F60..0x1F6F -- */ + No, No, No, No, No, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1F70..0x1F7F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Mc, Mc, Mc, Mn, +/* DATA_BLOCK: -- 0x1F80..0x1F8F -- */ + Mn, Mn, Mc, Mc, Mn, Mc, Mn, Mn, Po, Po, Po, Po, Po, Po, Mn, Cn, +/* DATA_BLOCK: -- 0x1F90..0x1F9F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Lo, Cn, Lo, Lo, Lo, Lo, Cn, Lo, +/* DATA_BLOCK: -- 0x1FA0..0x1FAF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Lo, +/* DATA_BLOCK: -- 0x1FB0..0x1FBF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Po, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1FC0..0x1FCF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Mn, +/* DATA_BLOCK: -- 0x1FD0..0x1FDF -- */ + Mc, Mc, Mc, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1FE0..0x1FEF -- */ + Mn, Mn, Mc, Mc, Cn, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Lo, +/* DATA_BLOCK: -- 0x1FF0..0x1FFF -- */ + Lo, Cn, Lo, Lo, Cn, Lo, Lo, Lo, Lo, Lo, Cn, Mn, Mn, Lo, Mc, Mc, +/* DATA_BLOCK: -- 0x2000..0x200F -- */ + Mn, Mc, Mc, Mc, Mc, Cn, Cn, Mc, Mc, Cn, Cn, Mc, Mc, Mc, Cn, Cn, +/* DATA_BLOCK: -- 0x2010..0x201F -- */ + Lo, Cn, Cn, Cn, Cn, Cn, Cn, Mc, Cn, Cn, Cn, Cn, Cn, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x2020..0x202F -- */ + Lo, Lo, Mc, Mc, Cn, Cn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2030..0x203F -- */ + Mn, Mn, Mn, Mn, Mn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2040..0x204F -- */ + Lo, Lo, Lo, Lo, Lo, Mc, Mc, Mc, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x2050..0x205F -- */ + Mc, Mc, Mn, Mn, Mn, Mc, Mn, Lo, Lo, Lo, Lo, Po, Po, Po, Po, Po, +/* DATA_BLOCK: -- 0x2060..0x206F -- */ + Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Po, Po, Cn, Po, Mn, Lo, +/* DATA_BLOCK: -- 0x2070..0x207F -- */ + Mc, Mc, Mc, Mn, Mn, Mn, Mn, Mn, Mn, Mc, Mn, Mc, Mc, Mc, Mc, Mn, +/* DATA_BLOCK: -- 0x2080..0x208F -- */ + Mn, Mc, Mn, Mn, Lo, Lo, Po, Lo, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2090..0x209F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Mc, +/* DATA_BLOCK: -- 0x20A0..0x20AF -- */ + Mc, Mc, Mn, Mn, Mn, Mn, Cn, Cn, Mc, Mc, Mc, Mc, Mn, Mn, Mc, Mn, +/* DATA_BLOCK: -- 0x20B0..0x20BF -- */ + Mn, Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, +/* DATA_BLOCK: -- 0x20C0..0x20CF -- */ + Po, Po, Po, Po, Po, Po, Po, Po, Lo, Lo, Lo, Lo, Mn, Mn, Cn, Cn, +/* DATA_BLOCK: -- 0x20D0..0x20DF -- */ + Mc, Mc, Mc, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mc, Mc, Mn, Mc, Mn, +/* DATA_BLOCK: -- 0x20E0..0x20EF -- */ + Mn, Po, Po, Po, Lo, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x20F0..0x20FF -- */ + Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2100..0x210F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Mn, Mc, Mn, Mc, Mc, +/* DATA_BLOCK: -- 0x2110..0x211F -- */ + Mn, Mn, Mn, Mn, Mn, Mn, Mc, Mn, Lo, Po, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2120..0x212F -- */ + Mc, Mc, Mn, Mn, Mn, Mn, Mc, Mn, Mn, Mn, Mn, Mn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2130..0x213F -- */ + Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, No, No, Po, Po, Po, So, +/* DATA_BLOCK: -- 0x2140..0x214F -- */ + Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mc, Mn, Mn, Po, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2150..0x215F -- */ + No, No, No, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Lo, +/* DATA_BLOCK: -- 0x2160..0x216F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Lo, Cn, Cn, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x2170..0x217F -- */ + Lo, Lo, Lo, Lo, Cn, Lo, Lo, Cn, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x2180..0x218F -- */ + Mc, Mc, Mc, Mc, Mc, Mc, Cn, Mc, Mc, Cn, Cn, Mn, Mn, Mc, Mn, Lo, +/* DATA_BLOCK: -- 0x2190..0x219F -- */ + Mc, Lo, Mc, Mn, Po, Po, Po, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x21A0..0x21AF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x21B0..0x21BF -- */ + Lo, Mc, Mc, Mc, Mn, Mn, Mn, Mn, Cn, Cn, Mn, Mn, Mc, Mc, Mc, Mc, +/* DATA_BLOCK: -- 0x21C0..0x21CF -- */ + Mn, Lo, Po, Lo, Mc, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x21D0..0x21DF -- */ + Lo, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x21E0..0x21EF -- */ + Lo, Lo, Lo, Mn, Mn, Mn, Mn, Mn, Mn, Mc, Lo, Mn, Mn, Mn, Mn, Po, +/* DATA_BLOCK: -- 0x21F0..0x21FF -- */ + Po, Po, Po, Po, Po, Po, Po, Mn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2200..0x220F -- */ + Lo, Mn, Mn, Mn, Mn, Mn, Mn, Mc, Mc, Mn, Mn, Mn, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x2210..0x221F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Mn, Mn, Mn, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x2220..0x222F -- */ + Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mc, Mn, Mn, Po, Po, Po, Lo, Po, Po, +/* DATA_BLOCK: -- 0x2230..0x223F -- */ + Po, Po, Po, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2240..0x224F -- */ + Mn, Mn, Mn, Mn, Mn, Mn, Mn, Cn, Mn, Mn, Mn, Mn, Mn, Mn, Mc, Mn, +/* DATA_BLOCK: -- 0x2250..0x225F -- */ + Lo, Po, Po, Po, Po, Po, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2260..0x226F -- */ + Po, Po, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x2270..0x227F -- */ + Cn, Cn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x2280..0x228F -- */ + Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Cn, Mc, Mn, Mn, Mn, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x2290..0x229F -- */ + Mn, Mc, Mn, Mn, Mc, Mn, Mn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x22A0..0x22AF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Lo, Lo, Cn, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x22B0..0x22BF -- */ + Lo, Mn, Mn, Mn, Mn, Mn, Mn, Cn, Cn, Cn, Mn, Cn, Mn, Mn, Cn, Mn, +/* DATA_BLOCK: -- 0x22C0..0x22CF -- */ + Mn, Mn, Mn, Mn, Mn, Mn, Lo, Mn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x22D0..0x22DF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Cn, Lo, Lo, Cn, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x22E0..0x22EF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Mc, Mc, Mc, Mc, Mc, Cn, +/* DATA_BLOCK: -- 0x22F0..0x22FF -- */ + Mn, Mn, Cn, Mc, Mc, Mn, Mc, Mn, Lo, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2300..0x230F -- */ + Lo, Lo, Lo, Mn, Mn, Mc, Mc, Po, Po, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2310..0x231F -- */ + No, No, No, No, No, So, So, So, So, So, So, So, So, Sc, Sc, Sc, +/* DATA_BLOCK: -- 0x2320..0x232F -- */ + Sc, So, So, So, So, So, So, So, So, So, So, So, So, So, So, So, +/* DATA_BLOCK: -- 0x2330..0x233F -- */ + So, So, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Po, +/* DATA_BLOCK: -- 0x2340..0x234F -- */ + Nl, Nl, Nl, Nl, Nl, Nl, Nl, Nl, Nl, Nl, Nl, Nl, Nl, Nl, Nl, Cn, +/* DATA_BLOCK: -- 0x2350..0x235F -- */ + Po, Po, Po, Po, Po, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2360..0x236F -- */ + Lo, Lo, Lo, Lo, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2370..0x237F -- */ + Lo, Po, Po, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2380..0x238F -- */ + Cf, Cf, Cf, Cf, Cf, Cf, Cf, Cf, Cf, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2390..0x239F -- */ + Mn, Mn, Mn, Mn, Mn, Po, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x23A0..0x23AF -- */ + Mn, Mn, Mn, Mn, Mn, Mn, Mn, Po, Po, Po, Po, Po, So, So, So, So, +/* DATA_BLOCK: -- 0x23B0..0x23BF -- */ + Lm, Lm, Lm, Lm, Po, So, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x23C0..0x23CF -- */ + Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Cn, No, No, No, No, No, +/* DATA_BLOCK: -- 0x23D0..0x23DF -- */ + No, No, Cn, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x23E0..0x23EF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Cn, Cn, Cn, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x23F0..0x23FF -- */ + No, No, No, No, No, No, No, Po, Po, Po, Po, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2400..0x240F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Cn, Cn, Mn, +/* DATA_BLOCK: -- 0x2410..0x241F -- */ + Lo, Mc, Mc, Mc, Mc, Mc, Mc, Mc, Mc, Mc, Mc, Mc, Mc, Mc, Mc, Mc, +/* DATA_BLOCK: -- 0x2420..0x242F -- */ + Mc, Mc, Mc, Mc, Mc, Mc, Mc, Mc, Mc, Mc, Mc, Mc, Mc, Mc, Mc, Mc, +/* DATA_BLOCK: -- 0x2430..0x243F -- */ + Mc, Mc, Mc, Mc, Mc, Mc, Mc, Mc, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Mn, +/* DATA_BLOCK: -- 0x2440..0x244F -- */ + Mn, Mn, Mn, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, +/* DATA_BLOCK: -- 0x2450..0x245F -- */ + Lm, Lm, Po, Lm, Mn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2460..0x246F -- */ + Mc, Mc, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2470..0x247F -- */ + Cn, Cn, Cn, Cn, Cn, Cn, Cn, Lo, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2480..0x248F -- */ + Lo, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Lo, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2490..0x249F -- */ + Lm, Lm, Lm, Lm, Cn, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Cn, Lm, Lm, Cn, +/* DATA_BLOCK: -- 0x24A0..0x24AF -- */ + Lo, Lo, Lo, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x24B0..0x24BF -- */ + Cn, Cn, Cn, Cn, Lo, Lo, Lo, Lo, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x24C0..0x24CF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, So, Mn, Mn, Po, +/* DATA_BLOCK: -- 0x24D0..0x24DF -- */ + Cf, Cf, Cf, Cf, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x24E0..0x24EF -- */ + Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Cn, Cn, +/* DATA_BLOCK: -- 0x24F0..0x24FF -- */ + Mn, Mn, Mn, Mn, Mn, Mn, Mn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2500..0x250F -- */ + So, So, So, So, So, So, So, Cn, Cn, So, So, So, So, So, So, So, +/* DATA_BLOCK: -- 0x2510..0x251F -- */ + So, So, So, So, So, Mc, Mc, Mn, Mn, Mn, So, So, So, Mc, Mc, Mc, +/* DATA_BLOCK: -- 0x2520..0x252F -- */ + Mc, Mc, Mc, Cf, Cf, Cf, Cf, Cf, Cf, Cf, Cf, Mn, Mn, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x2530..0x253F -- */ + Mn, Mn, Mn, So, So, Mn, Mn, Mn, Mn, Mn, Mn, Mn, So, So, So, So, +/* DATA_BLOCK: -- 0x2540..0x254F -- */ + So, So, So, So, So, So, So, So, So, So, Mn, Mn, Mn, Mn, So, So, +/* DATA_BLOCK: -- 0x2550..0x255F -- */ + So, So, Mn, Mn, Mn, So, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2560..0x256F -- */ + No, No, No, No, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2570..0x257F -- */ + Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Ll, Ll, Ll, Ll, Ll, Ll, +/* DATA_BLOCK: -- 0x2580..0x258F -- */ + Ll, Ll, Ll, Ll, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, +/* DATA_BLOCK: -- 0x2590..0x259F -- */ + Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Ll, Ll, +/* DATA_BLOCK: -- 0x25A0..0x25AF -- */ + Ll, Ll, Ll, Ll, Ll, Cn, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, +/* DATA_BLOCK: -- 0x25B0..0x25BF -- */ + Lu, Lu, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, +/* DATA_BLOCK: -- 0x25C0..0x25CF -- */ + Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Lu, Cn, Lu, Lu, +/* DATA_BLOCK: -- 0x25D0..0x25DF -- */ + Cn, Cn, Lu, Cn, Cn, Lu, Lu, Cn, Cn, Lu, Lu, Lu, Lu, Cn, Lu, Lu, +/* DATA_BLOCK: -- 0x25E0..0x25EF -- */ + Lu, Lu, Lu, Lu, Lu, Lu, Ll, Ll, Ll, Ll, Cn, Ll, Cn, Ll, Ll, Ll, +/* DATA_BLOCK: -- 0x25F0..0x25FF -- */ + Ll, Ll, Ll, Ll, Cn, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, +/* DATA_BLOCK: -- 0x2600..0x260F -- */ + Ll, Ll, Ll, Ll, Lu, Lu, Cn, Lu, Lu, Lu, Lu, Cn, Cn, Lu, Lu, Lu, +/* DATA_BLOCK: -- 0x2610..0x261F -- */ + Lu, Lu, Lu, Lu, Lu, Cn, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Cn, Ll, Ll, +/* DATA_BLOCK: -- 0x2620..0x262F -- */ + Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Lu, Lu, Cn, Lu, Lu, Lu, Lu, Cn, +/* DATA_BLOCK: -- 0x2630..0x263F -- */ + Lu, Lu, Lu, Lu, Lu, Cn, Lu, Cn, Cn, Cn, Lu, Lu, Lu, Lu, Lu, Lu, +/* DATA_BLOCK: -- 0x2640..0x264F -- */ + Lu, Cn, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, +/* DATA_BLOCK: -- 0x2650..0x265F -- */ + Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Lu, Lu, Lu, Lu, +/* DATA_BLOCK: -- 0x2660..0x266F -- */ + Lu, Lu, Lu, Lu, Lu, Lu, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, +/* DATA_BLOCK: -- 0x2670..0x267F -- */ + Ll, Ll, Ll, Ll, Ll, Ll, Cn, Cn, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, +/* DATA_BLOCK: -- 0x2680..0x268F -- */ + Lu, Sm, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, +/* DATA_BLOCK: -- 0x2690..0x269F -- */ + Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Sm, Ll, Ll, Ll, Ll, +/* DATA_BLOCK: -- 0x26A0..0x26AF -- */ + Ll, Ll, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, +/* DATA_BLOCK: -- 0x26B0..0x26BF -- */ + Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Sm, Ll, Ll, Ll, Ll, +/* DATA_BLOCK: -- 0x26C0..0x26CF -- */ + Ll, Ll, Ll, Ll, Ll, Sm, Ll, Ll, Ll, Ll, Ll, Ll, Lu, Lu, Lu, Lu, +/* DATA_BLOCK: -- 0x26D0..0x26DF -- */ + Lu, Lu, Lu, Lu, Lu, Sm, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, +/* DATA_BLOCK: -- 0x26E0..0x26EF -- */ + Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Sm, +/* DATA_BLOCK: -- 0x26F0..0x26FF -- */ + Ll, Ll, Ll, Ll, Ll, Ll, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, +/* DATA_BLOCK: -- 0x2700..0x270F -- */ + Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Sm, +/* DATA_BLOCK: -- 0x2710..0x271F -- */ + Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Sm, Ll, Ll, Ll, Ll, Ll, Ll, +/* DATA_BLOCK: -- 0x2720..0x272F -- */ + Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Sm, Ll, Ll, Ll, Ll, Ll, Ll, +/* DATA_BLOCK: -- 0x2730..0x273F -- */ + Ll, Ll, Ll, Sm, Ll, Ll, Ll, Ll, Ll, Ll, Lu, Ll, Cn, Cn, Nd, Nd, +/* DATA_BLOCK: -- 0x2740..0x274F -- */ + Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, +/* DATA_BLOCK: -- 0x2750..0x275F -- */ + Mn, Mn, Mn, Mn, Mn, Mn, Mn, So, So, So, So, Mn, Mn, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x2760..0x276F -- */ + Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, So, So, So, +/* DATA_BLOCK: -- 0x2770..0x277F -- */ + So, So, So, So, So, Mn, So, So, So, So, So, So, So, So, So, So, +/* DATA_BLOCK: -- 0x2780..0x278F -- */ + So, So, So, So, Mn, So, So, Po, Po, Po, Po, Po, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2790..0x279F -- */ + Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Mn, Mn, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x27A0..0x27AF -- */ + Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Lo, Ll, Ll, Ll, Ll, Ll, +/* DATA_BLOCK: -- 0x27B0..0x27BF -- */ + Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Cn, +/* DATA_BLOCK: -- 0x27C0..0x27CF -- */ + Mn, Mn, Mn, Mn, Mn, Mn, Mn, Cn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x27D0..0x27DF -- */ + Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Cn, Cn, Mn, Mn, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x27E0..0x27EF -- */ + Mn, Mn, Cn, Mn, Mn, Cn, Mn, Mn, Mn, Mn, Mn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x27F0..0x27FF -- */ + Mn, Mn, Mn, Mn, Mn, Mn, Mn, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Cn, Cn, +/* DATA_BLOCK: -- 0x2800..0x280F -- */ + Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Cn, Cn, Cn, Cn, Lo, So, +/* DATA_BLOCK: -- 0x2810..0x281F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Mn, Cn, +/* DATA_BLOCK: -- 0x2820..0x282F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Mn, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x2830..0x283F -- */ + Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Cn, Cn, Cn, Cn, Cn, Sc, +/* DATA_BLOCK: -- 0x2840..0x284F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Lo, Lo, Lo, Lo, Cn, Lo, Lo, Cn, +/* DATA_BLOCK: -- 0x2850..0x285F -- */ + Lo, Lo, Lo, Lo, Lo, Cn, Cn, No, No, No, No, No, No, No, No, No, +/* DATA_BLOCK: -- 0x2860..0x286F -- */ + Ll, Ll, Ll, Ll, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Lm, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2870..0x287F -- */ + No, No, No, No, No, No, No, No, No, No, No, No, So, No, No, No, +/* DATA_BLOCK: -- 0x2880..0x288F -- */ + Sc, No, No, No, No, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2890..0x289F -- */ + No, No, No, No, No, No, No, No, No, No, No, No, No, No, So, No, +/* DATA_BLOCK: -- 0x28A0..0x28AF -- */ + No, No, No, No, No, No, No, No, No, No, No, No, No, No, Cn, Cn, +/* DATA_BLOCK: -- 0x28B0..0x28BF -- */ + Lo, Lo, Lo, Lo, Cn, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x28C0..0x28CF -- */ + Cn, Lo, Lo, Cn, Lo, Cn, Cn, Lo, Cn, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x28D0..0x28DF -- */ + Lo, Lo, Lo, Cn, Lo, Lo, Lo, Lo, Cn, Lo, Cn, Lo, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x28E0..0x28EF -- */ + Cn, Cn, Lo, Cn, Cn, Cn, Cn, Lo, Cn, Lo, Cn, Lo, Cn, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x28F0..0x28FF -- */ + Cn, Lo, Lo, Cn, Lo, Cn, Cn, Lo, Cn, Lo, Cn, Lo, Cn, Lo, Cn, Lo, +/* DATA_BLOCK: -- 0x2900..0x290F -- */ + Cn, Lo, Lo, Cn, Lo, Cn, Cn, Lo, Lo, Lo, Lo, Cn, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x2910..0x291F -- */ + Lo, Lo, Lo, Cn, Lo, Lo, Lo, Lo, Cn, Lo, Lo, Lo, Lo, Cn, Lo, Cn, +/* DATA_BLOCK: -- 0x2920..0x292F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x2930..0x293F -- */ + Cn, Lo, Lo, Lo, Cn, Lo, Lo, Lo, Lo, Lo, Cn, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x2940..0x294F -- */ + Sm, Sm, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2950..0x295F -- */ + Cn, So, So, So, So, So, So, So, So, So, So, So, So, So, So, So, +/* DATA_BLOCK: -- 0x2960..0x296F -- */ + No, No, No, No, No, No, No, No, No, No, No, No, No, So, So, So, +/* DATA_BLOCK: -- 0x2970..0x297F -- */ + So, So, So, So, So, So, So, So, So, So, So, So, So, So, Cn, Cn, +/* DATA_BLOCK: -- 0x2980..0x298F -- */ + Cn, Cn, Cn, Cn, Cn, Cn, So, So, So, So, So, So, So, So, So, So, +/* DATA_BLOCK: -- 0x2990..0x299F -- */ + So, So, So, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x29A0..0x29AF -- */ + So, So, So, So, So, So, So, So, So, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x29B0..0x29BF -- */ + So, So, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x29C0..0x29CF -- */ + So, So, So, So, So, So, So, So, So, So, So, Sk, Sk, Sk, Sk, Sk, +/* DATA_BLOCK: -- 0x29D0..0x29DF -- */ + So, So, So, So, So, So, So, So, Cn, Cn, Cn, Cn, Cn, So, So, So, +/* DATA_BLOCK: -- 0x29E0..0x29EF -- */ + So, So, So, So, So, So, So, So, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x29F0..0x29FF -- */ + So, So, So, So, So, Cn, Cn, Cn, So, So, So, So, So, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2A00..0x2A0F -- */ + So, So, So, Cn, So, So, So, So, So, So, So, So, So, So, So, So, +/* DATA_BLOCK: -- 0x2A10..0x2A1F -- */ + Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Lo, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2A20..0x2A2F -- */ + Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Lo, Cn, Cn, +/* DATA_BLOCK: -- 0x2A30..0x2A3F -- */ + Cn, Lo, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2A40..0x2A4F -- */ + Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Lo, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2A50..0x2A5F -- */ + Cn, Cf, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2A60..0x2A6F -- */ + Cf, Cf, Cf, Cf, Cf, Cf, Cf, Cf, Cf, Cf, Cf, Cf, Cf, Cf, Cf, Cf, +/* DATA_BLOCK: -- 0x2A70..0x2A7F -- */ + Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Co, Cn, Cn, +/* DATA_BLOCK: -- 0x2A80..0x2A8D -- */ + Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Co +}; + +static const SBUInt16 MainGeneralCategoryIndexes[3972] = { +/* INDEX_BLOCK: -- 0x0000..0x0030 -- */ + 0x0000, 0x0000, 0x0010, 0x0020, 0x0030, 0x0040, 0x0050, 0x0060, 0x0000, 0x0000, 0x0070, 0x0080, + 0x0090, 0x00A0, 0x00B0, 0x00C0, 0x00D0, 0x00D0, 0x00D0, 0x00E0, 0x00F0, 0x00D0, 0x00D0, 0x0100, + 0x0110, 0x0120, 0x0130, 0x0140, 0x0150, 0x0160, 0x00D0, 0x0170, 0x00D0, 0x00D0, 0x00D0, 0x0180, + 0x0190, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x01A0, 0x00B0, 0x01B0, 0x01C0, 0x01D0, 0x01E0, 0x01F0, + 0x0200, +/* INDEX_BLOCK: -- 0x0031..0x0061 -- */ + 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0210, 0x0220, 0x0230, 0x0240, 0x00B0, 0x0250, + 0x0260, 0x00D0, 0x0270, 0x0090, 0x0090, 0x0090, 0x00B0, 0x00B0, 0x00B0, 0x00D0, 0x00D0, 0x0280, + 0x00D0, 0x00D0, 0x00D0, 0x0290, 0x00D0, 0x00D0, 0x00D0, 0x00D0, 0x00D0, 0x00D0, 0x02A0, 0x0090, + 0x02B0, 0x00B0, 0x00B0, 0x02C0, 0x02D0, 0x0200, 0x02E0, 0x02F0, 0x0300, 0x0310, 0x0320, 0x0330, + 0x0340, +/* INDEX_BLOCK: -- 0x0062..0x0092 -- */ + 0x0300, 0x0300, 0x0350, 0x0200, 0x0360, 0x0370, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0380, + 0x0390, 0x03A0, 0x03B0, 0x03C0, 0x0300, 0x0200, 0x03D0, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x03E0, 0x03F0, 0x0400, 0x0300, 0x0410, 0x0420, 0x0300, 0x0430, 0x0440, 0x0450, 0x0300, 0x0460, + 0x0470, 0x0300, 0x0480, 0x0490, 0x0300, 0x0300, 0x04A0, 0x0200, 0x04B0, 0x0200, 0x04C0, 0x0300, + 0x0300, +/* INDEX_BLOCK: -- 0x0093..0x00C3 -- */ + 0x04D0, 0x04E0, 0x04F0, 0x0500, 0x0510, 0x0520, 0x0530, 0x0540, 0x0550, 0x0560, 0x0570, 0x0580, + 0x0590, 0x05A0, 0x0530, 0x0540, 0x05B0, 0x05C0, 0x05D0, 0x05E0, 0x05F0, 0x0600, 0x0610, 0x0540, + 0x0620, 0x0630, 0x0640, 0x0580, 0x0650, 0x0660, 0x0530, 0x0540, 0x0670, 0x0680, 0x0690, 0x0580, + 0x06A0, 0x06B0, 0x06C0, 0x06D0, 0x06E0, 0x06F0, 0x0700, 0x05E0, 0x0710, 0x0720, 0x0730, 0x0540, + 0x0740, +/* INDEX_BLOCK: -- 0x00C4..0x00F4 -- */ + 0x0750, 0x0760, 0x0580, 0x0770, 0x0780, 0x0730, 0x0540, 0x0790, 0x07A0, 0x07B0, 0x0580, 0x07C0, + 0x07D0, 0x0730, 0x0300, 0x07E0, 0x07F0, 0x0800, 0x0580, 0x0810, 0x0820, 0x0830, 0x0300, 0x0840, + 0x0850, 0x0860, 0x05E0, 0x0870, 0x0880, 0x0300, 0x0300, 0x0890, 0x08A0, 0x08B0, 0x08C0, 0x08C0, + 0x08D0, 0x0300, 0x08E0, 0x08F0, 0x0900, 0x0910, 0x08C0, 0x08C0, 0x0920, 0x0930, 0x0940, 0x0950, + 0x0960, +/* INDEX_BLOCK: -- 0x00F5..0x0125 -- */ + 0x0300, 0x0970, 0x0980, 0x0990, 0x09A0, 0x0200, 0x09B0, 0x09C0, 0x09D0, 0x08C0, 0x08C0, 0x0300, + 0x0300, 0x09E0, 0x09F0, 0x0A00, 0x0A10, 0x0A20, 0x0A30, 0x0A40, 0x0A50, 0x0090, 0x0090, 0x0A60, + 0x00B0, 0x00B0, 0x0A70, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0A80, + 0x0A90, +/* INDEX_BLOCK: -- 0x0126..0x0156 -- */ + 0x0300, 0x0300, 0x0A80, 0x0300, 0x0300, 0x0AA0, 0x0AB0, 0x0AC0, 0x0300, 0x0300, 0x0300, 0x0AB0, + 0x0300, 0x0300, 0x0300, 0x0AD0, 0x0AE0, 0x0AF0, 0x0300, 0x0B00, 0x0090, 0x0090, 0x0090, 0x0090, + 0x0090, 0x0B10, 0x0B20, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, +/* INDEX_BLOCK: -- 0x0157..0x0187 -- */ + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0B30, 0x0300, 0x0B40, 0x0B50, 0x0300, 0x0300, 0x0300, 0x0300, 0x0B60, + 0x0B70, 0x0300, 0x0B80, 0x0300, 0x0B90, 0x0300, 0x0BA0, 0x0BB0, 0x0BC0, 0x0300, 0x0300, 0x0300, + 0x0BD0, 0x0BE0, 0x0BF0, 0x0C00, 0x0C10, 0x0C20, 0x0C00, 0x0300, 0x0300, 0x0C30, 0x0300, 0x0300, + 0x0C40, +/* INDEX_BLOCK: -- 0x0188..0x01B8 -- */ + 0x0C50, 0x0300, 0x0C60, 0x0300, 0x0300, 0x0300, 0x0300, 0x0C70, 0x0300, 0x0C80, 0x0C90, 0x0CA0, + 0x0CB0, 0x0300, 0x0CC0, 0x0CD0, 0x0300, 0x0300, 0x0CE0, 0x0300, 0x0CF0, 0x0D00, 0x0D10, 0x0D10, + 0x0300, 0x0D20, 0x0300, 0x0300, 0x0300, 0x0D30, 0x0D40, 0x0D50, 0x0C00, 0x0C00, 0x0D60, 0x0D70, + 0x0D80, 0x08C0, 0x08C0, 0x08C0, 0x0D90, 0x0300, 0x0300, 0x0DA0, 0x0DB0, 0x0A00, 0x0DC0, 0x0DD0, + 0x0DE0, +/* INDEX_BLOCK: -- 0x01B9..0x01E9 -- */ + 0x0300, 0x0DF0, 0x0400, 0x0300, 0x0300, 0x0E00, 0x0E10, 0x0300, 0x0300, 0x0E20, 0x0E30, 0x0E40, + 0x0400, 0x0300, 0x0E50, 0x0E60, 0x0090, 0x0090, 0x0E70, 0x0E80, 0x0E90, 0x0EA0, 0x0EB0, 0x00B0, + 0x00B0, 0x0EC0, 0x01B0, 0x01B0, 0x01B0, 0x0ED0, 0x0EE0, 0x00B0, 0x0EF0, 0x01B0, 0x01B0, 0x0200, + 0x0200, 0x0200, 0x0200, 0x00D0, 0x00D0, 0x00D0, 0x00D0, 0x00D0, 0x00D0, 0x00D0, 0x00D0, 0x00D0, + 0x0F00, +/* INDEX_BLOCK: -- 0x01EA..0x021A -- */ + 0x00D0, 0x00D0, 0x00D0, 0x00D0, 0x00D0, 0x00D0, 0x0F10, 0x0F20, 0x0F10, 0x0F10, 0x0F20, 0x0F30, + 0x0F10, 0x0F40, 0x0F50, 0x0F50, 0x0F50, 0x0F60, 0x0F70, 0x0F80, 0x0F90, 0x0FA0, 0x0FB0, 0x0FC0, + 0x0FD0, 0x0FE0, 0x0FF0, 0x1000, 0x1010, 0x1020, 0x1030, 0x1040, 0x1050, 0x1050, 0x1060, 0x1070, + 0x1080, 0x1090, 0x10A0, 0x10B0, 0x10C0, 0x10D0, 0x10E0, 0x10F0, 0x1100, 0x1100, 0x1110, 0x1120, + 0x1130, +/* INDEX_BLOCK: -- 0x021B..0x024B -- */ + 0x0D10, 0x1140, 0x1150, 0x0D10, 0x1160, 0x1170, 0x1170, 0x1170, 0x1170, 0x1170, 0x1170, 0x1170, + 0x1170, 0x1170, 0x1170, 0x1170, 0x1170, 0x1170, 0x1170, 0x1170, 0x1170, 0x1180, 0x0D10, 0x1190, + 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x11A0, 0x0D10, 0x11B0, 0x1170, 0x11C0, 0x0D10, 0x11D0, 0x11E0, + 0x0D10, 0x0D10, 0x0D10, 0x11F0, 0x08C0, 0x1200, 0x08C0, 0x10F0, 0x10F0, 0x10F0, 0x1210, 0x0D10, + 0x0D10, +/* INDEX_BLOCK: -- 0x024C..0x027C -- */ + 0x0D10, 0x0D10, 0x1220, 0x10F0, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, + 0x0D10, 0x0D10, 0x0D10, 0x1230, 0x1240, 0x0D10, 0x0D10, 0x1250, 0x0D10, 0x0D10, 0x0D10, 0x0D10, + 0x0D10, 0x0D10, 0x1260, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, + 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x1270, 0x1280, 0x10F0, 0x1290, 0x0D10, 0x0D10, + 0x12A0, +/* INDEX_BLOCK: -- 0x027D..0x02AD -- */ + 0x1170, 0x12B0, 0x1170, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, + 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x1170, 0x1170, 0x1170, 0x1170, 0x1170, + 0x1170, 0x1170, 0x1170, 0x12C0, 0x12D0, 0x1170, 0x1170, 0x1170, 0x12E0, 0x1170, 0x12F0, 0x1170, + 0x1170, 0x1170, 0x1170, 0x1170, 0x1170, 0x1170, 0x1170, 0x1170, 0x1170, 0x1170, 0x1170, 0x1170, + 0x1170, +/* INDEX_BLOCK: -- 0x02AE..0x02DE -- */ + 0x1170, 0x1170, 0x0D10, 0x0D10, 0x0D10, 0x1170, 0x1300, 0x0D10, 0x0D10, 0x1310, 0x0D10, 0x1320, + 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0090, 0x0090, 0x0090, 0x00B0, 0x00B0, 0x00B0, + 0x1330, 0x1340, 0x00D0, 0x00D0, 0x00D0, 0x00D0, 0x00D0, 0x00D0, 0x1350, 0x1360, 0x00B0, 0x00B0, + 0x1370, 0x0300, 0x0300, 0x0300, 0x1380, 0x1390, 0x0300, 0x13A0, 0x13B0, 0x13B0, 0x13B0, 0x13B0, + 0x0200, +/* INDEX_BLOCK: -- 0x02DF..0x030F -- */ + 0x0200, 0x13C0, 0x13D0, 0x13E0, 0x13F0, 0x1400, 0x1410, 0x08C0, 0x08C0, 0x0D10, 0x1420, 0x0D10, + 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x1430, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, + 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x1440, 0x08C0, 0x1450, 0x1460, 0x1470, 0x1480, + 0x1490, 0x0880, 0x0300, 0x0300, 0x0300, 0x0300, 0x14A0, 0x0B20, 0x0300, 0x0300, 0x0300, 0x0300, + 0x14B0, +/* INDEX_BLOCK: -- 0x0310..0x0340 -- */ + 0x14C0, 0x0300, 0x0300, 0x0880, 0x0300, 0x0300, 0x0300, 0x0300, 0x0C80, 0x14D0, 0x0300, 0x0300, + 0x0D10, 0x0D10, 0x1430, 0x0300, 0x0D10, 0x14E0, 0x14F0, 0x0D10, 0x1500, 0x1510, 0x0D10, 0x0D10, + 0x14F0, 0x0D10, 0x0D10, 0x1510, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, + 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, + 0x0640, +/* INDEX_BLOCK: -- 0x0341..0x0371 -- */ + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, +/* INDEX_BLOCK: -- 0x0372..0x03A2 -- */ + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x1520, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0640, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, +/* INDEX_BLOCK: -- 0x03A3..0x03D3 -- */ + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x1520, + 0x0300, 0x1530, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, +/* INDEX_BLOCK: -- 0x03D4..0x0404 -- */ + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0970, + 0x0D10, 0x0D10, 0x0D10, 0x11F0, 0x0300, 0x0300, 0x0E50, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, +/* INDEX_BLOCK: -- 0x0405..0x0435 -- */ + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x1540, 0x0300, + 0x1550, 0x08C0, 0x00D0, 0x00D0, 0x1560, 0x1570, 0x00D0, 0x1580, 0x0300, 0x0300, 0x0300, 0x0300, + 0x1590, 0x15A0, 0x01F0, 0x15B0, 0x15C0, 0x15D0, 0x00D0, 0x00D0, 0x00D0, 0x15E0, 0x15F0, 0x1600, + 0x1610, 0x1620, 0x1630, 0x1640, 0x08C0, 0x1650, 0x1660, 0x0300, 0x1670, 0x1680, 0x0300, 0x0300, + 0x0300, +/* INDEX_BLOCK: -- 0x0436..0x0466 -- */ + 0x1690, 0x16A0, 0x0300, 0x0300, 0x16B0, 0x16C0, 0x0C00, 0x0200, 0x16D0, 0x0400, 0x0300, 0x16E0, + 0x0300, 0x16F0, 0x1700, 0x0300, 0x0970, 0x04C0, 0x0300, 0x0300, 0x1710, 0x1720, 0x1730, 0x1740, + 0x1750, 0x0300, 0x0300, 0x1760, 0x1770, 0x1780, 0x1790, 0x0300, 0x17A0, 0x0300, 0x0300, 0x0300, + 0x17B0, 0x17C0, 0x17D0, 0x17E0, 0x17F0, 0x1800, 0x1810, 0x13B0, 0x00B0, 0x00B0, 0x1820, 0x1830, + 0x00B0, +/* INDEX_BLOCK: -- 0x0467..0x0497 -- */ + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0300, 0x0300, 0x1840, 0x0C00, 0x0640, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, +/* INDEX_BLOCK: -- 0x0498..0x04C8 -- */ + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x1850, 0x0300, 0x1860, 0x0300, + 0x0300, 0x0CE0, 0x1870, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, +/* INDEX_BLOCK: -- 0x04C9..0x04F9 -- */ + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x1880, 0x1870, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x1880, 0x1870, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, +/* INDEX_BLOCK: -- 0x04FA..0x052A -- */ + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x1880, 0x1890, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, +/* INDEX_BLOCK: -- 0x052B..0x055B -- */ + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x18A0, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0CC0, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0CF0, 0x08C0, 0x08C0, 0x18B0, + 0x18C0, +/* INDEX_BLOCK: -- 0x055C..0x058C -- */ + 0x18D0, 0x18E0, 0x18F0, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x1900, 0x1910, 0x1920, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x1930, 0x0D10, 0x0300, + 0x0300, 0x0300, 0x0300, 0x1940, 0x0300, 0x0300, 0x1950, 0x08C0, 0x08C0, 0x1960, 0x0200, 0x1970, + 0x0200, +/* INDEX_BLOCK: -- 0x058D..0x05BD -- */ + 0x1980, 0x1990, 0x19A0, 0x19B0, 0x19C0, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x19D0, 0x19E0, 0x0020, 0x0030, 0x0040, 0x0050, 0x19F0, 0x1A00, 0x1A10, 0x0300, 0x1A20, 0x0300, + 0x0C80, 0x1A30, 0x1A40, 0x1A50, 0x1A60, 0x1A70, 0x0300, 0x0AC0, 0x1A80, 0x0CC0, 0x0CC0, 0x08C0, + 0x08C0, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0470, 0x1A90, 0x10F0, 0x10F0, + 0x1AA0, +/* INDEX_BLOCK: -- 0x05BE..0x05EE -- */ + 0x1100, 0x1100, 0x1100, 0x1AB0, 0x1AC0, 0x1AD0, 0x1AE0, 0x08C0, 0x08C0, 0x0D10, 0x0D10, 0x1AF0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x0300, 0x0970, 0x0300, 0x0300, + 0x0300, 0x0640, 0x1B00, 0x1B10, 0x0300, 0x0300, 0x1B20, 0x0300, 0x1B30, 0x0300, 0x0300, 0x1B40, + 0x0300, 0x1B50, 0x0300, 0x0300, 0x1B60, 0x1B70, 0x08C0, 0x08C0, 0x0090, 0x0090, 0x1B80, 0x00B0, + 0x00B0, +/* INDEX_BLOCK: -- 0x05EF..0x061F -- */ + 0x0300, 0x0300, 0x0300, 0x0300, 0x0CC0, 0x0C00, 0x0090, 0x0090, 0x1B90, 0x00B0, 0x1BA0, 0x0300, + 0x0300, 0x1BB0, 0x0300, 0x0300, 0x0300, 0x1BC0, 0x1BD0, 0x1BD0, 0x1BE0, 0x1BF0, 0x1C00, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x13A0, 0x0300, + 0x0C70, +/* INDEX_BLOCK: -- 0x0620..0x0650 -- */ + 0x1BB0, 0x08C0, 0x1C10, 0x01B0, 0x01B0, 0x1C20, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x1C30, 0x0300, + 0x0300, 0x1C40, 0x0300, 0x1C50, 0x0300, 0x1C60, 0x0300, 0x0C80, 0x1C70, 0x08C0, 0x08C0, 0x08C0, + 0x0300, 0x1C80, 0x0300, 0x1C90, 0x0300, 0x1CA0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x0300, 0x0300, + 0x0300, 0x1CB0, 0x10F0, 0x1CC0, 0x10F0, 0x10F0, 0x1CD0, 0x1CE0, 0x0300, 0x1CF0, 0x1D00, 0x1D10, + 0x0300, +/* INDEX_BLOCK: -- 0x0651..0x0681 -- */ + 0x1D20, 0x0300, 0x1D30, 0x08C0, 0x08C0, 0x1D40, 0x0300, 0x1D50, 0x1D60, 0x0300, 0x0300, 0x0300, + 0x1D70, 0x0300, 0x1D80, 0x0300, 0x1D90, 0x0300, 0x1DA0, 0x1DB0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x0300, 0x0300, 0x0300, 0x0300, 0x0C40, 0x08C0, 0x08C0, 0x08C0, 0x0090, 0x0090, 0x0090, + 0x1DC0, 0x00B0, 0x00B0, 0x00B0, 0x1DD0, 0x0300, 0x0300, 0x1DE0, 0x0C00, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, +/* INDEX_BLOCK: -- 0x0682..0x06B2 -- */ + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x10F0, 0x1DF0, 0x0300, 0x0300, 0x1E00, 0x1E10, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x0300, 0x1D30, 0x1E20, 0x0300, 0x03E0, 0x1E30, 0x08C0, 0x0300, 0x1E40, 0x08C0, 0x08C0, 0x0300, + 0x1E50, 0x08C0, 0x0300, 0x13A0, 0x1E60, 0x0300, 0x0300, 0x1E70, 0x1E80, 0x1CC0, 0x1E90, 0x1EA0, + 0x0DE0, +/* INDEX_BLOCK: -- 0x06B3..0x06E3 -- */ + 0x0300, 0x0300, 0x1EB0, 0x1EC0, 0x0300, 0x0C40, 0x0C00, 0x1ED0, 0x0300, 0x1EE0, 0x1EF0, 0x1F00, + 0x0300, 0x0300, 0x1F10, 0x0DE0, 0x0300, 0x0300, 0x1F20, 0x1F30, 0x1F40, 0x1F50, 0x1F60, 0x0300, + 0x0610, 0x1F70, 0x1F80, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x1F90, 0x1FA0, 0x1FB0, 0x0300, 0x0300, + 0x1FC0, 0x1FD0, 0x0C00, 0x1FE0, 0x0530, 0x0540, 0x1FF0, 0x2000, 0x2010, 0x2020, 0x2030, 0x08C0, + 0x08C0, +/* INDEX_BLOCK: -- 0x06E4..0x0714 -- */ + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x0300, 0x0300, 0x0300, 0x2040, 0x2050, 0x2060, + 0x1E10, 0x08C0, 0x0300, 0x0300, 0x0300, 0x2070, 0x2080, 0x0C00, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x0300, 0x0300, 0x2090, 0x20A0, 0x20B0, 0x20C0, + 0x08C0, 0x08C0, 0x0300, 0x0300, 0x0300, 0x20D0, 0x20E0, 0x0C00, 0x20F0, 0x08C0, 0x0300, 0x0300, + 0x2100, +/* INDEX_BLOCK: -- 0x0715..0x0745 -- */ + 0x2110, 0x0C00, 0x08C0, 0x08C0, 0x08C0, 0x0300, 0x0AD0, 0x2120, 0x2130, 0x13A0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x0300, 0x0300, 0x1F70, + 0x2140, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x0090, 0x0090, 0x00B0, 0x00B0, 0x0940, + 0x2150, 0x2160, 0x2170, 0x0300, 0x2180, 0x2190, 0x0C00, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x21A0, + 0x0300, +/* INDEX_BLOCK: -- 0x0746..0x0776 -- */ + 0x0300, 0x21B0, 0x21C0, 0x08C0, 0x21D0, 0x0300, 0x0300, 0x21E0, 0x21F0, 0x2200, 0x0300, 0x0300, + 0x2210, 0x2220, 0x2230, 0x0300, 0x0300, 0x0300, 0x0300, 0x0C40, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x0540, 0x0300, 0x2090, 0x2240, 0x2250, 0x0940, 0x0AF0, 0x2260, 0x0300, 0x2270, 0x2280, 0x2290, + 0x08C0, +/* INDEX_BLOCK: -- 0x0777..0x07A7 -- */ + 0x08C0, 0x08C0, 0x08C0, 0x22A0, 0x0300, 0x0300, 0x22B0, 0x22C0, 0x0C00, 0x22D0, 0x0300, 0x22E0, + 0x22F0, 0x0C00, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x0300, 0x2300, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x0640, 0x10F0, + 0x2310, +/* INDEX_BLOCK: -- 0x07A8..0x07D8 -- */ + 0x2320, 0x2330, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, +/* INDEX_BLOCK: -- 0x07D9..0x0809 -- */ + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0CF0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x1100, 0x1100, 0x1100, 0x1100, 0x1100, 0x1100, 0x2340, + 0x2350, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x2360, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, +/* INDEX_BLOCK: -- 0x080A..0x083A -- */ + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x2370, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, +/* INDEX_BLOCK: -- 0x083B..0x086B -- */ + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0C80, 0x2380, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, +/* INDEX_BLOCK: -- 0x086C..0x089C -- */ + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, +/* INDEX_BLOCK: -- 0x089D..0x08CD -- */ + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x13A0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, +/* INDEX_BLOCK: -- 0x08CE..0x08FE -- */ + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, +/* INDEX_BLOCK: -- 0x08FF..0x092F -- */ + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0C40, 0x0300, 0x0C80, 0x1730, 0x0300, 0x0300, 0x0300, 0x0300, 0x0C80, 0x0C00, 0x0300, + 0x0CC0, 0x2390, 0x0300, 0x0300, 0x0300, 0x23A0, 0x23B0, 0x23C0, 0x23D0, 0x23E0, 0x0300, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, +/* INDEX_BLOCK: -- 0x0930..0x0960 -- */ + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x0090, 0x0090, 0x00B0, 0x00B0, 0x10F0, 0x23F0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x0300, 0x0300, 0x0300, 0x0300, 0x2400, 0x2410, 0x2420, + 0x2420, +/* INDEX_BLOCK: -- 0x0961..0x0991 -- */ + 0x2430, 0x2440, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x2450, 0x2460, 0x0640, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, +/* INDEX_BLOCK: -- 0x0992..0x09C2 -- */ + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x2470, +/* INDEX_BLOCK: -- 0x09C3..0x09F3 -- */ + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, +/* INDEX_BLOCK: -- 0x09F4..0x0A24 -- */ + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0C70, 0x08C0, 0x08C0, 0x2480, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, +/* INDEX_BLOCK: -- 0x0A25..0x0A55 -- */ + 0x08C0, 0x08C0, 0x2490, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x24A0, 0x08C0, 0x08C0, + 0x24A0, 0x24B0, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, +/* INDEX_BLOCK: -- 0x0A56..0x0A86 -- */ + 0x0300, 0x0CE0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, +/* INDEX_BLOCK: -- 0x0A87..0x0AB7 -- */ + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x0300, +/* INDEX_BLOCK: -- 0x0AB8..0x0AE8 -- */ + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0470, 0x0970, 0x0C40, 0x24C0, 0x24D0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, +/* INDEX_BLOCK: -- 0x0AE9..0x0B19 -- */ + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x0200, 0x0200, 0x24E0, + 0x0200, 0x24F0, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x1430, 0x08C0, 0x08C0, + 0x08C0, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, + 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x1440, 0x0D10, 0x0D10, 0x2500, 0x0D10, 0x0D10, 0x0D10, 0x2510, + 0x2520, +/* INDEX_BLOCK: -- 0x0B1A..0x0B4A -- */ + 0x2530, 0x0D10, 0x2540, 0x0D10, 0x0D10, 0x0D10, 0x1200, 0x08C0, 0x0D10, 0x0D10, 0x0D10, 0x0D10, + 0x2550, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x10F0, 0x2560, + 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x11F0, 0x10F0, 0x1D00, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x0090, 0x2570, 0x00B0, 0x2580, 0x2590, 0x25A0, 0x0F10, 0x0090, + 0x25B0, +/* INDEX_BLOCK: -- 0x0B4B..0x0B7B -- */ + 0x25C0, 0x25D0, 0x25E0, 0x25F0, 0x0090, 0x2570, 0x00B0, 0x2600, 0x2610, 0x00B0, 0x2620, 0x2630, + 0x2640, 0x2650, 0x0090, 0x2660, 0x00B0, 0x0090, 0x2570, 0x00B0, 0x2580, 0x2590, 0x00B0, 0x0F10, + 0x0090, 0x25B0, 0x2650, 0x0090, 0x2660, 0x00B0, 0x0090, 0x2570, 0x00B0, 0x2670, 0x0090, 0x2680, + 0x2690, 0x26A0, 0x26B0, 0x00B0, 0x26C0, 0x0090, 0x26D0, 0x26E0, 0x26F0, 0x2700, 0x00B0, 0x2710, + 0x0090, +/* INDEX_BLOCK: -- 0x0B7C..0x0BAC -- */ + 0x2720, 0x00B0, 0x2730, 0x2740, 0x2740, 0x2740, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, + 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, + 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, + 0x0D10, 0x0D10, 0x0200, 0x0200, 0x0200, 0x2750, 0x0200, 0x0200, 0x2760, 0x2770, 0x2780, 0x2790, + 0x02D0, +/* INDEX_BLOCK: -- 0x0BAD..0x0BDD -- */ + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x27A0, 0x27B0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x27C0, 0x27D0, 0x27E0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, +/* INDEX_BLOCK: -- 0x0BDE..0x0C0E -- */ + 0x08C0, 0x08C0, 0x08C0, 0x0300, 0x0300, 0x0970, 0x27F0, 0x2800, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x0300, 0x2810, 0x08C0, 0x0300, 0x0300, 0x2820, 0x2830, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, +/* INDEX_BLOCK: -- 0x0C0F..0x0C3F -- */ + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x2840, 0x0C80, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x2850, 0x24F0, 0x08C0, 0x08C0, 0x0090, 0x0090, 0x25B0, + 0x00B0, 0x2860, 0x1730, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, +/* INDEX_BLOCK: -- 0x0C40..0x0C70 -- */ + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x1F50, 0x10F0, 0x10F0, 0x2870, 0x2880, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x1F50, +/* INDEX_BLOCK: -- 0x0C71..0x0CA1 -- */ + 0x10F0, 0x2890, 0x28A0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x28B0, 0x0300, 0x28C0, 0x28D0, 0x28E0, 0x28F0, 0x2900, 0x2910, 0x2920, + 0x0CE0, 0x2930, 0x0CE0, 0x08C0, 0x08C0, 0x08C0, 0x2940, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x0D10, + 0x0D10, +/* INDEX_BLOCK: -- 0x0CA2..0x0CD2 -- */ + 0x1450, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x1430, 0x14E0, 0x2950, 0x2950, 0x2950, + 0x0D10, 0x1440, 0x2960, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, + 0x2970, 0x08C0, 0x08C0, 0x08C0, 0x2980, 0x0D10, 0x2990, 0x0D10, 0x0D10, 0x1450, 0x29A0, 0x29B0, + 0x1440, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x0D10, 0x0D10, + 0x0D10, +/* INDEX_BLOCK: -- 0x0CD3..0x0D03 -- */ + 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, + 0x29C0, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, + 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, + 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, + 0x0D10, +/* INDEX_BLOCK: -- 0x0D04..0x0D34 -- */ + 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x29D0, 0x1AD0, 0x1AD0, + 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x1430, 0x0D10, 0x0D10, 0x0D10, 0x0D10, + 0x0D10, 0x29A0, 0x1450, 0x1AE0, 0x1450, 0x0D10, 0x0D10, 0x0D10, 0x29E0, 0x0B00, 0x0D10, 0x0D10, + 0x29E0, 0x0D10, 0x2970, 0x29B0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x0D10, 0x0D10, 0x0D10, 0x0D10, + 0x0D10, +/* INDEX_BLOCK: -- 0x0D35..0x0D65 -- */ + 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, + 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x1430, 0x2970, 0x29F0, 0x11F0, 0x0D10, 0x1AD0, 0x1200, 0x1440, + 0x0B00, 0x29E0, 0x11F0, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, + 0x2A00, 0x0D10, 0x0D10, 0x1200, 0x08C0, 0x08C0, 0x0C00, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, +/* INDEX_BLOCK: -- 0x0D66..0x0D96 -- */ + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x0640, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, +/* INDEX_BLOCK: -- 0x0D97..0x0DC7 -- */ + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x1520, 0x08C0, 0x08C0, 0x0640, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, +/* INDEX_BLOCK: -- 0x0DC8..0x0DF8 -- */ + 0x2A10, 0x0640, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x2A20, 0x0640, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, +/* INDEX_BLOCK: -- 0x0DF9..0x0E29 -- */ + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x2A30, 0x0640, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, +/* INDEX_BLOCK: -- 0x0E2A..0x0E5A -- */ + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x0640, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, +/* INDEX_BLOCK: -- 0x0E5B..0x0E8B -- */ + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0CC0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, +/* INDEX_BLOCK: -- 0x0E8C..0x0EBC -- */ + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x0640, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, +/* INDEX_BLOCK: -- 0x0EBD..0x0EED -- */ + 0x08C0, 0x08C0, 0x08C0, 0x2A40, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, +/* INDEX_BLOCK: -- 0x0EEE..0x0F1E -- */ + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x2A50, 0x08C0, 0x2A60, 0x2A60, 0x2A60, 0x2A60, 0x2A60, 0x2A60, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, + 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, +/* INDEX_BLOCK: -- 0x0F1F..0x0F4F -- */ + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x1890, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, +/* INDEX_BLOCK: -- 0x0F50..0x0F80 -- */ + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x2A70, 0x1890, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, +/* INDEX_BLOCK: -- 0x0F81..0x0F83 -- */ + 0x08C0, 0x08C0, 0x2A80 +}; + +static const SBUInt16 BranchGeneralCategoryIndexes[1422] = { + 0x0000, 0x0031, 0x0062, 0x0093, 0x00C4, 0x00F5, 0x0126, 0x0157, 0x0188, 0x01B9, 0x01EA, 0x021B, + 0x024C, 0x027D, 0x02AE, 0x02DF, 0x0310, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0372, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x03A3, 0x03D4, 0x0405, 0x0436, 0x0467, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0498, 0x04C9, + 0x0341, 0x04FA, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x052B, 0x055C, 0x058D, + 0x05BE, 0x05EF, 0x0620, 0x0651, 0x0682, 0x06B3, 0x06E4, 0x0715, 0x0746, 0x0777, 0x07A8, 0x07D9, + 0x0341, 0x0341, 0x0341, 0x080A, 0x083B, 0x0341, 0x0341, 0x0341, 0x0341, 0x086C, 0x089D, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x08CE, 0x08FF, 0x0930, + 0x0961, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0992, 0x09C3, 0x09F4, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0A25, 0x0A56, 0x0341, + 0x0A87, 0x0AB8, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0AE9, 0x0B1A, 0x0B4B, 0x0B7C, 0x0341, + 0x0BAD, 0x0BDE, 0x0341, 0x0C0F, 0x0C40, 0x0C71, 0x0CA2, 0x0CD3, 0x0D04, 0x0D35, 0x0341, 0x0D66, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0D97, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0DC8, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0DF9, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0E2A, 0x0341, 0x0341, 0x0341, 0x0E5B, 0x0341, 0x0E8C, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0EBD, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0EEE, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0F1F, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0F50, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, + 0x0341, 0x0341, 0x0341, 0x0341, 0x0341, 0x0F81 +}; + +SB_INTERNAL SBGeneralCategory LookupGeneralCategory(SBCodepoint codepoint) { + if (codepoint <= 0x10FFFD) { + return PrimaryGeneralCategoryData[ + MainGeneralCategoryIndexes[ + BranchGeneralCategoryIndexes[ + codepoint / 0x0310 + ] + (codepoint % 0x0310) / 0x0010 + ] + (codepoint % 0x0010) + ]; + } + + return Cn; +} + +#undef Cc +#undef Cf +#undef Cn +#undef Co +#undef Cs +#undef Ll +#undef Lm +#undef Lo +#undef Lt +#undef Lu +#undef Mc +#undef Me +#undef Mn +#undef Nd +#undef Nl +#undef No +#undef Pc +#undef Pd +#undef Pe +#undef Pf +#undef Pi +#undef Po +#undef Ps +#undef Sc +#undef Sk +#undef Sm +#undef So +#undef Zl +#undef Zp +#undef Zs diff --git a/third_party/sheenbidi/source/GeneralCategoryLookup.h b/third_party/sheenbidi/source/GeneralCategoryLookup.h new file mode 100644 index 0000000..9a0f6aa --- /dev/null +++ b/third_party/sheenbidi/source/GeneralCategoryLookup.h @@ -0,0 +1,16 @@ +/* + * Automatically generated by SheenBidiGenerator tool. + * DO NOT EDIT!! + */ + +#ifndef _SB_INTERNAL_GENERAL_CATEGORY_LOOKUP_H +#define _SB_INTERNAL_GENERAL_CATEGORY_LOOKUP_H + +#include +#include + +#include "SBBase.h" + +SB_INTERNAL SBGeneralCategory LookupGeneralCategory(SBCodepoint codepoint); + +#endif diff --git a/third_party/sheenbidi/source/IsolatingRun.c b/third_party/sheenbidi/source/IsolatingRun.c new file mode 100644 index 0000000..07b38e3 --- /dev/null +++ b/third_party/sheenbidi/source/IsolatingRun.c @@ -0,0 +1,537 @@ +/* + * Copyright (C) 2014-2022 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ + +#include + +#include "BidiChain.h" +#include "BracketQueue.h" +#include "BracketType.h" +#include "LevelRun.h" +#include "PairingLookup.h" +#include "SBAssert.h" +#include "SBBase.h" +#include "SBLog.h" +#include "IsolatingRun.h" + +static void ResolveAvailableBracketPairs(IsolatingRunRef isolatingRun); + +static void AttachLevelRunLinks(IsolatingRunRef isolatingRun) +{ + BidiChainRef chain = isolatingRun->bidiChain; + LevelRunRef baseLevelRun = isolatingRun->baseLevelRun; + LevelRunRef current; + LevelRunRef next; + + isolatingRun->_originalLink = BidiChainGetNext(chain, chain->roller); + BidiChainSetNext(chain, chain->roller, baseLevelRun->firstLink); + + /* Iterate over level runs and attach their links to form an isolating run. */ + for (current = baseLevelRun; (next = current->next); current = next) { + BidiChainSetNext(chain, current->lastLink, next->firstLink); + } + BidiChainSetNext(chain, current->lastLink, chain->roller); + + isolatingRun->_lastLevelRun = current; + isolatingRun->_sos = RunExtrema_SOR(baseLevelRun->extrema); + + if (!RunKindIsPartialIsolate(baseLevelRun->kind)) { + isolatingRun->_eos = RunExtrema_EOR(current->extrema); + } else { + SBLevel paragraphLevel = isolatingRun->paragraphLevel; + SBLevel runLevel = baseLevelRun->level; + SBLevel eosLevel = (runLevel > paragraphLevel ? runLevel : paragraphLevel); + isolatingRun->_eos = ((eosLevel & 1) ? SBBidiTypeR : SBBidiTypeL); + } +} + +static void AttachOriginalLinks(IsolatingRunRef isolatingRun) +{ + BidiChainRef chain = isolatingRun->bidiChain; + LevelRunRef current; + + BidiChainSetNext(chain, chain->roller, isolatingRun->_originalLink); + + /* Iterate over level runs and attach original subsequent links. */ + for (current = isolatingRun->baseLevelRun; current; current = current->next) { + BidiChainSetNext(chain, current->lastLink, current->subsequentLink); + } +} + +static BidiLink ResolveWeakTypes(IsolatingRunRef isolatingRun) +{ + BidiChainRef chain = isolatingRun->bidiChain; + BidiLink roller = chain->roller; + BidiLink link; + + BidiLink priorLink; + SBBidiType sos; + + SBBidiType w1PriorType; + SBBidiType w2StrongType; + SBBidiType w4PriorType; + SBBidiType w5PriorType; + SBBidiType w7StrongType; + + priorLink = roller; + sos = isolatingRun->_sos; + + w1PriorType = sos; + w2StrongType = sos; + + BidiChainForEach(chain, roller, link) { + SBBidiType type = BidiChainGetType(chain, link); + SBBoolean forceMerge = SBFalse; + + /* Rule W1 */ + if (type == SBBidiTypeNSM) { + /* Change the 'type' variable as well because it can be EN on which W2 depends. */ + type = (SBBidiTypeIsIsolate(w1PriorType) ? SBBidiTypeON : w1PriorType); + BidiChainSetType(chain, link, type); + + /* Fix for 3rd point of rule N0. */ + if (w1PriorType == SBBidiTypeON) { + forceMerge = SBTrue; + } + } + w1PriorType = type; + + /* Rule W2 */ + if (type == SBBidiTypeEN) { + if (w2StrongType == SBBidiTypeAL) { + BidiChainSetType(chain, link, SBBidiTypeAN); + } + } + /* + * Rule W3 + * NOTE: It is safe to apply W3 in 'else-if' statement because it only depends on type AL. + * Even if W2 changes EN to AN, there won't be any harm. + */ + else if (type == SBBidiTypeAL) { + BidiChainSetType(chain, link, SBBidiTypeR); + } + + if (SBBidiTypeIsStrong(type)) { + /* Save the strong type as it is checked in W2. */ + w2StrongType = type; + } + + if ((type != SBBidiTypeON && BidiChainGetType(chain, priorLink) == type) || forceMerge) { + BidiChainAbandonNext(chain, priorLink); + } else { + priorLink = link; + } + } + + priorLink = roller; + w4PriorType = sos; + w5PriorType = sos; + w7StrongType = sos; + + BidiChainForEach(chain, roller, link) { + SBBidiType type = BidiChainGetType(chain, link); + SBBidiType nextType = BidiChainGetType(chain, BidiChainGetNext(chain, link)); + + /* Rule W4 */ + if (BidiChainIsSingle(chain, link) + && SBBidiTypeIsNumberSeparator(type) + && SBBidiTypeIsNumber(w4PriorType) + && (w4PriorType == nextType) + && (w4PriorType == SBBidiTypeEN || type == SBBidiTypeCS)) + { + /* Change the current type as well because it can be EN on which W5 depends. */ + type = w4PriorType; + BidiChainSetType(chain, link, type); + } + w4PriorType = type; + + /* Rule W5 */ + if (type == SBBidiTypeET && (w5PriorType == SBBidiTypeEN || nextType == SBBidiTypeEN)) { + /* Change the current type as well because it is EN on which W7 depends. */ + type = SBBidiTypeEN; + BidiChainSetType(chain, link, type); + } + w5PriorType = type; + + switch (type) { + /* Rule W6 */ + case SBBidiTypeET: + case SBBidiTypeCS: + case SBBidiTypeES: + BidiChainSetType(chain, link, SBBidiTypeON); + break; + + /* + * Rule W7 + * NOTE: W7 is expected to be applied after W6. However this is not the case here. The + * reason is that W6 can only create the type ON which is not tested in W7 by any + * means. So it won't affect the algorithm. + */ + case SBBidiTypeEN: + if (w7StrongType == SBBidiTypeL) { + BidiChainSetType(chain, link, SBBidiTypeL); + } + break; + + /* + * Save the strong type for W7. + * NOTE: The strong type is expected to be saved after applying W7 because W7 itself creates + * a strong type. However the strong type being saved here is based on the type after + * W5. This won't effect the algorithm because a single link contains all consecutive + * EN types. This means that even if W7 creates a strong type, it will be saved in + * next iteration. + */ + case SBBidiTypeL: + case SBBidiTypeR: + w7StrongType = type; + break; + } + + if (type != SBBidiTypeON && BidiChainGetType(chain, priorLink) == type) { + BidiChainAbandonNext(chain, priorLink); + } else { + priorLink = link; + } + } + + return priorLink; +} + +static SBBoolean ResolveBrackets(IsolatingRunRef isolatingRun) +{ + const SBCodepointSequence *sequence = isolatingRun->codepointSequence; + SBUInteger paragraphOffset = isolatingRun->paragraphOffset; + BracketQueueRef queue = &isolatingRun->_bracketQueue; + BidiChainRef chain = isolatingRun->bidiChain; + BidiLink roller = chain->roller; + BidiLink link; + + BidiLink priorStrongLink; + SBLevel runLevel; + + priorStrongLink = BidiLinkNone; + runLevel = isolatingRun->baseLevelRun->level; + + BracketQueueReset(queue, SBLevelAsNormalBidiType(runLevel)); + + BidiChainForEach(chain, roller, link) { + SBUInteger stringIndex; + SBCodepoint codepoint; + SBBidiType type; + + SBCodepoint bracketValue; + BracketType bracketType; + + type = BidiChainGetType(chain, link); + + switch (type) { + case SBBidiTypeON: + stringIndex = BidiChainGetOffset(chain, link) + paragraphOffset; + codepoint = SBCodepointSequenceGetCodepointAt(sequence, &stringIndex); + bracketValue = LookupBracketPair(codepoint, &bracketType); + + switch (bracketType) { + case BracketTypeOpen: + if (queue->count < BracketQueueGetMaxCapacity()) { + if (!BracketQueueEnqueue(queue, priorStrongLink, link, bracketValue)) { + return SBFalse; + } + } else { + goto Resolve; + } + break; + + case BracketTypeClose: + if (queue->count != 0) { + BracketQueueClosePair(queue, link, codepoint); + + if (BracketQueueShouldDequeue(queue)) { + ResolveAvailableBracketPairs(isolatingRun); + } + } + break; + } + break; + + case SBBidiTypeEN: + case SBBidiTypeAN: + type = SBBidiTypeR; + + case SBBidiTypeR: + case SBBidiTypeL: + if (queue->count != 0) { + BracketQueueSetStrongType(queue, type); + } + + priorStrongLink = link; + break; + } + } + +Resolve: + ResolveAvailableBracketPairs(isolatingRun); + return SBTrue; +} + +static void ResolveAvailableBracketPairs(IsolatingRunRef isolatingRun) +{ + BracketQueueRef queue = &isolatingRun->_bracketQueue; + BidiChainRef chain = isolatingRun->bidiChain; + + SBLevel runLevel; + SBBidiType embeddingDirection; + SBBidiType oppositeDirection; + + runLevel = isolatingRun->baseLevelRun->level; + embeddingDirection = SBLevelAsNormalBidiType(runLevel); + oppositeDirection = SBLevelAsOppositeBidiType(runLevel); + + while (queue->count != 0) { + BidiLink openingLink = BracketQueueGetOpeningLink(queue); + BidiLink closingLink = BracketQueueGetClosingLink(queue); + + if ((openingLink != BidiLinkNone) && (closingLink != BidiLinkNone)) { + SBBidiType innerStrongType; + SBBidiType pairType; + + innerStrongType = BracketQueueGetStrongType(queue); + + /* Rule: N0.b */ + if (innerStrongType == embeddingDirection) { + pairType = innerStrongType; + } + /* Rule: N0.c */ + else if (innerStrongType == oppositeDirection) { + BidiLink priorStrongLink; + SBBidiType priorStrongType; + + priorStrongLink = BracketQueueGetPriorStrongLink(queue); + + if (priorStrongLink != BidiLinkNone) { + BidiLink link; + + priorStrongType = BidiChainGetType(chain, priorStrongLink); + if (SBBidiTypeIsNumber(priorStrongType)) { + priorStrongType = SBBidiTypeR; + } + + link = BidiChainGetNext(chain, priorStrongLink); + + while (link != openingLink) { + SBBidiType type = BidiChainGetType(chain, link); + if (type == SBBidiTypeL || type == SBBidiTypeR) { + priorStrongType = type; + } + + link = BidiChainGetNext(chain, link); + } + } else { + priorStrongType = isolatingRun->_sos; + } + + /* Rule: N0.c.1 */ + if (priorStrongType == oppositeDirection) { + pairType = oppositeDirection; + } + /* Rule: N0.c.2 */ + else { + pairType = embeddingDirection; + } + } + /* Rule: N0.d */ + else { + pairType = SBBidiTypeNil; + } + + if (pairType != SBBidiTypeNil) { + /* Do the substitution */ + BidiChainSetType(chain, openingLink, pairType); + BidiChainSetType(chain, closingLink, pairType); + } + } + + BracketQueueDequeue(queue); + } +} + +static void ResolveNeutrals(IsolatingRunRef isolatingRun) +{ + BidiChainRef chain = isolatingRun->bidiChain; + BidiLink roller = chain->roller; + BidiLink link; + + SBLevel runLevel; + SBBidiType strongType; + BidiLink neutralLink; + + runLevel = isolatingRun->baseLevelRun->level; + strongType = isolatingRun->_sos; + neutralLink = BidiLinkNone; + + BidiChainForEach(chain, roller, link) { + SBBidiType type = BidiChainGetType(chain, link); + SBBidiType nextType; + + SBAssert(SBBidiTypeIsStrongOrNumber(type) || SBBidiTypeIsNeutralOrIsolate(type)); + + switch (type) { + case SBBidiTypeL: + strongType = SBBidiTypeL; + break; + + case SBBidiTypeR: + case SBBidiTypeEN: + case SBBidiTypeAN: + strongType = SBBidiTypeR; + break; + + case SBBidiTypeB: + case SBBidiTypeS: + case SBBidiTypeWS: + case SBBidiTypeON: + case SBBidiTypeLRI: + case SBBidiTypeRLI: + case SBBidiTypeFSI: + case SBBidiTypePDI: + if (neutralLink == BidiLinkNone) { + neutralLink = link; + } + + nextType = BidiChainGetType(chain, BidiChainGetNext(chain, link)); + if (SBBidiTypeIsNumber(nextType)) { + nextType = SBBidiTypeR; + } else if (nextType == SBBidiTypeNil) { + nextType = isolatingRun->_eos; + } + + if (SBBidiTypeIsStrong(nextType)) { + /* Rules N1, N2 */ + SBBidiType resolvedType = (strongType == nextType + ? strongType + : SBLevelAsNormalBidiType(runLevel)); + + do { + BidiChainSetType(chain, neutralLink, resolvedType); + neutralLink = BidiChainGetNext(chain, neutralLink); + } while (neutralLink != BidiChainGetNext(chain, link)); + + neutralLink = BidiLinkNone; + } + break; + } + } +} + +static void ResolveImplicitLevels(IsolatingRunRef isolatingRun) +{ + BidiChainRef chain = isolatingRun->bidiChain; + BidiLink roller = chain->roller; + BidiLink link; + + SBLevel runLevel = isolatingRun->baseLevelRun->level; + + if ((runLevel & 1) == 0) { + BidiChainForEach(chain, roller, link) { + SBBidiType type = BidiChainGetType(chain, link); + SBLevel level = BidiChainGetLevel(chain, link); + + SBAssert(SBBidiTypeIsStrongOrNumber(type)); + + /* Rule I1 */ + if (type == SBBidiTypeR) { + BidiChainSetLevel(chain, link, level + 1); + } else if (type != SBBidiTypeL) { + BidiChainSetLevel(chain, link, level + 2); + } + } + } else { + BidiChainForEach(chain, roller, link) { + SBBidiType type = BidiChainGetType(chain, link); + SBLevel level = BidiChainGetLevel(chain, link); + + SBAssert(SBBidiTypeIsStrongOrNumber(type)); + + /* Rule I2 */ + if (type != SBBidiTypeR) { + BidiChainSetLevel(chain, link, level + 1); + } + } + } +} + +SB_INTERNAL void IsolatingRunInitialize(IsolatingRunRef isolatingRun) +{ + BracketQueueInitialize(&isolatingRun->_bracketQueue); +} + +SB_INTERNAL SBBoolean IsolatingRunResolve(IsolatingRunRef isolatingRun) +{ + BidiLink lastLink; + BidiLink subsequentLink; + + SB_LOG_BLOCK_OPENER("Identified Isolating Run"); + + /* Attach level run links to form isolating run. */ + AttachLevelRunLinks(isolatingRun); + /* Save last subsequent link. */ + subsequentLink = isolatingRun->_lastLevelRun->subsequentLink; + + SB_LOG_STATEMENT("Range", 1, SB_LOG_RUN_RANGE(isolatingRun)); + SB_LOG_STATEMENT("Types", 1, SB_LOG_RUN_TYPES(isolatingRun)); + SB_LOG_STATEMENT("Level", 1, SB_LOG_LEVEL(isolatingRun->baseLevelRun->level)); + SB_LOG_STATEMENT("SOS", 1, SB_LOG_BIDI_TYPE(isolatingRun->_sos)); + SB_LOG_STATEMENT("EOS", 1, SB_LOG_BIDI_TYPE(isolatingRun->_eos)); + + /* Rules W1-W7 */ + lastLink = ResolveWeakTypes(isolatingRun); + SB_LOG_BLOCK_OPENER("Resolved Weak Types"); + SB_LOG_STATEMENT("Types", 1, SB_LOG_RUN_TYPES(isolatingRun)); + SB_LOG_BLOCK_CLOSER(); + + /* Rule N0 */ + if (!ResolveBrackets(isolatingRun)) { + return SBFalse; + } + + SB_LOG_BLOCK_OPENER("Resolved Brackets"); + SB_LOG_STATEMENT("Types", 1, SB_LOG_RUN_TYPES(isolatingRun)); + SB_LOG_BLOCK_CLOSER(); + + /* Rules N1, N2 */ + ResolveNeutrals(isolatingRun); + SB_LOG_BLOCK_OPENER("Resolved Neutrals"); + SB_LOG_STATEMENT("Types", 1, SB_LOG_RUN_TYPES(isolatingRun)); + SB_LOG_BLOCK_CLOSER(); + + /* Rules I1, I2 */ + ResolveImplicitLevels(isolatingRun); + SB_LOG_BLOCK_OPENER("Resolved Implicit Levels"); + SB_LOG_STATEMENT("Levels", 1, SB_LOG_RUN_LEVELS(isolatingRun)); + SB_LOG_BLOCK_CLOSER(); + + /* Re-attach original links. */ + AttachOriginalLinks(isolatingRun); + /* Attach new final link (of isolating run) with last subsequent link. */ + BidiChainSetNext(isolatingRun->bidiChain, lastLink, subsequentLink); + + SB_LOG_BLOCK_CLOSER(); + + return SBTrue; +} + +SB_INTERNAL void IsolatingRunFinalize(IsolatingRunRef isolatingRun) +{ + BracketQueueFinalize(&isolatingRun->_bracketQueue); +} diff --git a/third_party/sheenbidi/source/IsolatingRun.h b/third_party/sheenbidi/source/IsolatingRun.h new file mode 100644 index 0000000..fddf01b --- /dev/null +++ b/third_party/sheenbidi/source/IsolatingRun.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2014-2022 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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 _SB_INTERNAL_ISOLATING_RUN_H +#define _SB_INTERNAL_ISOLATING_RUN_H + +#include + +#include "BidiChain.h" +#include "BracketQueue.h" +#include "LevelRun.h" +#include "SBBase.h" +#include "SBCodepointSequence.h" + +typedef struct _IsolatingRun { + const SBCodepointSequence *codepointSequence; + const SBBidiType *bidiTypes; + BidiChainRef bidiChain; + LevelRunRef baseLevelRun; + LevelRunRef _lastLevelRun; + BracketQueue _bracketQueue; + SBUInteger paragraphOffset; + BidiLink _originalLink; + SBBidiType _sos; + SBBidiType _eos; + SBLevel paragraphLevel; +} IsolatingRun, *IsolatingRunRef; + +SB_INTERNAL void IsolatingRunInitialize(IsolatingRunRef isolatingRun); +SB_INTERNAL SBBoolean IsolatingRunResolve(IsolatingRunRef isolatingRun); + +SB_INTERNAL void IsolatingRunFinalize(IsolatingRunRef isolatingRun); + +#endif diff --git a/third_party/sheenbidi/source/LevelRun.c b/third_party/sheenbidi/source/LevelRun.c new file mode 100644 index 0000000..267a3ac --- /dev/null +++ b/third_party/sheenbidi/source/LevelRun.c @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2014-2019 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ + +#include +#include + +#include "BidiChain.h" +#include "RunExtrema.h" +#include "RunKind.h" +#include "SBAssert.h" +#include "LevelRun.h" + +SB_INTERNAL void LevelRunInitialize(LevelRunRef levelRun, + BidiChainRef bidiChain, BidiLink firstLink, BidiLink lastLink, + SBBidiType sor, SBBidiType eor) +{ + SBBidiType firstType = BidiChainGetType(bidiChain, firstLink); + SBBidiType lastType = BidiChainGetType(bidiChain, lastLink); + + levelRun->next = NULL; + levelRun->firstLink = firstLink; + levelRun->lastLink = lastLink; + levelRun->subsequentLink = BidiChainGetNext(bidiChain, lastLink); + levelRun->extrema = RunExtremaMake(sor, eor); + levelRun->kind = RunKindMake + ( + SBBidiTypeIsIsolateInitiator(lastType), + SBBidiTypeIsIsolateTerminator(firstType) + ); + levelRun->level = BidiChainGetLevel(bidiChain, firstLink); +} + +SB_INTERNAL void LevelRunAttach(LevelRunRef levelRun, LevelRunRef next) +{ + /* Only the runs of same level can be attached. */ + SBAssert(levelRun->level == next->level); + /* No other run can be attached with a simple run. */ + SBAssert(!RunKindIsSimple(levelRun->kind)); + /* No other run can be attached with a complete isolating run. */ + SBAssert(!RunKindIsCompleteIsolate(levelRun->kind)); + /* Only a terminating run can be attached with an isolating run. */ + SBAssert(RunKindIsIsolate(levelRun->kind) && RunKindIsTerminating(next->kind)); + /* The next run must be unattached. */ + SBAssert(!RunKindIsAttachedTerminating(next->kind)); + + if (RunKindIsTerminating(next->kind)) { + RunKindMakeAttached(next->kind); + } + + if (RunKindIsIsolate(levelRun->kind)) { + RunKindMakeComplete(levelRun->kind); + } + + levelRun->next = next; +} diff --git a/third_party/sheenbidi/source/LevelRun.h b/third_party/sheenbidi/source/LevelRun.h new file mode 100644 index 0000000..e7e392d --- /dev/null +++ b/third_party/sheenbidi/source/LevelRun.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2014-2019 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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 _SB_INTERNAL_LEVEL_RUN_H +#define _SB_INTERNAL_LEVEL_RUN_H + +#include + +#include "BidiChain.h" +#include "RunExtrema.h" +#include "RunKind.h" +#include "SBBase.h" + +typedef struct _LevelRun { + struct _LevelRun *next; /**< Reference to the next sequence of run links. */ + BidiLink firstLink; /**< First link of the run. */ + BidiLink lastLink; /**< Last link of the run. */ + BidiLink subsequentLink; /**< Subsequent link of the run. */ + RunExtrema extrema; + RunKind kind; + SBLevel level; +} LevelRun, *LevelRunRef; + +SB_INTERNAL void LevelRunInitialize(LevelRunRef levelRun, + BidiChainRef bidiChain, BidiLink firstLink, BidiLink lastLink, + SBBidiType sor, SBBidiType eor); +SB_INTERNAL void LevelRunAttach(LevelRunRef levelRun, LevelRunRef next); + +#endif diff --git a/third_party/sheenbidi/source/PairingLookup.c b/third_party/sheenbidi/source/PairingLookup.c new file mode 100644 index 0000000..9cd7063 --- /dev/null +++ b/third_party/sheenbidi/source/PairingLookup.c @@ -0,0 +1,267 @@ +/* + * Automatically generated by SheenBidiGenerator tool. + * DO NOT EDIT!! + * + * REQUIRED MEMORY: (37)+2310+(617*2) = 3618 Bytes + */ + +#include "PairingLookup.h" + +static const SBInt16 PairDifferences[37] = { + 0, 1, -1, 2, -2, 16, -16, 3, -3, 2016, 2527, 1923, 1914, 1918, + 2250, 138, 7, -7, 1824, 2104, 2108, 2106, 1316, -138, 8, -8, -1316, + -1914, -1918, -1923, -1824, -2016, -2104, -2106, -2108, -2250, -2527 +}; + +static const SBUInt8 PairData[2310] = { +/* DATA_BLOCK: -- 0x0000..0x0069 -- */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 65, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 3, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, 0, 132, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* DATA_BLOCK: -- 0x006A..0x00D3 -- */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, 0, + 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* DATA_BLOCK: -- 0x00D4..0x013D -- */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* DATA_BLOCK: -- 0x013E..0x01A7 -- */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 65, 130, 65, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* DATA_BLOCK: -- 0x01A8..0x0211 -- */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 65, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* DATA_BLOCK: -- 0x0212..0x027B -- */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 65, 130, 0, 0, 0, 0, 0, +/* DATA_BLOCK: -- 0x027C..0x02E5 -- */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 130, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 65, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* DATA_BLOCK: -- 0x02E6..0x034F -- */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 7, 7, 7, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 10, 11, 12, 13, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, + 0, 0, 0, 15, 0, 16, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 1, + 2, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, +/* DATA_BLOCK: -- 0x0350..0x03B9 -- */ + 0, 0, 0, 0, 0, 0, 1, 2, 1, 2, 1, 2, 1, 2, 0, 0, 1, 2, 1, + 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, + 1, 2, 1, 2, 1, 2, 1, 2, 0, 0, 0, 1, 2, 1, 2, 0, 0, 0, 0, + 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 19, 0, 20, 21, + 0, 21, 0, 0, 0, 0, 1, 2, 1, 2, 1, 2, 1, 2, 22, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* DATA_BLOCK: -- 0x03BA..0x0423 -- */ + 0, 1, 2, 1, 2, 23, 0, 0, 1, 2, 0, 0, 0, 0, 1, 2, 1, 2, 1, + 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, + 0, 0, 1, 2, 24, 24, 24, 0, 16, 16, 0, 0, 25, 25, 25, 17, 17, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 65, 130, 65, 130, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 65, 130, 0, 0, 0, 0, 0, 0, 0, +/* DATA_BLOCK: -- 0x0424..0x048D -- */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, + 130, 65, 130, 65, 130, 65, 130, 65, 130, 65, 130, 65, 130, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* DATA_BLOCK: -- 0x048E..0x04F7 -- */ + 0, 0, 0, 1, 2, 65, 130, 0, 1, 2, 0, 3, 0, 4, 0, 0, 0, 0, 0, + 0, 0, 1, 2, 0, 0, 0, 0, 0, 26, 1, 2, 0, 0, 0, 1, 2, 1, 2, + 65, 130, 65, 130, 65, 130, 65, 130, 65, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* DATA_BLOCK: -- 0x04F8..0x0561 -- */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 65, 130, 65, 130, 65, 130, 65, 130, 65, 130, 71, + 129, 66, 136, 65, 130, 65, 130, 65, 130, 65, 130, 0, 0, 27, 0, 0, 0, 0, 28, + 0, 0, 29, 1, 2, 0, 0, 1, 2, 1, 2, 1, 2, 1, 2, 0, 0, 0, 0, + 0, 0, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 1, 2, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, +/* DATA_BLOCK: -- 0x0562..0x05CB -- */ + 2, 0, 1, 2, 0, 0, 65, 130, 65, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 0, 0, + 1, 2, 0, 0, 65, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 2, 0, 0, + 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0, +/* DATA_BLOCK: -- 0x05CC..0x0635 -- */ + 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, + 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, + 1, 2, 1, 2, 1, 2, 1, 2, 0, 0, 0, +/* DATA_BLOCK: -- 0x0636..0x069F -- */ + 1, 2, 1, 2, 1, 2, 1, 2, 0, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, + 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, + 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 0, 0, 0, 0, 0, 0, 0, 32, + 0, 0, 0, 0, 33, 34, 33, 0, 0, 0, 0, 0, 0, 1, 2, 35, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 2, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* DATA_BLOCK: -- 0x06A0..0x0709 -- */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* DATA_BLOCK: -- 0x070A..0x0773 -- */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 2, 0, 0, 0, + 1, 2, 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 2, 0, 0, 1, 2, 65, 130, 65, 130, 65, 130, 65, 130, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 65, 130, 65, 130, 65, 130, 65, 130, 0, 0, 0, +/* DATA_BLOCK: -- 0x0774..0x07DD -- */ + 65, 130, 65, 130, 65, 130, 65, 130, 65, 130, 0, 0, 65, 130, 65, 130, 65, 130, 65, + 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* DATA_BLOCK: -- 0x07DE..0x0847 -- */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 130, 65, 130, 65, 130, 0, 0, 0, + 0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* DATA_BLOCK: -- 0x0848..0x08B1 -- */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 65, 130, 0, 0, 0, 0, 0, 0, +/* DATA_BLOCK: -- 0x08B2..0x0905 -- */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 4, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 67, 0, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, + 0, 132, 0, 65, 130, 0, 65, 130, +}; + +static const SBUInt16 PairIndexes[617] = { + 0x0000, 0x006A, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x013E, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x01A8, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x0212, 0x027C, 0x00D4, 0x00D4, 0x00D4, 0x02E6, 0x0350, + 0x03BA, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x0424, + 0x048E, 0x00D4, 0x00D4, 0x00D4, 0x04F8, 0x0562, 0x05CC, 0x0636, 0x00D4, 0x00D4, 0x06A0, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x070A, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x0774, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x07DE, 0x0848, 0x08B2 +}; + +SB_INTERNAL SBCodepoint LookupMirror(SBCodepoint codepoint) +{ + if (codepoint <= 0xFF63) { + SBInt16 diff = PairDifferences[ + PairData[ + PairIndexes[ + codepoint / 0x06A + ] + (codepoint % 0x06A) + ] & BracketTypeInverseMask + ]; + + if (diff != 0) { + return (codepoint + diff); + } + } + + return 0; +} + +SB_INTERNAL SBCodepoint LookupBracketPair(SBCodepoint codepoint, BracketType *type) +{ + if (codepoint <= 0xFF63) { + SBUInt8 data = PairData[ + PairIndexes[ + codepoint / 0x06A + ] + (codepoint % 0x06A) + ]; + *type = (data & BracketTypePrimaryMask); + + if (*type != 0) { + SBInt16 diff = PairDifferences[ + data & BracketTypeInverseMask + ]; + return (codepoint + diff); + } + } else { + *type = BracketTypeNone; + } + + return 0; +} diff --git a/third_party/sheenbidi/source/PairingLookup.h b/third_party/sheenbidi/source/PairingLookup.h new file mode 100644 index 0000000..28a0e9f --- /dev/null +++ b/third_party/sheenbidi/source/PairingLookup.h @@ -0,0 +1,17 @@ +/* + * Automatically generated by SheenBidiGenerator tool. + * DO NOT EDIT!! + */ + +#ifndef _SB_INTERNAL_PAIRING_LOOKUP_H +#define _SB_INTERNAL_PAIRING_LOOKUP_H + +#include + +#include "BracketType.h" +#include "SBBase.h" + +SB_INTERNAL SBCodepoint LookupMirror(SBCodepoint codepoint); +SB_INTERNAL SBCodepoint LookupBracketPair(SBCodepoint codepoint, BracketType *bracketType); + +#endif diff --git a/third_party/sheenbidi/source/RunExtrema.h b/third_party/sheenbidi/source/RunExtrema.h new file mode 100644 index 0000000..3ce68d3 --- /dev/null +++ b/third_party/sheenbidi/source/RunExtrema.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2014-2019 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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 _SB_INTERNAL_RUN_EXTREMA_H +#define _SB_INTERNAL_RUN_EXTREMA_H + +#include "SBBase.h" + +enum { + RunExtremaLeadingL = SBBidiTypeL << 0, + RunExtremaLeadingR = SBBidiTypeR << 0, + + RunExtremaTrailingL = SBBidiTypeL << 4, + RunExtremaTrailingR = SBBidiTypeR << 4 +}; +typedef SBUInt8 RunExtrema; + +#define RunExtremaMake(sor, eor) \ +(RunExtrema) \ +( \ + ((sor) << 0) \ + | ((eor) << 4) \ +) + +#define RunExtrema_SOR(e) \ +(RunExtrema) \ +( \ + (e) & 0xF \ +) + +#define RunExtrema_EOR(e) \ +(RunExtrema) \ +( \ + (e) >> 4 \ +) + +#endif diff --git a/third_party/sheenbidi/source/RunKind.h b/third_party/sheenbidi/source/RunKind.h new file mode 100644 index 0000000..ebda9fa --- /dev/null +++ b/third_party/sheenbidi/source/RunKind.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2014-2019 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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 _SB_INTERNAL_RUN_KIND_H +#define _SB_INTERNAL_RUN_KIND_H + +#include "SBBase.h" + +enum { + RunKindSimple = 0x00, + + RunKindIsolate = 0x01, + RunKindPartial = 0x02, + RunKindPartialIsolate = RunKindIsolate | RunKindPartial, + + RunKindTerminating = 0x04, + RunKindAttached = 0x08 +}; +typedef SBUInt8 RunKind; + +#define RunKindMake(i, t) \ +( \ + ((i) ? RunKindPartialIsolate : 0) \ + | ((t) ? RunKindTerminating : 0) \ +) + +#define RunKindMakeComplete(k) \ +( \ + (k) &= ~RunKindPartial \ +) + +#define RunKindMakeAttached(k) \ +( \ + (k) |= RunKindAttached \ +) + +#define RunKindIsSimple(k) \ +( \ + (k) == RunKindSimple \ +) + +#define RunKindIsIsolate(k) \ +( \ + (k) & RunKindIsolate \ +) + +#define RunKindIsTerminating(k) \ +( \ + (k) & RunKindTerminating \ +) + +#define RunKindIsPartialIsolate(k) \ +( \ + (k) & RunKindPartial \ +) + +#define RunKindIsCompleteIsolate(k) \ +( \ + ((k) & RunKindPartialIsolate) \ + == RunKindIsolate \ +) + +#define RunKindIsAttachedTerminating(k) \ +( \ + (k) & RunKindAttached \ +) + +#endif diff --git a/third_party/sheenbidi/source/RunQueue.c b/third_party/sheenbidi/source/RunQueue.c new file mode 100644 index 0000000..b6b8465 --- /dev/null +++ b/third_party/sheenbidi/source/RunQueue.c @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2014-2022 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ + +#include +#include +#include + +#include "LevelRun.h" +#include "SBAssert.h" +#include "SBBase.h" +#include "RunQueue.h" + +static SBBoolean RunQueueInsertElement(RunQueueRef queue) +{ + if (queue->_rearTop != RunQueueList_MaxIndex) { + queue->_rearTop += 1; + } else { + RunQueueListRef previousList = queue->_rearList; + RunQueueListRef rearList = previousList->next; + + if (!rearList) { + rearList = malloc(sizeof(RunQueueList)); + if (!rearList) { + return SBFalse; + } + + rearList->previous = previousList; + rearList->next = NULL; + + previousList->next = rearList; + } + + queue->_rearList = rearList; + queue->_rearTop = 0; + } + queue->count += 1; + + return SBTrue; +} + +static void FindPreviousPartialRun(RunQueueRef queue) +{ + RunQueueListRef list = queue->_partialList; + SBInteger top = queue->_partialTop; + + do { + SBInteger limit = (list == queue->_frontList ? queue->_frontTop : 0); + + do { + LevelRunRef levelRun = &list->elements[top]; + if (RunKindIsPartialIsolate(levelRun->kind)) { + queue->_partialList = list; + queue->_partialTop = top; + return; + } + } while (top-- > limit); + + list = list->previous; + top = RunQueueList_MaxIndex; + } while (list); + + queue->_partialList = NULL; + queue->_partialTop = -1; + queue->shouldDequeue = SBFalse; +} + +SB_INTERNAL void RunQueueInitialize(RunQueueRef queue) +{ + /* Initialize first list. */ + queue->_firstList.previous = NULL; + queue->_firstList.next = NULL; + + /* Initialize front and rear lists with first list. */ + queue->_frontList = &queue->_firstList; + queue->_rearList = &queue->_firstList; + queue->_partialList = NULL; + + /* Initialize list indexes. */ + queue->_frontTop = 0; + queue->_rearTop = -1; + queue->_partialTop = -1; + + /* Initialize rest of the elements. */ + queue->count = 0; + queue->peek = &queue->_frontList->elements[queue->_frontTop]; + queue->shouldDequeue = SBFalse; +} + +SB_INTERNAL SBBoolean RunQueueEnqueue(RunQueueRef queue, const LevelRunRef levelRun) +{ + if (RunQueueInsertElement(queue)) { + LevelRunRef element = &queue->_rearList->elements[queue->_rearTop]; + + /* Copy the level run into the current element. */ + *element = *levelRun; + + /* Complete the latest isolating run with this terminating run. */ + if (queue->_partialTop != -1 && RunKindIsTerminating(element->kind)) { + LevelRunRef incompleteRun = &queue->_partialList->elements[queue->_partialTop]; + LevelRunAttach(incompleteRun, element); + FindPreviousPartialRun(queue); + } + + /* Save the location of the isolating run. */ + if (RunKindIsIsolate(element->kind)) { + queue->_partialList = queue->_rearList; + queue->_partialTop = queue->_rearTop; + } + + return SBTrue; + } + + return SBFalse; +} + +SB_INTERNAL void RunQueueDequeue(RunQueueRef queue) +{ + /* The queue should not be empty. */ + SBAssert(queue->count != 0); + + if (queue->_frontTop != RunQueueList_MaxIndex) { + queue->_frontTop += 1; + } else { + RunQueueListRef frontList = queue->_frontList; + + if (frontList == queue->_rearList) { + queue->_rearTop = -1; + } else { + queue->_frontList = frontList->next; + } + + queue->_frontTop = 0; + } + + queue->count -= 1; + queue->peek = &queue->_frontList->elements[queue->_frontTop]; +} + +SB_INTERNAL void RunQueueFinalize(RunQueueRef queue) +{ + RunQueueListRef list = queue->_firstList.next; + + while (list) { + RunQueueListRef next = list->next; + free(list); + list = next; + }; +} diff --git a/third_party/sheenbidi/source/RunQueue.h b/third_party/sheenbidi/source/RunQueue.h new file mode 100644 index 0000000..375c842 --- /dev/null +++ b/third_party/sheenbidi/source/RunQueue.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2014-2022 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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 _SB_INTERNAL_RUN_QUEUE_H +#define _SB_INTERNAL_RUN_QUEUE_H + +#include + +#include "LevelRun.h" +#include "SBBase.h" + +#define RunQueueList_Length 8 +#define RunQueueList_MaxIndex (RunQueueList_Length - 1) + +typedef struct _RunQueueList { + LevelRun elements[RunQueueList_Length]; + + struct _RunQueueList *previous; /**< Reference to the previous list of queue elements */ + struct _RunQueueList *next; /**< Reference to the next list of queue elements */ +} RunQueueList, *RunQueueListRef; + +typedef struct _RunQueue { + RunQueueList _firstList; /**< First list of elements, which is part of the queue */ + RunQueueListRef _frontList; /**< The list containing front element of the queue */ + RunQueueListRef _rearList; /**< The list containing rear element of the queue */ + RunQueueListRef _partialList; /**< The list containing latest partial isolating run */ + SBInteger _frontTop; /**< Index of front element in front list */ + SBInteger _rearTop; /**< Index of rear element in rear list */ + SBInteger _partialTop; /**< Index of partial run in partial list */ + LevelRunRef peek; /**< Peek element of the queue */ + SBUInteger count; /**< Number of elements the queue contains */ + SBBoolean shouldDequeue; +} RunQueue, *RunQueueRef; + +SB_INTERNAL void RunQueueInitialize(RunQueueRef queue); + +SB_INTERNAL SBBoolean RunQueueEnqueue(RunQueueRef queue, const LevelRunRef levelRun); +SB_INTERNAL void RunQueueDequeue(RunQueueRef queue); + +SB_INTERNAL void RunQueueFinalize(RunQueueRef queue); + +#endif diff --git a/third_party/sheenbidi/source/SBAlgorithm.c b/third_party/sheenbidi/source/SBAlgorithm.c new file mode 100644 index 0000000..2a6fe50 --- /dev/null +++ b/third_party/sheenbidi/source/SBAlgorithm.c @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2016-2022 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ + +#include +#include +#include + +#include "BidiTypeLookup.h" +#include "SBBase.h" +#include "SBCodepointSequence.h" +#include "SBLog.h" +#include "SBParagraph.h" +#include "SBAlgorithm.h" + +static SBAlgorithmRef AllocateAlgorithm(SBUInteger stringLength) +{ + const SBUInteger sizeAlgorithm = sizeof(SBAlgorithm); + const SBUInteger sizeTypes = sizeof(SBBidiType) * stringLength; + const SBUInteger sizeMemory = sizeAlgorithm + sizeTypes; + + void *pointer = malloc(sizeMemory); + + if (pointer) { + const SBUInteger offsetAlgorithm = 0; + const SBUInteger offsetTypes = offsetAlgorithm + sizeAlgorithm; + + SBUInt8 *memory = (SBUInt8 *)pointer; + SBAlgorithmRef algorithm = (SBAlgorithmRef)(memory + offsetAlgorithm); + SBLevel *fixedTypes = (SBLevel *)(memory + offsetTypes); + + algorithm->fixedTypes = fixedTypes; + + return algorithm; + } + + return NULL; +} + +static void DisposeAlgorithm(SBAlgorithmRef algorithm) +{ + free(algorithm); +} + +static void DetermineBidiTypes(const SBCodepointSequence *sequence, SBBidiType *types) +{ + SBUInteger stringIndex = 0; + SBUInteger firstIndex = 0; + SBCodepoint codepoint; + + while ((codepoint = SBCodepointSequenceGetCodepointAt(sequence, &stringIndex)) != SBCodepointInvalid) { + types[firstIndex] = LookupBidiType(codepoint); + + /* Subsequent code units get 'BN' type. */ + while (++firstIndex < stringIndex) { + types[firstIndex] = SBBidiTypeBN; + } + } +} + +static SBAlgorithmRef CreateAlgorithm(const SBCodepointSequence *codepointSequence) +{ + SBUInteger stringLength = codepointSequence->stringLength; + SBAlgorithmRef algorithm; + + SB_LOG_BLOCK_OPENER("Algorithm Input"); + SB_LOG_STATEMENT("Codepoints", 1, SB_LOG_CODEPOINT_SEQUENCE(codepointSequence)); + SB_LOG_BLOCK_CLOSER(); + + algorithm = AllocateAlgorithm(stringLength); + + if (algorithm) { + algorithm->codepointSequence = *codepointSequence; + algorithm->retainCount = 1; + + DetermineBidiTypes(codepointSequence, algorithm->fixedTypes); + + SB_LOG_BLOCK_OPENER("Determined Types"); + SB_LOG_STATEMENT("Types", 1, SB_LOG_BIDI_TYPES_ARRAY(algorithm->fixedTypes, stringLength)); + SB_LOG_BLOCK_CLOSER(); + + SB_LOG_BREAKER(); + } + + return algorithm; +} + +SBAlgorithmRef SBAlgorithmCreate(const SBCodepointSequence *codepointSequence) +{ + if (SBCodepointSequenceIsValid(codepointSequence)) { + return CreateAlgorithm(codepointSequence); + } + + return NULL; +} + +const SBBidiType *SBAlgorithmGetBidiTypesPtr(SBAlgorithmRef algorithm) +{ + return algorithm->fixedTypes; +} + +SB_INTERNAL SBUInteger SBAlgorithmGetSeparatorLength(SBAlgorithmRef algorithm, SBUInteger separatorIndex) +{ + const SBCodepointSequence *codepointSequence = &algorithm->codepointSequence; + SBUInteger stringIndex = separatorIndex; + SBCodepoint codepoint; + SBUInteger separatorLength; + + codepoint = SBCodepointSequenceGetCodepointAt(codepointSequence, &stringIndex); + separatorLength = stringIndex - separatorIndex; + + if (codepoint == '\r') { + /* Don't break in between 'CR' and 'LF'. */ + if (stringIndex < codepointSequence->stringLength) { + codepoint = SBCodepointSequenceGetCodepointAt(codepointSequence, &stringIndex); + + if (codepoint == '\n') { + separatorLength = stringIndex - separatorIndex; + } + } + } + + return separatorLength; +} + +void SBAlgorithmGetParagraphBoundary(SBAlgorithmRef algorithm, + SBUInteger paragraphOffset, SBUInteger suggestedLength, + SBUInteger *acutalLength, SBUInteger *separatorLength) +{ + const SBCodepointSequence *codepointSequence = &algorithm->codepointSequence; + SBBidiType *bidiTypes = algorithm->fixedTypes; + SBUInteger limitIndex; + SBUInteger startIndex; + + SBUIntegerNormalizeRange(codepointSequence->stringLength, ¶graphOffset, &suggestedLength); + limitIndex = paragraphOffset + suggestedLength; + + for (startIndex = paragraphOffset; startIndex < limitIndex; startIndex++) { + SBBidiType currentType = bidiTypes[startIndex]; + + if (currentType == SBBidiTypeB) { + SBUInteger codeUnitCount = SBAlgorithmGetSeparatorLength(algorithm, startIndex); + + startIndex += codeUnitCount; + + if (separatorLength) { + *separatorLength = codeUnitCount; + } + break; + } + } + + if (acutalLength) { + *acutalLength = startIndex - paragraphOffset; + } +} + +SBParagraphRef SBAlgorithmCreateParagraph(SBAlgorithmRef algorithm, + SBUInteger paragraphOffset, SBUInteger suggestedLength, SBLevel baseLevel) +{ + const SBCodepointSequence *codepointSequence = &algorithm->codepointSequence; + SBUInteger stringLength = codepointSequence->stringLength; + + SBUIntegerNormalizeRange(stringLength, ¶graphOffset, &suggestedLength); + + if (suggestedLength > 0) { + return SBParagraphCreate(algorithm, paragraphOffset, suggestedLength, baseLevel); + } + + return NULL; +} + +SBAlgorithmRef SBAlgorithmRetain(SBAlgorithmRef algorithm) +{ + if (algorithm) { + algorithm->retainCount += 1; + } + + return algorithm; +} + +void SBAlgorithmRelease(SBAlgorithmRef algorithm) +{ + if (algorithm && --algorithm->retainCount == 0) { + DisposeAlgorithm(algorithm); + } +} diff --git a/third_party/sheenbidi/source/SBAlgorithm.h b/third_party/sheenbidi/source/SBAlgorithm.h new file mode 100644 index 0000000..6d417a3 --- /dev/null +++ b/third_party/sheenbidi/source/SBAlgorithm.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2016-2019 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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 _SB_INTERNAL_ALGORITHM_H +#define _SB_INTERNAL_ALGORITHM_H + +#include +#include +#include +#include +#include + +typedef struct _SBAlgorithm { + SBCodepointSequence codepointSequence; + SBBidiType *fixedTypes; + SBUInteger retainCount; +} SBAlgorithm; + +SB_INTERNAL SBUInteger SBAlgorithmGetSeparatorLength(SBAlgorithmRef algorithm, SBUInteger separatorIndex); + +#endif diff --git a/third_party/sheenbidi/source/SBAssert.h b/third_party/sheenbidi/source/SBAssert.h new file mode 100644 index 0000000..22923c7 --- /dev/null +++ b/third_party/sheenbidi/source/SBAssert.h @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2014 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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 _SB_INTERNAL_ASSERT_H +#define _SB_INTERNAL_ASSERT_H + +#include + +#define SBAssert(exp) assert(exp) + +#endif diff --git a/third_party/sheenbidi/source/SBBase.c b/third_party/sheenbidi/source/SBBase.c new file mode 100644 index 0000000..c5323a9 --- /dev/null +++ b/third_party/sheenbidi/source/SBBase.c @@ -0,0 +1,420 @@ +/* + * Copyright (C) 2016-2019 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ + +#include + +#include "BidiTypeLookup.h" +#include "GeneralCategoryLookup.h" +#include "PairingLookup.h" +#include "ScriptLookup.h" +#include "SBBase.h" + +#define TAG(a, b, c, d) \ +(SBUInt32) \ +( \ + ((SBUInt8)(a) << 24) \ + | ((SBUInt8)(b) << 16) \ + | ((SBUInt8)(c) << 8) \ + | ((SBUInt8)(d) << 0) \ +) + +SB_INTERNAL void SBUIntegerNormalizeRange(SBUInteger actualLength, + SBUInteger *rangeOffset, SBUInteger *rangeLength) +{ + /** + * Assume: + * Actual Length = 10 + * + * Case 1: + * Offset = 0, Length = 10 + * Result: + * Offset = 0, Length = 10 + * + * Case 2: + * Offset = 0, Length = 11 + * Result: + * Offset = 0, Length = 10 + * + * Case 3: + * Offset = 1, Length = -1 (MAX) + * Result: + * Offset = 1, Length = 9 + * + * Case 4: + * Offset = 10, Length = 0 + * Result: + * Offset = Invalid, Length = 0 + * + * Case 5: + * Offset = -1 (MAX), Length = 1 + * Result: + * Offset = Invalid, Length = 0 + */ + + if (*rangeOffset < actualLength) { + SBUInteger possibleLimit = *rangeOffset + *rangeLength; + + if (*rangeOffset <= possibleLimit && possibleLimit <= actualLength) { + /* The range is valid. Nothing to do here. */ + } else { + *rangeLength = actualLength - *rangeOffset; + } + } else { + *rangeOffset = SBInvalidIndex; + *rangeLength = 0; + } +} + +SB_INTERNAL SBBoolean SBUIntegerVerifyRange(SBUInteger actualLength, + SBUInteger rangeOffset, SBUInteger rangeLength) +{ + SBUInteger possibleLimit = rangeOffset + rangeLength; + + return rangeOffset < actualLength + && rangeOffset <= possibleLimit + && possibleLimit <= actualLength; +} + +SBBidiType SBCodepointGetBidiType(SBCodepoint codepoint) +{ + return LookupBidiType(codepoint); +} + +SBGeneralCategory SBCodepointGetGeneralCategory(SBCodepoint codepoint) +{ + return LookupGeneralCategory(codepoint); +} + +SBCodepoint SBCodepointGetMirror(SBCodepoint codepoint) +{ + return LookupMirror(codepoint); +} + +SBScript SBCodepointGetScript(SBCodepoint codepoint) +{ + return LookupScript(codepoint); +} + +SBUInt32 SBScriptGetOpenTypeTag(SBScript script) +{ + /* Reference: https://docs.microsoft.com/en-us/typography/opentype/spec/scripttags */ + /* Dated: 07/24/2017 */ + + switch (script) { + case SBScriptADLM: + return TAG('a', 'd', 'l', 'm'); + case SBScriptAHOM: + return TAG('a', 'h', 'o', 'm'); + case SBScriptHLUW: + return TAG('h', 'l', 'u', 'w'); + case SBScriptARAB: + return TAG('a', 'r', 'a', 'b'); + case SBScriptARMN: + return TAG('a', 'r', 'm', 'n'); + case SBScriptAVST: + return TAG('a', 'v', 's', 't'); + case SBScriptBALI: + return TAG('b', 'a', 'l', 'i'); + case SBScriptBAMU: + return TAG('b', 'a', 'm', 'u'); + case SBScriptBASS: + return TAG('b', 'a', 's', 's'); + case SBScriptBATK: + return TAG('b', 'a', 't', 'k'); + /* case SBScriptBENG: + return TAG('b', 'e', 'n', 'g'); */ + case SBScriptBENG: + return TAG('b', 'n', 'g', '2'); + case SBScriptBHKS: + return TAG('b', 'h', 'k', 's'); + case SBScriptBOPO: + return TAG('b', 'o', 'p', 'o'); + case SBScriptBRAH: + return TAG('b', 'r', 'a', 'h'); + case SBScriptBRAI: + return TAG('b', 'r', 'a', 'i'); + case SBScriptBUGI: + return TAG('b', 'u', 'g', 'i'); + case SBScriptBUHD: + return TAG('b', 'u', 'h', 'd'); + /* case SBScriptBYZM: + return TAG('b', 'y', 'z', 'm'); */ + case SBScriptCANS: + return TAG('c', 'a', 'n', 's'); + case SBScriptCARI: + return TAG('c', 'a', 'r', 'i'); + case SBScriptAGHB: + return TAG('a', 'g', 'h', 'b'); + case SBScriptCAKM: + return TAG('c', 'a', 'k', 'm'); + case SBScriptCHAM: + return TAG('c', 'h', 'a', 'm'); + case SBScriptCHER: + return TAG('c', 'h', 'e', 'r'); + case SBScriptHANI: + return TAG('h', 'a', 'n', 'i'); + case SBScriptCOPT: + return TAG('c', 'o', 'p', 't'); + case SBScriptCPRT: + return TAG('c', 'p', 'r', 't'); + case SBScriptCYRL: + return TAG('c', 'y', 'r', 'l'); + /* case SBScriptDFLT: + return TAG('D', 'F', 'L', 'T'); */ + case SBScriptDSRT: + return TAG('d', 's', 'r', 't'); + /* case SBScriptDEVA: + return TAG('d', 'e', 'v', 'a'); */ + case SBScriptDEVA: + return TAG('d', 'e', 'v', '2'); + case SBScriptDUPL: + return TAG('d', 'u', 'p', 'l'); + case SBScriptEGYP: + return TAG('e', 'g', 'y', 'p'); + case SBScriptELBA: + return TAG('e', 'l', 'b', 'a'); + case SBScriptETHI: + return TAG('e', 't', 'h', 'i'); + case SBScriptGEOR: + return TAG('g', 'e', 'o', 'r'); + case SBScriptGLAG: + return TAG('g', 'l', 'a', 'g'); + case SBScriptGOTH: + return TAG('g', 'o', 't', 'h'); + case SBScriptGRAN: + return TAG('g', 'r', 'a', 'n'); + case SBScriptGREK: + return TAG('g', 'r', 'e', 'k'); + /* case SBScriptGUJR: + return TAG('g', 'u', 'j', 'r'); */ + case SBScriptGUJR: + return TAG('g', 'j', 'r', '2'); + /* case SBScriptGURU: + return TAG('g', 'u', 'r', 'u'); */ + case SBScriptGURU: + return TAG('g', 'u', 'r', '2'); + case SBScriptHANG: + return TAG('h', 'a', 'n', 'g'); + /* case SBScriptJAMO: + return TAG('j', 'a', 'm', 'o'); */ + case SBScriptHANO: + return TAG('h', 'a', 'n', 'o'); + case SBScriptHATR: + return TAG('h', 'a', 't', 'r'); + case SBScriptHEBR: + return TAG('h', 'e', 'b', 'r'); + case SBScriptHIRA: + return TAG('k', 'a', 'n', 'a'); + case SBScriptARMI: + return TAG('a', 'r', 'm', 'i'); + case SBScriptPHLI: + return TAG('p', 'h', 'l', 'i'); + case SBScriptPRTI: + return TAG('p', 'r', 't', 'i'); + case SBScriptJAVA: + return TAG('j', 'a', 'v', 'a'); + case SBScriptKTHI: + return TAG('k', 't', 'h', 'i'); + /* case SBScriptKNDA: + return TAG('k', 'n', 'd', 'a'); */ + case SBScriptKNDA: + return TAG('k', 'n', 'd', '2'); + case SBScriptKANA: + return TAG('k', 'a', 'n', 'a'); + case SBScriptKALI: + return TAG('k', 'a', 'l', 'i'); + case SBScriptKHAR: + return TAG('k', 'h', 'a', 'r'); + case SBScriptKHMR: + return TAG('k', 'h', 'm', 'r'); + case SBScriptKHOJ: + return TAG('k', 'h', 'o', 'j'); + case SBScriptSIND: + return TAG('s', 'i', 'n', 'd'); + case SBScriptLAOO: + return TAG('l', 'a', 'o', ' '); + case SBScriptLATN: + return TAG('l', 'a', 't', 'n'); + case SBScriptLEPC: + return TAG('l', 'e', 'p', 'c'); + case SBScriptLIMB: + return TAG('l', 'i', 'm', 'b'); + case SBScriptLINA: + return TAG('l', 'i', 'n', 'a'); + case SBScriptLINB: + return TAG('l', 'i', 'n', 'b'); + case SBScriptLISU: + return TAG('l', 'i', 's', 'u'); + case SBScriptLYCI: + return TAG('l', 'y', 'c', 'i'); + case SBScriptLYDI: + return TAG('l', 'y', 'd', 'i'); + case SBScriptMAHJ: + return TAG('m', 'a', 'h', 'j'); + /* case SBScriptMLYM: + return TAG('m', 'l', 'y', 'm'); */ + case SBScriptMLYM: + return TAG('m', 'l', 'm', '2'); + case SBScriptMAND: + return TAG('m', 'a', 'n', 'd'); + case SBScriptMANI: + return TAG('m', 'a', 'n', 'i'); + case SBScriptMARC: + return TAG('m', 'a', 'r', 'c'); + /* case SBScriptMATH: + return TAG('m', 'a', 't', 'h'); */ + case SBScriptMTEI: + return TAG('m', 't', 'e', 'i'); + case SBScriptMEND: + return TAG('m', 'e', 'n', 'd'); + case SBScriptMERC: + return TAG('m', 'e', 'r', 'c'); + case SBScriptMERO: + return TAG('m', 'e', 'r', 'o'); + case SBScriptPLRD: + return TAG('p', 'l', 'r', 'd'); + case SBScriptMODI: + return TAG('m', 'o', 'd', 'i'); + case SBScriptMONG: + return TAG('m', 'o', 'n', 'g'); + case SBScriptMROO: + return TAG('m', 'r', 'o', 'o'); + case SBScriptMULT: + return TAG('m', 'u', 'l', 't'); + /* case SBScriptMUSC: + return TAG('m', 'u', 's', 'c'); */ + /* case SBScriptMYMR: + return TAG('m', 'y', 'm', 'r'); */ + case SBScriptMYMR: + return TAG('m', 'y', 'm', '2'); + case SBScriptNBAT: + return TAG('n', 'b', 'a', 't'); + case SBScriptNEWA: + return TAG('n', 'e', 'w', 'a'); + case SBScriptTALU: + return TAG('t', 'a', 'l', 'u'); + case SBScriptNKOO: + return TAG('n', 'k', 'o', ' '); + /* case SBScriptORYA: + return TAG('o', 'r', 'y', 'a'); */ + case SBScriptORYA: + return TAG('o', 'r', 'y', '2'); + case SBScriptOGAM: + return TAG('o', 'g', 'a', 'm'); + case SBScriptOLCK: + return TAG('o', 'l', 'c', 'k'); + case SBScriptITAL: + return TAG('i', 't', 'a', 'l'); + case SBScriptHUNG: + return TAG('h', 'u', 'n', 'g'); + case SBScriptNARB: + return TAG('n', 'a', 'r', 'b'); + case SBScriptPERM: + return TAG('p', 'e', 'r', 'm'); + case SBScriptXPEO: + return TAG('x', 'p', 'e', 'o'); + case SBScriptSARB: + return TAG('s', 'a', 'r', 'b'); + case SBScriptORKH: + return TAG('o', 'r', 'k', 'h'); + case SBScriptOSGE: + return TAG('o', 's', 'g', 'e'); + case SBScriptOSMA: + return TAG('o', 's', 'm', 'a'); + case SBScriptHMNG: + return TAG('h', 'm', 'n', 'g'); + case SBScriptPALM: + return TAG('p', 'a', 'l', 'm'); + case SBScriptPAUC: + return TAG('p', 'a', 'u', 'c'); + case SBScriptPHAG: + return TAG('p', 'h', 'a', 'g'); + case SBScriptPHNX: + return TAG('p', 'h', 'n', 'x'); + case SBScriptPHLP: + return TAG('p', 'h', 'l', 'p'); + case SBScriptRJNG: + return TAG('r', 'j', 'n', 'g'); + case SBScriptRUNR: + return TAG('r', 'u', 'n', 'r'); + case SBScriptSAMR: + return TAG('s', 'a', 'm', 'r'); + case SBScriptSAUR: + return TAG('s', 'a', 'u', 'r'); + case SBScriptSHRD: + return TAG('s', 'h', 'r', 'd'); + case SBScriptSHAW: + return TAG('s', 'h', 'a', 'w'); + case SBScriptSIDD: + return TAG('s', 'i', 'd', 'd'); + case SBScriptSGNW: + return TAG('s', 'g', 'n', 'w'); + case SBScriptSINH: + return TAG('s', 'i', 'n', 'h'); + case SBScriptSORA: + return TAG('s', 'o', 'r', 'a'); + case SBScriptXSUX: + return TAG('x', 's', 'u', 'x'); + case SBScriptSUND: + return TAG('s', 'u', 'n', 'd'); + case SBScriptSYLO: + return TAG('s', 'y', 'l', 'o'); + case SBScriptSYRC: + return TAG('s', 'y', 'r', 'c'); + case SBScriptTGLG: + return TAG('t', 'g', 'l', 'g'); + case SBScriptTAGB: + return TAG('t', 'a', 'g', 'b'); + case SBScriptTALE: + return TAG('t', 'a', 'l', 'e'); + case SBScriptLANA: + return TAG('l', 'a', 'n', 'a'); + case SBScriptTAVT: + return TAG('t', 'a', 'v', 't'); + case SBScriptTAKR: + return TAG('t', 'a', 'k', 'r'); + /* case SBScriptTAML: + return TAG('t', 'a', 'm', 'l'); */ + case SBScriptTAML: + return TAG('t', 'm', 'l', '2'); + case SBScriptTANG: + return TAG('t', 'a', 'n', 'g'); + /* case SBScriptTELU: + return TAG('t', 'e', 'l', 'u'); */ + case SBScriptTELU: + return TAG('t', 'e', 'l', '2'); + case SBScriptTHAA: + return TAG('t', 'h', 'a', 'a'); + case SBScriptTHAI: + return TAG('t', 'h', 'a', 'i'); + case SBScriptTIBT: + return TAG('t', 'i', 'b', 't'); + case SBScriptTFNG: + return TAG('t', 'f', 'n', 'g'); + case SBScriptTIRH: + return TAG('t', 'i', 'r', 'h'); + case SBScriptUGAR: + return TAG('u', 'g', 'a', 'r'); + case SBScriptVAII: + return TAG('v', 'a', 'i', ' '); + case SBScriptWARA: + return TAG('w', 'a', 'r', 'a'); + case SBScriptYIII: + return TAG('y', 'i', ' ', ' '); + default: + return TAG('D', 'F', 'L', 'T'); + } +} diff --git a/third_party/sheenbidi/source/SBBase.h b/third_party/sheenbidi/source/SBBase.h new file mode 100644 index 0000000..00cc977 --- /dev/null +++ b/third_party/sheenbidi/source/SBBase.h @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2016-2019 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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 _SB_INTERNAL_BASE_H +#define _SB_INTERNAL_BASE_H + +#include +#include +#include +#include +#include +#include + +/** + * A value that indicates an invalid unsigned index. + */ +#define SBInvalidIndex (SBUInteger)(-1) + +SB_INTERNAL void SBUIntegerNormalizeRange(SBUInteger actualLength, + SBUInteger *rangeOffset, SBUInteger *rangeLength); + +SB_INTERNAL SBBoolean SBUIntegerVerifyRange(SBUInteger actualLength, + SBUInteger rangeOffset, SBUInteger rangeLength); + + +#define SBNumberGetMax(first, second) \ +( \ + (first) > (second) \ + ? (first) \ + : (second) \ +) + +#define SBNumberLimitIncrement(number, limit) \ +( \ + (number) < (limit) \ + ? (number) + (1) \ + : (limit) \ +) + +#define SBNumberLimitDecrement(number, limit) \ +( \ + (number) > (limit) \ + ? (number) - (1) \ + : (limit) \ +) + +#define SBNumberRingAdd(number, count, capacity) \ + (((number) + (count)) % (capacity)) + +#define SBNumberRingIncrement(number, capacity) \ + SBNumberRingAdd(number, 1, capacity) + +#define SBNumberRingSubtract(number, count, capacity) \ + (((number) + (capacity) - (count)) % (capacity)) + +#define SBNumberRingDecrement(number, capacity) \ + SBNumberRingSubtract(number, 1, capacity) + + +#define SBLevelAsNormalBidiType(level) \ +( \ + ((level) & 1) \ + ? SBBidiTypeR \ + : SBBidiTypeL \ +) + +#define SBLevelAsOppositeBidiType(level) \ +( \ + ((level) & 1) \ + ? SBBidiTypeL \ + : SBBidiTypeR \ +) + + +#define SBBidiTypeIsEqual(t1, t2) ((t1) == (t2)) + +#define SBBidiTypeIsNumber(t) SBUInt8InRange(t, SBBidiTypeAN, SBBidiTypeEN) +#define SBBidiTypeIsIsolate(t) SBUInt8InRange(t, SBBidiTypeLRI, SBBidiTypePDI) + +#define SBBidiTypeIsStrongOrNumber(t) (SBBidiTypeIsStrong(t) || SBBidiTypeIsNumber(t)) +#define SBBidiTypeIsNumberSeparator(t) SBUInt8InRange(t, SBBidiTypeES, SBBidiTypeCS) +#define SBBidiTypeIsIsolateInitiator(t) SBUInt8InRange(t, SBBidiTypeLRI, SBBidiTypeFSI) +#define SBBidiTypeIsIsolateTerminator(t) SBBidiTypeIsEqual(t, SBBidiTypePDI) +#define SBBidiTypeIsNeutralOrIsolate(t) SBUInt8InRange(t, SBBidiTypeWS, SBBidiTypePDI) + + +#define SBCodepointMax 0x10FFFF +#define SBCodepointInRange(v, s, e) SBUInt32InRange(v, s, e) +#define SBCodepointIsSurrogate(c) SBCodepointInRange(c, 0xD800, 0xDFFF) +#define SBCodepointIsValid(c) (!SBCodepointIsSurrogate(c) && (c) <= SBCodepointMax) + + +#define SBScriptIsCommonOrInherited(s) ((s) <= SBScriptZYYY) + +#endif diff --git a/third_party/sheenbidi/source/SBCodepointSequence.c b/third_party/sheenbidi/source/SBCodepointSequence.c new file mode 100644 index 0000000..3828fa7 --- /dev/null +++ b/third_party/sheenbidi/source/SBCodepointSequence.c @@ -0,0 +1,303 @@ +/* + * Copyright (C) 2016-2019 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ + +#include + +#include +#include + +#include "SBAssert.h" +#include "SBBase.h" +#include "SBCodepointSequence.h" + +typedef struct { + SBUInt8 valid; + SBUInt8 total; + SBUInt8 start; + SBUInt8 end; +} UTF8State; + +static const UTF8State UTF8StateTable[9] = { + {1,0,0x00,0x00}, {0,0,0x00,0x00}, {1,2,0x80,0xBF}, {1,3,0xA0,0xBF}, {1,3,0x80,0xBF}, + {1,3,0x80,0x9F}, {1,4,0x90,0xBF}, {1,4,0x80,0xBF}, {1,4,0x80,0x8F} +}; + +static const SBUInt8 UTF8LookupTable[256] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +/* LEAD: -- 80..BF -- */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, +/* LEAD: -- C0..C1 -- */ + 1, 1, +/* LEAD: -- C2..DF -- */ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, +/* LEAD: -- E0..E0 -- */ + 3, +/* LEAD: -- E1..EC -- */ + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, +/* LEAD: -- ED..ED -- */ + 5, +/* LEAD: -- EE..EF -- */ + 4, 4, +/* LEAD: -- F0..F0 -- */ + 6, +/* LEAD: -- F1..F3 -- */ + 7, 7, 7, +/* LEAD: -- F4..F4 -- */ + 8, +/* LEAD: -- F5..F7 -- */ + 1, 1, 1, +/* LEAD: -- F8..FB -- */ + 1, 1, 1, 1, +/* LEAD: -- FC..FD -- */ + 1, 1, +/* LEAD: -- FE..FF -- */ + 1, 1 +}; + +static SBCodepoint GetUTF8CodepointAt(const SBCodepointSequence *codepointSequence, SBUInteger *stringIndex); +static SBCodepoint GetUTF8CodepointBefore(const SBCodepointSequence *codepointSequence, SBUInteger *stringIndex); +static SBCodepoint GetUTF16CodepointAt(const SBCodepointSequence *codepointSequence, SBUInteger *stringIndex); +static SBCodepoint GetUTF16CodepointBefore(const SBCodepointSequence *codepointSequence, SBUInteger *stringIndex); +static SBCodepoint GetUTF32CodepointAt(const SBCodepointSequence *codepointSequence, SBUInteger *stringIndex); +static SBCodepoint GetUTF32CodepointBefore(const SBCodepointSequence *codepointSequence, SBUInteger *stringIndex); + +SB_INTERNAL SBBoolean SBCodepointSequenceIsValid(const SBCodepointSequence *codepointSequence) +{ + if (codepointSequence) { + SBBoolean encodingValid = SBFalse; + + switch (codepointSequence->stringEncoding) { + case SBStringEncodingUTF8: + case SBStringEncodingUTF16: + case SBStringEncodingUTF32: + encodingValid = SBTrue; + break; + } + + return (encodingValid && codepointSequence->stringBuffer && codepointSequence->stringLength > 0); + } + + return SBFalse; +} + +SBCodepoint SBCodepointSequenceGetCodepointBefore(const SBCodepointSequence *codepointSequence, SBUInteger *stringIndex) +{ + SBCodepoint codepoint = SBCodepointInvalid; + + if ((*stringIndex - 1) < codepointSequence->stringLength) { + switch (codepointSequence->stringEncoding) { + case SBStringEncodingUTF8: + codepoint = GetUTF8CodepointBefore(codepointSequence, stringIndex); + break; + + case SBStringEncodingUTF16: + codepoint = GetUTF16CodepointBefore(codepointSequence, stringIndex); + break; + + case SBStringEncodingUTF32: + codepoint = GetUTF32CodepointBefore(codepointSequence, stringIndex); + break; + } + } + + return codepoint; +} + +SBCodepoint SBCodepointSequenceGetCodepointAt(const SBCodepointSequence *codepointSequence, SBUInteger *stringIndex) +{ + SBCodepoint codepoint = SBCodepointInvalid; + + if (*stringIndex < codepointSequence->stringLength) { + switch (codepointSequence->stringEncoding) { + case SBStringEncodingUTF8: + codepoint = GetUTF8CodepointAt(codepointSequence, stringIndex); + break; + + case SBStringEncodingUTF16: + codepoint = GetUTF16CodepointAt(codepointSequence, stringIndex); + break; + + case SBStringEncodingUTF32: + codepoint = GetUTF32CodepointAt(codepointSequence, stringIndex); + break; + } + } + + return codepoint; +} + +static SBCodepoint GetUTF8CodepointAt(const SBCodepointSequence *sequence, SBUInteger *index) +{ + const SBUInt8 *buffer = sequence->stringBuffer; + SBUInteger length = sequence->stringLength; + SBUInt8 lead; + UTF8State state; + SBUInteger limit; + SBCodepoint codepoint; + + lead = buffer[*index]; + state = UTF8StateTable[UTF8LookupTable[lead]]; + limit = *index + state.total; + + if (limit > length) { + limit = length; + state.valid = SBFalse; + } + + codepoint = lead & (0x7F >> state.total); + + while (++(*index) < limit) { + SBUInt8 byte = buffer[*index]; + + if (byte >= state.start && byte <= state.end) { + codepoint = (codepoint << 6) | (byte & 0x3F); + } else { + state.valid = SBFalse; + break; + } + + state.start = 0x80; + state.end = 0xBF; + } + + if (state.valid) { + return codepoint; + } + + return SBCodepointFaulty; +} + +static SBCodepoint GetUTF8CodepointBefore(const SBCodepointSequence *sequence, SBUInteger *index) +{ + const SBUInt8 *buffer = sequence->stringBuffer; + SBUInteger startIndex = *index; + SBUInteger limitIndex; + SBUInteger continuation; + SBCodepoint codepoint; + + continuation = 7; + + while (--continuation && --startIndex) { + SBUInt8 codeunit = buffer[startIndex]; + + if ((codeunit & 0xC0) != 0x80) { + break; + } + } + + limitIndex = startIndex; + codepoint = GetUTF8CodepointAt(sequence, &limitIndex); + + if (limitIndex == *index) { + *index = startIndex; + } else { + codepoint = SBCodepointFaulty; + *index -= 1; + } + + return codepoint; +} + +static SBCodepoint GetUTF16CodepointAt(const SBCodepointSequence *sequence, SBUInteger *index) +{ + const SBUInt16 *buffer = sequence->stringBuffer; + SBUInteger length = sequence->stringLength; + SBCodepoint codepoint; + SBUInt16 lead; + + codepoint = SBCodepointFaulty; + + lead = buffer[*index]; + *index += 1; + + if (!SBCodepointIsSurrogate(lead)) { + codepoint = lead; + } else if (lead <= 0xDBFF) { + if (*index < length) { + SBUInt16 trail = buffer[*index]; + + if (SBUInt16InRange(trail, 0xDC00, 0xDFFF)) { + codepoint = (lead << 10) + trail - ((0xD800 << 10) + 0xDC00 - 0x10000); + *index += 1; + } + } + } + + return codepoint; +} + +static SBCodepoint GetUTF16CodepointBefore(const SBCodepointSequence *sequence, SBUInteger *index) +{ + const SBUInt16 *buffer = sequence->stringBuffer; + SBCodepoint codepoint; + SBUInt16 trail; + + codepoint = SBCodepointFaulty; + + *index -= 1; + trail = buffer[*index]; + + if (!SBCodepointIsSurrogate(trail)) { + codepoint = trail; + } else if (trail >= 0xDC00) { + if (*index > 0) { + SBUInt16 lead = buffer[*index - 1]; + + if (SBUInt16InRange(lead, 0xD800, 0xDBFF)) { + codepoint = (lead << 10) + trail - ((0xD800 << 10) + 0xDC00 - 0x10000); + *index -= 1; + } + } + } + + return codepoint; +} + +static SBCodepoint GetUTF32CodepointAt(const SBCodepointSequence *sequence, SBUInteger *index) +{ + const SBUInt32 *buffer = sequence->stringBuffer; + SBCodepoint codepoint; + + codepoint = buffer[*index]; + *index += 1; + + if (SBCodepointIsValid(codepoint)) { + return codepoint; + } + + return SBCodepointFaulty; +} + +static SBCodepoint GetUTF32CodepointBefore(const SBCodepointSequence *sequence, SBUInteger *index) +{ + const SBUInt32 *buffer = sequence->stringBuffer; + SBCodepoint codepoint; + + *index -= 1; + codepoint = buffer[*index]; + + if (SBCodepointIsValid(codepoint)) { + return codepoint; + } + + return SBCodepointFaulty; +} diff --git a/third_party/sheenbidi/source/SBCodepointSequence.h b/third_party/sheenbidi/source/SBCodepointSequence.h new file mode 100644 index 0000000..e5967c4 --- /dev/null +++ b/third_party/sheenbidi/source/SBCodepointSequence.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2016 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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 _SB_INTERNAL_CODEPOINT_SEQUENCE_H +#define _SB_INTERNAL_CODEPOINT_SEQUENCE_H + +#include +#include + +SB_INTERNAL SBBoolean SBCodepointSequenceIsValid(const SBCodepointSequence *codepointSequence); + +#endif diff --git a/third_party/sheenbidi/source/SBLine.c b/third_party/sheenbidi/source/SBLine.c new file mode 100644 index 0000000..0134314 --- /dev/null +++ b/third_party/sheenbidi/source/SBLine.c @@ -0,0 +1,320 @@ +/* + * Copyright (C) 2014-2022 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ + +#include +#include +#include + +#include "PairingLookup.h" +#include "SBAlgorithm.h" +#include "SBAssert.h" +#include "SBBase.h" +#include "SBCodepointSequence.h" +#include "SBParagraph.h" +#include "SBRun.h" +#include "SBLine.h" + +typedef struct _LineContext { + const SBBidiType *refTypes; + SBLevel *fixedLevels; + SBUInteger runCount; + SBLevel maxLevel; +} LineContext, *LineContextRef; + +static SBLevel CopyLevels(SBLevel *destination, + const SBLevel *source, SBUInteger length, SBUInteger *runCount) +{ + SBLevel lastLevel = SBLevelInvalid; + SBLevel maxLevel = 0; + SBUInteger totalRuns = 0; + + while (length--) { + SBLevel level = *(source++); + *(destination++) = level; + + if (level != lastLevel) { + totalRuns += 1; + + if (level > maxLevel) { + maxLevel = level; + } + } + } + + *runCount = totalRuns; + + return maxLevel; +} + +static LineContextRef CreateLineContext(const SBBidiType *types, const SBLevel *levels, SBUInteger length) +{ + const SBUInteger sizeContext = sizeof(LineContext); + const SBUInteger sizeLevels = sizeof(SBLevel) * length; + const SBUInteger sizeMemory = sizeContext + sizeLevels; + + void *pointer = malloc(sizeMemory); + + if (pointer) { + const SBUInteger offsetContext = 0; + const SBUInteger offsetLevels = offsetContext + sizeContext; + + SBUInt8 *memory = (SBUInt8 *)pointer; + LineContextRef context = (LineContextRef)(memory + offsetContext); + SBLevel *fixedLevels = (SBLevel *)(memory + offsetLevels); + + context->refTypes = types; + context->fixedLevels = fixedLevels; + context->maxLevel = CopyLevels(fixedLevels, levels, length, &context->runCount); + + return context; + } + + return NULL; +} + +static void DisposeLineContext(LineContextRef context) +{ + free(context); +} + +static SBLineRef AllocateLine(SBUInteger runCount) +{ + const SBUInteger sizeLine = sizeof(SBLine); + const SBUInteger sizeRuns = sizeof(SBRun) * runCount; + const SBUInteger sizeMemory = sizeLine + sizeRuns; + + void *pointer = malloc(sizeMemory); + + if (pointer) { + const SBUInteger offsetLine = 0; + const SBUInteger offsetRuns = offsetLine + sizeLine; + + SBUInt8 *memory = (SBUInt8 *)pointer; + SBLineRef line = (SBLineRef)(memory + offsetLine); + SBRun *runs = (SBRun *)(memory + offsetRuns); + + line->fixedRuns = runs; + + return line; + } + + return NULL; +} + +static void SetNewLevel(SBLevel *levels, SBUInteger length, SBLevel newLevel) +{ + SBUInteger index = length; + + while (index--) { + levels[index] = newLevel; + } +} + +static void ResetLevels(LineContextRef context, SBLevel baseLevel, SBUInteger charCount) +{ + const SBBidiType *types = context->refTypes; + SBLevel *levels = context->fixedLevels; + SBUInteger index; + SBUInteger length; + SBBoolean reset; + + index = charCount; + length = 0; + reset = SBTrue; + + while (index--) { + SBBidiType type = types[index]; + + switch (type) { + case SBBidiTypeB: + case SBBidiTypeS: + SetNewLevel(levels + index, length + 1, baseLevel); + length = 0; + reset = SBTrue; + context->runCount += 1; + break; + + case SBBidiTypeLRE: + case SBBidiTypeRLE: + case SBBidiTypeLRO: + case SBBidiTypeRLO: + case SBBidiTypePDF: + case SBBidiTypeBN: + length += 1; + break; + + case SBBidiTypeWS: + case SBBidiTypeLRI: + case SBBidiTypeRLI: + case SBBidiTypeFSI: + case SBBidiTypePDI: + if (reset) { + SetNewLevel(levels + index, length + 1, baseLevel); + length = 0; + + context->runCount += 1; + } + break; + + default: + length = 0; + reset = SBFalse; + break; + } + } +} + +static SBUInteger InitializeRuns(SBRun *runs, + const SBLevel *levels, SBUInteger length, SBUInteger lineOffset) +{ + SBUInteger index; + SBUInteger runCount = 1; + + (*runs).offset = lineOffset; + (*runs).level = levels[0]; + + for (index = 0; index < length; index++) { + SBLevel level = levels[index]; + + if (level != (*runs).level) { + (*runs).length = index + lineOffset - (*runs).offset; + + ++runs; + (*runs).offset = lineOffset + index; + (*runs).level = level; + + runCount += 1; + } + } + + (*runs).length = index + lineOffset - (*runs).offset; + + return runCount; +} + +static void ReverseRunSequence(SBRun *runs, SBUInteger runCount) +{ + SBUInteger halfCount = runCount / 2; + SBUInteger finalIndex = runCount - 1; + SBUInteger index; + + for (index = 0; index < halfCount; index++) { + SBUInteger tieIndex; + SBRun tempRun; + + tieIndex = finalIndex - index; + + tempRun = runs[index]; + runs[index] = runs[tieIndex]; + runs[tieIndex] = tempRun; + } +} + +static void ReorderRuns(SBRun *runs, SBUInteger runCount, SBLevel maxLevel) +{ + SBLevel newLevel; + + for (newLevel = maxLevel; newLevel; newLevel--) { + SBUInteger start = runCount; + + while (start--) { + if (runs[start].level >= newLevel) { + SBUInteger count = 1; + + for (; start && runs[start - 1].level >= newLevel; start--) { + count += 1; + } + + ReverseRunSequence(runs + start, count); + } + } + } +} + +SB_INTERNAL SBLineRef SBLineCreate(SBParagraphRef paragraph, + SBUInteger lineOffset, SBUInteger lineLength) +{ + SBUInteger innerOffset = lineOffset - paragraph->offset; + const SBBidiType *refTypes = paragraph->refTypes + innerOffset; + const SBLevel *refLevels = paragraph->fixedLevels + innerOffset; + LineContextRef context; + SBLineRef line; + + /* Line range MUST be valid. */ + SBAssert(lineOffset < (lineOffset + lineLength) + && lineOffset >= paragraph->offset + && (lineOffset + lineLength) <= (paragraph->offset + paragraph->length)); + + context = CreateLineContext(refTypes, refLevels, lineLength); + + if (context) { + ResetLevels(context, paragraph->baseLevel, lineLength); + + line = AllocateLine(context->runCount); + + if (line) { + line->runCount = InitializeRuns(line->fixedRuns, context->fixedLevels, lineLength, lineOffset); + ReorderRuns(line->fixedRuns, line->runCount, context->maxLevel); + + line->codepointSequence = paragraph->algorithm->codepointSequence; + line->offset = lineOffset; + line->length = lineLength; + line->retainCount = 1; + } + + DisposeLineContext(context); + + return line; + } + + return NULL; +} + +SBUInteger SBLineGetOffset(SBLineRef line) +{ + return line->offset; +} + +SBUInteger SBLineGetLength(SBLineRef line) +{ + return line->length; +} + +SBUInteger SBLineGetRunCount(SBLineRef line) +{ + return line->runCount; +} + +const SBRun *SBLineGetRunsPtr(SBLineRef line) +{ + return line->fixedRuns; +} + +SBLineRef SBLineRetain(SBLineRef line) +{ + if (line) { + line->retainCount += 1; + } + + return line; +} + +void SBLineRelease(SBLineRef line) +{ + if (line && --line->retainCount == 0) { + free(line); + } +} diff --git a/third_party/sheenbidi/source/SBLine.h b/third_party/sheenbidi/source/SBLine.h new file mode 100644 index 0000000..6ecf103 --- /dev/null +++ b/third_party/sheenbidi/source/SBLine.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2014-2019 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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 _SB_INTERNAL_LINE_H +#define _SB_INTERNAL_LINE_H + +#include +#include +#include +#include +#include +#include + +typedef struct _SBLine { + SBCodepointSequence codepointSequence; + SBRun *fixedRuns; + SBUInteger runCount; + SBUInteger offset; + SBUInteger length; + SBUInteger retainCount; +} SBLine; + +SB_INTERNAL SBLineRef SBLineCreate(SBParagraphRef paragraph, + SBUInteger lineOffset, SBUInteger lineLength); + +#endif diff --git a/third_party/sheenbidi/source/SBLog.c b/third_party/sheenbidi/source/SBLog.c new file mode 100644 index 0000000..a77591f --- /dev/null +++ b/third_party/sheenbidi/source/SBLog.c @@ -0,0 +1,303 @@ +/* + * Copyright (C) 2014-2019 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ + +#include + +#ifdef SB_CONFIG_LOG + +#include "SBBase.h" +#include "SBBidiChain.h" +#include "SBBidiType.h" +#include "SBIsolatingRun.h" +#include "SBLog.h" + +int _SBLogPosition = 0; + +SB_INTERNAL void PrintBaseLevel(SBLevel baseLevel) +{ + switch (baseLevel) { + case SBLevelDefaultLTR: + SB_LOG_STRING("Auto-LTR"); + break; + + case SBLevelDefaultRTL: + SB_LOG_STRING("Auto-RTL"); + break; + + case 0: + SB_LOG_STRING("LTR"); + break; + + case 1: + SB_LOG_STRING("RTL"); + break; + + default: + SB_LOG(("Level - %d", baseLevel)); + break; + } +} + +SB_INTERNAL void PrintBidiType(SBBidiType type) +{ + switch (type) { + case SBBidiTypeNil: + SB_LOG_STRING("Nil"); + break; + + case SBBidiTypeL: + SB_LOG_STRING("L"); + break; + + case SBBidiTypeR: + SB_LOG_STRING("R"); + break; + + case SBBidiTypeAL: + SB_LOG_STRING("AL"); + break; + + case SBBidiTypeEN: + SB_LOG_STRING("EN"); + break; + + case SBBidiTypeES: + SB_LOG_STRING("ES"); + break; + + case SBBidiTypeET: + SB_LOG_STRING("EN"); + break; + + case SBBidiTypeAN: + SB_LOG_STRING("AN"); + break; + + case SBBidiTypeCS: + SB_LOG_STRING("CS"); + break; + + case SBBidiTypeNSM: + SB_LOG_STRING("NSM"); + break; + + case SBBidiTypeBN: + SB_LOG_STRING("BN"); + break; + + case SBBidiTypeB: + SB_LOG_STRING("B"); + break; + + case SBBidiTypeS: + SB_LOG_STRING("S"); + break; + + case SBBidiTypeWS: + SB_LOG_STRING("WS"); + break; + + case SBBidiTypeON: + SB_LOG_STRING("ON"); + break; + + case SBBidiTypeLRE: + SB_LOG_STRING("LRE"); + break; + + case SBBidiTypeRLE: + SB_LOG_STRING("RLE"); + break; + + case SBBidiTypeLRO: + SB_LOG_STRING("LRO"); + break; + + case SBBidiTypeRLO: + SB_LOG_STRING("RLO"); + break; + + case SBBidiTypePDF: + SB_LOG_STRING("PDF"); + break; + + case SBBidiTypeLRI: + SB_LOG_STRING("LRI"); + break; + + case SBBidiTypeRLI: + SB_LOG_STRING("RLI"); + break; + + case SBBidiTypeFSI: + SB_LOG_STRING("FSI"); + break; + + case SBBidiTypePDI: + SB_LOG_STRING("PDI"); + break; + } +} + +SB_INTERNAL void PrintCodepointSequence(const SBCodepointSequence *codepointSequence) +{ + SBUInteger stringIndex = 0; + SBCodepoint codepoint; + + while ((codepoint = SBCodepointSequenceGetCodepointAt(codepointSequence, &stringIndex)) != SBCodepointInvalid) { + SB_LOG(("%04X ", codepoint)); + } +} + +SB_INTERNAL void PrintBidiTypesArray(SBBidiType *types, SBUInteger length) +{ + SBUInteger index; + + for (index = 0; index < length; ++index) { + SB_LOG_BIDI_TYPE(types[index]); + SB_LOG_DIVIDER(1); + } +} + +SB_INTERNAL void PrintLevelsArray(SBLevel *levels, SBUInteger length) +{ + SBUInteger index; + + for (index = 0; index < length; ++index) { + SB_LOG_LEVEL(levels[index]); + SB_LOG_DIVIDER(1); + } +} + +typedef struct { + void *object; + BidiLink link; + SBUInteger length; +} IsolatingContext; + +typedef void (*IsolatingConsumer)(IsolatingRunRef isolatingRun, IsolatingContext *context); + +SB_INTERNAL void IsolatingRunForEach(IsolatingRunRef isolatingRun, + IsolatingContext *context, IsolatingConsumer consumer) +{ + BidiChainRef bidiChain = isolatingRun->bidiChain; + LevelRunRef levelRun; + + /* Iterate over individual level runs of the isolating run. */ + for (levelRun = isolatingRun->baseLevelRun; levelRun; levelRun = levelRun->next) { + BidiLink breakLink = BidiChainGetNext(bidiChain, levelRun->lastLink); + BidiLink currentLink = levelRun->firstLink; + BidiLink subsequentLink = levelRun->subsequentLink; + + /* Iterate over each link of the level run. */ + while (currentLink != breakLink) { + BidiLink nextLink = BidiChainGetNext(bidiChain, currentLink); + SBUInteger linkOffset = BidiChainGetOffset(bidiChain, currentLink); + SBUInteger linkLength; + SBUInteger index; + + if (nextLink != breakLink) { + linkLength = BidiChainGetOffset(bidiChain, nextLink) - linkOffset; + } else { + linkLength = BidiChainGetOffset(bidiChain, subsequentLink) - linkOffset; + } + + /* Skip any sequence of BN character types. */ + for (index = 1; index < linkLength; index++) { + SBBidiType bidiType = BidiChainGetType(bidiChain, currentLink + index); + if (bidiType == SBBidiTypeBN) { + linkLength = index; + break; + } + } + + context->link = currentLink; + context->length = linkLength; + consumer(isolatingRun, context); + + currentLink = nextLink; + } + } +} + +static void PrintTypesOperation(IsolatingRunRef isolatingRun, IsolatingContext *context) +{ + SBBidiType bidiType = BidiChainGetType(isolatingRun->bidiChain, context->link); + + while (context->length--) { + SB_LOG_BIDI_TYPE(bidiType); + SB_LOG_DIVIDER(1); + } +} + +SB_INTERNAL void PrintRunTypes(IsolatingRunRef isolatingRun) +{ + IsolatingContext context; + IsolatingRunForEach(isolatingRun, &context, _SBPrintTypesOperation); +} + +static void PrintLevelsOperation(IsolatingRunRef isolatingRun, IsolatingContext *context) +{ + SBLevel charLevel = BidiChainGetLevel(isolatingRun->bidiChain, context->link); + + while (context->length--) { + SB_LOG_LEVEL(charLevel); + SB_LOG_DIVIDER(1); + } +} + +SB_INTERNAL void PrintRunLevels(IsolatingRunRef isolatingRun) +{ + IsolatingContext context; + IsolatingRunForEach(isolatingRun, &context, _SBPrintLevelsOperation); +} + +typedef struct { + SBUInteger offset; + SBUInteger length; +} IsolatingRange; + +static void PrintRangeOperation(IsolatingRunRef isolatingRun, IsolatingContext *context) +{ + IsolatingRange *range = context->object; + SBUInteger offset = BidiChainGetOffset(isolatingRun->bidiChain, context->link); + + if (range->length == 0) { + range->offset = offset; + range->length = context->length; + } else if (offset == (range->offset + range->length)) { + range->length += context->length; + } else { + SB_LOG_RANGE(range->offset, range->length); + SB_LOG_DIVIDER(1); + + range->offset = offset; + range->length = context->length; + } +} + +SB_INTERNAL void PrintRunRange(IsolatingRunRef isolatingRun) +{ + IsolatingRange range = { 0, 0 }; + IsolatingContext context; + context.object = ⦥ + + IsolatingRunForEach(isolatingRun, &context, _SBPrintRangeOperation); + SB_LOG_RANGE(range.offset, range.length); + SB_LOG_DIVIDER(1); +} + +#endif diff --git a/third_party/sheenbidi/source/SBLog.h b/third_party/sheenbidi/source/SBLog.h new file mode 100644 index 0000000..5c70508 --- /dev/null +++ b/third_party/sheenbidi/source/SBLog.h @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2014-2019 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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 _SB_INTERNAL_LOG_H +#define _SB_INTERNAL_LOG_H + +#include + +#ifdef SB_CONFIG_LOG + +#include + +#include "SBBase.h" +#include "SBBidiType.h" +#include "SBCodepointSequence.h" +#include "SBIsolatingRun.h" + +SB_INTERNAL void PrintBaseLevel(SBLevel baseLevel); +SB_INTERNAL void PrintBidiType(SBBidiType type); + +SB_INTERNAL void PrintCodepointSequence(const SBCodepointSequence *codepointSequence); +SB_INTERNAL void PrintBidiTypesArray(SBBidiType *types, SBUInteger length); +SB_INTERNAL void PrintLevelsArray(SBLevel *levels, SBUInteger length); + +SB_INTERNAL void PrintRunTypes(IsolatingRunRef isolatingRun); +SB_INTERNAL void PrintRunLevels(IsolatingRunRef isolatingRun); +SB_INTERNAL void PrintRunRange(IsolatingRunRef isolatingRun); + +extern int _SBLogPosition; + +#define SB_LOG_BEGIN() (++_SBLogPosition) +#define SB_LOG_END() (--_SBLogPosition) + +#define SB_LOG(s) printf s + +#define SB_LOG_NUMBER(n) \ +SB_LOG(("%ld", (long)n)) + +#define SB_LOG_RANGE(o, l) \ +SB_LOG(("[%ld, %ld]", (long)o, (long)(o + l - 1))) + +#define SB_LOG_CHAR(c) \ +SBLOG(("%c", c)) + +#define SB_LOG_STRING(s) \ +SB_LOG(("%s", s)) + +#define SB_LOG_LEVEL(l) \ +SB_LOG_NUMBER(l) + +#define SB_LOG_BREAKER() \ +SB_LOG(("\n")) + +#define SB_LOG_DIVIDER(n) \ +SB_LOG(("%.*s", n, "\t\t\t\t\t\t\t\t\t\t")) + +#define SB_LOG_INITIATOR() \ +SB_LOG_DIVIDER(_SBLogPosition) + +#define SB_LOG_CAPTION(c) \ +SB_LOG((c":")) + +#define SB_LOG_STATEMENT_TEXT(t) \ +(t) + +#define SB_LOG_LINE(s) \ +do { \ + SB_LOG(s); \ + SB_LOG_BREAKER(); \ +} while (0) + +#define SB_LOG_STATEMENT(c, d, t) \ +do { \ + SB_LOG_INITIATOR(); \ + SB_LOG_CAPTION(c); \ + SB_LOG_DIVIDER(d); \ + SB_LOG_STATEMENT_TEXT(t); \ + SB_LOG_BREAKER(); \ +} while (0) + +#define SB_LOG_BLOCK_OPENER(c) \ +do { \ + SB_LOG_INITIATOR(); \ + SB_LOG_CAPTION(c); \ + SB_LOG_BREAKER(); \ + SB_LOG_BEGIN(); \ +} while (0) + +#define SB_LOG_BLOCK_CLOSER() SB_LOG_END() + +#define SB_LOG_BASE_LEVEL(l) PrintBaseLevel(l) +#define SB_LOG_BIDI_TYPE(t) PrintBidiType(t) + +#define SB_LOG_CODEPOINT_SEQUENCE(s) PrintCodepointSequence(s) +#define SB_LOG_BIDI_TYPES_ARRAY(a, l) PrintBidiTypesArray(a, l) +#define SB_LOG_LEVELS_ARRAY(a, l) PrintLevelsArray(a, l) + +#define SB_LOG_RUN_TYPES(r) PrintRunTypes(r) +#define SB_LOG_RUN_LEVELS(r) PrintRunLevels(r) +#define SB_LOG_RUN_RANGE(r) PrintRunRange(r) + +#else + +#define SB_LOG_NONE() + +#define SB_LOG(s) SB_LOG_NONE() + +#define SB_LOG_NUMBER(n) SB_LOG_NONE() +#define SB_LOG_RANGE(o, l) SB_LOG_NONE() +#define SB_LOG_CHAR(c) SB_LOG_NONE() +#define SB_LOG_STRING(s) SB_LOG_NONE() +#define SB_LOG_LEVEL(l) SB_LOG_NONE() + +#define SB_LOG_BREAKER() SB_LOG_NONE() +#define SB_LOG_DIVIDER(n) SB_LOG_NONE() +#define SB_LOG_INITIATOR() SB_LOG_NONE() +#define SB_LOG_CAPTION(c) SB_LOG_NONE() +#define SB_LOG_STATEMENT_TEXT(t) SB_LOG_NONE() + +#define SB_LOG_LINE(s) SB_LOG_NONE() +#define SB_LOG_STATEMENT(c, d, t) SB_LOG_NONE() + +#define SB_LOG_BLOCK_OPENER(c) SB_LOG_NONE() +#define SB_LOG_BLOCK_CLOSER() SB_LOG_NONE() + +#define SB_LOG_BASE_LEVEL(l) SB_LOG_NONE() +#define SB_LOG_BIDI_TYPE(t) SB_LOG_NONE() + +#define SB_LOG_CODEPOINT_SEQUENCE(s) SB_LOG_NONE() +#define SB_LOG_BIDI_TYPES_ARRAY(a, l) SB_LOG_NONE() +#define SB_LOG_LEVELS_ARRAY(a, l) SB_LOG_NONE() + +#define SB_LOG_RUN_TYPES(r) SB_LOG_NONE() +#define SB_LOG_RUN_LEVELS(r) SB_LOG_NONE() + +#define SB_LOG_RUN_RANGE(r) SB_LOG_NONE() + +#endif + +#endif diff --git a/third_party/sheenbidi/source/SBMirrorLocator.c b/third_party/sheenbidi/source/SBMirrorLocator.c new file mode 100644 index 0000000..c8a8c96 --- /dev/null +++ b/third_party/sheenbidi/source/SBMirrorLocator.c @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2014-2022 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ + +#include +#include + +#include "PairingLookup.h" +#include "SBBase.h" +#include "SBLine.h" +#include "SBMirrorLocator.h" + +SBMirrorLocatorRef SBMirrorLocatorCreate(void) +{ + SBMirrorLocatorRef locator = malloc(sizeof(SBMirrorLocator)); + + if (locator) { + locator->_line = NULL; + locator->retainCount = 1; + + SBMirrorLocatorReset(locator); + } + + return locator; +} + +void SBMirrorLocatorLoadLine(SBMirrorLocatorRef locator, SBLineRef line, void *stringBuffer) +{ + SBLineRelease(locator->_line); + + if (line && stringBuffer == line->codepointSequence.stringBuffer) { + locator->_line = SBLineRetain(line); + } + + SBMirrorLocatorReset(locator); +} + +const SBMirrorAgent *SBMirrorLocatorGetAgent(SBMirrorLocatorRef locator) +{ + return &locator->agent; +} + +SBBoolean SBMirrorLocatorMoveNext(SBMirrorLocatorRef locator) +{ + SBLineRef line = locator->_line; + + if (line) { + const SBCodepointSequence *sequence = &line->codepointSequence; + + do { + const SBRun *run = &line->fixedRuns[locator->_runIndex]; + + if (run->level & 1) { + SBUInteger stringIndex; + SBUInteger stringLimit; + + stringIndex = locator->_stringIndex; + if (stringIndex == SBInvalidIndex) { + stringIndex = run->offset; + } + stringLimit = run->offset + run->length; + + while (stringIndex < stringLimit) { + SBUInteger initialIndex = stringIndex; + SBCodepoint codepoint = SBCodepointSequenceGetCodepointAt(sequence, &stringIndex); + SBCodepoint mirror = LookupMirror(codepoint); + + if (mirror) { + locator->_stringIndex = stringIndex; + locator->agent.index = initialIndex; + locator->agent.mirror = mirror; + locator->agent.codepoint = codepoint; + + return SBTrue; + } + } + } + + locator->_stringIndex = SBInvalidIndex; + } while (++locator->_runIndex < line->runCount); + + SBMirrorLocatorReset(locator); + } + + return SBFalse; +} + +void SBMirrorLocatorReset(SBMirrorLocatorRef locator) +{ + locator->_runIndex = 0; + locator->_stringIndex = SBInvalidIndex; + locator->agent.index = SBInvalidIndex; + locator->agent.mirror = 0; +} + +SBMirrorLocatorRef SBMirrorLocatorRetain(SBMirrorLocatorRef locator) +{ + if (locator) { + locator->retainCount += 1; + } + + return locator; +} + +void SBMirrorLocatorRelease(SBMirrorLocatorRef locator) +{ + if (locator && --locator->retainCount == 0) { + SBLineRelease(locator->_line); + free(locator); + } +} diff --git a/third_party/sheenbidi/source/SBMirrorLocator.h b/third_party/sheenbidi/source/SBMirrorLocator.h new file mode 100644 index 0000000..2f4463a --- /dev/null +++ b/third_party/sheenbidi/source/SBMirrorLocator.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2014-2019 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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 _SB_INTERNAL_MIRROR_LOCATOR_H +#define _SB_INTERNAL_MIRROR_LOCATOR_H + +#include +#include +#include + +typedef struct _SBMirrorLocator { + SBLineRef _line; + SBUInteger _runIndex; + SBUInteger _stringIndex; + SBMirrorAgent agent; + SBUInteger retainCount; +} SBMirrorLocator; + +#endif diff --git a/third_party/sheenbidi/source/SBParagraph.c b/third_party/sheenbidi/source/SBParagraph.c new file mode 100644 index 0000000..a98bd89 --- /dev/null +++ b/third_party/sheenbidi/source/SBParagraph.c @@ -0,0 +1,702 @@ +/* + * Copyright (C) 2014-2022 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ + +#include +#include +#include + +#include "BidiChain.h" +#include "BidiTypeLookup.h" +#include "IsolatingRun.h" +#include "LevelRun.h" +#include "RunQueue.h" +#include "SBAlgorithm.h" +#include "SBAssert.h" +#include "SBBase.h" +#include "SBCodepointSequence.h" +#include "SBLine.h" +#include "SBLog.h" +#include "StatusStack.h" +#include "SBParagraph.h" + +typedef struct _ParagraphContext { + BidiChain bidiChain; + StatusStack statusStack; + RunQueue runQueue; + IsolatingRun isolatingRun; +} ParagraphContext, *ParagraphContextRef; + +static void PopulateBidiChain(BidiChainRef chain, const SBBidiType *types, SBUInteger length); +static SBBoolean ProcessRun(ParagraphContextRef context, const LevelRunRef levelRun, SBBoolean forceFinish); + +static ParagraphContextRef CreateParagraphContext(const SBBidiType *types, SBLevel *levels, SBUInteger length) +{ + const SBUInteger sizeContext = sizeof(ParagraphContext); + const SBUInteger sizeLinks = sizeof(BidiLink) * (length + 2); + const SBUInteger sizeTypes = sizeof(SBBidiType) * (length + 2); + const SBUInteger sizeMemory = sizeContext + sizeLinks + sizeTypes; + + void *pointer = malloc(sizeMemory); + + if (pointer) { + const SBUInteger offsetContext = 0; + const SBUInteger offsetLinks = offsetContext + sizeContext; + const SBUInteger offsetTypes = offsetLinks + sizeLinks; + + SBUInt8 *memory = (SBUInt8 *)pointer; + ParagraphContextRef context = (ParagraphContextRef)(memory + offsetContext); + BidiLink *fixedLinks = (BidiLink *)(memory + offsetLinks); + SBBidiType *fixedTypes = (SBBidiType *)(memory + offsetTypes); + + BidiChainInitialize(&context->bidiChain, fixedTypes, levels, fixedLinks); + StatusStackInitialize(&context->statusStack); + RunQueueInitialize(&context->runQueue); + IsolatingRunInitialize(&context->isolatingRun); + + PopulateBidiChain(&context->bidiChain, types, length); + + return context; + } + + return NULL; +} + +static void DisposeParagraphContext(ParagraphContextRef context) +{ + StatusStackFinalize(&context->statusStack); + RunQueueFinalize(&context->runQueue); + IsolatingRunFinalize(&context->isolatingRun); + free(context); +} + +static SBParagraphRef AllocateParagraph(SBUInteger length) +{ + const SBUInteger sizeParagraph = sizeof(SBParagraph); + const SBUInteger sizeLevels = sizeof(SBLevel) * (length + 2); + const SBUInteger sizeMemory = sizeParagraph + sizeLevels; + + void *pointer = malloc(sizeMemory); + + if (pointer) { + const SBUInteger offsetParagraph = 0; + const SBUInteger offsetLevels = offsetParagraph + sizeParagraph; + + SBUInt8 *memory = (SBUInt8 *)pointer; + SBParagraphRef paragraph = (SBParagraphRef)(memory + offsetParagraph); + SBLevel *levels = (SBLevel *)(memory + offsetLevels); + + paragraph->fixedLevels = levels; + + return paragraph; + } + + return NULL; +} + +static void DisposeParagraph(SBParagraphRef paragraph) +{ + free(paragraph); +} + +static SBUInteger DetermineBoundary(SBAlgorithmRef algorithm, SBUInteger paragraphOffset, SBUInteger suggestedLength) +{ + SBBidiType *bidiTypes = algorithm->fixedTypes; + SBUInteger suggestedLimit = paragraphOffset + suggestedLength; + SBUInteger stringIndex; + + for (stringIndex = paragraphOffset; stringIndex < suggestedLimit; stringIndex++) { + if (bidiTypes[stringIndex] == SBBidiTypeB) { + stringIndex += SBAlgorithmGetSeparatorLength(algorithm, stringIndex); + goto Return; + } + } + +Return: + return (stringIndex - paragraphOffset); +} + +static void PopulateBidiChain(BidiChainRef chain, const SBBidiType *types, SBUInteger length) +{ + SBBidiType type = SBBidiTypeNil; + SBUInteger priorIndex = SBInvalidIndex; + SBUInteger index; + + for (index = 0; index < length; index++) { + SBBidiType priorType = type; + type = types[index]; + + switch (type) { + case SBBidiTypeB: + case SBBidiTypeON: + case SBBidiTypeLRE: + case SBBidiTypeRLE: + case SBBidiTypeLRO: + case SBBidiTypeRLO: + case SBBidiTypePDF: + case SBBidiTypeLRI: + case SBBidiTypeRLI: + case SBBidiTypeFSI: + case SBBidiTypePDI: + BidiChainAdd(chain, type, index - priorIndex); + priorIndex = index; + + if (type == SBBidiTypeB) { + index = length; + goto AddLast; + } + break; + + default: + if (type != priorType) { + BidiChainAdd(chain, type, index - priorIndex); + priorIndex = index; + } + break; + } + } + +AddLast: + BidiChainAdd(chain, SBBidiTypeNil, index - priorIndex); +} + +static BidiLink SkipIsolatingRun(BidiChainRef chain, BidiLink skipLink, BidiLink breakLink) +{ + BidiLink link = skipLink; + SBUInteger depth = 1; + + while ((link = BidiChainGetNext(chain, link)) != breakLink) { + SBBidiType type = BidiChainGetType(chain, link); + + switch (type) { + case SBBidiTypeLRI: + case SBBidiTypeRLI: + case SBBidiTypeFSI: + depth += 1; + break; + + case SBBidiTypePDI: + if (--depth == 0) { + return link; + } + break; + } + } + + return BidiLinkNone; +} + +static SBLevel DetermineBaseLevel(BidiChainRef chain, BidiLink skipLink, BidiLink breakLink, SBLevel defaultLevel, SBBoolean isIsolate) +{ + BidiLink link = skipLink; + + /* Rules P2, P3 */ + while ((link = BidiChainGetNext(chain, link)) != breakLink) { + SBBidiType type = BidiChainGetType(chain, link); + + switch (type) { + case SBBidiTypeL: + return 0; + + case SBBidiTypeAL: + case SBBidiTypeR: + return 1; + + case SBBidiTypeLRI: + case SBBidiTypeRLI: + case SBBidiTypeFSI: + link = SkipIsolatingRun(chain, link, breakLink); + if (link == BidiLinkNone) { + goto Default; + } + break; + + case SBBidiTypePDI: + if (isIsolate) { + /* + * In case of isolating run, the PDI will be the last code point. + * NOTE: + * The inner isolating runs will be skipped by the case above this one. + */ + goto Default; + } + break; + } + } + +Default: + return defaultLevel; +} + +static SBLevel DetermineParagraphLevel(BidiChainRef chain, SBLevel baseLevel) +{ + if (baseLevel >= SBLevelMax) { + return DetermineBaseLevel(chain, chain->roller, chain->roller, + (baseLevel != SBLevelDefaultRTL ? 0 : 1), + SBFalse); + } + + return baseLevel; +} + +static SBBoolean DetermineLevels(ParagraphContextRef context, SBLevel baseLevel) +{ + BidiChainRef chain = &context->bidiChain; + StatusStackRef stack = &context->statusStack; + BidiLink roller = chain->roller; + BidiLink link; + + BidiLink priorLink; + BidiLink firstLink; + BidiLink lastLink; + + SBLevel priorLevel; + SBBidiType sor; + SBBidiType eor; + + SBUInteger overIsolate; + SBUInteger overEmbedding; + SBUInteger validIsolate; + + priorLink = chain->roller; + firstLink = BidiLinkNone; + lastLink = BidiLinkNone; + + priorLevel = baseLevel; + sor = SBBidiTypeNil; + + /* Rule X1 */ + overIsolate = 0; + overEmbedding = 0; + validIsolate = 0; + + StatusStackPush(stack, baseLevel, SBBidiTypeON, SBFalse); + + BidiChainForEach(chain, roller, link) { + SBBoolean forceFinish = SBFalse; + SBBoolean bnEquivalent = SBFalse; + SBBidiType type; + + type = BidiChainGetType(chain, link); + +#define LeastGreaterOddLevel() \ +( \ + (StatusStackGetEmbeddingLevel(stack) + 1) | 1 \ +) + +#define LeastGreaterEvenLevel() \ +( \ + (StatusStackGetEmbeddingLevel(stack) + 2) & ~1 \ +) + +#define MergeLinkIfNeeded() \ +{ \ + if (BidiChainMergeIfEqual(chain, priorLink, link)) { \ + continue; \ + } \ +} + +#define PushEmbedding(l, o) \ +{ \ + SBLevel newLevel = l; \ + \ + bnEquivalent = SBTrue; \ + \ + if (newLevel <= SBLevelMax && !overIsolate && !overEmbedding) { \ + if (!StatusStackPush(stack, newLevel, o, SBFalse)) { \ + return SBFalse; \ + } \ + } else { \ + if (!overIsolate) { \ + overEmbedding += 1; \ + } \ + } \ +} + +#define PushIsolate(l, o) \ +{ \ + SBBidiType priorStatus = StatusStackGetOverrideStatus(stack); \ + SBLevel newLevel = l; \ + \ + BidiChainSetLevel(chain, link, \ + StatusStackGetEmbeddingLevel(stack)); \ + \ + if (newLevel <= SBLevelMax && !overIsolate && !overEmbedding) { \ + validIsolate += 1; \ + \ + if (!StatusStackPush(stack, newLevel, o, SBTrue)) { \ + return SBFalse; \ + } \ + } else { \ + overIsolate += 1; \ + } \ + \ + if (priorStatus != SBBidiTypeON) { \ + BidiChainSetType(chain, link, priorStatus); \ + MergeLinkIfNeeded(); \ + } \ +} + + switch (type) { + /* Rule X2 */ + case SBBidiTypeRLE: + PushEmbedding(LeastGreaterOddLevel(), SBBidiTypeON); + break; + + /* Rule X3 */ + case SBBidiTypeLRE: + PushEmbedding(LeastGreaterEvenLevel(), SBBidiTypeON); + break; + + /* Rule X4 */ + case SBBidiTypeRLO: + PushEmbedding(LeastGreaterOddLevel(), SBBidiTypeR); + break; + + /* Rule X5 */ + case SBBidiTypeLRO: + PushEmbedding(LeastGreaterEvenLevel(), SBBidiTypeL); + break; + + /* Rule X5a */ + case SBBidiTypeRLI: + PushIsolate(LeastGreaterOddLevel(), SBBidiTypeON); + break; + + /* Rule X5b */ + case SBBidiTypeLRI: + PushIsolate(LeastGreaterEvenLevel(), SBBidiTypeON); + break; + + /* Rule X5c */ + case SBBidiTypeFSI: + { + SBBoolean isRTL = (DetermineBaseLevel(chain, link, roller, 0, SBTrue) == 1); + PushIsolate(isRTL ? LeastGreaterOddLevel() : LeastGreaterEvenLevel(), SBBidiTypeON); + break; + } + + /* Rule X6 */ + default: + BidiChainSetLevel(chain, link, StatusStackGetEmbeddingLevel(stack)); + + if (StatusStackGetOverrideStatus(stack) != SBBidiTypeON) { + BidiChainSetType(chain, link, StatusStackGetOverrideStatus(stack)); + MergeLinkIfNeeded(); + } + break; + + /* Rule X6a */ + case SBBidiTypePDI: + { + SBBidiType overrideStatus; + + if (overIsolate != 0) { + overIsolate -= 1; + } else if (validIsolate == 0) { + /* Do nothing */ + } else { + overEmbedding = 0; + + while (!StatusStackGetIsolateStatus(stack)) { + StatusStackPop(stack); + } + StatusStackPop(stack); + + validIsolate -= 1; + } + + BidiChainSetLevel(chain, link, StatusStackGetEmbeddingLevel(stack)); + overrideStatus = StatusStackGetOverrideStatus(stack); + + if (overrideStatus != SBBidiTypeON) { + BidiChainSetType(chain, link, overrideStatus); + MergeLinkIfNeeded(); + } + break; + } + + /* Rule X7 */ + case SBBidiTypePDF: + bnEquivalent = SBTrue; + + if (overIsolate != 0) { + /* Do nothing */ + } else if (overEmbedding != 0) { + overEmbedding -= 1; + } else if (!StatusStackGetIsolateStatus(stack) && stack->count >= 2) { + StatusStackPop(stack); + } + break; + + /* Rule X8 */ + case SBBidiTypeB: + /* + * These values are reset for clarity, in this implementation B can only occur as the + * last code in the array. + */ + StatusStackSetEmpty(stack); + StatusStackPush(stack, baseLevel, SBBidiTypeON, SBFalse); + + overIsolate = 0; + overEmbedding = 0; + validIsolate = 0; + + BidiChainSetLevel(chain, link, baseLevel); + break; + + case SBBidiTypeBN: + bnEquivalent = SBTrue; + break; + + case SBBidiTypeNil: + forceFinish = SBTrue; + BidiChainSetLevel(chain, link, baseLevel); + break; + } + + /* Rule X9 */ + if (bnEquivalent) { + /* The type of this link is BN equivalent, so abandon it and continue the loop. */ + BidiChainSetType(chain, link, SBBidiTypeBN); + BidiChainAbandonNext(chain, priorLink); + continue; + } + + if (sor == SBBidiTypeNil) { + sor = SBLevelAsNormalBidiType(SBNumberGetMax(baseLevel, BidiChainGetLevel(chain, link))); + firstLink = link; + priorLevel = BidiChainGetLevel(chain, link); + } else if (priorLevel != BidiChainGetLevel(chain, link) || forceFinish) { + LevelRun levelRun; + SBLevel currentLevel; + + /* Since the level has changed at this link, therefore the run must end at prior link. */ + lastLink = priorLink; + + /* Save the current level i.e. level of the next run. */ + currentLevel = BidiChainGetLevel(chain, link); + /* + * Now we have both the prior level and the current level i.e. unchanged levels of both + * the current run and the next run. So, identify eor of the current run. + * NOTE: + * sor of the run has been already determined at this stage. + */ + eor = SBLevelAsNormalBidiType(SBNumberGetMax(priorLevel, currentLevel)); + + LevelRunInitialize(&levelRun, chain, firstLink, lastLink, sor, eor); + + if (!ProcessRun(context, &levelRun, forceFinish)) { + return SBFalse; + } + + /* The sor of next run (if any) should be technically equal to eor of this run. */ + sor = eor; + /* The next run (if any) will start from this index. */ + firstLink = link; + + priorLevel = currentLevel; + } + + priorLink = link; + } + + return SBTrue; +} + +static SBBoolean ProcessRun(ParagraphContextRef context, const LevelRunRef levelRun, SBBoolean forceFinish) +{ + RunQueueRef queue = &context->runQueue; + + if (!RunQueueEnqueue(queue, levelRun)) { + return SBFalse; + } + + if (queue->shouldDequeue || forceFinish) { + IsolatingRunRef isolatingRun = &context->isolatingRun; + LevelRunRef peek; + + /* Rule X10 */ + for (; queue->count != 0; RunQueueDequeue(queue)) { + peek = queue->peek; + if (RunKindIsAttachedTerminating(peek->kind)) { + continue; + } + + isolatingRun->baseLevelRun = peek; + + if (!IsolatingRunResolve(isolatingRun)) { + return SBFalse; + } + } + } + + return SBTrue; +} + +static void SaveLevels(BidiChainRef chain, SBLevel *levels, SBLevel baseLevel) +{ + BidiLink roller = chain->roller; + BidiLink link; + + SBUInteger index = 0; + SBLevel level = baseLevel; + + BidiChainForEach(chain, roller, link) { + SBUInteger offset = BidiChainGetOffset(chain, link); + + for (; index < offset; index++) { + levels[index] = level; + } + + level = BidiChainGetLevel(chain, link); + } +} + +static SBBoolean ResolveParagraph(SBParagraphRef paragraph, + SBAlgorithmRef algorithm, SBUInteger offset, SBUInteger length, SBLevel baseLevel) +{ + const SBBidiType *bidiTypes = algorithm->fixedTypes + offset; + SBBoolean isSucceeded = SBFalse; + ParagraphContextRef context; + SBLevel resolvedLevel; + + context = CreateParagraphContext(bidiTypes, paragraph->fixedLevels, length); + + if (context) { + resolvedLevel = DetermineParagraphLevel(&context->bidiChain, baseLevel); + + SB_LOG_BLOCK_OPENER("Determined Paragraph Level"); + SB_LOG_STATEMENT("Base Level", 1, SB_LOG_LEVEL(resolvedLevel)); + SB_LOG_BLOCK_CLOSER(); + + context->isolatingRun.codepointSequence = &algorithm->codepointSequence; + context->isolatingRun.bidiTypes = bidiTypes; + context->isolatingRun.bidiChain = &context->bidiChain; + context->isolatingRun.paragraphOffset = offset; + context->isolatingRun.paragraphLevel = resolvedLevel; + + if (DetermineLevels(context, resolvedLevel)) { + SaveLevels(&context->bidiChain, ++paragraph->fixedLevels, resolvedLevel); + + SB_LOG_BLOCK_OPENER("Determined Embedding Levels"); + SB_LOG_STATEMENT("Levels", 1, SB_LOG_LEVELS_ARRAY(paragraph->fixedLevels, length)); + SB_LOG_BLOCK_CLOSER(); + + paragraph->algorithm = SBAlgorithmRetain(algorithm); + paragraph->refTypes = bidiTypes; + paragraph->offset = offset; + paragraph->length = length; + paragraph->baseLevel = resolvedLevel; + paragraph->retainCount = 1; + + isSucceeded = SBTrue; + } + + DisposeParagraphContext(context); + } + + return isSucceeded; +} + +SB_INTERNAL SBParagraphRef SBParagraphCreate(SBAlgorithmRef algorithm, + SBUInteger paragraphOffset, SBUInteger suggestedLength, SBLevel baseLevel) +{ + const SBCodepointSequence *codepointSequence = &algorithm->codepointSequence; + SBUInteger stringLength = codepointSequence->stringLength; + SBUInteger actualLength; + + SBParagraphRef paragraph; + + /* The given range MUST be valid. */ + SBAssert(SBUIntegerVerifyRange(stringLength, paragraphOffset, suggestedLength) && suggestedLength > 0); + + SB_LOG_BLOCK_OPENER("Paragraph Input"); + SB_LOG_STATEMENT("Paragraph Offset", 1, SB_LOG_NUMBER(paragraphOffset)); + SB_LOG_STATEMENT("Suggested Length", 1, SB_LOG_NUMBER(suggestedLength)); + SB_LOG_STATEMENT("Base Direction", 1, SB_LOG_BASE_LEVEL(baseLevel)); + SB_LOG_BLOCK_CLOSER(); + + actualLength = DetermineBoundary(algorithm, paragraphOffset, suggestedLength); + + SB_LOG_BLOCK_OPENER("Determined Paragraph Boundary"); + SB_LOG_STATEMENT("Actual Length", 1, SB_LOG_NUMBER(actualLength)); + SB_LOG_BLOCK_CLOSER(); + + paragraph = AllocateParagraph(actualLength); + + if (paragraph) { + if (ResolveParagraph(paragraph, algorithm, paragraphOffset, actualLength, baseLevel)) { + return paragraph; + } + + DisposeParagraph(paragraph); + } + + SB_LOG_BREAKER(); + + return NULL; +} + +SBUInteger SBParagraphGetOffset(SBParagraphRef paragraph) +{ + return paragraph->offset; +} + +SBUInteger SBParagraphGetLength(SBParagraphRef paragraph) +{ + return paragraph->length; +} + +SBLevel SBParagraphGetBaseLevel(SBParagraphRef paragraph) +{ + return paragraph->baseLevel; +} + +const SBLevel *SBParagraphGetLevelsPtr(SBParagraphRef paragraph) +{ + return paragraph->fixedLevels; +} + +SBLineRef SBParagraphCreateLine(SBParagraphRef paragraph, SBUInteger lineOffset, SBUInteger lineLength) +{ + SBUInteger paragraphOffset = paragraph->offset; + SBUInteger paragraphLength = paragraph->length; + SBUInteger paragraphLimit = paragraphOffset + paragraphLength; + SBUInteger lineLimit = lineOffset + lineLength; + + if (lineOffset < lineLimit && lineOffset >= paragraphOffset && lineLimit <= paragraphLimit) { + return SBLineCreate(paragraph, lineOffset, lineLength); + } + + return NULL; +} + +SBParagraphRef SBParagraphRetain(SBParagraphRef paragraph) +{ + if (paragraph) { + paragraph->retainCount += 1; + } + + return paragraph; +} + +void SBParagraphRelease(SBParagraphRef paragraph) +{ + if (paragraph && --paragraph->retainCount == 0) { + SBAlgorithmRelease(paragraph->algorithm); + DisposeParagraph(paragraph); + } +} diff --git a/third_party/sheenbidi/source/SBParagraph.h b/third_party/sheenbidi/source/SBParagraph.h new file mode 100644 index 0000000..c40b4ee --- /dev/null +++ b/third_party/sheenbidi/source/SBParagraph.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2014-2019 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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 _SB_INTERNAL_PARAGRAPH_H +#define _SB_INTERNAL_PARAGRAPH_H + +#include +#include +#include +#include + +typedef struct _SBParagraph { + SBAlgorithmRef algorithm; + const SBBidiType *refTypes; + SBLevel *fixedLevels; + SBUInteger offset; + SBUInteger length; + SBLevel baseLevel; + SBUInteger retainCount; +} SBParagraph; + +SB_INTERNAL SBParagraphRef SBParagraphCreate(SBAlgorithmRef algorithm, + SBUInteger paragraphOffset, SBUInteger suggestedLength, SBLevel baseLevel); + +#endif diff --git a/third_party/sheenbidi/source/SBScriptLocator.c b/third_party/sheenbidi/source/SBScriptLocator.c new file mode 100644 index 0000000..6156869 --- /dev/null +++ b/third_party/sheenbidi/source/SBScriptLocator.c @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2018-2022 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ + +#include +#include + +#include "GeneralCategoryLookup.h" +#include "PairingLookup.h" +#include "SBBase.h" +#include "SBCodepointSequence.h" +#include "ScriptLookup.h" +#include "ScriptStack.h" +#include "SBScriptLocator.h" + +static SBBoolean IsSimilarScript(SBScript lhs, SBScript rhs) +{ + return SBScriptIsCommonOrInherited(lhs) + || SBScriptIsCommonOrInherited(rhs) + || lhs == rhs; +} + +SBScriptLocatorRef SBScriptLocatorCreate(void) +{ + SBScriptLocatorRef locator = malloc(sizeof(SBScriptLocator)); + + if (locator) { + locator->_codepointSequence.stringEncoding = SBStringEncodingUTF8; + locator->_codepointSequence.stringBuffer = NULL; + locator->_codepointSequence.stringLength = 0; + locator->retainCount = 1; + + SBScriptLocatorReset(locator); + } + + return locator; +} + +void SBScriptLocatorLoadCodepoints(SBScriptLocatorRef locator, const SBCodepointSequence *codepointSequence) +{ + locator->_codepointSequence = *codepointSequence; + SBScriptLocatorReset(locator); +} + +const SBScriptAgent *SBScriptLocatorGetAgent(SBScriptLocatorRef locator) +{ + return &locator->agent; +} + +static void ResolveScriptRun(SBScriptLocatorRef locator, SBUInteger offset) +{ + const SBCodepointSequence *sequence = &locator->_codepointSequence; + ScriptStackRef stack = &locator->_scriptStack; + SBScript result = SBScriptZYYY; + SBUInteger current = offset; + SBUInteger next = offset; + SBCodepoint codepoint; + + /* Iterate over the code points of specified string buffer. */ + while ((codepoint = SBCodepointSequenceGetCodepointAt(sequence, &next)) != SBCodepointInvalid) { + SBBoolean isStacked = SBFalse; + SBScript script; + + script = LookupScript(codepoint); + + /* Handle paired punctuations in case of a common script. */ + if (script == SBScriptZYYY) { + SBGeneralCategory generalCategory = LookupGeneralCategory(codepoint); + + /* Check if current code point is an open punctuation. */ + if (generalCategory == SBGeneralCategoryPS) { + SBCodepoint mirror = LookupMirror(codepoint); + if (mirror) { + /* A closing pair exists for this punctuation, so push it onto the stack. */ + ScriptStackPush(stack, result, mirror); + } + } + /* Check if current code point is a close punctuation. */ + else if (generalCategory == SBGeneralCategoryPE) { + SBBoolean isMirrored = (LookupMirror(codepoint) != 0); + if (isMirrored) { + /* Find the matching entry in the stack, while popping the unmatched ones. */ + while (!ScriptStackIsEmpty(stack)) { + SBCodepoint mirror = ScriptStackGetMirror(stack); + if (mirror != codepoint) { + ScriptStackPop(stack); + } else { + break; + } + } + + if (!ScriptStackIsEmpty(stack)) { + isStacked = SBTrue; + /* Paired punctuation match the script of enclosing text. */ + script = ScriptStackGetScript(stack); + } + } + } + } + + if (IsSimilarScript(result, script)) { + if (SBScriptIsCommonOrInherited(result) && !SBScriptIsCommonOrInherited(script)) { + /* Set the concrete script of this code point as the result. */ + result = script; + /* Seal the pending punctuations with the result. */ + ScriptStackSealPairs(stack, result); + } + + if (isStacked) { + /* Pop the paired punctuation from the stack. */ + ScriptStackPop(stack); + } + } else { + /* The current code point has a different script, so finish the run. */ + break; + } + + current = next; + } + + ScriptStackLeavePairs(stack); + + /* Set the run info in agent. */ + locator->agent.offset = offset; + locator->agent.length = current - offset; + locator->agent.script = result; +} + +SBBoolean SBScriptLocatorMoveNext(SBScriptLocatorRef locator) +{ + SBUInteger offset = locator->agent.offset + locator->agent.length; + + if (offset < locator->_codepointSequence.stringLength) { + ResolveScriptRun(locator, offset); + return SBTrue; + } + + SBScriptLocatorReset(locator); + return SBFalse; +} + +void SBScriptLocatorReset(SBScriptLocatorRef locator) +{ + ScriptStackReset(&locator->_scriptStack); + locator->agent.offset = 0; + locator->agent.length = 0; + locator->agent.script = SBScriptNil; +} + +SBScriptLocatorRef SBScriptLocatorRetain(SBScriptLocatorRef locator) +{ + if (locator) { + locator->retainCount += 1; + } + + return locator; +} + +void SBScriptLocatorRelease(SBScriptLocatorRef locator) +{ + if (locator && --locator->retainCount == 0) { + free(locator); + } +} diff --git a/third_party/sheenbidi/source/SBScriptLocator.h b/third_party/sheenbidi/source/SBScriptLocator.h new file mode 100644 index 0000000..c9ea97e --- /dev/null +++ b/third_party/sheenbidi/source/SBScriptLocator.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2018-2019 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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 _SB_INTERNAL_SCRIPT_LOCATOR_H +#define _SB_INTERNAL_SCRIPT_LOCATOR_H + +#include +#include +#include + +#include "ScriptStack.h" + +typedef struct _SBScriptLocator { + SBCodepointSequence _codepointSequence; + ScriptStack _scriptStack; + SBScriptAgent agent; + SBUInteger retainCount; +} SBScriptLocator; + +#endif diff --git a/third_party/sheenbidi/source/ScriptLookup.c b/third_party/sheenbidi/source/ScriptLookup.c new file mode 100644 index 0000000..5ac96bd --- /dev/null +++ b/third_party/sheenbidi/source/ScriptLookup.c @@ -0,0 +1,2240 @@ +/* + * Automatically generated by SheenBidiGenerator tool. + * DO NOT EDIT!! + * + * REQUIRED MEMORY: 10624+(3231*2)+(1793*2) = 20672 Bytes + */ + +#include "ScriptLookup.h" + +#define Adlm SBScriptADLM +#define Aghb SBScriptAGHB +#define Ahom SBScriptAHOM +#define Arab SBScriptARAB +#define Armi SBScriptARMI +#define Armn SBScriptARMN +#define Avst SBScriptAVST +#define Bali SBScriptBALI +#define Bamu SBScriptBAMU +#define Bass SBScriptBASS +#define Batk SBScriptBATK +#define Beng SBScriptBENG +#define Bhks SBScriptBHKS +#define Bopo SBScriptBOPO +#define Brah SBScriptBRAH +#define Brai SBScriptBRAI +#define Bugi SBScriptBUGI +#define Buhd SBScriptBUHD +#define Cakm SBScriptCAKM +#define Cans SBScriptCANS +#define Cari SBScriptCARI +#define Cham SBScriptCHAM +#define Cher SBScriptCHER +#define Chrs SBScriptCHRS +#define Copt SBScriptCOPT +#define Cpmn SBScriptCPMN +#define Cprt SBScriptCPRT +#define Cyrl SBScriptCYRL +#define Deva SBScriptDEVA +#define Diak SBScriptDIAK +#define Dogr SBScriptDOGR +#define Dsrt SBScriptDSRT +#define Dupl SBScriptDUPL +#define Egyp SBScriptEGYP +#define Elba SBScriptELBA +#define Elym SBScriptELYM +#define Ethi SBScriptETHI +#define Geor SBScriptGEOR +#define Glag SBScriptGLAG +#define Gong SBScriptGONG +#define Gonm SBScriptGONM +#define Goth SBScriptGOTH +#define Gran SBScriptGRAN +#define Grek SBScriptGREK +#define Gujr SBScriptGUJR +#define Guru SBScriptGURU +#define Hang SBScriptHANG +#define Hani SBScriptHANI +#define Hano SBScriptHANO +#define Hatr SBScriptHATR +#define Hebr SBScriptHEBR +#define Hira SBScriptHIRA +#define Hluw SBScriptHLUW +#define Hmng SBScriptHMNG +#define Hmnp SBScriptHMNP +#define Hung SBScriptHUNG +#define Ital SBScriptITAL +#define Java SBScriptJAVA +#define Kali SBScriptKALI +#define Kana SBScriptKANA +#define Khar SBScriptKHAR +#define Khmr SBScriptKHMR +#define Khoj SBScriptKHOJ +#define Kits SBScriptKITS +#define Knda SBScriptKNDA +#define Kthi SBScriptKTHI +#define Lana SBScriptLANA +#define Laoo SBScriptLAOO +#define Latn SBScriptLATN +#define Lepc SBScriptLEPC +#define Limb SBScriptLIMB +#define Lina SBScriptLINA +#define Linb SBScriptLINB +#define Lisu SBScriptLISU +#define Lyci SBScriptLYCI +#define Lydi SBScriptLYDI +#define Mahj SBScriptMAHJ +#define Maka SBScriptMAKA +#define Mand SBScriptMAND +#define Mani SBScriptMANI +#define Marc SBScriptMARC +#define Medf SBScriptMEDF +#define Mend SBScriptMEND +#define Merc SBScriptMERC +#define Mero SBScriptMERO +#define Mlym SBScriptMLYM +#define Modi SBScriptMODI +#define Mong SBScriptMONG +#define Mroo SBScriptMROO +#define Mtei SBScriptMTEI +#define Mult SBScriptMULT +#define Mymr SBScriptMYMR +#define Nand SBScriptNAND +#define Narb SBScriptNARB +#define Nbat SBScriptNBAT +#define Newa SBScriptNEWA +#define Nkoo SBScriptNKOO +#define Nshu SBScriptNSHU +#define Ogam SBScriptOGAM +#define Olck SBScriptOLCK +#define Orkh SBScriptORKH +#define Orya SBScriptORYA +#define Osge SBScriptOSGE +#define Osma SBScriptOSMA +#define Ougr SBScriptOUGR +#define Palm SBScriptPALM +#define Pauc SBScriptPAUC +#define Perm SBScriptPERM +#define Phag SBScriptPHAG +#define Phli SBScriptPHLI +#define Phlp SBScriptPHLP +#define Phnx SBScriptPHNX +#define Plrd SBScriptPLRD +#define Prti SBScriptPRTI +#define Rjng SBScriptRJNG +#define Rohg SBScriptROHG +#define Runr SBScriptRUNR +#define Samr SBScriptSAMR +#define Sarb SBScriptSARB +#define Saur SBScriptSAUR +#define Sgnw SBScriptSGNW +#define Shaw SBScriptSHAW +#define Shrd SBScriptSHRD +#define Sidd SBScriptSIDD +#define Sind SBScriptSIND +#define Sinh SBScriptSINH +#define Sogd SBScriptSOGD +#define Sogo SBScriptSOGO +#define Sora SBScriptSORA +#define Soyo SBScriptSOYO +#define Sund SBScriptSUND +#define Sylo SBScriptSYLO +#define Syrc SBScriptSYRC +#define Tagb SBScriptTAGB +#define Takr SBScriptTAKR +#define Tale SBScriptTALE +#define Talu SBScriptTALU +#define Taml SBScriptTAML +#define Tang SBScriptTANG +#define Tavt SBScriptTAVT +#define Telu SBScriptTELU +#define Tfng SBScriptTFNG +#define Tglg SBScriptTGLG +#define Thaa SBScriptTHAA +#define Thai SBScriptTHAI +#define Tibt SBScriptTIBT +#define Tirh SBScriptTIRH +#define Tnsa SBScriptTNSA +#define Toto SBScriptTOTO +#define Ugar SBScriptUGAR +#define Vaii SBScriptVAII +#define Vith SBScriptVITH +#define Wara SBScriptWARA +#define Wcho SBScriptWCHO +#define Xpeo SBScriptXPEO +#define Xsux SBScriptXSUX +#define Yezi SBScriptYEZI +#define Yiii SBScriptYIII +#define Zanb SBScriptZANB +#define Zinh SBScriptZINH +#define Zyyy SBScriptZYYY +#define Zzzz SBScriptZZZZ + +static const SBUInt8 PrimaryScriptData[10624] = { +/* DATA_BLOCK: -- 0x0000..0x000F -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x0010..0x001F -- */ + Zyyy, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, +/* DATA_BLOCK: -- 0x0020..0x002F -- */ + Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x0030..0x003F -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Latn, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x0040..0x004F -- */ + Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, +/* DATA_BLOCK: -- 0x0050..0x005F -- */ + Latn, Latn, Latn, Latn, Latn, Latn, Latn, Zyyy, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, +/* DATA_BLOCK: -- 0x0060..0x006F -- */ + Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x0070..0x007F -- */ + Latn, Latn, Latn, Latn, Latn, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Bopo, Bopo, Zyyy, Zyyy, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x0080..0x008F -- */ + Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, +/* DATA_BLOCK: -- 0x0090..0x009F -- */ + Grek, Grek, Grek, Grek, Zyyy, Grek, Grek, Grek, Zzzz, Zzzz, Grek, Grek, Grek, Grek, Zyyy, Grek, +/* DATA_BLOCK: -- 0x00A0..0x00AF -- */ + Zzzz, Zzzz, Zzzz, Zzzz, Grek, Zyyy, Grek, Zyyy, Grek, Grek, Grek, Zzzz, Grek, Zzzz, Grek, Grek, +/* DATA_BLOCK: -- 0x00B0..0x00BF -- */ + Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, +/* DATA_BLOCK: -- 0x00C0..0x00CF -- */ + Grek, Grek, Zzzz, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, +/* DATA_BLOCK: -- 0x00D0..0x00DF -- */ + Grek, Grek, Copt, Copt, Copt, Copt, Copt, Copt, Copt, Copt, Copt, Copt, Copt, Copt, Copt, Copt, +/* DATA_BLOCK: -- 0x00E0..0x00EF -- */ + Cyrl, Cyrl, Cyrl, Cyrl, Cyrl, Cyrl, Cyrl, Cyrl, Cyrl, Cyrl, Cyrl, Cyrl, Cyrl, Cyrl, Cyrl, Cyrl, +/* DATA_BLOCK: -- 0x00F0..0x00FF -- */ + Cyrl, Cyrl, Cyrl, Cyrl, Cyrl, Zinh, Zinh, Cyrl, Cyrl, Cyrl, Cyrl, Cyrl, Cyrl, Cyrl, Cyrl, Cyrl, +/* DATA_BLOCK: -- 0x0100..0x010F -- */ + Zzzz, Armn, Armn, Armn, Armn, Armn, Armn, Armn, Armn, Armn, Armn, Armn, Armn, Armn, Armn, Armn, +/* DATA_BLOCK: -- 0x0110..0x011F -- */ + Armn, Armn, Armn, Armn, Armn, Armn, Armn, Armn, Armn, Armn, Armn, Armn, Armn, Armn, Armn, Armn, +/* DATA_BLOCK: -- 0x0120..0x012F -- */ + Armn, Armn, Armn, Armn, Armn, Armn, Armn, Zzzz, Zzzz, Armn, Armn, Armn, Armn, Armn, Armn, Armn, +/* DATA_BLOCK: -- 0x0130..0x013F -- */ + Armn, Armn, Armn, Armn, Armn, Armn, Armn, Armn, Armn, Armn, Armn, Zzzz, Zzzz, Armn, Armn, Armn, +/* DATA_BLOCK: -- 0x0140..0x014F -- */ + Zzzz, Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, +/* DATA_BLOCK: -- 0x0150..0x015F -- */ + Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, +/* DATA_BLOCK: -- 0x0160..0x016F -- */ + Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0170..0x017F -- */ + Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, Zzzz, Zzzz, Zzzz, Zzzz, Hebr, +/* DATA_BLOCK: -- 0x0180..0x018F -- */ + Hebr, Hebr, Hebr, Hebr, Hebr, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0190..0x019F -- */ + Arab, Arab, Arab, Arab, Arab, Zyyy, Arab, Arab, Arab, Arab, Arab, Arab, Zyyy, Arab, Arab, Arab, +/* DATA_BLOCK: -- 0x01A0..0x01AF -- */ + Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Zyyy, Arab, Arab, Arab, Zyyy, +/* DATA_BLOCK: -- 0x01B0..0x01BF -- */ + Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, +/* DATA_BLOCK: -- 0x01C0..0x01CF -- */ + Zyyy, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Zinh, Zinh, Zinh, Zinh, Zinh, +/* DATA_BLOCK: -- 0x01D0..0x01DF -- */ + Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, +/* DATA_BLOCK: -- 0x01E0..0x01EF -- */ + Zinh, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, +/* DATA_BLOCK: -- 0x01F0..0x01FF -- */ + Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Zyyy, Arab, Arab, +/* DATA_BLOCK: -- 0x0200..0x020F -- */ + Syrc, Syrc, Syrc, Syrc, Syrc, Syrc, Syrc, Syrc, Syrc, Syrc, Syrc, Syrc, Syrc, Syrc, Zzzz, Syrc, +/* DATA_BLOCK: -- 0x0210..0x021F -- */ + Syrc, Syrc, Syrc, Syrc, Syrc, Syrc, Syrc, Syrc, Syrc, Syrc, Syrc, Syrc, Syrc, Syrc, Syrc, Syrc, +/* DATA_BLOCK: -- 0x0220..0x022F -- */ + Syrc, Syrc, Syrc, Syrc, Syrc, Syrc, Syrc, Syrc, Syrc, Syrc, Syrc, Zzzz, Zzzz, Syrc, Syrc, Syrc, +/* DATA_BLOCK: -- 0x0230..0x023F -- */ + Thaa, Thaa, Thaa, Thaa, Thaa, Thaa, Thaa, Thaa, Thaa, Thaa, Thaa, Thaa, Thaa, Thaa, Thaa, Thaa, +/* DATA_BLOCK: -- 0x0240..0x024F -- */ + Thaa, Thaa, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0250..0x025F -- */ + Nkoo, Nkoo, Nkoo, Nkoo, Nkoo, Nkoo, Nkoo, Nkoo, Nkoo, Nkoo, Nkoo, Nkoo, Nkoo, Nkoo, Nkoo, Nkoo, +/* DATA_BLOCK: -- 0x0260..0x026F -- */ + Nkoo, Nkoo, Nkoo, Nkoo, Nkoo, Nkoo, Nkoo, Nkoo, Nkoo, Nkoo, Nkoo, Zzzz, Zzzz, Nkoo, Nkoo, Nkoo, +/* DATA_BLOCK: -- 0x0270..0x027F -- */ + Samr, Samr, Samr, Samr, Samr, Samr, Samr, Samr, Samr, Samr, Samr, Samr, Samr, Samr, Samr, Samr, +/* DATA_BLOCK: -- 0x0280..0x028F -- */ + Samr, Samr, Samr, Samr, Samr, Samr, Samr, Samr, Samr, Samr, Samr, Samr, Samr, Samr, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0290..0x029F -- */ + Samr, Samr, Samr, Samr, Samr, Samr, Samr, Samr, Samr, Samr, Samr, Samr, Samr, Samr, Samr, Zzzz, +/* DATA_BLOCK: -- 0x02A0..0x02AF -- */ + Mand, Mand, Mand, Mand, Mand, Mand, Mand, Mand, Mand, Mand, Mand, Mand, Mand, Mand, Mand, Mand, +/* DATA_BLOCK: -- 0x02B0..0x02BF -- */ + Mand, Mand, Mand, Mand, Mand, Mand, Mand, Mand, Mand, Mand, Mand, Mand, Zzzz, Zzzz, Mand, Zzzz, +/* DATA_BLOCK: -- 0x02C0..0x02CF -- */ + Syrc, Syrc, Syrc, Syrc, Syrc, Syrc, Syrc, Syrc, Syrc, Syrc, Syrc, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x02D0..0x02DF -- */ + Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Zzzz, +/* DATA_BLOCK: -- 0x02E0..0x02EF -- */ + Arab, Arab, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, +/* DATA_BLOCK: -- 0x02F0..0x02FF -- */ + Arab, Arab, Zyyy, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, +/* DATA_BLOCK: -- 0x0300..0x030F -- */ + Deva, Deva, Deva, Deva, Deva, Deva, Deva, Deva, Deva, Deva, Deva, Deva, Deva, Deva, Deva, Deva, +/* DATA_BLOCK: -- 0x0310..0x031F -- */ + Deva, Zinh, Zinh, Zinh, Zinh, Deva, Deva, Deva, Deva, Deva, Deva, Deva, Deva, Deva, Deva, Deva, +/* DATA_BLOCK: -- 0x0320..0x032F -- */ + Deva, Deva, Deva, Deva, Zyyy, Zyyy, Deva, Deva, Deva, Deva, Deva, Deva, Deva, Deva, Deva, Deva, +/* DATA_BLOCK: -- 0x0330..0x033F -- */ + Beng, Beng, Beng, Beng, Zzzz, Beng, Beng, Beng, Beng, Beng, Beng, Beng, Beng, Zzzz, Zzzz, Beng, +/* DATA_BLOCK: -- 0x0340..0x034F -- */ + Beng, Zzzz, Zzzz, Beng, Beng, Beng, Beng, Beng, Beng, Beng, Beng, Beng, Beng, Beng, Beng, Beng, +/* DATA_BLOCK: -- 0x0350..0x035F -- */ + Beng, Beng, Beng, Beng, Beng, Beng, Beng, Beng, Beng, Zzzz, Beng, Beng, Beng, Beng, Beng, Beng, +/* DATA_BLOCK: -- 0x0360..0x036F -- */ + Beng, Zzzz, Beng, Zzzz, Zzzz, Zzzz, Beng, Beng, Beng, Beng, Zzzz, Zzzz, Beng, Beng, Beng, Beng, +/* DATA_BLOCK: -- 0x0370..0x037F -- */ + Beng, Beng, Beng, Beng, Beng, Zzzz, Zzzz, Beng, Beng, Zzzz, Zzzz, Beng, Beng, Beng, Beng, Zzzz, +/* DATA_BLOCK: -- 0x0380..0x038F -- */ + Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Beng, Zzzz, Zzzz, Zzzz, Zzzz, Beng, Beng, Zzzz, Beng, +/* DATA_BLOCK: -- 0x0390..0x039F -- */ + Beng, Beng, Beng, Beng, Zzzz, Zzzz, Beng, Beng, Beng, Beng, Beng, Beng, Beng, Beng, Beng, Beng, +/* DATA_BLOCK: -- 0x03A0..0x03AF -- */ + Beng, Beng, Beng, Beng, Beng, Beng, Beng, Beng, Beng, Beng, Beng, Beng, Beng, Beng, Beng, Zzzz, +/* DATA_BLOCK: -- 0x03B0..0x03BF -- */ + Zzzz, Guru, Guru, Guru, Zzzz, Guru, Guru, Guru, Guru, Guru, Guru, Zzzz, Zzzz, Zzzz, Zzzz, Guru, +/* DATA_BLOCK: -- 0x03C0..0x03CF -- */ + Guru, Zzzz, Zzzz, Guru, Guru, Guru, Guru, Guru, Guru, Guru, Guru, Guru, Guru, Guru, Guru, Guru, +/* DATA_BLOCK: -- 0x03D0..0x03DF -- */ + Guru, Guru, Guru, Guru, Guru, Guru, Guru, Guru, Guru, Zzzz, Guru, Guru, Guru, Guru, Guru, Guru, +/* DATA_BLOCK: -- 0x03E0..0x03EF -- */ + Guru, Zzzz, Guru, Guru, Zzzz, Guru, Guru, Zzzz, Guru, Guru, Zzzz, Zzzz, Guru, Zzzz, Guru, Guru, +/* DATA_BLOCK: -- 0x03F0..0x03FF -- */ + Guru, Guru, Guru, Zzzz, Zzzz, Zzzz, Zzzz, Guru, Guru, Zzzz, Zzzz, Guru, Guru, Guru, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0400..0x040F -- */ + Zzzz, Guru, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Guru, Guru, Guru, Guru, Zzzz, Guru, Zzzz, +/* DATA_BLOCK: -- 0x0410..0x041F -- */ + Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Guru, Guru, Guru, Guru, Guru, Guru, Guru, Guru, Guru, Guru, +/* DATA_BLOCK: -- 0x0420..0x042F -- */ + Guru, Guru, Guru, Guru, Guru, Guru, Guru, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0430..0x043F -- */ + Zzzz, Gujr, Gujr, Gujr, Zzzz, Gujr, Gujr, Gujr, Gujr, Gujr, Gujr, Gujr, Gujr, Gujr, Zzzz, Gujr, +/* DATA_BLOCK: -- 0x0440..0x044F -- */ + Gujr, Gujr, Zzzz, Gujr, Gujr, Gujr, Gujr, Gujr, Gujr, Gujr, Gujr, Gujr, Gujr, Gujr, Gujr, Gujr, +/* DATA_BLOCK: -- 0x0450..0x045F -- */ + Gujr, Gujr, Gujr, Gujr, Gujr, Gujr, Gujr, Gujr, Gujr, Zzzz, Gujr, Gujr, Gujr, Gujr, Gujr, Gujr, +/* DATA_BLOCK: -- 0x0460..0x046F -- */ + Gujr, Zzzz, Gujr, Gujr, Zzzz, Gujr, Gujr, Gujr, Gujr, Gujr, Zzzz, Zzzz, Gujr, Gujr, Gujr, Gujr, +/* DATA_BLOCK: -- 0x0470..0x047F -- */ + Gujr, Gujr, Gujr, Gujr, Gujr, Gujr, Zzzz, Gujr, Gujr, Gujr, Zzzz, Gujr, Gujr, Gujr, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0480..0x048F -- */ + Gujr, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0490..0x049F -- */ + Gujr, Gujr, Gujr, Gujr, Zzzz, Zzzz, Gujr, Gujr, Gujr, Gujr, Gujr, Gujr, Gujr, Gujr, Gujr, Gujr, +/* DATA_BLOCK: -- 0x04A0..0x04AF -- */ + Gujr, Gujr, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Gujr, Gujr, Gujr, Gujr, Gujr, Gujr, Gujr, +/* DATA_BLOCK: -- 0x04B0..0x04BF -- */ + Zzzz, Orya, Orya, Orya, Zzzz, Orya, Orya, Orya, Orya, Orya, Orya, Orya, Orya, Zzzz, Zzzz, Orya, +/* DATA_BLOCK: -- 0x04C0..0x04CF -- */ + Orya, Zzzz, Zzzz, Orya, Orya, Orya, Orya, Orya, Orya, Orya, Orya, Orya, Orya, Orya, Orya, Orya, +/* DATA_BLOCK: -- 0x04D0..0x04DF -- */ + Orya, Orya, Orya, Orya, Orya, Orya, Orya, Orya, Orya, Zzzz, Orya, Orya, Orya, Orya, Orya, Orya, +/* DATA_BLOCK: -- 0x04E0..0x04EF -- */ + Orya, Zzzz, Orya, Orya, Zzzz, Orya, Orya, Orya, Orya, Orya, Zzzz, Zzzz, Orya, Orya, Orya, Orya, +/* DATA_BLOCK: -- 0x04F0..0x04FF -- */ + Orya, Orya, Orya, Orya, Orya, Zzzz, Zzzz, Orya, Orya, Zzzz, Zzzz, Orya, Orya, Orya, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0500..0x050F -- */ + Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Orya, Orya, Orya, Zzzz, Zzzz, Zzzz, Zzzz, Orya, Orya, Zzzz, Orya, +/* DATA_BLOCK: -- 0x0510..0x051F -- */ + Orya, Orya, Orya, Orya, Zzzz, Zzzz, Orya, Orya, Orya, Orya, Orya, Orya, Orya, Orya, Orya, Orya, +/* DATA_BLOCK: -- 0x0520..0x052F -- */ + Orya, Orya, Orya, Orya, Orya, Orya, Orya, Orya, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0530..0x053F -- */ + Zzzz, Zzzz, Taml, Taml, Zzzz, Taml, Taml, Taml, Taml, Taml, Taml, Zzzz, Zzzz, Zzzz, Taml, Taml, +/* DATA_BLOCK: -- 0x0540..0x054F -- */ + Taml, Zzzz, Taml, Taml, Taml, Taml, Zzzz, Zzzz, Zzzz, Taml, Taml, Zzzz, Taml, Zzzz, Taml, Taml, +/* DATA_BLOCK: -- 0x0550..0x055F -- */ + Zzzz, Zzzz, Zzzz, Taml, Taml, Zzzz, Zzzz, Zzzz, Taml, Taml, Taml, Zzzz, Zzzz, Zzzz, Taml, Taml, +/* DATA_BLOCK: -- 0x0560..0x056F -- */ + Taml, Taml, Taml, Taml, Taml, Taml, Taml, Taml, Taml, Taml, Zzzz, Zzzz, Zzzz, Zzzz, Taml, Taml, +/* DATA_BLOCK: -- 0x0570..0x057F -- */ + Taml, Taml, Taml, Zzzz, Zzzz, Zzzz, Taml, Taml, Taml, Zzzz, Taml, Taml, Taml, Taml, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0580..0x058F -- */ + Taml, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Taml, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0590..0x059F -- */ + Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Taml, Taml, Taml, Taml, Taml, Taml, Taml, Taml, Taml, Taml, +/* DATA_BLOCK: -- 0x05A0..0x05AF -- */ + Taml, Taml, Taml, Taml, Taml, Taml, Taml, Taml, Taml, Taml, Taml, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x05B0..0x05BF -- */ + Telu, Telu, Telu, Telu, Telu, Telu, Telu, Telu, Telu, Telu, Telu, Telu, Telu, Zzzz, Telu, Telu, +/* DATA_BLOCK: -- 0x05C0..0x05CF -- */ + Telu, Zzzz, Telu, Telu, Telu, Telu, Telu, Telu, Telu, Telu, Telu, Telu, Telu, Telu, Telu, Telu, +/* DATA_BLOCK: -- 0x05D0..0x05DF -- */ + Telu, Telu, Telu, Telu, Telu, Telu, Telu, Telu, Telu, Zzzz, Telu, Telu, Telu, Telu, Telu, Telu, +/* DATA_BLOCK: -- 0x05E0..0x05EF -- */ + Telu, Telu, Telu, Telu, Telu, Telu, Telu, Telu, Telu, Telu, Zzzz, Zzzz, Telu, Telu, Telu, Telu, +/* DATA_BLOCK: -- 0x05F0..0x05FF -- */ + Telu, Telu, Telu, Telu, Telu, Zzzz, Telu, Telu, Telu, Zzzz, Telu, Telu, Telu, Telu, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0600..0x060F -- */ + Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Telu, Telu, Zzzz, Telu, Telu, Telu, Zzzz, Zzzz, Telu, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0610..0x061F -- */ + Telu, Telu, Telu, Telu, Zzzz, Zzzz, Telu, Telu, Telu, Telu, Telu, Telu, Telu, Telu, Telu, Telu, +/* DATA_BLOCK: -- 0x0620..0x062F -- */ + Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Telu, Telu, Telu, Telu, Telu, Telu, Telu, Telu, Telu, +/* DATA_BLOCK: -- 0x0630..0x063F -- */ + Knda, Knda, Knda, Knda, Knda, Knda, Knda, Knda, Knda, Knda, Knda, Knda, Knda, Zzzz, Knda, Knda, +/* DATA_BLOCK: -- 0x0640..0x064F -- */ + Knda, Zzzz, Knda, Knda, Knda, Knda, Knda, Knda, Knda, Knda, Knda, Knda, Knda, Knda, Knda, Knda, +/* DATA_BLOCK: -- 0x0650..0x065F -- */ + Knda, Knda, Knda, Knda, Knda, Knda, Knda, Knda, Knda, Zzzz, Knda, Knda, Knda, Knda, Knda, Knda, +/* DATA_BLOCK: -- 0x0660..0x066F -- */ + Knda, Knda, Knda, Knda, Zzzz, Knda, Knda, Knda, Knda, Knda, Zzzz, Zzzz, Knda, Knda, Knda, Knda, +/* DATA_BLOCK: -- 0x0670..0x067F -- */ + Knda, Knda, Knda, Knda, Knda, Zzzz, Knda, Knda, Knda, Zzzz, Knda, Knda, Knda, Knda, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0680..0x068F -- */ + Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Knda, Knda, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Knda, Knda, Zzzz, +/* DATA_BLOCK: -- 0x0690..0x069F -- */ + Knda, Knda, Knda, Knda, Zzzz, Zzzz, Knda, Knda, Knda, Knda, Knda, Knda, Knda, Knda, Knda, Knda, +/* DATA_BLOCK: -- 0x06A0..0x06AF -- */ + Zzzz, Knda, Knda, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x06B0..0x06BF -- */ + Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Zzzz, Mlym, Mlym, +/* DATA_BLOCK: -- 0x06C0..0x06CF -- */ + Mlym, Zzzz, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, +/* DATA_BLOCK: -- 0x06D0..0x06DF -- */ + Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, +/* DATA_BLOCK: -- 0x06E0..0x06EF -- */ + Mlym, Mlym, Mlym, Mlym, Mlym, Zzzz, Mlym, Mlym, Mlym, Zzzz, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, +/* DATA_BLOCK: -- 0x06F0..0x06FF -- */ + Zzzz, Zzzz, Zzzz, Zzzz, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, +/* DATA_BLOCK: -- 0x0700..0x070F -- */ + Mlym, Mlym, Mlym, Mlym, Zzzz, Zzzz, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, +/* DATA_BLOCK: -- 0x0710..0x071F -- */ + Zzzz, Sinh, Sinh, Sinh, Zzzz, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, +/* DATA_BLOCK: -- 0x0720..0x072F -- */ + Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Zzzz, Zzzz, Zzzz, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, +/* DATA_BLOCK: -- 0x0730..0x073F -- */ + Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, +/* DATA_BLOCK: -- 0x0740..0x074F -- */ + Sinh, Sinh, Zzzz, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Zzzz, Sinh, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0750..0x075F -- */ + Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Zzzz, Zzzz, Zzzz, Sinh, Zzzz, Zzzz, Zzzz, Zzzz, Sinh, +/* DATA_BLOCK: -- 0x0760..0x076F -- */ + Sinh, Sinh, Sinh, Sinh, Sinh, Zzzz, Sinh, Zzzz, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, +/* DATA_BLOCK: -- 0x0770..0x077F -- */ + Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, +/* DATA_BLOCK: -- 0x0780..0x078F -- */ + Zzzz, Zzzz, Sinh, Sinh, Sinh, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0790..0x079F -- */ + Zzzz, Thai, Thai, Thai, Thai, Thai, Thai, Thai, Thai, Thai, Thai, Thai, Thai, Thai, Thai, Thai, +/* DATA_BLOCK: -- 0x07A0..0x07AF -- */ + Thai, Thai, Thai, Thai, Thai, Thai, Thai, Thai, Thai, Thai, Thai, Thai, Thai, Thai, Thai, Thai, +/* DATA_BLOCK: -- 0x07B0..0x07BF -- */ + Thai, Thai, Thai, Thai, Thai, Thai, Thai, Thai, Thai, Thai, Thai, Zzzz, Zzzz, Zzzz, Zzzz, Zyyy, +/* DATA_BLOCK: -- 0x07C0..0x07CF -- */ + Thai, Thai, Thai, Thai, Thai, Thai, Thai, Thai, Thai, Thai, Thai, Thai, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x07D0..0x07DF -- */ + Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x07E0..0x07EF -- */ + Zzzz, Laoo, Laoo, Zzzz, Laoo, Zzzz, Laoo, Laoo, Laoo, Laoo, Laoo, Zzzz, Laoo, Laoo, Laoo, Laoo, +/* DATA_BLOCK: -- 0x07F0..0x07FF -- */ + Laoo, Laoo, Laoo, Laoo, Laoo, Laoo, Laoo, Laoo, Laoo, Laoo, Laoo, Laoo, Laoo, Laoo, Laoo, Laoo, +/* DATA_BLOCK: -- 0x0800..0x080F -- */ + Laoo, Laoo, Laoo, Laoo, Zzzz, Laoo, Zzzz, Laoo, Laoo, Laoo, Laoo, Laoo, Laoo, Laoo, Laoo, Laoo, +/* DATA_BLOCK: -- 0x0810..0x081F -- */ + Laoo, Laoo, Laoo, Laoo, Laoo, Laoo, Laoo, Laoo, Laoo, Laoo, Laoo, Laoo, Laoo, Laoo, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0820..0x082F -- */ + Laoo, Laoo, Laoo, Laoo, Laoo, Zzzz, Laoo, Zzzz, Laoo, Laoo, Laoo, Laoo, Laoo, Laoo, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0830..0x083F -- */ + Laoo, Laoo, Laoo, Laoo, Laoo, Laoo, Laoo, Laoo, Laoo, Laoo, Zzzz, Zzzz, Laoo, Laoo, Laoo, Laoo, +/* DATA_BLOCK: -- 0x0840..0x084F -- */ + Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, +/* DATA_BLOCK: -- 0x0850..0x085F -- */ + Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Zzzz, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, +/* DATA_BLOCK: -- 0x0860..0x086F -- */ + Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0870..0x087F -- */ + Zzzz, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, +/* DATA_BLOCK: -- 0x0880..0x088F -- */ + Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Zzzz, Tibt, Tibt, +/* DATA_BLOCK: -- 0x0890..0x089F -- */ + Tibt, Tibt, Tibt, Tibt, Tibt, Zyyy, Zyyy, Zyyy, Zyyy, Tibt, Tibt, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x08A0..0x08AF -- */ + Mymr, Mymr, Mymr, Mymr, Mymr, Mymr, Mymr, Mymr, Mymr, Mymr, Mymr, Mymr, Mymr, Mymr, Mymr, Mymr, +/* DATA_BLOCK: -- 0x08B0..0x08BF -- */ + Geor, Geor, Geor, Geor, Geor, Geor, Geor, Geor, Geor, Geor, Geor, Geor, Geor, Geor, Geor, Geor, +/* DATA_BLOCK: -- 0x08C0..0x08CF -- */ + Geor, Geor, Geor, Geor, Geor, Geor, Zzzz, Geor, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Geor, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x08D0..0x08DF -- */ + Geor, Geor, Geor, Geor, Geor, Geor, Geor, Geor, Geor, Geor, Geor, Zyyy, Geor, Geor, Geor, Geor, +/* DATA_BLOCK: -- 0x08E0..0x08EF -- */ + Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, +/* DATA_BLOCK: -- 0x08F0..0x08FF -- */ + Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, +/* DATA_BLOCK: -- 0x0900..0x090F -- */ + Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Zzzz, Ethi, Ethi, Ethi, Ethi, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0910..0x091F -- */ + Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Zzzz, Ethi, Zzzz, Ethi, Ethi, Ethi, Ethi, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0920..0x092F -- */ + Ethi, Zzzz, Ethi, Ethi, Ethi, Ethi, Zzzz, Zzzz, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Zzzz, +/* DATA_BLOCK: -- 0x0930..0x093F -- */ + Ethi, Zzzz, Ethi, Ethi, Ethi, Ethi, Zzzz, Zzzz, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, +/* DATA_BLOCK: -- 0x0940..0x094F -- */ + Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Zzzz, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, +/* DATA_BLOCK: -- 0x0950..0x095F -- */ + Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Zzzz, Zzzz, Ethi, Ethi, Ethi, +/* DATA_BLOCK: -- 0x0960..0x096F -- */ + Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0970..0x097F -- */ + Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0980..0x098F -- */ + Cher, Cher, Cher, Cher, Cher, Cher, Cher, Cher, Cher, Cher, Cher, Cher, Cher, Cher, Cher, Cher, +/* DATA_BLOCK: -- 0x0990..0x099F -- */ + Cher, Cher, Cher, Cher, Cher, Cher, Zzzz, Zzzz, Cher, Cher, Cher, Cher, Cher, Cher, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x09A0..0x09AF -- */ + Cans, Cans, Cans, Cans, Cans, Cans, Cans, Cans, Cans, Cans, Cans, Cans, Cans, Cans, Cans, Cans, +/* DATA_BLOCK: -- 0x09B0..0x09BF -- */ + Ogam, Ogam, Ogam, Ogam, Ogam, Ogam, Ogam, Ogam, Ogam, Ogam, Ogam, Ogam, Ogam, Ogam, Ogam, Ogam, +/* DATA_BLOCK: -- 0x09C0..0x09CF -- */ + Ogam, Ogam, Ogam, Ogam, Ogam, Ogam, Ogam, Ogam, Ogam, Ogam, Ogam, Ogam, Ogam, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x09D0..0x09DF -- */ + Runr, Runr, Runr, Runr, Runr, Runr, Runr, Runr, Runr, Runr, Runr, Runr, Runr, Runr, Runr, Runr, +/* DATA_BLOCK: -- 0x09E0..0x09EF -- */ + Runr, Runr, Runr, Runr, Runr, Runr, Runr, Runr, Runr, Runr, Runr, Zyyy, Zyyy, Zyyy, Runr, Runr, +/* DATA_BLOCK: -- 0x09F0..0x09FF -- */ + Runr, Runr, Runr, Runr, Runr, Runr, Runr, Runr, Runr, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0A00..0x0A0F -- */ + Tglg, Tglg, Tglg, Tglg, Tglg, Tglg, Tglg, Tglg, Tglg, Tglg, Tglg, Tglg, Tglg, Tglg, Tglg, Tglg, +/* DATA_BLOCK: -- 0x0A10..0x0A1F -- */ + Tglg, Tglg, Tglg, Tglg, Tglg, Tglg, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Tglg, +/* DATA_BLOCK: -- 0x0A20..0x0A2F -- */ + Hano, Hano, Hano, Hano, Hano, Hano, Hano, Hano, Hano, Hano, Hano, Hano, Hano, Hano, Hano, Hano, +/* DATA_BLOCK: -- 0x0A30..0x0A3F -- */ + Hano, Hano, Hano, Hano, Hano, Zyyy, Zyyy, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0A40..0x0A4F -- */ + Buhd, Buhd, Buhd, Buhd, Buhd, Buhd, Buhd, Buhd, Buhd, Buhd, Buhd, Buhd, Buhd, Buhd, Buhd, Buhd, +/* DATA_BLOCK: -- 0x0A50..0x0A5F -- */ + Buhd, Buhd, Buhd, Buhd, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0A60..0x0A6F -- */ + Tagb, Tagb, Tagb, Tagb, Tagb, Tagb, Tagb, Tagb, Tagb, Tagb, Tagb, Tagb, Tagb, Zzzz, Tagb, Tagb, +/* DATA_BLOCK: -- 0x0A70..0x0A7F -- */ + Tagb, Zzzz, Tagb, Tagb, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0A80..0x0A8F -- */ + Khmr, Khmr, Khmr, Khmr, Khmr, Khmr, Khmr, Khmr, Khmr, Khmr, Khmr, Khmr, Khmr, Khmr, Khmr, Khmr, +/* DATA_BLOCK: -- 0x0A90..0x0A9F -- */ + Khmr, Khmr, Khmr, Khmr, Khmr, Khmr, Khmr, Khmr, Khmr, Khmr, Khmr, Khmr, Khmr, Khmr, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0AA0..0x0AAF -- */ + Khmr, Khmr, Khmr, Khmr, Khmr, Khmr, Khmr, Khmr, Khmr, Khmr, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0AB0..0x0ABF -- */ + Mong, Mong, Zyyy, Zyyy, Mong, Zyyy, Mong, Mong, Mong, Mong, Mong, Mong, Mong, Mong, Mong, Mong, +/* DATA_BLOCK: -- 0x0AC0..0x0ACF -- */ + Mong, Mong, Mong, Mong, Mong, Mong, Mong, Mong, Mong, Mong, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0AD0..0x0ADF -- */ + Mong, Mong, Mong, Mong, Mong, Mong, Mong, Mong, Mong, Mong, Mong, Mong, Mong, Mong, Mong, Mong, +/* DATA_BLOCK: -- 0x0AE0..0x0AEF -- */ + Mong, Mong, Mong, Mong, Mong, Mong, Mong, Mong, Mong, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0AF0..0x0AFF -- */ + Mong, Mong, Mong, Mong, Mong, Mong, Mong, Mong, Mong, Mong, Mong, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0B00..0x0B0F -- */ + Cans, Cans, Cans, Cans, Cans, Cans, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0B10..0x0B1F -- */ + Limb, Limb, Limb, Limb, Limb, Limb, Limb, Limb, Limb, Limb, Limb, Limb, Limb, Limb, Limb, Limb, +/* DATA_BLOCK: -- 0x0B20..0x0B2F -- */ + Limb, Limb, Limb, Limb, Limb, Limb, Limb, Limb, Limb, Limb, Limb, Limb, Limb, Limb, Limb, Zzzz, +/* DATA_BLOCK: -- 0x0B30..0x0B3F -- */ + Limb, Limb, Limb, Limb, Limb, Limb, Limb, Limb, Limb, Limb, Limb, Limb, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0B40..0x0B4F -- */ + Limb, Zzzz, Zzzz, Zzzz, Limb, Limb, Limb, Limb, Limb, Limb, Limb, Limb, Limb, Limb, Limb, Limb, +/* DATA_BLOCK: -- 0x0B50..0x0B5F -- */ + Tale, Tale, Tale, Tale, Tale, Tale, Tale, Tale, Tale, Tale, Tale, Tale, Tale, Tale, Tale, Tale, +/* DATA_BLOCK: -- 0x0B60..0x0B6F -- */ + Tale, Tale, Tale, Tale, Tale, Tale, Tale, Tale, Tale, Tale, Tale, Tale, Tale, Tale, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0B70..0x0B7F -- */ + Tale, Tale, Tale, Tale, Tale, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0B80..0x0B8F -- */ + Talu, Talu, Talu, Talu, Talu, Talu, Talu, Talu, Talu, Talu, Talu, Talu, Talu, Talu, Talu, Talu, +/* DATA_BLOCK: -- 0x0B90..0x0B9F -- */ + Talu, Talu, Talu, Talu, Talu, Talu, Talu, Talu, Talu, Talu, Talu, Talu, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0BA0..0x0BAF -- */ + Talu, Talu, Talu, Talu, Talu, Talu, Talu, Talu, Talu, Talu, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0BB0..0x0BBF -- */ + Talu, Talu, Talu, Talu, Talu, Talu, Talu, Talu, Talu, Talu, Talu, Zzzz, Zzzz, Zzzz, Talu, Talu, +/* DATA_BLOCK: -- 0x0BC0..0x0BCF -- */ + Bugi, Bugi, Bugi, Bugi, Bugi, Bugi, Bugi, Bugi, Bugi, Bugi, Bugi, Bugi, Bugi, Bugi, Bugi, Bugi, +/* DATA_BLOCK: -- 0x0BD0..0x0BDF -- */ + Bugi, Bugi, Bugi, Bugi, Bugi, Bugi, Bugi, Bugi, Bugi, Bugi, Bugi, Bugi, Zzzz, Zzzz, Bugi, Bugi, +/* DATA_BLOCK: -- 0x0BE0..0x0BEF -- */ + Lana, Lana, Lana, Lana, Lana, Lana, Lana, Lana, Lana, Lana, Lana, Lana, Lana, Lana, Lana, Lana, +/* DATA_BLOCK: -- 0x0BF0..0x0BFF -- */ + Lana, Lana, Lana, Lana, Lana, Lana, Lana, Lana, Lana, Lana, Lana, Lana, Lana, Lana, Lana, Zzzz, +/* DATA_BLOCK: -- 0x0C00..0x0C0F -- */ + Lana, Lana, Lana, Lana, Lana, Lana, Lana, Lana, Lana, Lana, Lana, Lana, Lana, Zzzz, Zzzz, Lana, +/* DATA_BLOCK: -- 0x0C10..0x0C1F -- */ + Lana, Lana, Lana, Lana, Lana, Lana, Lana, Lana, Lana, Lana, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0C20..0x0C2F -- */ + Lana, Lana, Lana, Lana, Lana, Lana, Lana, Lana, Lana, Lana, Lana, Lana, Lana, Lana, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0C30..0x0C3F -- */ + Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zzzz, +/* DATA_BLOCK: -- 0x0C40..0x0C4F -- */ + Bali, Bali, Bali, Bali, Bali, Bali, Bali, Bali, Bali, Bali, Bali, Bali, Bali, Bali, Bali, Bali, +/* DATA_BLOCK: -- 0x0C50..0x0C5F -- */ + Bali, Bali, Bali, Bali, Bali, Bali, Bali, Bali, Bali, Bali, Bali, Bali, Bali, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0C60..0x0C6F -- */ + Bali, Bali, Bali, Bali, Bali, Bali, Bali, Bali, Bali, Bali, Bali, Bali, Bali, Bali, Bali, Zzzz, +/* DATA_BLOCK: -- 0x0C70..0x0C7F -- */ + Sund, Sund, Sund, Sund, Sund, Sund, Sund, Sund, Sund, Sund, Sund, Sund, Sund, Sund, Sund, Sund, +/* DATA_BLOCK: -- 0x0C80..0x0C8F -- */ + Batk, Batk, Batk, Batk, Batk, Batk, Batk, Batk, Batk, Batk, Batk, Batk, Batk, Batk, Batk, Batk, +/* DATA_BLOCK: -- 0x0C90..0x0C9F -- */ + Batk, Batk, Batk, Batk, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Batk, Batk, Batk, Batk, +/* DATA_BLOCK: -- 0x0CA0..0x0CAF -- */ + Lepc, Lepc, Lepc, Lepc, Lepc, Lepc, Lepc, Lepc, Lepc, Lepc, Lepc, Lepc, Lepc, Lepc, Lepc, Lepc, +/* DATA_BLOCK: -- 0x0CB0..0x0CBF -- */ + Lepc, Lepc, Lepc, Lepc, Lepc, Lepc, Lepc, Lepc, Zzzz, Zzzz, Zzzz, Lepc, Lepc, Lepc, Lepc, Lepc, +/* DATA_BLOCK: -- 0x0CC0..0x0CCF -- */ + Lepc, Lepc, Lepc, Lepc, Lepc, Lepc, Lepc, Lepc, Lepc, Lepc, Zzzz, Zzzz, Zzzz, Lepc, Lepc, Lepc, +/* DATA_BLOCK: -- 0x0CD0..0x0CDF -- */ + Olck, Olck, Olck, Olck, Olck, Olck, Olck, Olck, Olck, Olck, Olck, Olck, Olck, Olck, Olck, Olck, +/* DATA_BLOCK: -- 0x0CE0..0x0CEF -- */ + Cyrl, Cyrl, Cyrl, Cyrl, Cyrl, Cyrl, Cyrl, Cyrl, Cyrl, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0CF0..0x0CFF -- */ + Geor, Geor, Geor, Geor, Geor, Geor, Geor, Geor, Geor, Geor, Geor, Zzzz, Zzzz, Geor, Geor, Geor, +/* DATA_BLOCK: -- 0x0D00..0x0D0F -- */ + Sund, Sund, Sund, Sund, Sund, Sund, Sund, Sund, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0D10..0x0D1F -- */ + Zinh, Zinh, Zinh, Zyyy, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, +/* DATA_BLOCK: -- 0x0D20..0x0D2F -- */ + Zinh, Zyyy, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zyyy, Zyyy, Zyyy, Zyyy, Zinh, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x0D30..0x0D3F -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zinh, Zyyy, Zyyy, Zyyy, Zinh, Zinh, Zyyy, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0D40..0x0D4F -- */ + Latn, Latn, Latn, Latn, Latn, Latn, Grek, Grek, Grek, Grek, Grek, Cyrl, Latn, Latn, Latn, Latn, +/* DATA_BLOCK: -- 0x0D50..0x0D5F -- */ + Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Grek, Grek, Grek, +/* DATA_BLOCK: -- 0x0D60..0x0D6F -- */ + Grek, Grek, Latn, Latn, Latn, Latn, Grek, Grek, Grek, Grek, Grek, Latn, Latn, Latn, Latn, Latn, +/* DATA_BLOCK: -- 0x0D70..0x0D7F -- */ + Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Cyrl, Latn, Latn, Latn, Latn, Latn, Latn, Latn, +/* DATA_BLOCK: -- 0x0D80..0x0D8F -- */ + Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Grek, +/* DATA_BLOCK: -- 0x0D90..0x0D9F -- */ + Grek, Grek, Grek, Grek, Grek, Grek, Zzzz, Zzzz, Grek, Grek, Grek, Grek, Grek, Grek, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0DA0..0x0DAF -- */ + Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Zzzz, Grek, Zzzz, Grek, Zzzz, Grek, Zzzz, Grek, +/* DATA_BLOCK: -- 0x0DB0..0x0DBF -- */ + Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0DC0..0x0DCF -- */ + Grek, Grek, Grek, Grek, Grek, Zzzz, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, +/* DATA_BLOCK: -- 0x0DD0..0x0DDF -- */ + Grek, Grek, Grek, Grek, Zzzz, Zzzz, Grek, Grek, Grek, Grek, Grek, Grek, Zzzz, Grek, Grek, Grek, +/* DATA_BLOCK: -- 0x0DE0..0x0DEF -- */ + Zzzz, Zzzz, Grek, Grek, Grek, Zzzz, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Zzzz, +/* DATA_BLOCK: -- 0x0DF0..0x0DFF -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zinh, Zinh, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x0E00..0x0E0F -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x0E10..0x0E1F -- */ + Zyyy, Latn, Zzzz, Zzzz, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Latn, +/* DATA_BLOCK: -- 0x0E20..0x0E2F -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, +/* DATA_BLOCK: -- 0x0E30..0x0E3F -- */ + Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0E40..0x0E4F -- */ + Zyyy, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0E50..0x0E5F -- */ + Zinh, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0E60..0x0E6F -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Grek, Zyyy, Zyyy, Zyyy, Latn, Latn, Zyyy, Zyyy, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x0E70..0x0E7F -- */ + Zyyy, Zyyy, Latn, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x0E80..0x0E8F -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Latn, Zyyy, +/* DATA_BLOCK: -- 0x0E90..0x0E9F -- */ + Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Zyyy, Zyyy, Zyyy, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0EA0..0x0EAF -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0EB0..0x0EBF -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0EC0..0x0ECF -- */ + Brai, Brai, Brai, Brai, Brai, Brai, Brai, Brai, Brai, Brai, Brai, Brai, Brai, Brai, Brai, Brai, +/* DATA_BLOCK: -- 0x0ED0..0x0EDF -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zzzz, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x0EE0..0x0EEF -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x0EF0..0x0EFF -- */ + Glag, Glag, Glag, Glag, Glag, Glag, Glag, Glag, Glag, Glag, Glag, Glag, Glag, Glag, Glag, Glag, +/* DATA_BLOCK: -- 0x0F00..0x0F0F -- */ + Copt, Copt, Copt, Copt, Copt, Copt, Copt, Copt, Copt, Copt, Copt, Copt, Copt, Copt, Copt, Copt, +/* DATA_BLOCK: -- 0x0F10..0x0F1F -- */ + Copt, Copt, Copt, Copt, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Copt, Copt, Copt, Copt, Copt, Copt, Copt, +/* DATA_BLOCK: -- 0x0F20..0x0F2F -- */ + Tfng, Tfng, Tfng, Tfng, Tfng, Tfng, Tfng, Tfng, Tfng, Tfng, Tfng, Tfng, Tfng, Tfng, Tfng, Tfng, +/* DATA_BLOCK: -- 0x0F30..0x0F3F -- */ + Tfng, Tfng, Tfng, Tfng, Tfng, Tfng, Tfng, Tfng, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Tfng, +/* DATA_BLOCK: -- 0x0F40..0x0F4F -- */ + Tfng, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Tfng, +/* DATA_BLOCK: -- 0x0F50..0x0F5F -- */ + Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0F60..0x0F6F -- */ + Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Zzzz, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Zzzz, +/* DATA_BLOCK: -- 0x0F70..0x0F7F -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0F80..0x0F8F -- */ + Hani, Hani, Hani, Hani, Hani, Hani, Hani, Hani, Hani, Hani, Hani, Hani, Hani, Hani, Hani, Hani, +/* DATA_BLOCK: -- 0x0F90..0x0F9F -- */ + Hani, Hani, Hani, Hani, Hani, Hani, Hani, Hani, Hani, Hani, Zzzz, Hani, Hani, Hani, Hani, Hani, +/* DATA_BLOCK: -- 0x0FA0..0x0FAF -- */ + Hani, Hani, Hani, Hani, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0FB0..0x0FBF -- */ + Hani, Hani, Hani, Hani, Hani, Hani, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0FC0..0x0FCF -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0FD0..0x0FDF -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Hani, Zyyy, Hani, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x0FE0..0x0FEF -- */ + Zyyy, Hani, Hani, Hani, Hani, Hani, Hani, Hani, Hani, Hani, Zinh, Zinh, Zinh, Zinh, Hang, Hang, +/* DATA_BLOCK: -- 0x0FF0..0x0FFF -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Hani, Hani, Hani, Hani, Zyyy, Zyyy, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x1000..0x100F -- */ + Zzzz, Hira, Hira, Hira, Hira, Hira, Hira, Hira, Hira, Hira, Hira, Hira, Hira, Hira, Hira, Hira, +/* DATA_BLOCK: -- 0x1010..0x101F -- */ + Hira, Hira, Hira, Hira, Hira, Hira, Hira, Hira, Hira, Hira, Hira, Hira, Hira, Hira, Hira, Hira, +/* DATA_BLOCK: -- 0x1020..0x102F -- */ + Hira, Hira, Hira, Hira, Hira, Hira, Hira, Zzzz, Zzzz, Zinh, Zinh, Zyyy, Zyyy, Hira, Hira, Hira, +/* DATA_BLOCK: -- 0x1030..0x103F -- */ + Zyyy, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, +/* DATA_BLOCK: -- 0x1040..0x104F -- */ + Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, +/* DATA_BLOCK: -- 0x1050..0x105F -- */ + Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Zyyy, Zyyy, Kana, Kana, Kana, +/* DATA_BLOCK: -- 0x1060..0x106F -- */ + Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Bopo, Bopo, Bopo, Bopo, Bopo, Bopo, Bopo, Bopo, Bopo, Bopo, Bopo, +/* DATA_BLOCK: -- 0x1070..0x107F -- */ + Bopo, Bopo, Bopo, Bopo, Bopo, Bopo, Bopo, Bopo, Bopo, Bopo, Bopo, Bopo, Bopo, Bopo, Bopo, Bopo, +/* DATA_BLOCK: -- 0x1080..0x108F -- */ + Zzzz, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, +/* DATA_BLOCK: -- 0x1090..0x109F -- */ + Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Zzzz, +/* DATA_BLOCK: -- 0x10A0..0x10AF -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x10B0..0x10BF -- */ + Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Zyyy, +/* DATA_BLOCK: -- 0x10C0..0x10CF -- */ + Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Zyyy, +/* DATA_BLOCK: -- 0x10D0..0x10DF -- */ + Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x10E0..0x10EF -- */ + Yiii, Yiii, Yiii, Yiii, Yiii, Yiii, Yiii, Yiii, Yiii, Yiii, Yiii, Yiii, Yiii, Yiii, Yiii, Yiii, +/* DATA_BLOCK: -- 0x10F0..0x10FF -- */ + Yiii, Yiii, Yiii, Yiii, Yiii, Yiii, Yiii, Yiii, Yiii, Yiii, Yiii, Yiii, Yiii, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1100..0x110F -- */ + Yiii, Yiii, Yiii, Yiii, Yiii, Yiii, Yiii, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1110..0x111F -- */ + Lisu, Lisu, Lisu, Lisu, Lisu, Lisu, Lisu, Lisu, Lisu, Lisu, Lisu, Lisu, Lisu, Lisu, Lisu, Lisu, +/* DATA_BLOCK: -- 0x1120..0x112F -- */ + Vaii, Vaii, Vaii, Vaii, Vaii, Vaii, Vaii, Vaii, Vaii, Vaii, Vaii, Vaii, Vaii, Vaii, Vaii, Vaii, +/* DATA_BLOCK: -- 0x1130..0x113F -- */ + Vaii, Vaii, Vaii, Vaii, Vaii, Vaii, Vaii, Vaii, Vaii, Vaii, Vaii, Vaii, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1140..0x114F -- */ + Bamu, Bamu, Bamu, Bamu, Bamu, Bamu, Bamu, Bamu, Bamu, Bamu, Bamu, Bamu, Bamu, Bamu, Bamu, Bamu, +/* DATA_BLOCK: -- 0x1150..0x115F -- */ + Bamu, Bamu, Bamu, Bamu, Bamu, Bamu, Bamu, Bamu, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1160..0x116F -- */ + Zyyy, Zyyy, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, +/* DATA_BLOCK: -- 0x1170..0x117F -- */ + Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Zyyy, Zyyy, Zyyy, Latn, Latn, Latn, Latn, Latn, +/* DATA_BLOCK: -- 0x1180..0x118F -- */ + Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1190..0x119F -- */ + Latn, Latn, Zzzz, Latn, Zzzz, Latn, Latn, Latn, Latn, Latn, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x11A0..0x11AF -- */ + Zzzz, Zzzz, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, +/* DATA_BLOCK: -- 0x11B0..0x11BF -- */ + Sylo, Sylo, Sylo, Sylo, Sylo, Sylo, Sylo, Sylo, Sylo, Sylo, Sylo, Sylo, Sylo, Sylo, Sylo, Sylo, +/* DATA_BLOCK: -- 0x11C0..0x11CF -- */ + Sylo, Sylo, Sylo, Sylo, Sylo, Sylo, Sylo, Sylo, Sylo, Sylo, Sylo, Sylo, Sylo, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x11D0..0x11DF -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x11E0..0x11EF -- */ + Phag, Phag, Phag, Phag, Phag, Phag, Phag, Phag, Phag, Phag, Phag, Phag, Phag, Phag, Phag, Phag, +/* DATA_BLOCK: -- 0x11F0..0x11FF -- */ + Phag, Phag, Phag, Phag, Phag, Phag, Phag, Phag, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1200..0x120F -- */ + Saur, Saur, Saur, Saur, Saur, Saur, Saur, Saur, Saur, Saur, Saur, Saur, Saur, Saur, Saur, Saur, +/* DATA_BLOCK: -- 0x1210..0x121F -- */ + Saur, Saur, Saur, Saur, Saur, Saur, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Saur, Saur, +/* DATA_BLOCK: -- 0x1220..0x122F -- */ + Saur, Saur, Saur, Saur, Saur, Saur, Saur, Saur, Saur, Saur, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1230..0x123F -- */ + Kali, Kali, Kali, Kali, Kali, Kali, Kali, Kali, Kali, Kali, Kali, Kali, Kali, Kali, Kali, Kali, +/* DATA_BLOCK: -- 0x1240..0x124F -- */ + Kali, Kali, Kali, Kali, Kali, Kali, Kali, Kali, Kali, Kali, Kali, Kali, Kali, Kali, Zyyy, Kali, +/* DATA_BLOCK: -- 0x1250..0x125F -- */ + Rjng, Rjng, Rjng, Rjng, Rjng, Rjng, Rjng, Rjng, Rjng, Rjng, Rjng, Rjng, Rjng, Rjng, Rjng, Rjng, +/* DATA_BLOCK: -- 0x1260..0x126F -- */ + Rjng, Rjng, Rjng, Rjng, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Rjng, +/* DATA_BLOCK: -- 0x1270..0x127F -- */ + Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1280..0x128F -- */ + Java, Java, Java, Java, Java, Java, Java, Java, Java, Java, Java, Java, Java, Java, Java, Java, +/* DATA_BLOCK: -- 0x1290..0x129F -- */ + Java, Java, Java, Java, Java, Java, Java, Java, Java, Java, Java, Java, Java, Java, Zzzz, Zyyy, +/* DATA_BLOCK: -- 0x12A0..0x12AF -- */ + Java, Java, Java, Java, Java, Java, Java, Java, Java, Java, Zzzz, Zzzz, Zzzz, Zzzz, Java, Java, +/* DATA_BLOCK: -- 0x12B0..0x12BF -- */ + Mymr, Mymr, Mymr, Mymr, Mymr, Mymr, Mymr, Mymr, Mymr, Mymr, Mymr, Mymr, Mymr, Mymr, Mymr, Zzzz, +/* DATA_BLOCK: -- 0x12C0..0x12CF -- */ + Cham, Cham, Cham, Cham, Cham, Cham, Cham, Cham, Cham, Cham, Cham, Cham, Cham, Cham, Cham, Cham, +/* DATA_BLOCK: -- 0x12D0..0x12DF -- */ + Cham, Cham, Cham, Cham, Cham, Cham, Cham, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x12E0..0x12EF -- */ + Cham, Cham, Cham, Cham, Cham, Cham, Cham, Cham, Cham, Cham, Cham, Cham, Cham, Cham, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x12F0..0x12FF -- */ + Cham, Cham, Cham, Cham, Cham, Cham, Cham, Cham, Cham, Cham, Zzzz, Zzzz, Cham, Cham, Cham, Cham, +/* DATA_BLOCK: -- 0x1300..0x130F -- */ + Tavt, Tavt, Tavt, Tavt, Tavt, Tavt, Tavt, Tavt, Tavt, Tavt, Tavt, Tavt, Tavt, Tavt, Tavt, Tavt, +/* DATA_BLOCK: -- 0x1310..0x131F -- */ + Tavt, Tavt, Tavt, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1320..0x132F -- */ + Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Tavt, Tavt, Tavt, Tavt, Tavt, +/* DATA_BLOCK: -- 0x1330..0x133F -- */ + Mtei, Mtei, Mtei, Mtei, Mtei, Mtei, Mtei, Mtei, Mtei, Mtei, Mtei, Mtei, Mtei, Mtei, Mtei, Mtei, +/* DATA_BLOCK: -- 0x1340..0x134F -- */ + Mtei, Mtei, Mtei, Mtei, Mtei, Mtei, Mtei, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1350..0x135F -- */ + Zzzz, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Zzzz, Zzzz, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Zzzz, +/* DATA_BLOCK: -- 0x1360..0x136F -- */ + Zzzz, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1370..0x137F -- */ + Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Zyyy, Latn, Latn, Latn, Latn, +/* DATA_BLOCK: -- 0x1380..0x138F -- */ + Latn, Latn, Latn, Latn, Latn, Grek, Latn, Latn, Latn, Latn, Zyyy, Zyyy, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1390..0x139F -- */ + Mtei, Mtei, Mtei, Mtei, Mtei, Mtei, Mtei, Mtei, Mtei, Mtei, Mtei, Mtei, Mtei, Mtei, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x13A0..0x13AF -- */ + Mtei, Mtei, Mtei, Mtei, Mtei, Mtei, Mtei, Mtei, Mtei, Mtei, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x13B0..0x13BF -- */ + Hang, Hang, Hang, Hang, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x13C0..0x13CF -- */ + Hang, Hang, Hang, Hang, Hang, Hang, Hang, Zzzz, Zzzz, Zzzz, Zzzz, Hang, Hang, Hang, Hang, Hang, +/* DATA_BLOCK: -- 0x13D0..0x13DF -- */ + Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x13E0..0x13EF -- */ + Hani, Hani, Hani, Hani, Hani, Hani, Hani, Hani, Hani, Hani, Hani, Hani, Hani, Hani, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x13F0..0x13FF -- */ + Hani, Hani, Hani, Hani, Hani, Hani, Hani, Hani, Hani, Hani, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1400..0x140F -- */ + Latn, Latn, Latn, Latn, Latn, Latn, Latn, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1410..0x141F -- */ + Zzzz, Zzzz, Zzzz, Armn, Armn, Armn, Armn, Armn, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Hebr, Hebr, Hebr, +/* DATA_BLOCK: -- 0x1420..0x142F -- */ + Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, Zzzz, Hebr, Hebr, Hebr, Hebr, Hebr, Zzzz, Hebr, Zzzz, +/* DATA_BLOCK: -- 0x1430..0x143F -- */ + Hebr, Hebr, Zzzz, Hebr, Hebr, Zzzz, Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, +/* DATA_BLOCK: -- 0x1440..0x144F -- */ + Arab, Arab, Arab, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1450..0x145F -- */ + Zzzz, Zzzz, Zzzz, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, +/* DATA_BLOCK: -- 0x1460..0x146F -- */ + Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x1470..0x147F -- */ + Zzzz, Zzzz, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, +/* DATA_BLOCK: -- 0x1480..0x148F -- */ + Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Arab, +/* DATA_BLOCK: -- 0x1490..0x149F -- */ + Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Cyrl, Cyrl, +/* DATA_BLOCK: -- 0x14A0..0x14AF -- */ + Zyyy, Zyyy, Zyyy, Zzzz, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x14B0..0x14BF -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x14C0..0x14CF -- */ + Arab, Arab, Arab, Arab, Arab, Zzzz, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, +/* DATA_BLOCK: -- 0x14D0..0x14DF -- */ + Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Zzzz, Zzzz, Zyyy, +/* DATA_BLOCK: -- 0x14E0..0x14EF -- */ + Zzzz, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x14F0..0x14FF -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, +/* DATA_BLOCK: -- 0x1500..0x150F -- */ + Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x1510..0x151F -- */ + Zzzz, Zzzz, Hang, Hang, Hang, Hang, Hang, Hang, Zzzz, Zzzz, Hang, Hang, Hang, Hang, Hang, Hang, +/* DATA_BLOCK: -- 0x1520..0x152F -- */ + Zzzz, Zzzz, Hang, Hang, Hang, Hang, Hang, Hang, Zzzz, Zzzz, Hang, Hang, Hang, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1530..0x153F -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, +/* DATA_BLOCK: -- 0x1540..0x154F -- */ + Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1550..0x155F -- */ + Linb, Linb, Linb, Linb, Linb, Linb, Linb, Linb, Linb, Linb, Linb, Linb, Zzzz, Linb, Linb, Linb, +/* DATA_BLOCK: -- 0x1560..0x156F -- */ + Linb, Linb, Linb, Linb, Linb, Linb, Linb, Linb, Linb, Linb, Linb, Linb, Linb, Linb, Linb, Linb, +/* DATA_BLOCK: -- 0x1570..0x157F -- */ + Linb, Linb, Linb, Linb, Linb, Linb, Linb, Zzzz, Linb, Linb, Linb, Linb, Linb, Linb, Linb, Linb, +/* DATA_BLOCK: -- 0x1580..0x158F -- */ + Linb, Linb, Linb, Linb, Linb, Linb, Linb, Linb, Linb, Linb, Linb, Zzzz, Linb, Linb, Zzzz, Linb, +/* DATA_BLOCK: -- 0x1590..0x159F -- */ + Linb, Linb, Linb, Linb, Linb, Linb, Linb, Linb, Linb, Linb, Linb, Linb, Linb, Linb, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x15A0..0x15AF -- */ + Linb, Linb, Linb, Linb, Linb, Linb, Linb, Linb, Linb, Linb, Linb, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x15B0..0x15BF -- */ + Zyyy, Zyyy, Zyyy, Zzzz, Zzzz, Zzzz, Zzzz, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x15C0..0x15CF -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zzzz, Zzzz, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x15D0..0x15DF -- */ + Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Zzzz, +/* DATA_BLOCK: -- 0x15E0..0x15EF -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x15F0..0x15FF -- */ + Grek, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1600..0x160F -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zinh, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1610..0x161F -- */ + Lyci, Lyci, Lyci, Lyci, Lyci, Lyci, Lyci, Lyci, Lyci, Lyci, Lyci, Lyci, Lyci, Lyci, Lyci, Lyci, +/* DATA_BLOCK: -- 0x1620..0x162F -- */ + Lyci, Lyci, Lyci, Lyci, Lyci, Lyci, Lyci, Lyci, Lyci, Lyci, Lyci, Lyci, Lyci, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1630..0x163F -- */ + Cari, Cari, Cari, Cari, Cari, Cari, Cari, Cari, Cari, Cari, Cari, Cari, Cari, Cari, Cari, Cari, +/* DATA_BLOCK: -- 0x1640..0x164F -- */ + Cari, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1650..0x165F -- */ + Zinh, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x1660..0x166F -- */ + Ital, Ital, Ital, Ital, Ital, Ital, Ital, Ital, Ital, Ital, Ital, Ital, Ital, Ital, Ital, Ital, +/* DATA_BLOCK: -- 0x1670..0x167F -- */ + Ital, Ital, Ital, Ital, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Ital, Ital, Ital, +/* DATA_BLOCK: -- 0x1680..0x168F -- */ + Goth, Goth, Goth, Goth, Goth, Goth, Goth, Goth, Goth, Goth, Goth, Goth, Goth, Goth, Goth, Goth, +/* DATA_BLOCK: -- 0x1690..0x169F -- */ + Goth, Goth, Goth, Goth, Goth, Goth, Goth, Goth, Goth, Goth, Goth, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x16A0..0x16AF -- */ + Perm, Perm, Perm, Perm, Perm, Perm, Perm, Perm, Perm, Perm, Perm, Perm, Perm, Perm, Perm, Perm, +/* DATA_BLOCK: -- 0x16B0..0x16BF -- */ + Perm, Perm, Perm, Perm, Perm, Perm, Perm, Perm, Perm, Perm, Perm, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x16C0..0x16CF -- */ + Ugar, Ugar, Ugar, Ugar, Ugar, Ugar, Ugar, Ugar, Ugar, Ugar, Ugar, Ugar, Ugar, Ugar, Ugar, Ugar, +/* DATA_BLOCK: -- 0x16D0..0x16DF -- */ + Ugar, Ugar, Ugar, Ugar, Ugar, Ugar, Ugar, Ugar, Ugar, Ugar, Ugar, Ugar, Ugar, Ugar, Zzzz, Ugar, +/* DATA_BLOCK: -- 0x16E0..0x16EF -- */ + Xpeo, Xpeo, Xpeo, Xpeo, Xpeo, Xpeo, Xpeo, Xpeo, Xpeo, Xpeo, Xpeo, Xpeo, Xpeo, Xpeo, Xpeo, Xpeo, +/* DATA_BLOCK: -- 0x16F0..0x16FF -- */ + Xpeo, Xpeo, Xpeo, Xpeo, Zzzz, Zzzz, Zzzz, Zzzz, Xpeo, Xpeo, Xpeo, Xpeo, Xpeo, Xpeo, Xpeo, Xpeo, +/* DATA_BLOCK: -- 0x1700..0x170F -- */ + Xpeo, Xpeo, Xpeo, Xpeo, Xpeo, Xpeo, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1710..0x171F -- */ + Dsrt, Dsrt, Dsrt, Dsrt, Dsrt, Dsrt, Dsrt, Dsrt, Dsrt, Dsrt, Dsrt, Dsrt, Dsrt, Dsrt, Dsrt, Dsrt, +/* DATA_BLOCK: -- 0x1720..0x172F -- */ + Shaw, Shaw, Shaw, Shaw, Shaw, Shaw, Shaw, Shaw, Shaw, Shaw, Shaw, Shaw, Shaw, Shaw, Shaw, Shaw, +/* DATA_BLOCK: -- 0x1730..0x173F -- */ + Osma, Osma, Osma, Osma, Osma, Osma, Osma, Osma, Osma, Osma, Osma, Osma, Osma, Osma, Osma, Osma, +/* DATA_BLOCK: -- 0x1740..0x174F -- */ + Osma, Osma, Osma, Osma, Osma, Osma, Osma, Osma, Osma, Osma, Osma, Osma, Osma, Osma, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1750..0x175F -- */ + Osma, Osma, Osma, Osma, Osma, Osma, Osma, Osma, Osma, Osma, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1760..0x176F -- */ + Osge, Osge, Osge, Osge, Osge, Osge, Osge, Osge, Osge, Osge, Osge, Osge, Osge, Osge, Osge, Osge, +/* DATA_BLOCK: -- 0x1770..0x177F -- */ + Osge, Osge, Osge, Osge, Zzzz, Zzzz, Zzzz, Zzzz, Osge, Osge, Osge, Osge, Osge, Osge, Osge, Osge, +/* DATA_BLOCK: -- 0x1780..0x178F -- */ + Osge, Osge, Osge, Osge, Osge, Osge, Osge, Osge, Osge, Osge, Osge, Osge, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1790..0x179F -- */ + Elba, Elba, Elba, Elba, Elba, Elba, Elba, Elba, Elba, Elba, Elba, Elba, Elba, Elba, Elba, Elba, +/* DATA_BLOCK: -- 0x17A0..0x17AF -- */ + Elba, Elba, Elba, Elba, Elba, Elba, Elba, Elba, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x17B0..0x17BF -- */ + Aghb, Aghb, Aghb, Aghb, Aghb, Aghb, Aghb, Aghb, Aghb, Aghb, Aghb, Aghb, Aghb, Aghb, Aghb, Aghb, +/* DATA_BLOCK: -- 0x17C0..0x17CF -- */ + Aghb, Aghb, Aghb, Aghb, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Aghb, +/* DATA_BLOCK: -- 0x17D0..0x17DF -- */ + Vith, Vith, Vith, Vith, Vith, Vith, Vith, Vith, Vith, Vith, Vith, Zzzz, Vith, Vith, Vith, Vith, +/* DATA_BLOCK: -- 0x17E0..0x17EF -- */ + Vith, Vith, Vith, Zzzz, Vith, Vith, Zzzz, Vith, Vith, Vith, Vith, Vith, Vith, Vith, Vith, Vith, +/* DATA_BLOCK: -- 0x17F0..0x17FF -- */ + Vith, Vith, Zzzz, Vith, Vith, Vith, Vith, Vith, Vith, Vith, Vith, Vith, Vith, Vith, Vith, Vith, +/* DATA_BLOCK: -- 0x1800..0x180F -- */ + Vith, Vith, Zzzz, Vith, Vith, Vith, Vith, Vith, Vith, Vith, Zzzz, Vith, Vith, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1810..0x181F -- */ + Lina, Lina, Lina, Lina, Lina, Lina, Lina, Lina, Lina, Lina, Lina, Lina, Lina, Lina, Lina, Lina, +/* DATA_BLOCK: -- 0x1820..0x182F -- */ + Lina, Lina, Lina, Lina, Lina, Lina, Lina, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1830..0x183F -- */ + Lina, Lina, Lina, Lina, Lina, Lina, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1840..0x184F -- */ + Lina, Lina, Lina, Lina, Lina, Lina, Lina, Lina, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1850..0x185F -- */ + Latn, Latn, Latn, Latn, Latn, Latn, Zzzz, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, +/* DATA_BLOCK: -- 0x1860..0x186F -- */ + Latn, Zzzz, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1870..0x187F -- */ + Cprt, Cprt, Cprt, Cprt, Cprt, Cprt, Zzzz, Zzzz, Cprt, Zzzz, Cprt, Cprt, Cprt, Cprt, Cprt, Cprt, +/* DATA_BLOCK: -- 0x1880..0x188F -- */ + Cprt, Cprt, Cprt, Cprt, Cprt, Cprt, Cprt, Cprt, Cprt, Cprt, Cprt, Cprt, Cprt, Cprt, Cprt, Cprt, +/* DATA_BLOCK: -- 0x1890..0x189F -- */ + Cprt, Cprt, Cprt, Cprt, Cprt, Cprt, Zzzz, Cprt, Cprt, Zzzz, Zzzz, Zzzz, Cprt, Zzzz, Zzzz, Cprt, +/* DATA_BLOCK: -- 0x18A0..0x18AF -- */ + Armi, Armi, Armi, Armi, Armi, Armi, Armi, Armi, Armi, Armi, Armi, Armi, Armi, Armi, Armi, Armi, +/* DATA_BLOCK: -- 0x18B0..0x18BF -- */ + Armi, Armi, Armi, Armi, Armi, Armi, Zzzz, Armi, Armi, Armi, Armi, Armi, Armi, Armi, Armi, Armi, +/* DATA_BLOCK: -- 0x18C0..0x18CF -- */ + Palm, Palm, Palm, Palm, Palm, Palm, Palm, Palm, Palm, Palm, Palm, Palm, Palm, Palm, Palm, Palm, +/* DATA_BLOCK: -- 0x18D0..0x18DF -- */ + Nbat, Nbat, Nbat, Nbat, Nbat, Nbat, Nbat, Nbat, Nbat, Nbat, Nbat, Nbat, Nbat, Nbat, Nbat, Nbat, +/* DATA_BLOCK: -- 0x18E0..0x18EF -- */ + Nbat, Nbat, Nbat, Nbat, Nbat, Nbat, Nbat, Nbat, Nbat, Nbat, Nbat, Nbat, Nbat, Nbat, Nbat, Zzzz, +/* DATA_BLOCK: -- 0x18F0..0x18FF -- */ + Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Nbat, Nbat, Nbat, Nbat, Nbat, Nbat, Nbat, Nbat, Nbat, +/* DATA_BLOCK: -- 0x1900..0x190F -- */ + Hatr, Hatr, Hatr, Hatr, Hatr, Hatr, Hatr, Hatr, Hatr, Hatr, Hatr, Hatr, Hatr, Hatr, Hatr, Hatr, +/* DATA_BLOCK: -- 0x1910..0x191F -- */ + Hatr, Hatr, Hatr, Zzzz, Hatr, Hatr, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Hatr, Hatr, Hatr, Hatr, Hatr, +/* DATA_BLOCK: -- 0x1920..0x192F -- */ + Phnx, Phnx, Phnx, Phnx, Phnx, Phnx, Phnx, Phnx, Phnx, Phnx, Phnx, Phnx, Phnx, Phnx, Phnx, Phnx, +/* DATA_BLOCK: -- 0x1930..0x193F -- */ + Phnx, Phnx, Phnx, Phnx, Phnx, Phnx, Phnx, Phnx, Phnx, Phnx, Phnx, Phnx, Zzzz, Zzzz, Zzzz, Phnx, +/* DATA_BLOCK: -- 0x1940..0x194F -- */ + Lydi, Lydi, Lydi, Lydi, Lydi, Lydi, Lydi, Lydi, Lydi, Lydi, Lydi, Lydi, Lydi, Lydi, Lydi, Lydi, +/* DATA_BLOCK: -- 0x1950..0x195F -- */ + Lydi, Lydi, Lydi, Lydi, Lydi, Lydi, Lydi, Lydi, Lydi, Lydi, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Lydi, +/* DATA_BLOCK: -- 0x1960..0x196F -- */ + Mero, Mero, Mero, Mero, Mero, Mero, Mero, Mero, Mero, Mero, Mero, Mero, Mero, Mero, Mero, Mero, +/* DATA_BLOCK: -- 0x1970..0x197F -- */ + Merc, Merc, Merc, Merc, Merc, Merc, Merc, Merc, Merc, Merc, Merc, Merc, Merc, Merc, Merc, Merc, +/* DATA_BLOCK: -- 0x1980..0x198F -- */ + Merc, Merc, Merc, Merc, Merc, Merc, Merc, Merc, Zzzz, Zzzz, Zzzz, Zzzz, Merc, Merc, Merc, Merc, +/* DATA_BLOCK: -- 0x1990..0x199F -- */ + Zzzz, Zzzz, Merc, Merc, Merc, Merc, Merc, Merc, Merc, Merc, Merc, Merc, Merc, Merc, Merc, Merc, +/* DATA_BLOCK: -- 0x19A0..0x19AF -- */ + Khar, Khar, Khar, Khar, Zzzz, Khar, Khar, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Khar, Khar, Khar, Khar, +/* DATA_BLOCK: -- 0x19B0..0x19BF -- */ + Khar, Khar, Khar, Khar, Zzzz, Khar, Khar, Khar, Zzzz, Khar, Khar, Khar, Khar, Khar, Khar, Khar, +/* DATA_BLOCK: -- 0x19C0..0x19CF -- */ + Khar, Khar, Khar, Khar, Khar, Khar, Khar, Khar, Khar, Khar, Khar, Khar, Khar, Khar, Khar, Khar, +/* DATA_BLOCK: -- 0x19D0..0x19DF -- */ + Khar, Khar, Khar, Khar, Khar, Khar, Zzzz, Zzzz, Khar, Khar, Khar, Zzzz, Zzzz, Zzzz, Zzzz, Khar, +/* DATA_BLOCK: -- 0x19E0..0x19EF -- */ + Khar, Khar, Khar, Khar, Khar, Khar, Khar, Khar, Khar, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x19F0..0x19FF -- */ + Sarb, Sarb, Sarb, Sarb, Sarb, Sarb, Sarb, Sarb, Sarb, Sarb, Sarb, Sarb, Sarb, Sarb, Sarb, Sarb, +/* DATA_BLOCK: -- 0x1A00..0x1A0F -- */ + Narb, Narb, Narb, Narb, Narb, Narb, Narb, Narb, Narb, Narb, Narb, Narb, Narb, Narb, Narb, Narb, +/* DATA_BLOCK: -- 0x1A10..0x1A1F -- */ + Mani, Mani, Mani, Mani, Mani, Mani, Mani, Mani, Mani, Mani, Mani, Mani, Mani, Mani, Mani, Mani, +/* DATA_BLOCK: -- 0x1A20..0x1A2F -- */ + Mani, Mani, Mani, Mani, Mani, Mani, Mani, Zzzz, Zzzz, Zzzz, Zzzz, Mani, Mani, Mani, Mani, Mani, +/* DATA_BLOCK: -- 0x1A30..0x1A3F -- */ + Mani, Mani, Mani, Mani, Mani, Mani, Mani, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1A40..0x1A4F -- */ + Avst, Avst, Avst, Avst, Avst, Avst, Avst, Avst, Avst, Avst, Avst, Avst, Avst, Avst, Avst, Avst, +/* DATA_BLOCK: -- 0x1A50..0x1A5F -- */ + Avst, Avst, Avst, Avst, Avst, Avst, Zzzz, Zzzz, Zzzz, Avst, Avst, Avst, Avst, Avst, Avst, Avst, +/* DATA_BLOCK: -- 0x1A60..0x1A6F -- */ + Prti, Prti, Prti, Prti, Prti, Prti, Prti, Prti, Prti, Prti, Prti, Prti, Prti, Prti, Prti, Prti, +/* DATA_BLOCK: -- 0x1A70..0x1A7F -- */ + Prti, Prti, Prti, Prti, Prti, Prti, Zzzz, Zzzz, Prti, Prti, Prti, Prti, Prti, Prti, Prti, Prti, +/* DATA_BLOCK: -- 0x1A80..0x1A8F -- */ + Phli, Phli, Phli, Phli, Phli, Phli, Phli, Phli, Phli, Phli, Phli, Phli, Phli, Phli, Phli, Phli, +/* DATA_BLOCK: -- 0x1A90..0x1A9F -- */ + Phli, Phli, Phli, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Phli, Phli, Phli, Phli, Phli, Phli, Phli, Phli, +/* DATA_BLOCK: -- 0x1AA0..0x1AAF -- */ + Phlp, Phlp, Phlp, Phlp, Phlp, Phlp, Phlp, Phlp, Phlp, Phlp, Phlp, Phlp, Phlp, Phlp, Phlp, Phlp, +/* DATA_BLOCK: -- 0x1AB0..0x1ABF -- */ + Phlp, Phlp, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Phlp, Phlp, Phlp, Phlp, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1AC0..0x1ACF -- */ + Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Phlp, Phlp, Phlp, Phlp, Phlp, Phlp, Phlp, +/* DATA_BLOCK: -- 0x1AD0..0x1ADF -- */ + Orkh, Orkh, Orkh, Orkh, Orkh, Orkh, Orkh, Orkh, Orkh, Orkh, Orkh, Orkh, Orkh, Orkh, Orkh, Orkh, +/* DATA_BLOCK: -- 0x1AE0..0x1AEF -- */ + Orkh, Orkh, Orkh, Orkh, Orkh, Orkh, Orkh, Orkh, Orkh, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1AF0..0x1AFF -- */ + Hung, Hung, Hung, Hung, Hung, Hung, Hung, Hung, Hung, Hung, Hung, Hung, Hung, Hung, Hung, Hung, +/* DATA_BLOCK: -- 0x1B00..0x1B0F -- */ + Hung, Hung, Hung, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1B10..0x1B1F -- */ + Hung, Hung, Hung, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Hung, Hung, Hung, Hung, Hung, Hung, +/* DATA_BLOCK: -- 0x1B20..0x1B2F -- */ + Rohg, Rohg, Rohg, Rohg, Rohg, Rohg, Rohg, Rohg, Rohg, Rohg, Rohg, Rohg, Rohg, Rohg, Rohg, Rohg, +/* DATA_BLOCK: -- 0x1B30..0x1B3F -- */ + Rohg, Rohg, Rohg, Rohg, Rohg, Rohg, Rohg, Rohg, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1B40..0x1B4F -- */ + Rohg, Rohg, Rohg, Rohg, Rohg, Rohg, Rohg, Rohg, Rohg, Rohg, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1B50..0x1B5F -- */ + Yezi, Yezi, Yezi, Yezi, Yezi, Yezi, Yezi, Yezi, Yezi, Yezi, Yezi, Yezi, Yezi, Yezi, Yezi, Yezi, +/* DATA_BLOCK: -- 0x1B60..0x1B6F -- */ + Yezi, Yezi, Yezi, Yezi, Yezi, Yezi, Yezi, Yezi, Yezi, Yezi, Zzzz, Yezi, Yezi, Yezi, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1B70..0x1B7F -- */ + Yezi, Yezi, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1B80..0x1B8F -- */ + Sogo, Sogo, Sogo, Sogo, Sogo, Sogo, Sogo, Sogo, Sogo, Sogo, Sogo, Sogo, Sogo, Sogo, Sogo, Sogo, +/* DATA_BLOCK: -- 0x1B90..0x1B9F -- */ + Sogo, Sogo, Sogo, Sogo, Sogo, Sogo, Sogo, Sogo, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1BA0..0x1BAF -- */ + Sogd, Sogd, Sogd, Sogd, Sogd, Sogd, Sogd, Sogd, Sogd, Sogd, Sogd, Sogd, Sogd, Sogd, Sogd, Sogd, +/* DATA_BLOCK: -- 0x1BB0..0x1BBF -- */ + Sogd, Sogd, Sogd, Sogd, Sogd, Sogd, Sogd, Sogd, Sogd, Sogd, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1BC0..0x1BCF -- */ + Ougr, Ougr, Ougr, Ougr, Ougr, Ougr, Ougr, Ougr, Ougr, Ougr, Ougr, Ougr, Ougr, Ougr, Ougr, Ougr, +/* DATA_BLOCK: -- 0x1BD0..0x1BDF -- */ + Ougr, Ougr, Ougr, Ougr, Ougr, Ougr, Ougr, Ougr, Ougr, Ougr, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1BE0..0x1BEF -- */ + Chrs, Chrs, Chrs, Chrs, Chrs, Chrs, Chrs, Chrs, Chrs, Chrs, Chrs, Chrs, Chrs, Chrs, Chrs, Chrs, +/* DATA_BLOCK: -- 0x1BF0..0x1BFF -- */ + Chrs, Chrs, Chrs, Chrs, Chrs, Chrs, Chrs, Chrs, Chrs, Chrs, Chrs, Chrs, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1C00..0x1C0F -- */ + Elym, Elym, Elym, Elym, Elym, Elym, Elym, Elym, Elym, Elym, Elym, Elym, Elym, Elym, Elym, Elym, +/* DATA_BLOCK: -- 0x1C10..0x1C1F -- */ + Elym, Elym, Elym, Elym, Elym, Elym, Elym, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1C20..0x1C2F -- */ + Brah, Brah, Brah, Brah, Brah, Brah, Brah, Brah, Brah, Brah, Brah, Brah, Brah, Brah, Brah, Brah, +/* DATA_BLOCK: -- 0x1C30..0x1C3F -- */ + Brah, Brah, Brah, Brah, Brah, Brah, Brah, Brah, Brah, Brah, Brah, Brah, Brah, Brah, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1C40..0x1C4F -- */ + Zzzz, Zzzz, Brah, Brah, Brah, Brah, Brah, Brah, Brah, Brah, Brah, Brah, Brah, Brah, Brah, Brah, +/* DATA_BLOCK: -- 0x1C50..0x1C5F -- */ + Brah, Brah, Brah, Brah, Brah, Brah, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Brah, +/* DATA_BLOCK: -- 0x1C60..0x1C6F -- */ + Kthi, Kthi, Kthi, Kthi, Kthi, Kthi, Kthi, Kthi, Kthi, Kthi, Kthi, Kthi, Kthi, Kthi, Kthi, Kthi, +/* DATA_BLOCK: -- 0x1C70..0x1C7F -- */ + Kthi, Kthi, Kthi, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Kthi, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1C80..0x1C8F -- */ + Sora, Sora, Sora, Sora, Sora, Sora, Sora, Sora, Sora, Sora, Sora, Sora, Sora, Sora, Sora, Sora, +/* DATA_BLOCK: -- 0x1C90..0x1C9F -- */ + Sora, Sora, Sora, Sora, Sora, Sora, Sora, Sora, Sora, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1CA0..0x1CAF -- */ + Sora, Sora, Sora, Sora, Sora, Sora, Sora, Sora, Sora, Sora, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1CB0..0x1CBF -- */ + Cakm, Cakm, Cakm, Cakm, Cakm, Cakm, Cakm, Cakm, Cakm, Cakm, Cakm, Cakm, Cakm, Cakm, Cakm, Cakm, +/* DATA_BLOCK: -- 0x1CC0..0x1CCF -- */ + Cakm, Cakm, Cakm, Cakm, Cakm, Zzzz, Cakm, Cakm, Cakm, Cakm, Cakm, Cakm, Cakm, Cakm, Cakm, Cakm, +/* DATA_BLOCK: -- 0x1CD0..0x1CDF -- */ + Cakm, Cakm, Cakm, Cakm, Cakm, Cakm, Cakm, Cakm, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1CE0..0x1CEF -- */ + Mahj, Mahj, Mahj, Mahj, Mahj, Mahj, Mahj, Mahj, Mahj, Mahj, Mahj, Mahj, Mahj, Mahj, Mahj, Mahj, +/* DATA_BLOCK: -- 0x1CF0..0x1CFF -- */ + Mahj, Mahj, Mahj, Mahj, Mahj, Mahj, Mahj, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1D00..0x1D0F -- */ + Shrd, Shrd, Shrd, Shrd, Shrd, Shrd, Shrd, Shrd, Shrd, Shrd, Shrd, Shrd, Shrd, Shrd, Shrd, Shrd, +/* DATA_BLOCK: -- 0x1D10..0x1D1F -- */ + Zzzz, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, +/* DATA_BLOCK: -- 0x1D20..0x1D2F -- */ + Sinh, Sinh, Sinh, Sinh, Sinh, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1D30..0x1D3F -- */ + Khoj, Khoj, Khoj, Khoj, Khoj, Khoj, Khoj, Khoj, Khoj, Khoj, Khoj, Khoj, Khoj, Khoj, Khoj, Khoj, +/* DATA_BLOCK: -- 0x1D40..0x1D4F -- */ + Khoj, Khoj, Zzzz, Khoj, Khoj, Khoj, Khoj, Khoj, Khoj, Khoj, Khoj, Khoj, Khoj, Khoj, Khoj, Khoj, +/* DATA_BLOCK: -- 0x1D50..0x1D5F -- */ + Khoj, Khoj, Khoj, Khoj, Khoj, Khoj, Khoj, Khoj, Khoj, Khoj, Khoj, Khoj, Khoj, Khoj, Khoj, Zzzz, +/* DATA_BLOCK: -- 0x1D60..0x1D6F -- */ + Mult, Mult, Mult, Mult, Mult, Mult, Mult, Zzzz, Mult, Zzzz, Mult, Mult, Mult, Mult, Zzzz, Mult, +/* DATA_BLOCK: -- 0x1D70..0x1D7F -- */ + Mult, Mult, Mult, Mult, Mult, Mult, Mult, Mult, Mult, Mult, Mult, Mult, Mult, Mult, Zzzz, Mult, +/* DATA_BLOCK: -- 0x1D80..0x1D8F -- */ + Mult, Mult, Mult, Mult, Mult, Mult, Mult, Mult, Mult, Mult, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1D90..0x1D9F -- */ + Sind, Sind, Sind, Sind, Sind, Sind, Sind, Sind, Sind, Sind, Sind, Sind, Sind, Sind, Sind, Sind, +/* DATA_BLOCK: -- 0x1DA0..0x1DAF -- */ + Sind, Sind, Sind, Sind, Sind, Sind, Sind, Sind, Sind, Sind, Sind, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1DB0..0x1DBF -- */ + Sind, Sind, Sind, Sind, Sind, Sind, Sind, Sind, Sind, Sind, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1DC0..0x1DCF -- */ + Gran, Gran, Gran, Gran, Zzzz, Gran, Gran, Gran, Gran, Gran, Gran, Gran, Gran, Zzzz, Zzzz, Gran, +/* DATA_BLOCK: -- 0x1DD0..0x1DDF -- */ + Gran, Zzzz, Zzzz, Gran, Gran, Gran, Gran, Gran, Gran, Gran, Gran, Gran, Gran, Gran, Gran, Gran, +/* DATA_BLOCK: -- 0x1DE0..0x1DEF -- */ + Gran, Gran, Gran, Gran, Gran, Gran, Gran, Gran, Gran, Zzzz, Gran, Gran, Gran, Gran, Gran, Gran, +/* DATA_BLOCK: -- 0x1DF0..0x1DFF -- */ + Gran, Zzzz, Gran, Gran, Zzzz, Gran, Gran, Gran, Gran, Gran, Zzzz, Zinh, Gran, Gran, Gran, Gran, +/* DATA_BLOCK: -- 0x1E00..0x1E0F -- */ + Gran, Gran, Gran, Gran, Gran, Zzzz, Zzzz, Gran, Gran, Zzzz, Zzzz, Gran, Gran, Gran, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1E10..0x1E1F -- */ + Gran, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Gran, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Gran, Gran, Gran, +/* DATA_BLOCK: -- 0x1E20..0x1E2F -- */ + Gran, Gran, Gran, Gran, Zzzz, Zzzz, Gran, Gran, Gran, Gran, Gran, Gran, Gran, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1E30..0x1E3F -- */ + Gran, Gran, Gran, Gran, Gran, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1E40..0x1E4F -- */ + Newa, Newa, Newa, Newa, Newa, Newa, Newa, Newa, Newa, Newa, Newa, Newa, Newa, Newa, Newa, Newa, +/* DATA_BLOCK: -- 0x1E50..0x1E5F -- */ + Newa, Newa, Newa, Newa, Newa, Newa, Newa, Newa, Newa, Newa, Newa, Newa, Zzzz, Newa, Newa, Newa, +/* DATA_BLOCK: -- 0x1E60..0x1E6F -- */ + Newa, Newa, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1E70..0x1E7F -- */ + Tirh, Tirh, Tirh, Tirh, Tirh, Tirh, Tirh, Tirh, Tirh, Tirh, Tirh, Tirh, Tirh, Tirh, Tirh, Tirh, +/* DATA_BLOCK: -- 0x1E80..0x1E8F -- */ + Tirh, Tirh, Tirh, Tirh, Tirh, Tirh, Tirh, Tirh, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1E90..0x1E9F -- */ + Tirh, Tirh, Tirh, Tirh, Tirh, Tirh, Tirh, Tirh, Tirh, Tirh, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1EA0..0x1EAF -- */ + Sidd, Sidd, Sidd, Sidd, Sidd, Sidd, Sidd, Sidd, Sidd, Sidd, Sidd, Sidd, Sidd, Sidd, Sidd, Sidd, +/* DATA_BLOCK: -- 0x1EB0..0x1EBF -- */ + Sidd, Sidd, Sidd, Sidd, Sidd, Sidd, Zzzz, Zzzz, Sidd, Sidd, Sidd, Sidd, Sidd, Sidd, Sidd, Sidd, +/* DATA_BLOCK: -- 0x1EC0..0x1ECF -- */ + Sidd, Sidd, Sidd, Sidd, Sidd, Sidd, Sidd, Sidd, Sidd, Sidd, Sidd, Sidd, Sidd, Sidd, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1ED0..0x1EDF -- */ + Modi, Modi, Modi, Modi, Modi, Modi, Modi, Modi, Modi, Modi, Modi, Modi, Modi, Modi, Modi, Modi, +/* DATA_BLOCK: -- 0x1EE0..0x1EEF -- */ + Modi, Modi, Modi, Modi, Modi, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1EF0..0x1EFF -- */ + Modi, Modi, Modi, Modi, Modi, Modi, Modi, Modi, Modi, Modi, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1F00..0x1F0F -- */ + Mong, Mong, Mong, Mong, Mong, Mong, Mong, Mong, Mong, Mong, Mong, Mong, Mong, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1F10..0x1F1F -- */ + Takr, Takr, Takr, Takr, Takr, Takr, Takr, Takr, Takr, Takr, Takr, Takr, Takr, Takr, Takr, Takr, +/* DATA_BLOCK: -- 0x1F20..0x1F2F -- */ + Takr, Takr, Takr, Takr, Takr, Takr, Takr, Takr, Takr, Takr, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1F30..0x1F3F -- */ + Ahom, Ahom, Ahom, Ahom, Ahom, Ahom, Ahom, Ahom, Ahom, Ahom, Ahom, Ahom, Ahom, Ahom, Ahom, Ahom, +/* DATA_BLOCK: -- 0x1F40..0x1F4F -- */ + Ahom, Ahom, Ahom, Ahom, Ahom, Ahom, Ahom, Ahom, Ahom, Ahom, Ahom, Zzzz, Zzzz, Ahom, Ahom, Ahom, +/* DATA_BLOCK: -- 0x1F50..0x1F5F -- */ + Ahom, Ahom, Ahom, Ahom, Ahom, Ahom, Ahom, Ahom, Ahom, Ahom, Ahom, Ahom, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1F60..0x1F6F -- */ + Ahom, Ahom, Ahom, Ahom, Ahom, Ahom, Ahom, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1F70..0x1F7F -- */ + Dogr, Dogr, Dogr, Dogr, Dogr, Dogr, Dogr, Dogr, Dogr, Dogr, Dogr, Dogr, Dogr, Dogr, Dogr, Dogr, +/* DATA_BLOCK: -- 0x1F80..0x1F8F -- */ + Dogr, Dogr, Dogr, Dogr, Dogr, Dogr, Dogr, Dogr, Dogr, Dogr, Dogr, Dogr, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1F90..0x1F9F -- */ + Wara, Wara, Wara, Wara, Wara, Wara, Wara, Wara, Wara, Wara, Wara, Wara, Wara, Wara, Wara, Wara, +/* DATA_BLOCK: -- 0x1FA0..0x1FAF -- */ + Wara, Wara, Wara, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Wara, +/* DATA_BLOCK: -- 0x1FB0..0x1FBF -- */ + Diak, Diak, Diak, Diak, Diak, Diak, Diak, Zzzz, Zzzz, Diak, Zzzz, Zzzz, Diak, Diak, Diak, Diak, +/* DATA_BLOCK: -- 0x1FC0..0x1FCF -- */ + Diak, Diak, Diak, Diak, Zzzz, Diak, Diak, Zzzz, Diak, Diak, Diak, Diak, Diak, Diak, Diak, Diak, +/* DATA_BLOCK: -- 0x1FD0..0x1FDF -- */ + Diak, Diak, Diak, Diak, Diak, Diak, Diak, Diak, Diak, Diak, Diak, Diak, Diak, Diak, Diak, Diak, +/* DATA_BLOCK: -- 0x1FE0..0x1FEF -- */ + Diak, Diak, Diak, Diak, Diak, Diak, Zzzz, Diak, Diak, Zzzz, Zzzz, Diak, Diak, Diak, Diak, Diak, +/* DATA_BLOCK: -- 0x1FF0..0x1FFF -- */ + Diak, Diak, Diak, Diak, Diak, Diak, Diak, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2000..0x200F -- */ + Diak, Diak, Diak, Diak, Diak, Diak, Diak, Diak, Diak, Diak, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2010..0x201F -- */ + Nand, Nand, Nand, Nand, Nand, Nand, Nand, Nand, Zzzz, Zzzz, Nand, Nand, Nand, Nand, Nand, Nand, +/* DATA_BLOCK: -- 0x2020..0x202F -- */ + Nand, Nand, Nand, Nand, Nand, Nand, Nand, Nand, Nand, Nand, Nand, Nand, Nand, Nand, Nand, Nand, +/* DATA_BLOCK: -- 0x2030..0x203F -- */ + Nand, Nand, Nand, Nand, Nand, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2040..0x204F -- */ + Zanb, Zanb, Zanb, Zanb, Zanb, Zanb, Zanb, Zanb, Zanb, Zanb, Zanb, Zanb, Zanb, Zanb, Zanb, Zanb, +/* DATA_BLOCK: -- 0x2050..0x205F -- */ + Zanb, Zanb, Zanb, Zanb, Zanb, Zanb, Zanb, Zanb, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2060..0x206F -- */ + Soyo, Soyo, Soyo, Soyo, Soyo, Soyo, Soyo, Soyo, Soyo, Soyo, Soyo, Soyo, Soyo, Soyo, Soyo, Soyo, +/* DATA_BLOCK: -- 0x2070..0x207F -- */ + Soyo, Soyo, Soyo, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2080..0x208F -- */ + Pauc, Pauc, Pauc, Pauc, Pauc, Pauc, Pauc, Pauc, Pauc, Pauc, Pauc, Pauc, Pauc, Pauc, Pauc, Pauc, +/* DATA_BLOCK: -- 0x2090..0x209F -- */ + Pauc, Pauc, Pauc, Pauc, Pauc, Pauc, Pauc, Pauc, Pauc, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x20A0..0x20AF -- */ + Bhks, Bhks, Bhks, Bhks, Bhks, Bhks, Bhks, Bhks, Bhks, Zzzz, Bhks, Bhks, Bhks, Bhks, Bhks, Bhks, +/* DATA_BLOCK: -- 0x20B0..0x20BF -- */ + Bhks, Bhks, Bhks, Bhks, Bhks, Bhks, Bhks, Bhks, Bhks, Bhks, Bhks, Bhks, Bhks, Bhks, Bhks, Bhks, +/* DATA_BLOCK: -- 0x20C0..0x20CF -- */ + Bhks, Bhks, Bhks, Bhks, Bhks, Bhks, Bhks, Zzzz, Bhks, Bhks, Bhks, Bhks, Bhks, Bhks, Bhks, Bhks, +/* DATA_BLOCK: -- 0x20D0..0x20DF -- */ + Bhks, Bhks, Bhks, Bhks, Bhks, Bhks, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x20E0..0x20EF -- */ + Bhks, Bhks, Bhks, Bhks, Bhks, Bhks, Bhks, Bhks, Bhks, Bhks, Bhks, Bhks, Bhks, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x20F0..0x20FF -- */ + Marc, Marc, Marc, Marc, Marc, Marc, Marc, Marc, Marc, Marc, Marc, Marc, Marc, Marc, Marc, Marc, +/* DATA_BLOCK: -- 0x2100..0x210F -- */ + Zzzz, Zzzz, Marc, Marc, Marc, Marc, Marc, Marc, Marc, Marc, Marc, Marc, Marc, Marc, Marc, Marc, +/* DATA_BLOCK: -- 0x2110..0x211F -- */ + Marc, Marc, Marc, Marc, Marc, Marc, Marc, Marc, Zzzz, Marc, Marc, Marc, Marc, Marc, Marc, Marc, +/* DATA_BLOCK: -- 0x2120..0x212F -- */ + Marc, Marc, Marc, Marc, Marc, Marc, Marc, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2130..0x213F -- */ + Gonm, Gonm, Gonm, Gonm, Gonm, Gonm, Gonm, Zzzz, Gonm, Gonm, Zzzz, Gonm, Gonm, Gonm, Gonm, Gonm, +/* DATA_BLOCK: -- 0x2140..0x214F -- */ + Gonm, Gonm, Gonm, Gonm, Gonm, Gonm, Gonm, Gonm, Gonm, Gonm, Gonm, Gonm, Gonm, Gonm, Gonm, Gonm, +/* DATA_BLOCK: -- 0x2150..0x215F -- */ + Gonm, Gonm, Gonm, Gonm, Gonm, Gonm, Gonm, Zzzz, Zzzz, Zzzz, Gonm, Zzzz, Gonm, Gonm, Zzzz, Gonm, +/* DATA_BLOCK: -- 0x2160..0x216F -- */ + Gonm, Gonm, Gonm, Gonm, Gonm, Gonm, Gonm, Gonm, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2170..0x217F -- */ + Gonm, Gonm, Gonm, Gonm, Gonm, Gonm, Gonm, Gonm, Gonm, Gonm, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2180..0x218F -- */ + Gong, Gong, Gong, Gong, Gong, Gong, Zzzz, Gong, Gong, Zzzz, Gong, Gong, Gong, Gong, Gong, Gong, +/* DATA_BLOCK: -- 0x2190..0x219F -- */ + Gong, Gong, Gong, Gong, Gong, Gong, Gong, Gong, Gong, Gong, Gong, Gong, Gong, Gong, Gong, Gong, +/* DATA_BLOCK: -- 0x21A0..0x21AF -- */ + Gong, Gong, Gong, Gong, Gong, Gong, Gong, Gong, Gong, Gong, Gong, Gong, Gong, Gong, Gong, Zzzz, +/* DATA_BLOCK: -- 0x21B0..0x21BF -- */ + Gong, Gong, Zzzz, Gong, Gong, Gong, Gong, Gong, Gong, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x21C0..0x21CF -- */ + Gong, Gong, Gong, Gong, Gong, Gong, Gong, Gong, Gong, Gong, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x21D0..0x21DF -- */ + Maka, Maka, Maka, Maka, Maka, Maka, Maka, Maka, Maka, Maka, Maka, Maka, Maka, Maka, Maka, Maka, +/* DATA_BLOCK: -- 0x21E0..0x21EF -- */ + Maka, Maka, Maka, Maka, Maka, Maka, Maka, Maka, Maka, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x21F0..0x21FF -- */ + Lisu, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2200..0x220F -- */ + Taml, Taml, Taml, Taml, Taml, Taml, Taml, Taml, Taml, Taml, Taml, Taml, Taml, Taml, Taml, Taml, +/* DATA_BLOCK: -- 0x2210..0x221F -- */ + Taml, Taml, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Taml, +/* DATA_BLOCK: -- 0x2220..0x222F -- */ + Xsux, Xsux, Xsux, Xsux, Xsux, Xsux, Xsux, Xsux, Xsux, Xsux, Xsux, Xsux, Xsux, Xsux, Xsux, Xsux, +/* DATA_BLOCK: -- 0x2230..0x223F -- */ + Xsux, Xsux, Xsux, Xsux, Xsux, Xsux, Xsux, Xsux, Xsux, Xsux, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2240..0x224F -- */ + Xsux, Xsux, Xsux, Xsux, Xsux, Xsux, Xsux, Xsux, Xsux, Xsux, Xsux, Xsux, Xsux, Xsux, Xsux, Zzzz, +/* DATA_BLOCK: -- 0x2250..0x225F -- */ + Xsux, Xsux, Xsux, Xsux, Xsux, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2260..0x226F -- */ + Xsux, Xsux, Xsux, Xsux, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2270..0x227F -- */ + Cpmn, Cpmn, Cpmn, Cpmn, Cpmn, Cpmn, Cpmn, Cpmn, Cpmn, Cpmn, Cpmn, Cpmn, Cpmn, Cpmn, Cpmn, Cpmn, +/* DATA_BLOCK: -- 0x2280..0x228F -- */ + Cpmn, Cpmn, Cpmn, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2290..0x229F -- */ + Egyp, Egyp, Egyp, Egyp, Egyp, Egyp, Egyp, Egyp, Egyp, Egyp, Egyp, Egyp, Egyp, Egyp, Egyp, Egyp, +/* DATA_BLOCK: -- 0x22A0..0x22AF -- */ + Egyp, Egyp, Egyp, Egyp, Egyp, Egyp, Egyp, Egyp, Egyp, Egyp, Egyp, Egyp, Egyp, Egyp, Egyp, Zzzz, +/* DATA_BLOCK: -- 0x22B0..0x22BF -- */ + Egyp, Egyp, Egyp, Egyp, Egyp, Egyp, Egyp, Egyp, Egyp, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x22C0..0x22CF -- */ + Hluw, Hluw, Hluw, Hluw, Hluw, Hluw, Hluw, Hluw, Hluw, Hluw, Hluw, Hluw, Hluw, Hluw, Hluw, Hluw, +/* DATA_BLOCK: -- 0x22D0..0x22DF -- */ + Hluw, Hluw, Hluw, Hluw, Hluw, Hluw, Hluw, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x22E0..0x22EF -- */ + Bamu, Bamu, Bamu, Bamu, Bamu, Bamu, Bamu, Bamu, Bamu, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x22F0..0x22FF -- */ + Mroo, Mroo, Mroo, Mroo, Mroo, Mroo, Mroo, Mroo, Mroo, Mroo, Mroo, Mroo, Mroo, Mroo, Mroo, Mroo, +/* DATA_BLOCK: -- 0x2300..0x230F -- */ + Mroo, Mroo, Mroo, Mroo, Mroo, Mroo, Mroo, Mroo, Mroo, Mroo, Mroo, Mroo, Mroo, Mroo, Mroo, Zzzz, +/* DATA_BLOCK: -- 0x2310..0x231F -- */ + Mroo, Mroo, Mroo, Mroo, Mroo, Mroo, Mroo, Mroo, Mroo, Mroo, Zzzz, Zzzz, Zzzz, Zzzz, Mroo, Mroo, +/* DATA_BLOCK: -- 0x2320..0x232F -- */ + Tnsa, Tnsa, Tnsa, Tnsa, Tnsa, Tnsa, Tnsa, Tnsa, Tnsa, Tnsa, Tnsa, Tnsa, Tnsa, Tnsa, Tnsa, Tnsa, +/* DATA_BLOCK: -- 0x2330..0x233F -- */ + Tnsa, Tnsa, Tnsa, Tnsa, Tnsa, Tnsa, Tnsa, Tnsa, Tnsa, Tnsa, Tnsa, Tnsa, Tnsa, Tnsa, Tnsa, Zzzz, +/* DATA_BLOCK: -- 0x2340..0x234F -- */ + Tnsa, Tnsa, Tnsa, Tnsa, Tnsa, Tnsa, Tnsa, Tnsa, Tnsa, Tnsa, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2350..0x235F -- */ + Bass, Bass, Bass, Bass, Bass, Bass, Bass, Bass, Bass, Bass, Bass, Bass, Bass, Bass, Bass, Bass, +/* DATA_BLOCK: -- 0x2360..0x236F -- */ + Bass, Bass, Bass, Bass, Bass, Bass, Bass, Bass, Bass, Bass, Bass, Bass, Bass, Bass, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2370..0x237F -- */ + Bass, Bass, Bass, Bass, Bass, Bass, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2380..0x238F -- */ + Hmng, Hmng, Hmng, Hmng, Hmng, Hmng, Hmng, Hmng, Hmng, Hmng, Hmng, Hmng, Hmng, Hmng, Hmng, Hmng, +/* DATA_BLOCK: -- 0x2390..0x239F -- */ + Hmng, Hmng, Hmng, Hmng, Hmng, Hmng, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x23A0..0x23AF -- */ + Hmng, Hmng, Hmng, Hmng, Hmng, Hmng, Hmng, Hmng, Hmng, Hmng, Zzzz, Hmng, Hmng, Hmng, Hmng, Hmng, +/* DATA_BLOCK: -- 0x23B0..0x23BF -- */ + Hmng, Hmng, Zzzz, Hmng, Hmng, Hmng, Hmng, Hmng, Hmng, Hmng, Hmng, Hmng, Hmng, Hmng, Hmng, Hmng, +/* DATA_BLOCK: -- 0x23C0..0x23CF -- */ + Hmng, Hmng, Hmng, Hmng, Hmng, Hmng, Hmng, Hmng, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Hmng, Hmng, Hmng, +/* DATA_BLOCK: -- 0x23D0..0x23DF -- */ + Medf, Medf, Medf, Medf, Medf, Medf, Medf, Medf, Medf, Medf, Medf, Medf, Medf, Medf, Medf, Medf, +/* DATA_BLOCK: -- 0x23E0..0x23EF -- */ + Medf, Medf, Medf, Medf, Medf, Medf, Medf, Medf, Medf, Medf, Medf, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x23F0..0x23FF -- */ + Plrd, Plrd, Plrd, Plrd, Plrd, Plrd, Plrd, Plrd, Plrd, Plrd, Plrd, Plrd, Plrd, Plrd, Plrd, Plrd, +/* DATA_BLOCK: -- 0x2400..0x240F -- */ + Plrd, Plrd, Plrd, Plrd, Plrd, Plrd, Plrd, Plrd, Plrd, Plrd, Plrd, Zzzz, Zzzz, Zzzz, Zzzz, Plrd, +/* DATA_BLOCK: -- 0x2410..0x241F -- */ + Plrd, Plrd, Plrd, Plrd, Plrd, Plrd, Plrd, Plrd, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Plrd, +/* DATA_BLOCK: -- 0x2420..0x242F -- */ + Tang, Nshu, Hani, Hani, Kits, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2430..0x243F -- */ + Hani, Hani, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2440..0x244F -- */ + Tang, Tang, Tang, Tang, Tang, Tang, Tang, Tang, Tang, Tang, Tang, Tang, Tang, Tang, Tang, Tang, +/* DATA_BLOCK: -- 0x2450..0x245F -- */ + Tang, Tang, Tang, Tang, Tang, Tang, Tang, Tang, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2460..0x246F -- */ + Kits, Kits, Kits, Kits, Kits, Kits, Kits, Kits, Kits, Kits, Kits, Kits, Kits, Kits, Kits, Kits, +/* DATA_BLOCK: -- 0x2470..0x247F -- */ + Kits, Kits, Kits, Kits, Kits, Kits, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2480..0x248F -- */ + Tang, Tang, Tang, Tang, Tang, Tang, Tang, Tang, Tang, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2490..0x249F -- */ + Kana, Kana, Kana, Kana, Zzzz, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Zzzz, Kana, Kana, Zzzz, +/* DATA_BLOCK: -- 0x24A0..0x24AF -- */ + Kana, Hira, Hira, Hira, Hira, Hira, Hira, Hira, Hira, Hira, Hira, Hira, Hira, Hira, Hira, Hira, +/* DATA_BLOCK: -- 0x24B0..0x24BF -- */ + Kana, Kana, Kana, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x24C0..0x24CF -- */ + Hira, Hira, Hira, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x24D0..0x24DF -- */ + Zzzz, Zzzz, Zzzz, Zzzz, Kana, Kana, Kana, Kana, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x24E0..0x24EF -- */ + Nshu, Nshu, Nshu, Nshu, Nshu, Nshu, Nshu, Nshu, Nshu, Nshu, Nshu, Nshu, Nshu, Nshu, Nshu, Nshu, +/* DATA_BLOCK: -- 0x24F0..0x24FF -- */ + Nshu, Nshu, Nshu, Nshu, Nshu, Nshu, Nshu, Nshu, Nshu, Nshu, Nshu, Nshu, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2500..0x250F -- */ + Dupl, Dupl, Dupl, Dupl, Dupl, Dupl, Dupl, Dupl, Dupl, Dupl, Dupl, Dupl, Dupl, Dupl, Dupl, Dupl, +/* DATA_BLOCK: -- 0x2510..0x251F -- */ + Dupl, Dupl, Dupl, Dupl, Dupl, Dupl, Dupl, Dupl, Dupl, Dupl, Dupl, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2520..0x252F -- */ + Dupl, Dupl, Dupl, Dupl, Dupl, Dupl, Dupl, Dupl, Dupl, Dupl, Dupl, Dupl, Dupl, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2530..0x253F -- */ + Dupl, Dupl, Dupl, Dupl, Dupl, Dupl, Dupl, Dupl, Dupl, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2540..0x254F -- */ + Dupl, Dupl, Dupl, Dupl, Dupl, Dupl, Dupl, Dupl, Dupl, Dupl, Zzzz, Zzzz, Dupl, Dupl, Dupl, Dupl, +/* DATA_BLOCK: -- 0x2550..0x255F -- */ + Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2560..0x256F -- */ + Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2570..0x257F -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2580..0x258F -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zzzz, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x2590..0x259F -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zinh, Zinh, Zinh, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x25A0..0x25AF -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zinh, Zinh, Zinh, Zinh, Zinh, +/* DATA_BLOCK: -- 0x25B0..0x25BF -- */ + Zinh, Zinh, Zinh, Zyyy, Zyyy, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zyyy, Zyyy, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x25C0..0x25CF -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zinh, Zinh, Zinh, Zinh, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x25D0..0x25DF -- */ + Grek, Grek, Grek, Grek, Grek, Grek, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x25E0..0x25EF -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x25F0..0x25FF -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x2600..0x260F -- */ + Zzzz, Zzzz, Zyyy, Zzzz, Zzzz, Zyyy, Zyyy, Zzzz, Zzzz, Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x2610..0x261F -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zyyy, Zzzz, Zyyy, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x2620..0x262F -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x2630..0x263F -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zzzz, Zyyy, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x2640..0x264F -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x2650..0x265F -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, +/* DATA_BLOCK: -- 0x2660..0x266F -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zyyy, Zzzz, Zzzz, Zzzz, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x2670..0x267F -- */ + Zyyy, Zzzz, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x2680..0x268F -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zzzz, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x2690..0x269F -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zzzz, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x26A0..0x26AF -- */ + Sgnw, Sgnw, Sgnw, Sgnw, Sgnw, Sgnw, Sgnw, Sgnw, Sgnw, Sgnw, Sgnw, Sgnw, Sgnw, Sgnw, Sgnw, Sgnw, +/* DATA_BLOCK: -- 0x26B0..0x26BF -- */ + Sgnw, Sgnw, Sgnw, Sgnw, Sgnw, Sgnw, Sgnw, Sgnw, Sgnw, Sgnw, Sgnw, Sgnw, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x26C0..0x26CF -- */ + Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Sgnw, Sgnw, Sgnw, Sgnw, Sgnw, +/* DATA_BLOCK: -- 0x26D0..0x26DF -- */ + Zzzz, Sgnw, Sgnw, Sgnw, Sgnw, Sgnw, Sgnw, Sgnw, Sgnw, Sgnw, Sgnw, Sgnw, Sgnw, Sgnw, Sgnw, Sgnw, +/* DATA_BLOCK: -- 0x26E0..0x26EF -- */ + Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Zzzz, +/* DATA_BLOCK: -- 0x26F0..0x26FF -- */ + Glag, Glag, Glag, Glag, Glag, Glag, Glag, Zzzz, Glag, Glag, Glag, Glag, Glag, Glag, Glag, Glag, +/* DATA_BLOCK: -- 0x2700..0x270F -- */ + Glag, Glag, Glag, Glag, Glag, Glag, Glag, Glag, Glag, Zzzz, Zzzz, Glag, Glag, Glag, Glag, Glag, +/* DATA_BLOCK: -- 0x2710..0x271F -- */ + Glag, Glag, Zzzz, Glag, Glag, Zzzz, Glag, Glag, Glag, Glag, Glag, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2720..0x272F -- */ + Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, +/* DATA_BLOCK: -- 0x2730..0x273F -- */ + Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2740..0x274F -- */ + Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2750..0x275F -- */ + Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Zzzz, Zzzz, Zzzz, Zzzz, Hmnp, Hmnp, +/* DATA_BLOCK: -- 0x2760..0x276F -- */ + Toto, Toto, Toto, Toto, Toto, Toto, Toto, Toto, Toto, Toto, Toto, Toto, Toto, Toto, Toto, Toto, +/* DATA_BLOCK: -- 0x2770..0x277F -- */ + Toto, Toto, Toto, Toto, Toto, Toto, Toto, Toto, Toto, Toto, Toto, Toto, Toto, Toto, Toto, Zzzz, +/* DATA_BLOCK: -- 0x2780..0x278F -- */ + Wcho, Wcho, Wcho, Wcho, Wcho, Wcho, Wcho, Wcho, Wcho, Wcho, Wcho, Wcho, Wcho, Wcho, Wcho, Wcho, +/* DATA_BLOCK: -- 0x2790..0x279F -- */ + Wcho, Wcho, Wcho, Wcho, Wcho, Wcho, Wcho, Wcho, Wcho, Wcho, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Wcho, +/* DATA_BLOCK: -- 0x27A0..0x27AF -- */ + Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Zzzz, Ethi, Ethi, Ethi, Ethi, Zzzz, Ethi, Ethi, Zzzz, +/* DATA_BLOCK: -- 0x27B0..0x27BF -- */ + Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Zzzz, +/* DATA_BLOCK: -- 0x27C0..0x27CF -- */ + Mend, Mend, Mend, Mend, Mend, Mend, Mend, Mend, Mend, Mend, Mend, Mend, Mend, Mend, Mend, Mend, +/* DATA_BLOCK: -- 0x27D0..0x27DF -- */ + Mend, Mend, Mend, Mend, Mend, Zzzz, Zzzz, Mend, Mend, Mend, Mend, Mend, Mend, Mend, Mend, Mend, +/* DATA_BLOCK: -- 0x27E0..0x27EF -- */ + Mend, Mend, Mend, Mend, Mend, Mend, Mend, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x27F0..0x27FF -- */ + Adlm, Adlm, Adlm, Adlm, Adlm, Adlm, Adlm, Adlm, Adlm, Adlm, Adlm, Adlm, Adlm, Adlm, Adlm, Adlm, +/* DATA_BLOCK: -- 0x2800..0x280F -- */ + Adlm, Adlm, Adlm, Adlm, Adlm, Adlm, Adlm, Adlm, Adlm, Adlm, Adlm, Adlm, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2810..0x281F -- */ + Adlm, Adlm, Adlm, Adlm, Adlm, Adlm, Adlm, Adlm, Adlm, Adlm, Zzzz, Zzzz, Zzzz, Zzzz, Adlm, Adlm, +/* DATA_BLOCK: -- 0x2820..0x282F -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2830..0x283F -- */ + Arab, Arab, Arab, Arab, Zzzz, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, +/* DATA_BLOCK: -- 0x2840..0x284F -- */ + Zzzz, Arab, Arab, Zzzz, Arab, Zzzz, Zzzz, Arab, Zzzz, Arab, Arab, Arab, Arab, Arab, Arab, Arab, +/* DATA_BLOCK: -- 0x2850..0x285F -- */ + Arab, Arab, Arab, Zzzz, Arab, Arab, Arab, Arab, Zzzz, Arab, Zzzz, Arab, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2860..0x286F -- */ + Zzzz, Zzzz, Arab, Zzzz, Zzzz, Zzzz, Zzzz, Arab, Zzzz, Arab, Zzzz, Arab, Zzzz, Arab, Arab, Arab, +/* DATA_BLOCK: -- 0x2870..0x287F -- */ + Zzzz, Arab, Arab, Zzzz, Arab, Zzzz, Zzzz, Arab, Zzzz, Arab, Zzzz, Arab, Zzzz, Arab, Zzzz, Arab, +/* DATA_BLOCK: -- 0x2880..0x288F -- */ + Zzzz, Arab, Arab, Zzzz, Arab, Zzzz, Zzzz, Arab, Arab, Arab, Arab, Zzzz, Arab, Arab, Arab, Arab, +/* DATA_BLOCK: -- 0x2890..0x289F -- */ + Arab, Arab, Arab, Zzzz, Arab, Arab, Arab, Arab, Zzzz, Arab, Arab, Arab, Arab, Zzzz, Arab, Zzzz, +/* DATA_BLOCK: -- 0x28A0..0x28AF -- */ + Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Zzzz, Arab, Arab, Arab, Arab, Arab, +/* DATA_BLOCK: -- 0x28B0..0x28BF -- */ + Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x28C0..0x28CF -- */ + Zzzz, Arab, Arab, Arab, Zzzz, Arab, Arab, Arab, Arab, Arab, Zzzz, Arab, Arab, Arab, Arab, Arab, +/* DATA_BLOCK: -- 0x28D0..0x28DF -- */ + Arab, Arab, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x28E0..0x28EF -- */ + Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x28F0..0x28FF -- */ + Hira, Zyyy, Zyyy, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2900..0x290F -- */ + Zyyy, Zyyy, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2910..0x291F -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zyyy, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x2920..0x292F -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2930..0x293F -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zzzz, Zzzz, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2940..0x294F -- */ + Hani, Hani, Hani, Hani, Hani, Hani, Hani, Hani, Hani, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2950..0x295F -- */ + Hani, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2960..0x296F -- */ + Hani, Hani, Hani, Hani, Hani, Hani, Hani, Hani, Hani, Hani, Hani, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2970..0x297F -- */ + Zzzz, Zyyy, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz +}; + +static const SBUInt16 MainScriptIndexes[3231] = { +/* INDEX_BLOCK: -- 0x0000..0x001F -- */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0010, 0x0020, 0x0010, 0x0020, 0x0000, 0x0000, 0x0030, 0x0030, + 0x0040, 0x0050, 0x0040, 0x0050, 0x0040, 0x0040, 0x0040, 0x0040, 0x0040, 0x0040, 0x0040, 0x0040, + 0x0040, 0x0040, 0x0040, 0x0040, 0x0040, 0x0040, 0x0040, 0x0040, +/* INDEX_BLOCK: -- 0x0020..0x003F -- */ + 0x0040, 0x0040, 0x0040, 0x0040, 0x0040, 0x0040, 0x0040, 0x0040, 0x0040, 0x0040, 0x0040, 0x0060, + 0x0000, 0x0000, 0x0070, 0x0000, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0090, + 0x00A0, 0x00B0, 0x00C0, 0x00B0, 0x00B0, 0x00B0, 0x00D0, 0x00B0, +/* INDEX_BLOCK: -- 0x0040..0x005F -- */ + 0x00E0, 0x00E0, 0x00E0, 0x00E0, 0x00E0, 0x00E0, 0x00E0, 0x00E0, 0x00F0, 0x00E0, 0x00E0, 0x00E0, + 0x00E0, 0x00E0, 0x00E0, 0x00E0, 0x00E0, 0x00E0, 0x00E0, 0x0100, 0x0110, 0x0120, 0x0110, 0x0110, + 0x0130, 0x0140, 0x0150, 0x0150, 0x0160, 0x0150, 0x0170, 0x0180, +/* INDEX_BLOCK: -- 0x0060..0x007F -- */ + 0x0190, 0x01A0, 0x01B0, 0x01B0, 0x01C0, 0x01D0, 0x01B0, 0x01E0, 0x01B0, 0x01B0, 0x01B0, 0x01B0, + 0x01B0, 0x01F0, 0x01B0, 0x01B0, 0x0200, 0x0210, 0x0210, 0x0210, 0x0220, 0x01B0, 0x01B0, 0x01B0, + 0x0230, 0x0230, 0x0230, 0x0240, 0x0250, 0x0250, 0x0250, 0x0260, +/* INDEX_BLOCK: -- 0x0080..0x009F -- */ + 0x0270, 0x0270, 0x0280, 0x0290, 0x02A0, 0x02B0, 0x02C0, 0x01B0, 0x02D0, 0x02E0, 0x01B0, 0x01B0, + 0x01B0, 0x01B0, 0x02F0, 0x01B0, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0310, 0x0320, 0x0300, + 0x0330, 0x0340, 0x0350, 0x0360, 0x0370, 0x0380, 0x0390, 0x03A0, +/* INDEX_BLOCK: -- 0x00A0..0x00BF -- */ + 0x03B0, 0x03C0, 0x03D0, 0x03E0, 0x03F0, 0x0400, 0x0410, 0x0420, 0x0430, 0x0440, 0x0450, 0x0460, + 0x0470, 0x0480, 0x0490, 0x04A0, 0x04B0, 0x04C0, 0x04D0, 0x04E0, 0x04F0, 0x0500, 0x0510, 0x0520, + 0x0530, 0x0540, 0x0550, 0x0560, 0x0570, 0x0580, 0x0590, 0x05A0, +/* INDEX_BLOCK: -- 0x00C0..0x00DF -- */ + 0x05B0, 0x05C0, 0x05D0, 0x05E0, 0x05F0, 0x0600, 0x0610, 0x0620, 0x0630, 0x0640, 0x0650, 0x0660, + 0x0670, 0x0680, 0x0690, 0x06A0, 0x06B0, 0x06C0, 0x06D0, 0x06D0, 0x06E0, 0x06F0, 0x0700, 0x06D0, + 0x0710, 0x0720, 0x0730, 0x0740, 0x0750, 0x0760, 0x0770, 0x0780, +/* INDEX_BLOCK: -- 0x00E0..0x00FF -- */ + 0x0790, 0x07A0, 0x07A0, 0x07B0, 0x07A0, 0x07C0, 0x07D0, 0x07D0, 0x07E0, 0x07F0, 0x0800, 0x0810, + 0x0820, 0x0830, 0x07D0, 0x07D0, 0x0840, 0x0840, 0x0840, 0x0840, 0x0850, 0x0840, 0x0860, 0x0870, + 0x0840, 0x0850, 0x0840, 0x0880, 0x0880, 0x0890, 0x07D0, 0x07D0, +/* INDEX_BLOCK: -- 0x0100..0x011F -- */ + 0x08A0, 0x08A0, 0x08A0, 0x08A0, 0x08A0, 0x08A0, 0x08A0, 0x08A0, 0x08A0, 0x08A0, 0x08B0, 0x08B0, + 0x08C0, 0x08B0, 0x08B0, 0x08D0, 0x08E0, 0x08E0, 0x08E0, 0x08E0, 0x08E0, 0x08E0, 0x08E0, 0x08E0, + 0x08E0, 0x08E0, 0x08E0, 0x08E0, 0x08E0, 0x08E0, 0x08E0, 0x08E0, +/* INDEX_BLOCK: -- 0x0120..0x013F -- */ + 0x08F0, 0x08F0, 0x08F0, 0x08F0, 0x0900, 0x0910, 0x08F0, 0x08F0, 0x0900, 0x08F0, 0x08F0, 0x0920, + 0x0930, 0x0940, 0x08F0, 0x08F0, 0x08F0, 0x0930, 0x08F0, 0x08F0, 0x08F0, 0x0950, 0x08F0, 0x0960, + 0x08F0, 0x0970, 0x0980, 0x0980, 0x0980, 0x0980, 0x0980, 0x0990, +/* INDEX_BLOCK: -- 0x0140..0x015F -- */ + 0x09A0, 0x09A0, 0x09A0, 0x09A0, 0x09A0, 0x09A0, 0x09A0, 0x09A0, 0x09A0, 0x09A0, 0x09A0, 0x09A0, + 0x09A0, 0x09A0, 0x09A0, 0x09A0, 0x09A0, 0x09A0, 0x09A0, 0x09A0, 0x09A0, 0x09A0, 0x09A0, 0x09A0, + 0x09A0, 0x09A0, 0x09A0, 0x09A0, 0x09A0, 0x09A0, 0x09A0, 0x09A0, +/* INDEX_BLOCK: -- 0x0160..0x017F -- */ + 0x09A0, 0x09A0, 0x09A0, 0x09A0, 0x09A0, 0x09A0, 0x09A0, 0x09A0, 0x09B0, 0x09C0, 0x09D0, 0x09D0, + 0x09D0, 0x09D0, 0x09E0, 0x09F0, 0x0A00, 0x0A10, 0x0A20, 0x0A30, 0x0A40, 0x0A50, 0x0A60, 0x0A70, + 0x0A80, 0x0A80, 0x0A80, 0x0A80, 0x0A80, 0x0A90, 0x0AA0, 0x0AA0, +/* INDEX_BLOCK: -- 0x0180..0x019F -- */ + 0x0AB0, 0x0AC0, 0x0AD0, 0x0AD0, 0x0AD0, 0x0AD0, 0x0AD0, 0x0AE0, 0x0AD0, 0x0AD0, 0x0AF0, 0x09A0, + 0x09A0, 0x09A0, 0x09A0, 0x0B00, 0x0B10, 0x0B20, 0x0B30, 0x0B30, 0x0B40, 0x0B50, 0x0B60, 0x0B70, + 0x0B80, 0x0B80, 0x0B90, 0x0B80, 0x0BA0, 0x0BB0, 0x0A80, 0x0A80, +/* INDEX_BLOCK: -- 0x01A0..0x01BF -- */ + 0x0BC0, 0x0BD0, 0x0BE0, 0x0BE0, 0x0BE0, 0x0BF0, 0x0BE0, 0x0C00, 0x0C10, 0x0C10, 0x0C20, 0x0080, + 0x0C30, 0x07D0, 0x07D0, 0x07D0, 0x0C40, 0x0C40, 0x0C40, 0x0C40, 0x0C50, 0x0C40, 0x0C40, 0x0C60, + 0x0C70, 0x0C70, 0x0C70, 0x0C70, 0x0C80, 0x0C80, 0x0C80, 0x0C90, +/* INDEX_BLOCK: -- 0x01C0..0x01DF -- */ + 0x0CA0, 0x0CA0, 0x0CA0, 0x0CB0, 0x0CC0, 0x0CD0, 0x0CD0, 0x0CD0, 0x0CE0, 0x08B0, 0x08B0, 0x0CF0, + 0x0D00, 0x0D10, 0x0D20, 0x0D30, 0x0040, 0x0040, 0x0D40, 0x0040, 0x0040, 0x0D50, 0x0D60, 0x0D70, + 0x0040, 0x0040, 0x0040, 0x0D80, 0x0080, 0x0080, 0x0080, 0x0080, +/* INDEX_BLOCK: -- 0x01E0..0x01FF -- */ + 0x0040, 0x0040, 0x0040, 0x0040, 0x0040, 0x0040, 0x0040, 0x0040, 0x0040, 0x0040, 0x0040, 0x0040, + 0x0040, 0x0040, 0x0040, 0x0040, 0x00B0, 0x0D90, 0x00B0, 0x00B0, 0x0D90, 0x0DA0, 0x00B0, 0x0DB0, + 0x00B0, 0x00B0, 0x00B0, 0x0DC0, 0x0DC0, 0x0DD0, 0x00B0, 0x0DE0, +/* INDEX_BLOCK: -- 0x0200..0x021F -- */ + 0x0DF0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0E00, 0x0E10, 0x0E20, 0x0E30, 0x0000, 0x0000, + 0x0E40, 0x0080, 0x0080, 0x0E50, 0x0000, 0x0000, 0x0E60, 0x0E70, 0x0E80, 0x0000, 0x0040, 0x0040, + 0x0E90, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +/* INDEX_BLOCK: -- 0x0220..0x023F -- */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +/* INDEX_BLOCK: -- 0x0240..0x025F -- */ + 0x0000, 0x0000, 0x0EA0, 0x07D0, 0x0EB0, 0x07D0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +/* INDEX_BLOCK: -- 0x0260..0x027F -- */ + 0x0EC0, 0x0EC0, 0x0EC0, 0x0EC0, 0x0EC0, 0x0EC0, 0x0EC0, 0x0EC0, 0x0EC0, 0x0EC0, 0x0EC0, 0x0EC0, + 0x0EC0, 0x0EC0, 0x0EC0, 0x0EC0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +/* INDEX_BLOCK: -- 0x0280..0x029F -- */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0ED0, + 0x0000, 0x0EE0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +/* INDEX_BLOCK: -- 0x02A0..0x02BF -- */ + 0x0EF0, 0x0EF0, 0x0EF0, 0x0EF0, 0x0EF0, 0x0EF0, 0x0040, 0x0040, 0x0F00, 0x0F00, 0x0F00, 0x0F00, + 0x0F00, 0x0F00, 0x0F00, 0x0F10, 0x08B0, 0x08B0, 0x08C0, 0x0F20, 0x0F20, 0x0F20, 0x0F30, 0x0F40, + 0x08F0, 0x0F50, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x00E0, 0x00E0, +/* INDEX_BLOCK: -- 0x02C0..0x02DF -- */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0F70, 0x07D0, 0x07D0, 0x0F80, 0x0F90, 0x0F80, 0x0F80, + 0x0F80, 0x0F80, 0x0F80, 0x0FA0, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, + 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0FB0, 0x07D0, 0x0FC0, +/* INDEX_BLOCK: -- 0x02E0..0x02FF -- */ + 0x0FD0, 0x0000, 0x0FE0, 0x0FF0, 0x1000, 0x1010, 0x1010, 0x1010, 0x1010, 0x1020, 0x1030, 0x1040, + 0x1040, 0x1040, 0x1040, 0x1050, 0x1060, 0x1070, 0x1070, 0x1080, 0x08E0, 0x08E0, 0x08E0, 0x08E0, + 0x1090, 0x0000, 0x1070, 0x1070, 0x0000, 0x0000, 0x10A0, 0x1040, +/* INDEX_BLOCK: -- 0x0300..0x031F -- */ + 0x08E0, 0x1090, 0x0000, 0x0000, 0x0000, 0x0000, 0x08E0, 0x10B0, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x1040, 0x1040, 0x10C0, 0x1040, 0x1040, 0x1040, 0x1040, 0x1040, 0x10D0, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +/* INDEX_BLOCK: -- 0x0320..0x033F -- */ + 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, + 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, + 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, +/* INDEX_BLOCK: -- 0x0340..0x035F -- */ + 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, + 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, + 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0000, 0x0000, 0x0000, 0x0000, +/* INDEX_BLOCK: -- 0x0360..0x037F -- */ + 0x10E0, 0x10E0, 0x10E0, 0x10E0, 0x10E0, 0x10E0, 0x10E0, 0x10E0, 0x10E0, 0x10E0, 0x10E0, 0x10E0, + 0x10E0, 0x10E0, 0x10E0, 0x10E0, 0x10E0, 0x10E0, 0x10E0, 0x10E0, 0x10E0, 0x10E0, 0x10E0, 0x10E0, + 0x10E0, 0x10E0, 0x10E0, 0x10E0, 0x10E0, 0x10E0, 0x10E0, 0x10E0, +/* INDEX_BLOCK: -- 0x0380..0x039F -- */ + 0x10E0, 0x10E0, 0x10E0, 0x10E0, 0x10E0, 0x10E0, 0x10E0, 0x10E0, 0x10F0, 0x10E0, 0x10E0, 0x10E0, + 0x1100, 0x1110, 0x1110, 0x1110, 0x1120, 0x1120, 0x1120, 0x1120, 0x1120, 0x1120, 0x1120, 0x1120, + 0x1120, 0x1120, 0x1120, 0x1120, 0x1120, 0x1120, 0x1120, 0x1120, +/* INDEX_BLOCK: -- 0x03A0..0x03BF -- */ + 0x1120, 0x1120, 0x1130, 0x07D0, 0x00E0, 0x00E0, 0x00E0, 0x00E0, 0x00E0, 0x00E0, 0x1140, 0x1140, + 0x1140, 0x1140, 0x1140, 0x1150, 0x0000, 0x0000, 0x1160, 0x0040, 0x0040, 0x0040, 0x0040, 0x0040, + 0x1170, 0x0040, 0x0040, 0x0040, 0x1180, 0x1190, 0x07D0, 0x11A0, +/* INDEX_BLOCK: -- 0x03C0..0x03DF -- */ + 0x11B0, 0x11B0, 0x11C0, 0x11D0, 0x11E0, 0x11E0, 0x11E0, 0x11F0, 0x1200, 0x1200, 0x1200, 0x1200, + 0x1210, 0x1220, 0x0300, 0x0300, 0x1230, 0x1230, 0x1240, 0x1250, 0x1250, 0x1260, 0x08E0, 0x1270, + 0x1280, 0x1280, 0x1280, 0x1280, 0x1290, 0x12A0, 0x08A0, 0x12B0, +/* INDEX_BLOCK: -- 0x03E0..0x03FF -- */ + 0x12C0, 0x12C0, 0x12C0, 0x12D0, 0x12E0, 0x12F0, 0x08A0, 0x08A0, 0x1300, 0x1300, 0x1300, 0x1300, + 0x1310, 0x1320, 0x1330, 0x1340, 0x1350, 0x1360, 0x0F60, 0x0040, 0x0040, 0x1370, 0x1380, 0x0980, + 0x0980, 0x0980, 0x0980, 0x0980, 0x1330, 0x1330, 0x1390, 0x13A0, +/* INDEX_BLOCK: -- 0x0400..0x041F -- */ + 0x08E0, 0x08E0, 0x08E0, 0x08E0, 0x08E0, 0x08E0, 0x08E0, 0x08E0, 0x08E0, 0x08E0, 0x08E0, 0x08E0, + 0x08E0, 0x08E0, 0x08E0, 0x08E0, 0x08E0, 0x08E0, 0x08E0, 0x08E0, 0x08E0, 0x08E0, 0x08E0, 0x08E0, + 0x08E0, 0x08E0, 0x08E0, 0x08E0, 0x08E0, 0x08E0, 0x08E0, 0x08E0, +/* INDEX_BLOCK: -- 0x0420..0x043F -- */ + 0x08E0, 0x08E0, 0x08E0, 0x08E0, 0x08E0, 0x08E0, 0x08E0, 0x08E0, 0x08E0, 0x08E0, 0x08E0, 0x08E0, + 0x08E0, 0x08E0, 0x08E0, 0x08E0, 0x08E0, 0x08E0, 0x08E0, 0x08E0, 0x08E0, 0x08E0, 0x08E0, 0x08E0, + 0x08E0, 0x08E0, 0x13B0, 0x08E0, 0x13C0, 0x08E0, 0x08E0, 0x13D0, +/* INDEX_BLOCK: -- 0x0440..0x045F -- */ + 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, + 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, + 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, +/* INDEX_BLOCK: -- 0x0460..0x047F -- */ + 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, + 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, + 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, +/* INDEX_BLOCK: -- 0x0480..0x049F -- */ + 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x13E0, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, + 0x0F80, 0x13F0, 0x07D0, 0x07D0, 0x1400, 0x1410, 0x0150, 0x1420, 0x1430, 0x01B0, 0x01B0, 0x01B0, + 0x01B0, 0x01B0, 0x01B0, 0x01B0, 0x1440, 0x1450, 0x01B0, 0x01B0, +/* INDEX_BLOCK: -- 0x04A0..0x04BF -- */ + 0x01B0, 0x01B0, 0x01B0, 0x01B0, 0x01B0, 0x01B0, 0x01B0, 0x01B0, 0x01B0, 0x01B0, 0x01B0, 0x01B0, + 0x01B0, 0x01B0, 0x01B0, 0x01B0, 0x01B0, 0x01B0, 0x01B0, 0x1460, 0x01B0, 0x01B0, 0x01B0, 0x01B0, + 0x01B0, 0x1470, 0x01B0, 0x01B0, 0x1480, 0x07D0, 0x07D0, 0x01B0, +/* INDEX_BLOCK: -- 0x04C0..0x04DF -- */ + 0x0080, 0x11D0, 0x1490, 0x0000, 0x0000, 0x14A0, 0x14B0, 0x14C0, 0x01B0, 0x01B0, 0x01B0, 0x01B0, + 0x01B0, 0x01B0, 0x01B0, 0x14D0, 0x14E0, 0x0000, 0x0010, 0x0020, 0x0010, 0x0020, 0x14F0, 0x1030, + 0x1040, 0x1500, 0x08E0, 0x1090, 0x1510, 0x1520, 0x1530, 0x1540, +/* INDEX_BLOCK: -- 0x04E0..0x04FF -- */ + 0x1550, 0x1560, 0x1570, 0x1580, 0x1590, 0x1590, 0x07D0, 0x07D0, 0x1560, 0x1560, 0x1560, 0x1560, + 0x1560, 0x1560, 0x1560, 0x15A0, 0x15B0, 0x0000, 0x0000, 0x15C0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x15D0, 0x15E0, 0x15F0, 0x07D0, 0x07D0, 0x0000, 0x0000, 0x1600, +/* INDEX_BLOCK: -- 0x0500..0x051F -- */ + 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x1610, 0x1620, 0x1630, 0x1630, + 0x1630, 0x1640, 0x1650, 0x0FC0, 0x1660, 0x1660, 0x1670, 0x1680, 0x1690, 0x16A0, 0x16A0, 0x16B0, + 0x16C0, 0x16D0, 0x16E0, 0x16E0, 0x16F0, 0x1700, 0x07D0, 0x07D0, +/* INDEX_BLOCK: -- 0x0520..0x053F -- */ + 0x1710, 0x1710, 0x1710, 0x1710, 0x1710, 0x1720, 0x1720, 0x1720, 0x1730, 0x1740, 0x1750, 0x1760, + 0x1760, 0x1770, 0x1760, 0x1780, 0x1790, 0x1790, 0x17A0, 0x17B0, 0x17B0, 0x17B0, 0x17C0, 0x17D0, + 0x17D0, 0x17E0, 0x17F0, 0x1800, 0x07D0, 0x07D0, 0x07D0, 0x07D0, +/* INDEX_BLOCK: -- 0x0540..0x055F -- */ + 0x1810, 0x1810, 0x1810, 0x1810, 0x1810, 0x1810, 0x1810, 0x1810, 0x1810, 0x1810, 0x1810, 0x1810, + 0x1810, 0x1810, 0x1810, 0x1810, 0x1810, 0x1810, 0x1810, 0x1820, 0x1810, 0x1830, 0x1840, 0x07D0, + 0x1850, 0x0040, 0x0040, 0x1860, 0x07D0, 0x07D0, 0x07D0, 0x07D0, +/* INDEX_BLOCK: -- 0x0560..0x057F -- */ + 0x1870, 0x1880, 0x1880, 0x1890, 0x18A0, 0x18B0, 0x18C0, 0x18C0, 0x18D0, 0x18E0, 0x18F0, 0x07D0, + 0x07D0, 0x07D0, 0x1900, 0x1910, 0x1920, 0x1930, 0x1940, 0x1950, 0x07D0, 0x07D0, 0x07D0, 0x07D0, + 0x1960, 0x1960, 0x1970, 0x1980, 0x1970, 0x1990, 0x1970, 0x1970, +/* INDEX_BLOCK: -- 0x0580..0x059F -- */ + 0x19A0, 0x19B0, 0x19C0, 0x19D0, 0x19E0, 0x19E0, 0x19F0, 0x19F0, 0x1A00, 0x1A00, 0x07D0, 0x07D0, + 0x1A10, 0x1A10, 0x1A20, 0x1A30, 0x1A40, 0x1A40, 0x1A40, 0x1A50, 0x1A60, 0x1A70, 0x1A80, 0x1A90, + 0x1AA0, 0x1AB0, 0x1AC0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, +/* INDEX_BLOCK: -- 0x05A0..0x05BF -- */ + 0x1AD0, 0x1AD0, 0x1AD0, 0x1AD0, 0x1AE0, 0x07D0, 0x07D0, 0x07D0, 0x1AF0, 0x1AF0, 0x1AF0, 0x1B00, + 0x1AF0, 0x1AF0, 0x1AF0, 0x1B10, 0x1B20, 0x1B20, 0x1B30, 0x1B40, 0x07D0, 0x07D0, 0x07D0, 0x07D0, + 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, +/* INDEX_BLOCK: -- 0x05C0..0x05DF -- */ + 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x01B0, 0x02D0, 0x1B50, 0x1B50, 0x1B60, 0x1B70, + 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x1B80, 0x1B80, 0x1B90, 0x1BA0, 0x1BA0, 0x1BB0, 0x07D0, 0x1BC0, + 0x1BD0, 0x07D0, 0x07D0, 0x1BE0, 0x1BF0, 0x07D0, 0x1C00, 0x1C10, +/* INDEX_BLOCK: -- 0x05E0..0x05FF -- */ + 0x1C20, 0x1C20, 0x1C20, 0x1C20, 0x1C30, 0x1C40, 0x1C20, 0x1C50, 0x1C60, 0x1C60, 0x1C60, 0x1C60, + 0x1C70, 0x1C80, 0x1C90, 0x1CA0, 0x1CB0, 0x1CB0, 0x1CB0, 0x1CC0, 0x1CD0, 0x1CE0, 0x1CE0, 0x1CF0, + 0x1D00, 0x1D00, 0x1D00, 0x1D00, 0x1D00, 0x1D00, 0x1D10, 0x1D20, +/* INDEX_BLOCK: -- 0x0600..0x061F -- */ + 0x1D30, 0x1D40, 0x1D30, 0x1D50, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x1D60, 0x1D70, 0x1D80, 0x1D90, + 0x1D90, 0x1D90, 0x1DA0, 0x1DB0, 0x1DC0, 0x1DD0, 0x1DE0, 0x1DF0, 0x1E00, 0x1E10, 0x1E20, 0x1E30, + 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, +/* INDEX_BLOCK: -- 0x0620..0x063F -- */ + 0x1E40, 0x1E40, 0x1E40, 0x1E40, 0x1E40, 0x1E50, 0x1E60, 0x07D0, 0x1E70, 0x1E70, 0x1E70, 0x1E70, + 0x1E80, 0x1E90, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, + 0x1EA0, 0x1EA0, 0x1EA0, 0x1EB0, 0x1EA0, 0x1EC0, 0x07D0, 0x07D0, +/* INDEX_BLOCK: -- 0x0640..0x065F -- */ + 0x1ED0, 0x1ED0, 0x1ED0, 0x1ED0, 0x1EE0, 0x1EF0, 0x1F00, 0x07D0, 0x1F10, 0x1F10, 0x1F10, 0x1F20, + 0x1F20, 0x07D0, 0x07D0, 0x07D0, 0x1F30, 0x1F40, 0x1F50, 0x1F30, 0x1F60, 0x07D0, 0x07D0, 0x07D0, + 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, +/* INDEX_BLOCK: -- 0x0660..0x067F -- */ + 0x1F70, 0x1F70, 0x1F70, 0x1F80, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x1F90, 0x1F90, + 0x1F90, 0x1F90, 0x1F90, 0x1FA0, 0x1FB0, 0x1FC0, 0x1FD0, 0x1FE0, 0x1FF0, 0x2000, 0x07D0, 0x07D0, + 0x07D0, 0x07D0, 0x2010, 0x2020, 0x2020, 0x2010, 0x2030, 0x07D0, +/* INDEX_BLOCK: -- 0x0680..0x069F -- */ + 0x2040, 0x2040, 0x2040, 0x2040, 0x2050, 0x2060, 0x2060, 0x2060, 0x2060, 0x2060, 0x2070, 0x09A0, + 0x2080, 0x2080, 0x2080, 0x2090, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, + 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, +/* INDEX_BLOCK: -- 0x06A0..0x06BF -- */ + 0x20A0, 0x20B0, 0x20B0, 0x20C0, 0x20D0, 0x20B0, 0x20E0, 0x20F0, 0x20F0, 0x2100, 0x2110, 0x2120, + 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x2130, 0x2140, 0x2140, 0x2150, 0x2160, 0x2170, 0x2180, 0x2190, + 0x21A0, 0x21B0, 0x21C0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, +/* INDEX_BLOCK: -- 0x06C0..0x06DF -- */ + 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, + 0x07D0, 0x07D0, 0x21D0, 0x21E0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, + 0x07D0, 0x07D0, 0x07D0, 0x21F0, 0x2200, 0x2200, 0x2200, 0x2210, +/* INDEX_BLOCK: -- 0x06E0..0x06FF -- */ + 0x2220, 0x2220, 0x2220, 0x2220, 0x2220, 0x2220, 0x2220, 0x2220, 0x2220, 0x2220, 0x2220, 0x2220, + 0x2220, 0x2220, 0x2220, 0x2220, 0x2220, 0x2220, 0x2220, 0x2220, 0x2220, 0x2220, 0x2220, 0x2220, + 0x2220, 0x2220, 0x2220, 0x2220, 0x2220, 0x2220, 0x2220, 0x2220, +/* INDEX_BLOCK: -- 0x0700..0x071F -- */ + 0x2220, 0x2220, 0x2220, 0x2220, 0x2220, 0x2220, 0x2220, 0x2220, 0x2220, 0x2220, 0x2220, 0x2220, + 0x2220, 0x2220, 0x2220, 0x2220, 0x2220, 0x2220, 0x2220, 0x2220, 0x2220, 0x2220, 0x2220, 0x2220, + 0x2220, 0x2230, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, +/* INDEX_BLOCK: -- 0x0720..0x073F -- */ + 0x2220, 0x2220, 0x2220, 0x2220, 0x2220, 0x2220, 0x2240, 0x2250, 0x2220, 0x2220, 0x2220, 0x2220, + 0x2220, 0x2220, 0x2220, 0x2220, 0x2220, 0x2220, 0x2220, 0x2220, 0x2260, 0x07D0, 0x07D0, 0x07D0, + 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, +/* INDEX_BLOCK: -- 0x0740..0x075F -- */ + 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, + 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, + 0x07D0, 0x2270, 0x2270, 0x2270, 0x2270, 0x2270, 0x2270, 0x2280, +/* INDEX_BLOCK: -- 0x0760..0x077F -- */ + 0x2290, 0x2290, 0x2290, 0x2290, 0x2290, 0x2290, 0x2290, 0x2290, 0x2290, 0x2290, 0x2290, 0x2290, + 0x2290, 0x2290, 0x2290, 0x2290, 0x2290, 0x2290, 0x2290, 0x2290, 0x2290, 0x2290, 0x2290, 0x2290, + 0x2290, 0x2290, 0x2290, 0x2290, 0x2290, 0x2290, 0x2290, 0x2290, +/* INDEX_BLOCK: -- 0x0780..0x079F -- */ + 0x2290, 0x2290, 0x22A0, 0x22B0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, + 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, + 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, +/* INDEX_BLOCK: -- 0x07A0..0x07BF -- */ + 0x22C0, 0x22C0, 0x22C0, 0x22C0, 0x22C0, 0x22C0, 0x22C0, 0x22C0, 0x22C0, 0x22C0, 0x22C0, 0x22C0, + 0x22C0, 0x22C0, 0x22C0, 0x22C0, 0x22C0, 0x22C0, 0x22C0, 0x22C0, 0x22C0, 0x22C0, 0x22C0, 0x22C0, + 0x22C0, 0x22C0, 0x22C0, 0x22C0, 0x22C0, 0x22C0, 0x22C0, 0x22C0, +/* INDEX_BLOCK: -- 0x07C0..0x07DF -- */ + 0x22C0, 0x22C0, 0x22C0, 0x22C0, 0x22D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, + 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, + 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, +/* INDEX_BLOCK: -- 0x07E0..0x07FF -- */ + 0x1140, 0x1140, 0x1140, 0x1140, 0x1140, 0x1140, 0x1140, 0x1140, 0x1140, 0x1140, 0x1140, 0x1140, + 0x1140, 0x1140, 0x1140, 0x1140, 0x1140, 0x1140, 0x1140, 0x1140, 0x1140, 0x1140, 0x1140, 0x1140, + 0x1140, 0x1140, 0x1140, 0x1140, 0x1140, 0x1140, 0x1140, 0x1140, +/* INDEX_BLOCK: -- 0x0800..0x081F -- */ + 0x1140, 0x1140, 0x1140, 0x22E0, 0x22F0, 0x2300, 0x2310, 0x2320, 0x2320, 0x2320, 0x2320, 0x2330, + 0x2340, 0x2350, 0x2360, 0x2370, 0x2380, 0x2380, 0x2380, 0x2380, 0x2390, 0x23A0, 0x23B0, 0x23C0, + 0x2380, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, +/* INDEX_BLOCK: -- 0x0820..0x083F -- */ + 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x23D0, 0x23D0, 0x23D0, 0x23D0, 0x23D0, 0x23E0, 0x07D0, 0x07D0, + 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x23F0, 0x23F0, 0x23F0, 0x23F0, 0x2400, 0x23F0, 0x23F0, 0x23F0, + 0x2410, 0x23F0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x2420, 0x2430, +/* INDEX_BLOCK: -- 0x0840..0x085F -- */ + 0x2440, 0x2440, 0x2440, 0x2440, 0x2440, 0x2440, 0x2440, 0x2440, 0x2440, 0x2440, 0x2440, 0x2440, + 0x2440, 0x2440, 0x2440, 0x2440, 0x2440, 0x2440, 0x2440, 0x2440, 0x2440, 0x2440, 0x2440, 0x2440, + 0x2440, 0x2440, 0x2440, 0x2440, 0x2440, 0x2440, 0x2440, 0x2440, +/* INDEX_BLOCK: -- 0x0860..0x087F -- */ + 0x2440, 0x2440, 0x2440, 0x2440, 0x2440, 0x2440, 0x2440, 0x2440, 0x2440, 0x2440, 0x2440, 0x2440, + 0x2440, 0x2440, 0x2440, 0x2440, 0x2440, 0x2440, 0x2440, 0x2440, 0x2440, 0x2440, 0x2440, 0x2440, + 0x2440, 0x2440, 0x2440, 0x2440, 0x2440, 0x2440, 0x2440, 0x2450, +/* INDEX_BLOCK: -- 0x0880..0x089F -- */ + 0x2440, 0x2440, 0x2440, 0x2440, 0x2440, 0x2440, 0x2440, 0x2440, 0x2440, 0x2440, 0x2440, 0x2440, + 0x2440, 0x2440, 0x2440, 0x2440, 0x2460, 0x2460, 0x2460, 0x2460, 0x2460, 0x2460, 0x2460, 0x2460, + 0x2460, 0x2460, 0x2460, 0x2460, 0x2460, 0x2460, 0x2460, 0x2460, +/* INDEX_BLOCK: -- 0x08A0..0x08BF -- */ + 0x2460, 0x2460, 0x2460, 0x2460, 0x2460, 0x2460, 0x2460, 0x2460, 0x2460, 0x2460, 0x2460, 0x2460, + 0x2460, 0x2470, 0x07D0, 0x07D0, 0x2480, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, + 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, +/* INDEX_BLOCK: -- 0x08C0..0x08DF -- */ + 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, + 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, + 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x2490, +/* INDEX_BLOCK: -- 0x08E0..0x08FF -- */ + 0x24A0, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, + 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x24B0, 0x07D0, 0x07D0, 0x24C0, 0x24D0, 0x24E0, + 0x24E0, 0x24E0, 0x24E0, 0x24E0, 0x24E0, 0x24E0, 0x24E0, 0x24E0, +/* INDEX_BLOCK: -- 0x0900..0x091F -- */ + 0x24E0, 0x24E0, 0x24E0, 0x24E0, 0x24E0, 0x24E0, 0x24E0, 0x24E0, 0x24E0, 0x24E0, 0x24E0, 0x24E0, + 0x24E0, 0x24E0, 0x24E0, 0x24F0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, + 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, +/* INDEX_BLOCK: -- 0x0920..0x093F -- */ + 0x2500, 0x2500, 0x2500, 0x2500, 0x2500, 0x2500, 0x2510, 0x2520, 0x2530, 0x2540, 0x10A0, 0x07D0, + 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, + 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, +/* INDEX_BLOCK: -- 0x0940..0x095F -- */ + 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, + 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x0080, 0x0080, 0x2550, 0x0080, 0x2560, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x10A0, 0x07D0, 0x07D0, 0x07D0, +/* INDEX_BLOCK: -- 0x0960..0x097F -- */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x2570, 0x0000, 0x0000, 0x2580, 0x0000, 0x0000, 0x0000, 0x2590, 0x25A0, + 0x25B0, 0x0000, 0x25C0, 0x0000, 0x0000, 0x0000, 0x0EB0, 0x07D0, +/* INDEX_BLOCK: -- 0x0980..0x099F -- */ + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x25D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, + 0x07D0, 0x07D0, 0x0000, 0x10A0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0EA0, 0x0000, 0x25E0, + 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, +/* INDEX_BLOCK: -- 0x09A0..0x09BF -- */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0E00, 0x0000, 0x0000, 0x0000, 0x25F0, 0x2600, 0x2610, + 0x2620, 0x0000, 0x0000, 0x0000, 0x2630, 0x2640, 0x0000, 0x2650, 0x2660, 0x2670, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +/* INDEX_BLOCK: -- 0x09C0..0x09DF -- */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2680, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x2690, 0x0000, 0x0000, 0x0000, +/* INDEX_BLOCK: -- 0x09E0..0x09FF -- */ + 0x26A0, 0x26A0, 0x26A0, 0x26A0, 0x26A0, 0x26A0, 0x26A0, 0x26A0, 0x26A0, 0x26A0, 0x26A0, 0x26A0, + 0x26A0, 0x26A0, 0x26A0, 0x26A0, 0x26A0, 0x26A0, 0x26A0, 0x26A0, 0x26A0, 0x26A0, 0x26A0, 0x26A0, + 0x26A0, 0x26A0, 0x26A0, 0x26A0, 0x26A0, 0x26A0, 0x26A0, 0x26A0, +/* INDEX_BLOCK: -- 0x0A00..0x0A1F -- */ + 0x26A0, 0x26A0, 0x26A0, 0x26A0, 0x26A0, 0x26A0, 0x26A0, 0x26A0, 0x26B0, 0x26C0, 0x26D0, 0x07D0, + 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, + 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, +/* INDEX_BLOCK: -- 0x0A20..0x0A3F -- */ + 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, + 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x0040, 0x26E0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, + 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, +/* INDEX_BLOCK: -- 0x0A40..0x0A5F -- */ + 0x26F0, 0x2700, 0x2710, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, + 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x2720, 0x2720, 0x2730, 0x2740, 0x2750, 0x07D0, 0x07D0, 0x07D0, + 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, +/* INDEX_BLOCK: -- 0x0A60..0x0A7F -- */ + 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x2760, 0x2770, 0x07D0, + 0x2780, 0x2780, 0x2780, 0x2790, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, + 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, +/* INDEX_BLOCK: -- 0x0A80..0x0A9F -- */ + 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, + 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, + 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x27A0, 0x27B0, +/* INDEX_BLOCK: -- 0x0AA0..0x0ABF -- */ + 0x27C0, 0x27C0, 0x27C0, 0x27C0, 0x27C0, 0x27C0, 0x27C0, 0x27C0, 0x27C0, 0x27C0, 0x27C0, 0x27C0, + 0x27D0, 0x27E0, 0x07D0, 0x07D0, 0x27F0, 0x27F0, 0x27F0, 0x27F0, 0x2800, 0x2810, 0x07D0, 0x07D0, + 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, +/* INDEX_BLOCK: -- 0x0AC0..0x0ADF -- */ + 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x14E0, 0x0000, 0x0000, 0x0000, 0x2820, + 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x14E0, 0x0000, 0x0000, 0x0F70, 0x07D0, 0x07D0, 0x07D0, 0x07D0, + 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, +/* INDEX_BLOCK: -- 0x0AE0..0x0AFF -- */ + 0x2830, 0x01B0, 0x2840, 0x2850, 0x2860, 0x2870, 0x2880, 0x2890, 0x28A0, 0x28B0, 0x28C0, 0x28B0, + 0x07D0, 0x07D0, 0x07D0, 0x28D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, + 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, +/* INDEX_BLOCK: -- 0x0B00..0x0B1F -- */ + 0x0000, 0x0000, 0x0FC0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x10A0, 0x0E20, 0x14E0, + 0x14E0, 0x14E0, 0x0000, 0x2570, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0F70, 0x07D0, 0x07D0, 0x07D0, 0x28E0, 0x0000, +/* INDEX_BLOCK: -- 0x0B20..0x0B3F -- */ + 0x28F0, 0x0000, 0x0000, 0x0FC0, 0x25E0, 0x2900, 0x2570, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, + 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +/* INDEX_BLOCK: -- 0x0B40..0x0B5F -- */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x2910, 0x15E0, 0x15E0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x10A0, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x25E0, 0x0FC0, 0x0E40, +/* INDEX_BLOCK: -- 0x0B60..0x0B7F -- */ + 0x0FC0, 0x0000, 0x0000, 0x0000, 0x2920, 0x11D0, 0x0000, 0x0000, 0x2920, 0x0000, 0x0F70, 0x2900, + 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +/* INDEX_BLOCK: -- 0x0B80..0x0B9F -- */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x10A0, 0x0F70, 0x2930, 0x0EA0, 0x0000, 0x15E0, 0x0EB0, + 0x2570, 0x11D0, 0x2920, 0x0EA0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x14A0, 0x0000, 0x0000, 0x0EB0, 0x07D0, 0x07D0, 0x11D0, +/* INDEX_BLOCK: -- 0x0BA0..0x0BBF -- */ + 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, + 0x0F80, 0x0F80, 0x07D0, 0x07D0, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, + 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, +/* INDEX_BLOCK: -- 0x0BC0..0x0BDF -- */ + 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, + 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x2940, 0x0F80, 0x0F80, 0x0F80, 0x0F80, + 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, +/* INDEX_BLOCK: -- 0x0BE0..0x0BFF -- */ + 0x0F80, 0x13E0, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, + 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, + 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, +/* INDEX_BLOCK: -- 0x0C00..0x0C1F -- */ + 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x2430, 0x0F80, + 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, + 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, +/* INDEX_BLOCK: -- 0x0C20..0x0C3F -- */ + 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, + 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, + 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x2950, 0x07D0, +/* INDEX_BLOCK: -- 0x0C40..0x0C5F -- */ + 0x0F80, 0x13E0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, + 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, + 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, +/* INDEX_BLOCK: -- 0x0C60..0x0C7F -- */ + 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, + 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x0F80, 0x2960, 0x07D0, 0x07D0, 0x07D0, + 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x07D0, +/* INDEX_BLOCK: -- 0x0C80..0x0C9E -- */ + 0x2970, 0x07D0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x07D0, 0x07D0, 0x07D0, 0x07D0, + 0x07D0, 0x07D0, 0x07D0, 0x07D0, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, + 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080 +}; + +static const SBUInt16 BranchScriptIndexes[1793] = { + 0x0000, 0x0020, 0x0040, 0x0060, 0x0080, 0x00A0, 0x00C0, 0x00E0, 0x0100, 0x0120, 0x0140, 0x0160, + 0x0180, 0x01A0, 0x01C0, 0x01E0, 0x0200, 0x0220, 0x0240, 0x0220, 0x0260, 0x0280, 0x02A0, 0x02C0, + 0x02E0, 0x0300, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, + 0x0320, 0x0320, 0x0340, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, + 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, + 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, + 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0360, 0x0360, 0x0380, 0x03A0, + 0x03C0, 0x03E0, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, + 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0420, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0460, 0x0480, 0x04A0, 0x04C0, 0x04E0, 0x0500, 0x0520, 0x0540, + 0x0560, 0x0580, 0x05A0, 0x05C0, 0x05E0, 0x0600, 0x0620, 0x0640, 0x0660, 0x0680, 0x06A0, 0x06C0, + 0x06E0, 0x0700, 0x0720, 0x0440, 0x0440, 0x0440, 0x0440, 0x0740, 0x0760, 0x0760, 0x0780, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x07A0, 0x07C0, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x07E0, 0x0800, 0x0440, 0x0820, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, + 0x0840, 0x0840, 0x0840, 0x0860, 0x0840, 0x0880, 0x08A0, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x08C0, + 0x08E0, 0x0900, 0x0440, 0x0440, 0x0440, 0x0440, 0x0920, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0940, 0x0960, 0x0980, 0x09A0, 0x09C0, 0x09E0, 0x0A00, 0x0440, 0x0A20, + 0x0A40, 0x0A60, 0x0440, 0x0A80, 0x0AA0, 0x0440, 0x0AC0, 0x0AE0, 0x0B00, 0x0B20, 0x0220, 0x0B40, + 0x0B60, 0x0B80, 0x0440, 0x0440, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, + 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, + 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, + 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, + 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, + 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, + 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, + 0x0320, 0x0320, 0x0320, 0x0BA0, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0BC0, + 0x0BE0, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0C00, + 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, + 0x0320, 0x0C20, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0320, 0x0C40, 0x0440, 0x0440, + 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0C60, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0C80 +}; + +SB_INTERNAL SBScript LookupScript(SBCodepoint codepoint) +{ + if (codepoint <= 0x0E01EF) { + return PrimaryScriptData[ + MainScriptIndexes[ + BranchScriptIndexes[ + codepoint / 0x0200 + ] + (codepoint % 0x0200) / 0x0010 + ] + codepoint % 0x0010 + ]; + } + + return Zzzz; +} + +#undef Adlm +#undef Aghb +#undef Ahom +#undef Arab +#undef Armi +#undef Armn +#undef Avst +#undef Bali +#undef Bamu +#undef Bass +#undef Batk +#undef Beng +#undef Bhks +#undef Bopo +#undef Brah +#undef Brai +#undef Bugi +#undef Buhd +#undef Cakm +#undef Cans +#undef Cari +#undef Cham +#undef Cher +#undef Chrs +#undef Copt +#undef Cpmn +#undef Cprt +#undef Cyrl +#undef Deva +#undef Diak +#undef Dogr +#undef Dsrt +#undef Dupl +#undef Egyp +#undef Elba +#undef Elym +#undef Ethi +#undef Geor +#undef Glag +#undef Gong +#undef Gonm +#undef Goth +#undef Gran +#undef Grek +#undef Gujr +#undef Guru +#undef Hang +#undef Hani +#undef Hano +#undef Hatr +#undef Hebr +#undef Hira +#undef Hluw +#undef Hmng +#undef Hmnp +#undef Hung +#undef Ital +#undef Java +#undef Kali +#undef Kana +#undef Khar +#undef Khmr +#undef Khoj +#undef Kits +#undef Knda +#undef Kthi +#undef Lana +#undef Laoo +#undef Latn +#undef Lepc +#undef Limb +#undef Lina +#undef Linb +#undef Lisu +#undef Lyci +#undef Lydi +#undef Mahj +#undef Maka +#undef Mand +#undef Mani +#undef Marc +#undef Medf +#undef Mend +#undef Merc +#undef Mero +#undef Mlym +#undef Modi +#undef Mong +#undef Mroo +#undef Mtei +#undef Mult +#undef Mymr +#undef Nand +#undef Narb +#undef Nbat +#undef Newa +#undef Nkoo +#undef Nshu +#undef Ogam +#undef Olck +#undef Orkh +#undef Orya +#undef Osge +#undef Osma +#undef Ougr +#undef Palm +#undef Pauc +#undef Perm +#undef Phag +#undef Phli +#undef Phlp +#undef Phnx +#undef Plrd +#undef Prti +#undef Rjng +#undef Rohg +#undef Runr +#undef Samr +#undef Sarb +#undef Saur +#undef Sgnw +#undef Shaw +#undef Shrd +#undef Sidd +#undef Sind +#undef Sinh +#undef Sogd +#undef Sogo +#undef Sora +#undef Soyo +#undef Sund +#undef Sylo +#undef Syrc +#undef Tagb +#undef Takr +#undef Tale +#undef Talu +#undef Taml +#undef Tang +#undef Tavt +#undef Telu +#undef Tfng +#undef Tglg +#undef Thaa +#undef Thai +#undef Tibt +#undef Tirh +#undef Tnsa +#undef Toto +#undef Ugar +#undef Vaii +#undef Vith +#undef Wara +#undef Wcho +#undef Xpeo +#undef Xsux +#undef Yezi +#undef Yiii +#undef Zanb +#undef Zinh +#undef Zyyy +#undef Zzzz diff --git a/third_party/sheenbidi/source/ScriptLookup.h b/third_party/sheenbidi/source/ScriptLookup.h new file mode 100644 index 0000000..da92eb5 --- /dev/null +++ b/third_party/sheenbidi/source/ScriptLookup.h @@ -0,0 +1,16 @@ +/* + * Automatically generated by SheenBidiGenerator tool. + * DO NOT EDIT!! + */ + +#ifndef _SB_INTERNAL_SCRIPT_LOOKUP_H +#define _SB_INTERNAL_SCRIPT_LOOKUP_H + +#include +#include + +#include "SBBase.h" + +SB_INTERNAL SBScript LookupScript(SBCodepoint codepoint); + +#endif diff --git a/third_party/sheenbidi/source/ScriptStack.c b/third_party/sheenbidi/source/ScriptStack.c new file mode 100644 index 0000000..a525a3d --- /dev/null +++ b/third_party/sheenbidi/source/ScriptStack.c @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2018-2019 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ + +#include + +#include "SBAssert.h" +#include "SBBase.h" +#include "ScriptStack.h" + +SB_INTERNAL void ScriptStackReset(ScriptStackRef stack) +{ + stack->top = -1; + stack->count = 0; + stack->open = 0; +} + +SB_INTERNAL void ScriptStackPush(ScriptStackRef stack, SBScript script, SBCodepoint mirror) +{ + stack->count = SBNumberLimitIncrement(stack->count, _SBScriptStackCapacity); + stack->open = SBNumberLimitIncrement(stack->open, _SBScriptStackCapacity); + + stack->top = SBNumberRingIncrement(stack->top, _SBScriptStackCapacity); + stack->_elements[stack->top].script = script; + stack->_elements[stack->top].mirror = mirror; +} + +SB_INTERNAL void ScriptStackPop(ScriptStackRef stack) +{ + /* There must be at least one entry in the stack. */ + SBAssert(stack->count > 0); + + stack->count -= 1; + stack->open = SBNumberLimitDecrement(stack->open, 0); + stack->top = SBNumberRingDecrement(stack->top, _SBScriptStackCapacity); + + if (ScriptStackIsEmpty(stack)) { + stack->top = -1; + } +} + +SB_INTERNAL void ScriptStackLeavePairs(ScriptStackRef stack) +{ + stack->open = 0; +} + +SB_INTERNAL void ScriptStackSealPairs(ScriptStackRef stack, SBScript script) +{ + SBInteger index = SBNumberRingSubtract(stack->top, (SBInteger)stack->open, _SBScriptStackCapacity); + + while (stack->open) { + index = SBNumberRingIncrement(index, _SBScriptStackCapacity); + stack->_elements[index].script = script; + stack->open -= 1; + } +} + +SB_INTERNAL SBBoolean ScriptStackIsEmpty(ScriptStackRef stack) +{ + return (stack->count == 0); +} + +SB_INTERNAL SBScript ScriptStackGetScript(ScriptStackRef stack) +{ + return stack->_elements[stack->top].script; +} + +SB_INTERNAL SBCodepoint ScriptStackGetMirror(ScriptStackRef stack) +{ + return stack->_elements[stack->top].mirror; +} diff --git a/third_party/sheenbidi/source/ScriptStack.h b/third_party/sheenbidi/source/ScriptStack.h new file mode 100644 index 0000000..fee54c9 --- /dev/null +++ b/third_party/sheenbidi/source/ScriptStack.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2018-2019 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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 _SB_INTERNAL_SCRIPT_STACK_H +#define _SB_INTERNAL_SCRIPT_STACK_H + +#include +#include + +#define _SBScriptStackCapacity 63 + +typedef struct _SBScriptStackElement { + SBScript script; + SBCodepoint mirror; +} _SBScriptStackElement; + +typedef struct _SBScriptStack { + _SBScriptStackElement _elements[_SBScriptStackCapacity]; + SBInteger top; + SBUInteger count; + SBUInteger open; +} ScriptStack, *ScriptStackRef; + +SB_INTERNAL void ScriptStackReset(ScriptStackRef stack); + +SB_INTERNAL void ScriptStackPush(ScriptStackRef stack, SBScript script, SBCodepoint mirror); +SB_INTERNAL void ScriptStackPop(ScriptStackRef stack); + +SB_INTERNAL void ScriptStackLeavePairs(ScriptStackRef stack); +SB_INTERNAL void ScriptStackSealPairs(ScriptStackRef stack, SBScript script); + +SB_INTERNAL SBBoolean ScriptStackIsEmpty(ScriptStackRef stack); +SB_INTERNAL SBScript ScriptStackGetScript(ScriptStackRef stack); +SB_INTERNAL SBCodepoint ScriptStackGetMirror(ScriptStackRef stack); + +#endif diff --git a/third_party/sheenbidi/source/SheenBidi.c b/third_party/sheenbidi/source/SheenBidi.c new file mode 100644 index 0000000..4a49176 --- /dev/null +++ b/third_party/sheenbidi/source/SheenBidi.c @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2014-2019 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ + +#include +#include + +#ifdef SB_CONFIG_UNITY + +#include "BidiChain.c" +#include "BidiTypeLookup.c" +#include "BracketQueue.c" +#include "GeneralCategoryLookup.c" +#include "IsolatingRun.c" +#include "LevelRun.c" +#include "PairingLookup.c" +#include "RunQueue.c" +#include "SBAlgorithm.c" +#include "SBBase.c" +#include "SBCodepointSequence.c" +#include "SBLine.c" +#include "SBLog.c" +#include "SBMirrorLocator.c" +#include "SBParagraph.c" +#include "SBScriptLocator.c" +#include "ScriptLookup.c" +#include "ScriptStack.c" +#include "StatusStack.c" + +#endif diff --git a/third_party/sheenbidi/source/StatusStack.c b/third_party/sheenbidi/source/StatusStack.c new file mode 100644 index 0000000..ec7d71a --- /dev/null +++ b/third_party/sheenbidi/source/StatusStack.c @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2014-2022 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ + +#include +#include +#include + +#include "SBAssert.h" +#include "SBBase.h" +#include "StatusStack.h" + +static SBBoolean StatusStackInsertElement(StatusStackRef stack) +{ + if (stack->_peekTop != _StatusStackList_MaxIndex) { + stack->_peekTop += 1; + } else { + _StatusStackListRef previousList = stack->_peekList; + _StatusStackListRef peekList = previousList->next; + + if (!peekList) { + peekList = malloc(sizeof(_StatusStackList)); + if (!peekList) { + return SBFalse; + } + + peekList->previous = previousList; + peekList->next = NULL; + + previousList->next = peekList; + } + + stack->_peekList = peekList; + stack->_peekTop = 0; + } + stack->count += 1; + + return SBTrue; +} + +SB_INTERNAL void StatusStackInitialize(StatusStackRef stack) +{ + stack->_firstList.previous = NULL; + stack->_firstList.next = NULL; + + StatusStackSetEmpty(stack); +} + +SB_INTERNAL SBBoolean StatusStackPush(StatusStackRef stack, + SBLevel embeddingLevel, SBBidiType overrideStatus, SBBoolean isolateStatus) +{ + /* The stack can hold upto 127 elements. */ + SBAssert(stack->count <= 127); + + if (StatusStackInsertElement(stack)) { + _StatusStackElementRef element = &stack->_peekList->elements[stack->_peekTop]; + element->embeddingLevel = embeddingLevel; + element->overrideStatus = overrideStatus; + element->isolateStatus = isolateStatus; + + return SBTrue; + } + + return SBFalse; +} + +SB_INTERNAL void StatusStackPop(StatusStackRef stack) +{ + /* The stack should not be empty. */ + SBAssert(stack->count != 0); + + if (stack->_peekTop != 0) { + stack->_peekTop -= 1; + } else { + stack->_peekList = stack->_peekList->previous; + stack->_peekTop = _StatusStackList_MaxIndex; + } + stack->count -= 1; +} + +SB_INTERNAL void StatusStackSetEmpty(StatusStackRef stack) +{ + stack->_peekList = &stack->_firstList; + stack->_peekTop = 0; + stack->count = 0; +} + +SB_INTERNAL SBLevel StatusStackGetEmbeddingLevel(StatusStackRef stack) +{ + return stack->_peekList->elements[stack->_peekTop].embeddingLevel; +} + +SB_INTERNAL SBBidiType StatusStackGetOverrideStatus(StatusStackRef stack) +{ + return stack->_peekList->elements[stack->_peekTop].overrideStatus; +} + +SB_INTERNAL SBBoolean StatusStackGetIsolateStatus(StatusStackRef stack) +{ + return stack->_peekList->elements[stack->_peekTop].isolateStatus; +} + +SB_INTERNAL void StatusStackFinalize(StatusStackRef stack) +{ + _StatusStackListRef list = stack->_firstList.next; + + while (list) { + _StatusStackListRef next = list->next; + free(list); + list = next; + }; +} diff --git a/third_party/sheenbidi/source/StatusStack.h b/third_party/sheenbidi/source/StatusStack.h new file mode 100644 index 0000000..f4d8b0c --- /dev/null +++ b/third_party/sheenbidi/source/StatusStack.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2014-2022 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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 _SB_INTERNAL_STATUS_STACK_H +#define _SB_INTERNAL_STATUS_STACK_H + +#include +#include "SBBase.h" + +#define _StatusStackList_Length 16 +#define _StatusStackList_MaxIndex (_StatusStackList_Length - 1) + +typedef struct _StatusStackElement { + SBBoolean isolateStatus; + SBBidiType overrideStatus; + SBLevel embeddingLevel; +} _StatusStackElement, *_StatusStackElementRef; + +typedef struct _StatusStackList { + _StatusStackElement elements[_StatusStackList_Length]; + + struct _StatusStackList *previous; + struct _StatusStackList *next; +} _StatusStackList, *_StatusStackListRef; + +typedef struct _StatusStack { + _StatusStackList _firstList; + _StatusStackListRef _peekList; + SBUInteger _peekTop; + SBUInteger count; +} StatusStack, *StatusStackRef; + +SB_INTERNAL void StatusStackInitialize(StatusStackRef stack); +SB_INTERNAL void StatusStackFinalize(StatusStackRef stack); + +SB_INTERNAL SBBoolean StatusStackPush(StatusStackRef stack, + SBLevel embeddingLevel, SBBidiType overrideStatus, SBBoolean isolateStatus); +SB_INTERNAL void StatusStackPop(StatusStackRef stack); +SB_INTERNAL void StatusStackSetEmpty(StatusStackRef stack); + +SB_INTERNAL SBLevel StatusStackGetEmbeddingLevel(StatusStackRef stack); +SB_INTERNAL SBBidiType StatusStackGetOverrideStatus(StatusStackRef stack); +SB_INTERNAL SBBoolean StatusStackGetIsolateStatus(StatusStackRef stack); + +#endif diff --git a/vcpkg.json b/vcpkg.json index ae90946..56cf069 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -1,5 +1,22 @@ { "name": "rive-tests", "version-string": "0.1.0", - "dependencies": ["sdl3"] + "dependencies": [ + "sdl3", + { + "name": "harfbuzz", + "features": ["coretext"] + }, + "libpng", + "libwebp", + "yoga", + "libjpeg-turbo", + "glad" + ], + "overrides": [ + { + "name": "yoga", + "version": "2.0.1" + } + ] }