mirror of
https://github.com/RetroDECK/ES-DE.git
synced 2024-11-25 15:45:38 +00:00
Squashed 'external/rlottie/' content from commit bf3d272df
git-subtree-dir: external/rlottie git-subtree-split: bf3d272df3916a0c34575ac8286cb0fe672fd0d4
This commit is contained in:
commit
73411266c1
BIN
.Gifs/1.gif
Executable file
BIN
.Gifs/1.gif
Executable file
Binary file not shown.
After Width: | Height: | Size: 1.5 MiB |
BIN
.Gifs/2.gif
Executable file
BIN
.Gifs/2.gif
Executable file
Binary file not shown.
After Width: | Height: | Size: 848 KiB |
BIN
.Gifs/logo.png
Normal file
BIN
.Gifs/logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 11 KiB |
BIN
.Gifs/rlottie.xcf
Normal file
BIN
.Gifs/rlottie.xcf
Normal file
Binary file not shown.
23
.appveyor.yml
Normal file
23
.appveyor.yml
Normal file
|
@ -0,0 +1,23 @@
|
|||
os: Visual Studio 2017
|
||||
platform:
|
||||
- x86
|
||||
environment:
|
||||
matrix:
|
||||
- ARCH: x86
|
||||
PYTHON: "C:\\Python35"
|
||||
- ARCH: x64
|
||||
PYTHON: "C:\\Python35-x64"
|
||||
skip_branch_with_pr: true
|
||||
install:
|
||||
- git submodule update --init --recursive
|
||||
- set PATH=%cd%;%PYTHON%;%PYTHON%\Scripts;%PATH%
|
||||
- pip install meson==0.50.0 ninja
|
||||
- call "%VS140COMNTOOLS%\..\..\VC\vcvarsall.bat" %ARCH%
|
||||
build_script:
|
||||
- meson -Dwerror=false --backend=ninja --prefix=%cd% build
|
||||
- where link
|
||||
- ninja -C build
|
||||
test_script:
|
||||
- ninja -C build test
|
||||
after_build:
|
||||
- ninja -C build install
|
90
.clang-format
Normal file
90
.clang-format
Normal file
|
@ -0,0 +1,90 @@
|
|||
---
|
||||
Language: Cpp
|
||||
BasedOnStyle: Google
|
||||
AccessModifierOffset: -4
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignConsecutiveAssignments: false
|
||||
AlignConsecutiveDeclarations: true
|
||||
AlignEscapedNewlinesLeft: true
|
||||
AlignOperands: true
|
||||
AlignTrailingComments: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
AllowShortBlocksOnASingleLine: false
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: Inline
|
||||
AllowShortIfStatementsOnASingleLine: true
|
||||
AllowShortLoopsOnASingleLine: true
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: true
|
||||
AlwaysBreakTemplateDeclarations: true
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
BraceWrapping:
|
||||
AfterClass: false
|
||||
AfterControlStatement: false
|
||||
AfterEnum: false
|
||||
AfterFunction: false
|
||||
AfterNamespace: false
|
||||
AfterObjCDeclaration: false
|
||||
AfterStruct: false
|
||||
AfterUnion: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
IndentBraces: false
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeBraces: WebKit
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializersBeforeComma: false
|
||||
ColumnLimit: 80
|
||||
CommentPragmas: '^ IWYU pragma:'
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
ContinuationIndentWidth: 4
|
||||
Cpp11BracedListStyle: true
|
||||
DerivePointerAlignment: true
|
||||
DisableFormat: false
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ]
|
||||
IncludeCategories:
|
||||
- Regex: '^<.*\.h>'
|
||||
Priority: 1
|
||||
- Regex: '^<.*'
|
||||
Priority: 2
|
||||
- Regex: '.*'
|
||||
Priority: 3
|
||||
IndentCaseLabels: false
|
||||
IndentWidth: 4
|
||||
IndentWrappedFunctionNames: false
|
||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
MacroBlockBegin: ''
|
||||
MacroBlockEnd: ''
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: None
|
||||
ObjCBlockIndentWidth: 2
|
||||
ObjCSpaceAfterProperty: false
|
||||
ObjCSpaceBeforeProtocolList: false
|
||||
PenaltyBreakBeforeFirstCallParameter: 1
|
||||
PenaltyBreakComment: 300
|
||||
PenaltyBreakFirstLessLess: 120
|
||||
PenaltyBreakString: 1000
|
||||
PenaltyExcessCharacter: 1000000
|
||||
PenaltyReturnTypeOnItsOwnLine: 200
|
||||
PointerAlignment: Right
|
||||
ReflowComments: true
|
||||
SortIncludes: true
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 2
|
||||
SpacesInAngles: false
|
||||
SpacesInContainerLiterals: true
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
Standard: Auto
|
||||
TabWidth: 4
|
||||
UseTab: Never
|
||||
...
|
||||
|
13
.gitignore
vendored
Normal file
13
.gitignore
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
build
|
||||
*.creator*
|
||||
*.config
|
||||
*.files
|
||||
*.includes
|
||||
html
|
||||
latex
|
||||
*.swp
|
||||
tmp
|
||||
.cproject
|
||||
.project
|
||||
.vs
|
||||
**/*.DS_Store
|
22
.travis.yml
Normal file
22
.travis.yml
Normal file
|
@ -0,0 +1,22 @@
|
|||
sudo: false
|
||||
|
||||
os:
|
||||
- linux
|
||||
|
||||
language:
|
||||
- cpp
|
||||
|
||||
services:
|
||||
- docker
|
||||
|
||||
before_install:
|
||||
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then docker pull smohantty/rlottie-ci-setup; fi
|
||||
|
||||
script:
|
||||
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then echo FROM smohantty/rlottie-ci-setup > Dockerfile; fi
|
||||
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then echo ADD . /root >> Dockerfile; fi
|
||||
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then docker build -t withgit .; fi
|
||||
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then docker run withgit /bin/sh -c "cd /root && TRAVIS=true meson -Dtest=true builddir && ninja -C builddir test && ninja -C builddir install"; fi
|
||||
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then docker run withgit /bin/sh -c "cd /root && TRAVIS=true meson -Dcache=false -Dmodule=false -Ddumptree=true builddir && ninja -C builddir install"; fi
|
||||
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then docker run withgit /bin/sh -c "cd /root && TRAVIS=true meson -Dthread=false builddir && ninja -C builddir install"; fi
|
||||
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then docker run withgit /bin/sh -c "cd /root && TRAVIS=true cmake -DLOTTIE_TEST=ON -Bbuilddir -H. && make -C builddir -j$(nproc) all test && make -C builddir install"; fi
|
12
AUTHORS
Normal file
12
AUTHORS
Normal file
|
@ -0,0 +1,12 @@
|
|||
Subhransu Mohanty <sub.mohanty@samsung.com>
|
||||
Hermet Park <hermetpark@gmail.com>
|
||||
Youngbok Shin <youngb.shin@samsung.com>
|
||||
Jaeun Choi <jaeun12.choi@samsung.com>
|
||||
Bryce Harrington <bryce@bryceharrington.org>
|
||||
Junsu Choi <jsuya.choi@samsung.com>
|
||||
Yuangu <lifulinghan@aol.com>
|
||||
Mihai Serban <mihai.serban@gmail.com>
|
||||
Shinwoo Kim <cinoo.kim@samsung.com>
|
||||
Vincent Torri <vincent.torri@gmail.com>
|
||||
Nicholas Guriev <guriev-ns@ya.ru>
|
||||
John Preston <johnprestonmail@gmail.com>
|
198
CMakeLists.txt
Normal file
198
CMakeLists.txt
Normal file
|
@ -0,0 +1,198 @@
|
|||
cmake_minimum_required( VERSION 3.3 )
|
||||
|
||||
#declare project
|
||||
project( rlottie VERSION 0.2 LANGUAGES C CXX ASM)
|
||||
|
||||
if (NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE MinSizeRel)
|
||||
endif()
|
||||
|
||||
if (NOT DEFINED BUILD_SHARED_LIBS)
|
||||
# Keep the previous behavior of the build system, consistent with Meson.
|
||||
set(BUILD_SHARED_LIBS ON)
|
||||
endif()
|
||||
|
||||
#declare target
|
||||
add_library( rlottie )
|
||||
set_target_properties( rlottie PROPERTIES DEFINE_SYMBOL RLOTTIE_BUILD )
|
||||
|
||||
#declare version of the target
|
||||
set(player_version_major 0)
|
||||
set(player_version_minor 2)
|
||||
set(player_version ${player_version_major}.${player_version_minor})
|
||||
set_target_properties(rlottie PROPERTIES
|
||||
VERSION ${player_version}
|
||||
SOVERSION ${player_version_major}
|
||||
)
|
||||
|
||||
#declare alias so that library can be used inside the build tree, e.g. when testing
|
||||
add_library(rlottie::rlottie ALIAS rlottie)
|
||||
|
||||
option(LOTTIE_MODULE "Enable LOTTIE MODULE SUPPORT" ON)
|
||||
option(LOTTIE_THREAD "Enable LOTTIE THREAD SUPPORT" ON)
|
||||
option(LOTTIE_CACHE "Enable LOTTIE CACHE SUPPORT" ON)
|
||||
option(LOTTIE_TEST "Build LOTTIE AUTOTESTS" OFF)
|
||||
option(LOTTIE_CCACHE "Enable LOTTIE ccache SUPPORT" OFF)
|
||||
option(LOTTIE_ASAN "Compile with asan" OFF)
|
||||
|
||||
set(LOTTIE_MODULE_PATH "${CMAKE_SHARED_LIBRARY_PREFIX}rlottie-image-loader${CMAKE_SHARED_LIBRARY_SUFFIX}"
|
||||
CACHE STRING "Absolute or relative path to dynamic loader plugin.")
|
||||
|
||||
configure_file(${CMAKE_CURRENT_LIST_DIR}/cmake/config.h.in config.h)
|
||||
|
||||
target_include_directories(rlottie
|
||||
PRIVATE
|
||||
"${CMAKE_CURRENT_BINARY_DIR}"
|
||||
)
|
||||
|
||||
#declare common target compilation options
|
||||
target_compile_options(rlottie
|
||||
PUBLIC
|
||||
PRIVATE
|
||||
-std=c++14
|
||||
-fno-exceptions
|
||||
-fno-unwind-tables
|
||||
-fno-asynchronous-unwind-tables
|
||||
-fno-rtti
|
||||
-Wall
|
||||
-fvisibility=hidden
|
||||
)
|
||||
|
||||
#MSVC does not recognize these parameters
|
||||
if (NOT WIN32)
|
||||
target_compile_options(rlottie
|
||||
PUBLIC
|
||||
PRIVATE
|
||||
-Wnon-virtual-dtor
|
||||
-Woverloaded-virtual
|
||||
-Wno-unused-parameter
|
||||
)
|
||||
endif()
|
||||
|
||||
if (WIN32 AND NOT BUILD_SHARED_LIBS)
|
||||
target_compile_definitions(rlottie PUBLIC -DRLOTTIE_BUILD=0)
|
||||
endif()
|
||||
|
||||
#declare dependancy
|
||||
set( CMAKE_THREAD_PREFER_PTHREAD TRUE )
|
||||
find_package( Threads )
|
||||
|
||||
target_link_libraries(rlottie
|
||||
PUBLIC
|
||||
"${CMAKE_THREAD_LIBS_INIT}"
|
||||
)
|
||||
|
||||
if (NOT APPLE AND NOT WIN32)
|
||||
target_link_libraries(rlottie
|
||||
PRIVATE
|
||||
"-Wl,--version-script=${CMAKE_SOURCE_DIR}/rlottie.expmap"
|
||||
)
|
||||
endif()
|
||||
|
||||
if (LOTTIE_MODULE)
|
||||
# for dlopen, dlsym and dlclose dependancy
|
||||
target_link_libraries(rlottie PRIVATE ${CMAKE_DL_LIBS})
|
||||
endif()
|
||||
|
||||
if (NOT LOTTIE_ASAN)
|
||||
if(APPLE)
|
||||
target_link_libraries(rlottie
|
||||
PUBLIC
|
||||
"-Wl, -undefined error"
|
||||
)
|
||||
else()
|
||||
target_link_libraries(rlottie
|
||||
PUBLIC
|
||||
"-Wl,--no-undefined"
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (LOTTIE_CCACHE)
|
||||
find_program(CCACHE_FOUND ccache)
|
||||
if (CCACHE_FOUND)
|
||||
message(STATUS "Found ccache")
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache)
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache)
|
||||
else()
|
||||
message(STATUS "Could NOT find ccache (this is NOT an error)")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (LOTTIE_ASAN)
|
||||
target_compile_options(rlottie PUBLIC -fsanitize=address)
|
||||
target_link_options(rlottie PUBLIC -fsanitize=address)
|
||||
endif()
|
||||
|
||||
if (NOT LIB_INSTALL_DIR)
|
||||
set (LIB_INSTALL_DIR "/usr/lib")
|
||||
endif (NOT LIB_INSTALL_DIR)
|
||||
|
||||
#declare source and include files
|
||||
add_subdirectory(inc)
|
||||
add_subdirectory(src)
|
||||
add_subdirectory(example)
|
||||
|
||||
if (LOTTIE_TEST)
|
||||
enable_testing()
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
|
||||
SET(PREFIX ${CMAKE_INSTALL_PREFIX})
|
||||
SET(EXEC_DIR ${PREFIX})
|
||||
SET(LIBDIR ${LIB_INSTALL_DIR})
|
||||
SET(INCDIR ${PREFIX}/include)
|
||||
|
||||
CONFIGURE_FILE(${PROJECT_NAME}.pc.in ${PROJECT_NAME}.pc)
|
||||
INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig)
|
||||
|
||||
|
||||
#install header
|
||||
install(FILES
|
||||
inc/rlottie.h
|
||||
inc/rlottie_capi.h
|
||||
inc/rlottiecommon.h
|
||||
DESTINATION include)
|
||||
|
||||
#install lib
|
||||
install( TARGETS rlottie EXPORT rlottie-targets
|
||||
LIBRARY DESTINATION ${LIB_INSTALL_DIR}
|
||||
ARCHIVE DESTINATION ${LIB_INSTALL_DIR}
|
||||
INCLUDES DESTINATION include
|
||||
)
|
||||
|
||||
#install config file.
|
||||
|
||||
install( EXPORT rlottie-targets
|
||||
FILE rlottieTargets.cmake
|
||||
NAMESPACE rlottie::
|
||||
DESTINATION ${LIB_INSTALL_DIR}/cmake/rlottie
|
||||
)
|
||||
|
||||
|
||||
#Create a ConfigVersion.cmake file
|
||||
include(CMakePackageConfigHelpers)
|
||||
write_basic_package_version_file(
|
||||
${CMAKE_CURRENT_BINARY_DIR}/rlottieConfigVersion.cmake
|
||||
VERSION ${PROJECT_VERSION}
|
||||
COMPATIBILITY AnyNewerVersion
|
||||
)
|
||||
|
||||
configure_package_config_file(${CMAKE_CURRENT_LIST_DIR}/cmake/rlottieConfig.cmake.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/rlottieConfig.cmake
|
||||
INSTALL_DESTINATION ${LIB_INSTALL_DIR}/cmake/rlottie
|
||||
)
|
||||
|
||||
#Install the config, configversion and custom find modules
|
||||
install(FILES
|
||||
${CMAKE_CURRENT_BINARY_DIR}/rlottieConfig.cmake
|
||||
${CMAKE_CURRENT_BINARY_DIR}/rlottieConfigVersion.cmake
|
||||
DESTINATION ${LIB_INSTALL_DIR}/cmake/rlottie
|
||||
)
|
||||
|
||||
|
||||
export(EXPORT rlottie-targets FILE ${CMAKE_CURRENT_BINARY_DIR}/rlottieTargets.cmake NAMESPACE rlottie::)
|
||||
|
||||
#Register package in user's package registry
|
||||
export(PACKAGE rlottie)
|
||||
|
17
COPYING
Normal file
17
COPYING
Normal file
|
@ -0,0 +1,17 @@
|
|||
Licensing
|
||||
|
||||
rlottie basically comes with MIT license(licenses/COPYING.MIT)
|
||||
but some parts of shared code are covered by different licenses. Listed
|
||||
below are the folder names and the license file covering it. Note that this
|
||||
license would cover all of the source invovled in each folders, unless
|
||||
specifically noted otherwise. So please refer to these imported project sources
|
||||
for details.
|
||||
|
||||
Dependencies and licenses:
|
||||
|
||||
src/vector/ licenses/COPYING.MIT, COPYING.SKIA
|
||||
src/vector/freetype licenses/COPYING.FTL
|
||||
src/vector/pixman licenses/COPYING.PIX
|
||||
src/vector/stb licenses/COPYING.STB
|
||||
src/lottie/rapidjson licenses/COPYING.RPD
|
||||
|
318
README.md
Normal file
318
README.md
Normal file
|
@ -0,0 +1,318 @@
|
|||
|
||||
# rlottie
|
||||
|
||||
[![Build Status](https://travis-ci.org/Samsung/rlottie.svg?branch=master)](https://travis-ci.org/Samsung/rlottie)
|
||||
[![Build status](https://ci.appveyor.com/api/projects/status/n3xonxk1ooo6s7nr?svg=true&passingText=windows%20-%20passing)](https://ci.appveyor.com/project/smohantty/rlottie-mliua)
|
||||
|
||||
<p align="center">
|
||||
<img width="240" height="240" src="https://github.com/Samsung/rlottie/blob/master/.Gifs/logo.png">
|
||||
</p>
|
||||
|
||||
rlottie is a platform independent standalone c++ library for rendering vector based animations and art in realtime.
|
||||
|
||||
Lottie loads and renders animations and vectors exported in the bodymovin JSON format. Bodymovin JSON can be created and exported from After Effects with [bodymovin](https://github.com/bodymovin/bodymovin), Sketch with [Lottie Sketch Export](https://github.com/buba447/Lottie-Sketch-Export), and from [Haiku](https://www.haiku.ai).
|
||||
|
||||
For the first time, designers can create and ship beautiful animations without an engineer painstakingly recreating it by hand. Since the animation is backed by JSON they are extremely small in size but can be large in complexity!
|
||||
|
||||
Here are small samples of the power of Lottie.
|
||||
|
||||
<p align="center">
|
||||
<img src="https://github.com/Samsung/rlottie/blob/master/.Gifs/1.gif">
|
||||
<img src="https://github.com/Samsung/rlottie/blob/master/.Gifs/2.gif">
|
||||
<img src="https://github.com/airbnb/lottie-ios/blob/master/_Gifs/Examples1.gif">
|
||||
</p>
|
||||
|
||||
## Contents
|
||||
- [Building Lottie](#building-lottie)
|
||||
- [Meson Build](#meson-build)
|
||||
- [Cmake Build](#cmake-build)
|
||||
- [Test](#test)
|
||||
- [Demo](#demo)
|
||||
- [Previewing Lottie JSON Files](#previewing-lottie-json-files)
|
||||
- [Quick Start](#quick-start)
|
||||
- [Dynamic Property](#dynamic-property)
|
||||
- [Supported After Effects Features](#supported-after-effects-features)
|
||||
- [Issues or Feature Requests?](#issues-or-feature-requests)
|
||||
|
||||
## Building Lottie
|
||||
rottie supports [meson](https://mesonbuild.com/) and [cmake](https://cmake.org/) build system. rottie is written in `C++14`. and has a public header dependancy of `C++11`
|
||||
|
||||
### Meson Build
|
||||
install [meson](http://mesonbuild.com/Getting-meson.html) and [ninja](https://ninja-build.org/) if not already installed.
|
||||
|
||||
Run meson to configure rlottie
|
||||
```
|
||||
meson build
|
||||
```
|
||||
Run ninja to build rlottie
|
||||
```
|
||||
ninja -C build
|
||||
```
|
||||
|
||||
### Cmake Build
|
||||
|
||||
Install [cmake](https://cmake.org/download/) if not already installed
|
||||
|
||||
Create a build directory for out of source `build`
|
||||
```
|
||||
mkdir build
|
||||
```
|
||||
Run cmake command inside `build` directory to configure rlottie.
|
||||
```
|
||||
cd build
|
||||
cmake ..
|
||||
|
||||
# install in a different path. eg ~/test/usr/lib
|
||||
cmake -DCMAKE_INSTALL_PREFIX=~/test ..
|
||||
|
||||
# static build
|
||||
cmake -DBUILD_SHARED_LIBS=OFF ..
|
||||
```
|
||||
Run make to build rlottie
|
||||
|
||||
```
|
||||
make -j 2
|
||||
```
|
||||
To install rlottie library
|
||||
|
||||
```
|
||||
make install
|
||||
```
|
||||
|
||||
### Test
|
||||
|
||||
Configure to build test
|
||||
```
|
||||
meson configure -Dtest=true
|
||||
```
|
||||
Build test suit
|
||||
|
||||
```
|
||||
ninja
|
||||
```
|
||||
Run test suit
|
||||
```
|
||||
ninja test
|
||||
```
|
||||
[Back to contents](#contents)
|
||||
|
||||
#
|
||||
## Demo
|
||||
If you want to see rlottie librray in action without building it please visit [rlottie online viewer](http://rlottie.com)
|
||||
|
||||
While building rlottie library it generates a simple lottie to GIF converter which can be used to convert lottie json file to GIF file.
|
||||
|
||||
Run Demo
|
||||
```
|
||||
lottie2gif [lottie file name]
|
||||
```
|
||||
|
||||
#
|
||||
## Previewing Lottie JSON Files
|
||||
Please visit [rlottie online viewer](http://rlottie.com)
|
||||
|
||||
[rlottie online viewer](http://rlottie.com) uses rlottie wasm library to render the resource locally in your browser. To test your JSON resource drag and drop it to the browser window.
|
||||
|
||||
#
|
||||
## Quick Start
|
||||
|
||||
Lottie loads and renders animations and vectors exported in the bodymovin JSON format. Bodymovin JSON can be created and exported from After Effects with [bodymovin](https://github.com/bodymovin/bodymovin), Sketch with [Lottie Sketch Export](https://github.com/buba447/Lottie-Sketch-Export), and from [Haiku](https://www.haiku.ai).
|
||||
|
||||
You can quickly load a Lottie animation with:
|
||||
```cpp
|
||||
auto animation = rlottie::Animation::loadFromFile("absolute_path/test.json");
|
||||
```
|
||||
You can load a lottie animation from raw data with:
|
||||
```cpp
|
||||
auto animation = rlottie::Animation::loadFromData(std::string(rawData), std::string(cacheKey));
|
||||
```
|
||||
|
||||
Properties like `frameRate` , `totalFrame` , `duration` can be queried with:
|
||||
```cpp
|
||||
# get the frame rate of the resource.
|
||||
double frameRate = animation->frameRate();
|
||||
|
||||
#get total frame that exists in the resource
|
||||
size_t totalFrame = animation->totalFrame();
|
||||
|
||||
#get total animation duration in sec for the resource
|
||||
double duration = animation->duration();
|
||||
```
|
||||
Render a particular frame in a surface buffer `immediately` with:
|
||||
```cpp
|
||||
rlottie::Surface surface(buffer, width , height , stride);
|
||||
animation->renderSync(frameNo, surface);
|
||||
```
|
||||
Render a particular frame in a surface buffer `asyncronousely` with:
|
||||
```cpp
|
||||
rlottie::Surface surface(buffer, width , height , stride);
|
||||
# give a render request
|
||||
std::future<rlottie::Surface> handle = animation->render(frameNo, surface);
|
||||
...
|
||||
#when the render data is needed
|
||||
rlottie::Surface surface = handle.get();
|
||||
```
|
||||
|
||||
[Back to contents](#contents)
|
||||
|
||||
|
||||
## Dynamic Property
|
||||
|
||||
You can update properties dynamically at runtime. This can be used for a variety of purposes such as:
|
||||
- Theming (day and night or arbitrary themes).
|
||||
- Responding to events such as an error or a success.
|
||||
- Animating a single part of an animation in response to an event.
|
||||
- Responding to view sizes or other values not known at design time.
|
||||
|
||||
### Understanding After Effects
|
||||
|
||||
To understand how to change animation properties in Lottie, you should first understand how animation properties are stored in Lottie. Animation properties are stored in a data tree that mimics the information heirarchy of After Effects. In After Effects a Composition is a collection of Layers that each have their own timelines. Layer objects have string names, and their contents can be an image, shape layers, fills, strokes, or just about anything that is drawable. Each object in After Effects has a name. Lottie can find these objects and properties by their name using a KeyPath.
|
||||
|
||||
### Usage
|
||||
|
||||
To update a property at runtime, you need 3 things:
|
||||
1. KeyPath
|
||||
2. rLottie::Property
|
||||
3. setValue()
|
||||
|
||||
### KeyPath
|
||||
|
||||
A KeyPath is used to target a specific content or a set of contents that will be updated. A KeyPath is specified by a list of strings that correspond to the hierarchy of After Effects contents in the original animation.
|
||||
KeyPaths can include the specific name of the contents or wildcards:
|
||||
- Wildcard *
|
||||
- Wildcards match any single content name in its position in the keypath.
|
||||
- Globstar **
|
||||
- Globstars match zero or more layers.
|
||||
|
||||
### Properties
|
||||
|
||||
`rLottie::Property` is an enumeration of properties that can be set. They correspond to the animatable value in After Effects and the available properties are listed below.
|
||||
```cpp
|
||||
enum class Property {
|
||||
FillColor, /*!< Color property of Fill object , value type is rlottie::Color */
|
||||
FillOpacity, /*!< Opacity property of Fill object , value type is float [ 0 .. 100] */
|
||||
StrokeColor, /*!< Color property of Stroke object , value type is rlottie::Color */
|
||||
StrokeOpacity, /*!< Opacity property of Stroke object , value type is float [ 0 .. 100] */
|
||||
StrokeWidth, /*!< stroke with property of Stroke object , value type is float */
|
||||
...
|
||||
};
|
||||
```
|
||||
|
||||
### setValue()
|
||||
|
||||
`setValue()` requires a keypath of string and value. The value can be `Color`, `Size` and `Point` structure or a function that returns them. `Color`, `Size`, and `Point` vary depending on the type of `rLottie::Property`. This value or function(callback) is called and applied to every frame. This value can be set differently for each frame by using the `FrameInfo` argument passed to the function.
|
||||
|
||||
|
||||
### Usage
|
||||
```cpp
|
||||
animation->setValue<rlottie::Property::FillColor>("**",rlottie::Color(0, 1, 0));
|
||||
```
|
||||
|
||||
```cpp
|
||||
animation->setValue<rlottie::Property::FillColor>("Layer1.Box 1.Fill1",
|
||||
[](const rlottie::FrameInfo& info) {
|
||||
if (info.curFrame() < 15 )
|
||||
return rlottie::Color(0, 1, 0);
|
||||
else {
|
||||
return rlottie::Color(1, 0, 0);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
[Back to contents](#contents)
|
||||
|
||||
#
|
||||
#
|
||||
## Supported After Effects Features
|
||||
|
||||
| **Shapes** | **Supported** |
|
||||
|:--|:-:|
|
||||
| Shape | 👍 |
|
||||
| Ellipse | 👍 |
|
||||
| Rectangle | 👍 |
|
||||
| Rounded Rectangle | 👍 |
|
||||
| Polystar | 👍 |
|
||||
| Group | 👍 |
|
||||
| Trim Path (individually) | 👍 |
|
||||
| Trim Path (simultaneously) | 👍 |
|
||||
| **Renderable** | **Supported** |
|
||||
| Fill | 👍 |
|
||||
| Stroke | 👍 |
|
||||
| Radial Gradient | 👍 |
|
||||
| Linear Gradient | 👍 |
|
||||
| Gradient Stroke | 👍 |
|
||||
| **Transforms** | **Supported** |
|
||||
| Position | 👍 |
|
||||
| Position (separated X/Y) | 👍 |
|
||||
| Scale | 👍 |
|
||||
| Skew | ⛔️ |
|
||||
| Rotation | 👍 |
|
||||
| Anchor Point | 👍 |
|
||||
| Opacity | 👍 |
|
||||
| Parenting | 👍 |
|
||||
| Auto Orient | 👍 |
|
||||
| **Interpolation** | **Supported** |
|
||||
| Linear Interpolation | 👍 |
|
||||
| Bezier Interpolation | 👍 |
|
||||
| Hold Interpolation | 👍 |
|
||||
| Spatial Bezier Interpolation | 👍 |
|
||||
| Rove Across Time | 👍 |
|
||||
| **Masks** | **Supported** |
|
||||
| Mask Path | 👍 |
|
||||
| Mask Opacity | 👍 |
|
||||
| Add | 👍 |
|
||||
| Subtract | 👍 |
|
||||
| Intersect | 👍 |
|
||||
| Lighten | ⛔️ |
|
||||
| Darken | ⛔️ |
|
||||
| Difference | ⛔️ |
|
||||
| Expansion | ⛔️ |
|
||||
| Feather | ⛔️ |
|
||||
| **Mattes** | **Supported** |
|
||||
| Alpha Matte | 👍 |
|
||||
| Alpha Inverted Matte | 👍 |
|
||||
| Luma Matte | 👍 |
|
||||
| Luma Inverted Matte | 👍 |
|
||||
| **Merge Paths** | **Supported** |
|
||||
| Merge | ⛔️ |
|
||||
| Add | ⛔️ |
|
||||
| Subtract | ⛔️ |
|
||||
| Intersect | ⛔️ |
|
||||
| Exclude Intersection | ⛔️ |
|
||||
| **Layer Effects** | **Supported** |
|
||||
| Fill | ⛔️ |
|
||||
| Stroke | ⛔️ |
|
||||
| Tint | ⛔️ |
|
||||
| Tritone | ⛔️ |
|
||||
| Levels Individual Controls | ⛔️ |
|
||||
| **Text** | **Supported** |
|
||||
| Glyphs | ⛔️ |
|
||||
| Fonts | ⛔️ |
|
||||
| Transform | ⛔️ |
|
||||
| Fill | ⛔️ |
|
||||
| Stroke | ⛔️ |
|
||||
| Tracking | ⛔️ |
|
||||
| Anchor point grouping | ⛔️ |
|
||||
| Text Path | ⛔️ |
|
||||
| Per-character 3D | ⛔️ |
|
||||
| Range selector (Units) | ⛔️ |
|
||||
| Range selector (Based on) | ⛔️ |
|
||||
| Range selector (Amount) | ⛔️ |
|
||||
| Range selector (Shape) | ⛔️ |
|
||||
| Range selector (Ease High) | ⛔️ |
|
||||
| Range selector (Ease Low) | ⛔️ |
|
||||
| Range selector (Randomize order) | ⛔️ |
|
||||
| expression selector | ⛔️ |
|
||||
| **Other** | **Supported** |
|
||||
| Expressions | ⛔️ |
|
||||
| Images | 👍 |
|
||||
| Precomps | 👍 |
|
||||
| Time Stretch | 👍 |
|
||||
| Time remap | 👍 |
|
||||
| Markers | 👍 |
|
||||
|
||||
#
|
||||
[Back to contents](#contents)
|
||||
|
||||
## Issues or Feature Requests?
|
||||
File github issues for anything that is broken. Be sure to check the [list of supported features](#supported-after-effects-features) before submitting. If an animation is not working, please attach the After Effects file to your issue. Debugging without the original can be very difficult. For immidiate assistant or support please reach us in [Gitter](https://gitter.im/rLottie-dev/community#)
|
14
arm_build.sh
Executable file
14
arm_build.sh
Executable file
|
@ -0,0 +1,14 @@
|
|||
#!/bin/bash
|
||||
|
||||
if [ -z "$1" ]; then
|
||||
echo "Sysroot PATH is not provided"
|
||||
echo "Usage: arm_build SYSROOT_PATH"
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
if [ ! -d "./builddir_wasm" ]; then
|
||||
sed "s|SYSROOT:|$1|g" arm_cross.txt > /tmp/.arm_cross.txt
|
||||
meson builddir_arm --cross-file /tmp/.arm_cross.txt
|
||||
fi
|
||||
|
||||
sudo ninja -C builddir_arm/
|
16
arm_cross.txt
Normal file
16
arm_cross.txt
Normal file
|
@ -0,0 +1,16 @@
|
|||
[binaries]
|
||||
cpp = 'SYSROOT:/bin/arm-none-linux-gnueabihf-g++'
|
||||
ar = 'SYSROOT:/bin/arm-none-linux-gnueabihf-ar'
|
||||
|
||||
[properties]
|
||||
root = 'SYSROOT:'
|
||||
shared_lib_suffix = 'so'
|
||||
static_lib_suffix = 'so'
|
||||
shared_module_suffix = 'so'
|
||||
exe_suffix = 'exe'
|
||||
|
||||
[host_machine]
|
||||
system = 'arm'
|
||||
cpu_family = 'arm'
|
||||
cpu = 'armv7l'
|
||||
endian = 'little'
|
19
cmake/config.h.in
Normal file
19
cmake/config.h.in
Normal file
|
@ -0,0 +1,19 @@
|
|||
#cmakedefine LOTTIE_MODULE
|
||||
|
||||
#ifdef LOTTIE_MODULE
|
||||
#define LOTTIE_IMAGE_MODULE_SUPPORT
|
||||
#endif
|
||||
|
||||
#define LOTTIE_IMAGE_MODULE_PLUGIN "@LOTTIE_MODULE_PATH@"
|
||||
|
||||
#cmakedefine LOTTIE_THREAD
|
||||
|
||||
#ifdef LOTTIE_THREAD
|
||||
#define LOTTIE_THREAD_SUPPORT
|
||||
#endif
|
||||
|
||||
#cmakedefine LOTTIE_CACHE
|
||||
|
||||
#ifdef LOTTIE_CACHE
|
||||
#define LOTTIE_CACHE_SUPPORT
|
||||
#endif
|
16
cmake/rlottieConfig.cmake.in
Normal file
16
cmake/rlottieConfig.cmake.in
Normal file
|
@ -0,0 +1,16 @@
|
|||
get_filename_component(rlottie_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
|
||||
include(CMakeFindDependencyMacro)
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH ${rlottie_CMAKE_DIR})
|
||||
|
||||
# NOTE Had to use find_package because find_dependency does not support COMPONENTS or MODULE until 3.8.0
|
||||
|
||||
#find_dependency(RapidJSON 1.0 REQUIRED MODULE)
|
||||
#find_package(Boost 1.55 REQUIRED COMPONENTS regex)
|
||||
list(REMOVE_AT CMAKE_MODULE_PATH -1)
|
||||
|
||||
if(NOT TARGET rlottie::rlottie)
|
||||
include("${rlottie_CMAKE_DIR}/rlottieTargets.cmake")
|
||||
endif()
|
||||
|
||||
set(rlottie_LIBRARIES rlottie::rlottie)
|
11
example/CMakeLists.txt
Normal file
11
example/CMakeLists.txt
Normal file
|
@ -0,0 +1,11 @@
|
|||
add_executable(lottie2gif "lottie2gif.cpp")
|
||||
|
||||
target_compile_options(lottie2gif
|
||||
PRIVATE
|
||||
-std=c++14)
|
||||
|
||||
target_link_libraries(lottie2gif rlottie)
|
||||
|
||||
target_include_directories(lottie2gif
|
||||
PRIVATE
|
||||
"${CMAKE_CURRENT_LIST_DIR}/../inc/")
|
257
example/demo.cpp
Normal file
257
example/demo.cpp
Normal file
|
@ -0,0 +1,257 @@
|
|||
/*
|
||||
* Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved.
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "evasapp.h"
|
||||
#include "lottieview.h"
|
||||
#include<iostream>
|
||||
#include <stdio.h>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
using namespace std;
|
||||
|
||||
class Demo
|
||||
{
|
||||
public:
|
||||
Demo(EvasApp *app, std::string &filePath) {
|
||||
Demo1(app, filePath);
|
||||
Demo2(app, filePath);
|
||||
Demo3(app, filePath);
|
||||
Demo4(app, filePath);
|
||||
Demo5(app, filePath);
|
||||
Demo6(app, filePath);
|
||||
Demo7(app, filePath);
|
||||
Demo8(app, filePath);
|
||||
}
|
||||
void Demo1(EvasApp *app, std::string &filePath) {
|
||||
/* Fill Color */
|
||||
view1.reset(new LottieView(app->evas()));
|
||||
view1->setFilePath(filePath.c_str());
|
||||
if (view1->player()) {
|
||||
view1->player()->setValue<rlottie::Property::FillColor>("Shape Layer 1.Ellipse 1.Fill 1",
|
||||
[](const rlottie::FrameInfo& info) {
|
||||
if (info.curFrame() < 60 )
|
||||
return rlottie::Color(0, 0, 1);
|
||||
else {
|
||||
return rlottie::Color(1, 0, 0);
|
||||
}
|
||||
});
|
||||
}
|
||||
view1->setPos(0, 0);
|
||||
view1->setSize(300, 300);
|
||||
view1->show();
|
||||
view1->play();
|
||||
view1->loop(true);
|
||||
view1->setRepeatMode(LottieView::RepeatMode::Reverse);
|
||||
}
|
||||
|
||||
void Demo2(EvasApp *app, std::string &filePath) {
|
||||
/* Stroke Opacity */
|
||||
view2.reset(new LottieView(app->evas()));
|
||||
view2->setFilePath(filePath.c_str());
|
||||
if (view2->player()) {
|
||||
view2->player()->setValue<rlottie::Property::StrokeOpacity>("Shape Layer 2.Shape 1.Stroke 1",
|
||||
[](const rlottie::FrameInfo& info) {
|
||||
if (info.curFrame() < 60 )
|
||||
return 20;
|
||||
else {
|
||||
return 100;
|
||||
}
|
||||
});
|
||||
}
|
||||
view2->setPos(300, 0);
|
||||
view2->setSize(300, 300);
|
||||
view2->show();
|
||||
view2->play();
|
||||
view2->loop(true);
|
||||
view2->setRepeatMode(LottieView::RepeatMode::Reverse);
|
||||
}
|
||||
|
||||
void Demo3(EvasApp *app, std::string &filePath) {
|
||||
/* Stroke Opacity */
|
||||
view3.reset(new LottieView(app->evas()));
|
||||
view3->setFilePath(filePath.c_str());
|
||||
if (view3->player()) {
|
||||
view3->player()->setValue<rlottie::Property::StrokeWidth>("**",
|
||||
[](const rlottie::FrameInfo& info) {
|
||||
if (info.curFrame() < 60 )
|
||||
return 1.0;
|
||||
else {
|
||||
return 5.0;
|
||||
}
|
||||
});
|
||||
}
|
||||
view3->setPos(600, 0);
|
||||
view3->setSize(300, 300);
|
||||
view3->show();
|
||||
view3->play();
|
||||
view3->loop(true);
|
||||
view3->setRepeatMode(LottieView::RepeatMode::Reverse);
|
||||
}
|
||||
|
||||
void Demo4(EvasApp *app, std::string &filePath) {
|
||||
/* Transform position */
|
||||
view4.reset(new LottieView(app->evas()));
|
||||
view4->setFilePath(filePath.c_str());
|
||||
if (view4->player()) {
|
||||
view4->player()->setValue<rlottie::Property::TrPosition>("Shape Layer 1.Ellipse 1",
|
||||
[](const rlottie::FrameInfo& info) {
|
||||
return rlottie::Point(-20 + (double)info.curFrame()/2.0,
|
||||
-20 + (double)info.curFrame()/2.0);
|
||||
});
|
||||
}
|
||||
view4->setPos(900, 0);
|
||||
view4->setSize(300, 300);
|
||||
view4->show();
|
||||
view4->play();
|
||||
view4->loop(true);
|
||||
view4->setRepeatMode(LottieView::RepeatMode::Reverse);
|
||||
}
|
||||
|
||||
void Demo5(EvasApp *app, std::string &filePath) {
|
||||
/* Transform position */
|
||||
view5.reset(new LottieView(app->evas()));
|
||||
view5->setFilePath(filePath.c_str());
|
||||
if (view5->player()) {
|
||||
view5->player()->setValue<rlottie::Property::TrPosition>("Shape Layer 2.Shape 1",
|
||||
[](const rlottie::FrameInfo& info) {
|
||||
return rlottie::Point(-20 + (double)info.curFrame()/2.0,
|
||||
-20 + (double)info.curFrame()/2.0);
|
||||
});
|
||||
}
|
||||
view5->setPos(1200, 0);
|
||||
view5->setSize(300, 300);
|
||||
view5->show();
|
||||
view5->play();
|
||||
view5->loop(true);
|
||||
view5->setRepeatMode(LottieView::RepeatMode::Reverse);
|
||||
}
|
||||
|
||||
void Demo6(EvasApp *app, std::string &filePath) {
|
||||
/* Transform scale */
|
||||
view6.reset(new LottieView(app->evas()));
|
||||
view6->setFilePath(filePath.c_str());
|
||||
if (view6->player()) {
|
||||
view6->player()->setValue<rlottie::Property::TrScale>("Shape Layer 1.Ellipse 1",
|
||||
[](const rlottie::FrameInfo& info) {
|
||||
return rlottie::Size(100 - info.curFrame(),
|
||||
50);
|
||||
});
|
||||
}
|
||||
view6->setPos(1500, 0);
|
||||
view6->setSize(300, 300);
|
||||
view6->show();
|
||||
view6->play();
|
||||
view6->loop(true);
|
||||
view6->setRepeatMode(LottieView::RepeatMode::Reverse);
|
||||
}
|
||||
|
||||
void Demo7(EvasApp *app, std::string &filePath) {
|
||||
/* Transform rotation */
|
||||
view7.reset(new LottieView(app->evas()));
|
||||
view7->setFilePath(filePath.c_str());
|
||||
if (view7->player()) {
|
||||
view7->player()->setValue<rlottie::Property::TrRotation>("Shape Layer 2.Shape 1",
|
||||
[](const rlottie::FrameInfo& info) {
|
||||
return info.curFrame() * 20;
|
||||
});
|
||||
}
|
||||
view7->setPos(1800, 0);
|
||||
view7->setSize(300, 300);
|
||||
view7->show();
|
||||
view7->play();
|
||||
view7->loop(true);
|
||||
view7->setRepeatMode(LottieView::RepeatMode::Reverse);
|
||||
}
|
||||
void Demo8(EvasApp *app, std::string &filePath) {
|
||||
/* Transform + color */
|
||||
view8.reset(new LottieView(app->evas()));
|
||||
view8->setFilePath(filePath.c_str());
|
||||
if (view8->player()) {
|
||||
view8->player()->setValue<rlottie::Property::TrRotation>("Shape Layer 1.Ellipse 1",
|
||||
[](const rlottie::FrameInfo& info) {
|
||||
return info.curFrame() * 20;
|
||||
});
|
||||
view8->player()->setValue<rlottie::Property::TrScale>("Shape Layer 1.Ellipse 1",
|
||||
[](const rlottie::FrameInfo& info) {
|
||||
return rlottie::Size(50, 100 - info.curFrame());
|
||||
});
|
||||
view8->player()->setValue<rlottie::Property::TrPosition>("Shape Layer 1.Ellipse 1",
|
||||
[](const rlottie::FrameInfo& info) {
|
||||
return rlottie::Point(-20 + (double)info.curFrame()/2.0,
|
||||
-20 + (double)info.curFrame()/2.0);
|
||||
});
|
||||
view8->player()->setValue<rlottie::Property::FillColor>("Shape Layer 1.Ellipse 1.Fill 1",
|
||||
[](const rlottie::FrameInfo& info) {
|
||||
if (info.curFrame() < 60 )
|
||||
return rlottie::Color(0, 0, 1);
|
||||
else {
|
||||
return rlottie::Color(1, 0, 0);
|
||||
}
|
||||
});
|
||||
}
|
||||
view8->setPos(2100, 0);
|
||||
view8->setSize(300, 300);
|
||||
view8->show();
|
||||
view8->play();
|
||||
view8->loop(true);
|
||||
view8->setRepeatMode(LottieView::RepeatMode::Reverse);
|
||||
}
|
||||
private:
|
||||
std::unique_ptr<LottieView> view1;
|
||||
std::unique_ptr<LottieView> view2;
|
||||
std::unique_ptr<LottieView> view3;
|
||||
std::unique_ptr<LottieView> view4;
|
||||
std::unique_ptr<LottieView> view5;
|
||||
std::unique_ptr<LottieView> view6;
|
||||
std::unique_ptr<LottieView> view7;
|
||||
std::unique_ptr<LottieView> view8;
|
||||
};
|
||||
|
||||
static void
|
||||
onExitCb(void *data, void */*extra*/)
|
||||
{
|
||||
Demo *demo = (Demo *)data;
|
||||
delete demo;
|
||||
}
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
EvasApp *app = new EvasApp(2400, 300);
|
||||
app->setup();
|
||||
|
||||
std::string filePath = DEMO_DIR;
|
||||
filePath +="done.json";
|
||||
|
||||
auto demo = new Demo(app, filePath);
|
||||
|
||||
app->addExitCb(onExitCb, demo);
|
||||
app->run();
|
||||
|
||||
delete app;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
96
example/demo_marker.cpp
Normal file
96
example/demo_marker.cpp
Normal file
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved.
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "evasapp.h"
|
||||
#include "lottieview.h"
|
||||
#include<iostream>
|
||||
#include <stdio.h>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
using namespace std;
|
||||
|
||||
class DemoMarker
|
||||
{
|
||||
public:
|
||||
DemoMarker(EvasApp *app, std::string filePath) {
|
||||
view1.reset(new LottieView(app->evas()));
|
||||
view1->setFilePath(filePath.c_str());
|
||||
view1->setPos(0, 0);
|
||||
view1->setSize(400, 400);
|
||||
view1->show();
|
||||
view1->play();
|
||||
view1->loop(true);
|
||||
|
||||
/* Play with marker */
|
||||
view2.reset(new LottieView(app->evas()));
|
||||
view2->setFilePath(filePath.c_str());
|
||||
view2->setPos(400, 0);
|
||||
view2->setSize(400, 400);
|
||||
view2->show();
|
||||
view2->play("second");
|
||||
view2->loop(true);
|
||||
|
||||
/* Play marker to marker */
|
||||
view3.reset(new LottieView(app->evas()));
|
||||
view3->setFilePath(filePath.c_str());
|
||||
view3->setPos(800, 0);
|
||||
view3->setSize(400, 400);
|
||||
view3->show();
|
||||
view3->play("second", "third");
|
||||
view3->loop(true);
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<LottieView> view1;
|
||||
std::unique_ptr<LottieView> view2;
|
||||
std::unique_ptr<LottieView> view3;
|
||||
};
|
||||
|
||||
static void
|
||||
onExitCb(void *data, void */*extra*/)
|
||||
{
|
||||
DemoMarker *demo = (DemoMarker *)data;
|
||||
delete demo;
|
||||
}
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
EvasApp *app = new EvasApp(1200, 400);
|
||||
app->setup();
|
||||
|
||||
std::string filePath = DEMO_DIR;
|
||||
filePath +="marker.json";
|
||||
|
||||
auto demo = new DemoMarker(app, filePath);
|
||||
|
||||
app->addExitCb(onExitCb, demo);
|
||||
app->run();
|
||||
|
||||
delete app;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
149
example/evasapp.cpp
Normal file
149
example/evasapp.cpp
Normal file
|
@ -0,0 +1,149 @@
|
|||
/*
|
||||
* Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved.
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "evasapp.h"
|
||||
#include <dirent.h>
|
||||
#include <algorithm>
|
||||
|
||||
static void
|
||||
_on_resize(Ecore_Evas *ee)
|
||||
{
|
||||
EvasApp *app = (EvasApp *)ecore_evas_data_get(ee, "app");
|
||||
int w, h;
|
||||
ecore_evas_geometry_get(ee, NULL, NULL, &w, &h);
|
||||
app->resize(w, h);
|
||||
if (app->mResizeCb)
|
||||
app->mResizeCb(app->mResizeData, nullptr);
|
||||
}
|
||||
|
||||
static void
|
||||
_on_delete(Ecore_Evas *ee)
|
||||
{
|
||||
EvasApp *app = (EvasApp *)ecore_evas_data_get(ee, "app");
|
||||
if (app->mExitCb)
|
||||
app->mExitCb(app->mExitData, nullptr);
|
||||
|
||||
ecore_main_loop_quit();
|
||||
ecore_evas_free(ee);
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
on_key_down(void *data, int /*type*/, void *event)
|
||||
{
|
||||
Ecore_Event_Key *keyData = (Ecore_Event_Key *)event;
|
||||
|
||||
EvasApp *app = (EvasApp *) data;
|
||||
if (app && app->mKeyCb)
|
||||
app->mKeyCb(app->mKeyData, (void *)keyData->key);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void
|
||||
on_pre_render(Ecore_Evas *ee)
|
||||
{
|
||||
EvasApp *app = (EvasApp *)ecore_evas_data_get(ee, "app");
|
||||
if (app->mRenderPreCb)
|
||||
app->mRenderPreCb(app->mRenderPreData, nullptr);
|
||||
}
|
||||
|
||||
static void
|
||||
on_post_render(Ecore_Evas *ee)
|
||||
{
|
||||
EvasApp *app = (EvasApp *)ecore_evas_data_get(ee, "app");
|
||||
if (app && app->mRenderPostCb)
|
||||
app->mRenderPostCb(app->mRenderPostData, nullptr);
|
||||
}
|
||||
|
||||
void EvasApp::exit()
|
||||
{
|
||||
_on_delete(mEcoreEvas);
|
||||
}
|
||||
EvasApp::EvasApp(int w, int h)
|
||||
{
|
||||
if (!ecore_evas_init())
|
||||
return;
|
||||
mw = w;
|
||||
mh = h;
|
||||
//setenv("ECORE_EVAS_ENGINE", "opengl_x11", 1);
|
||||
mEcoreEvas = ecore_evas_new(NULL, 0, 0, mw, mh, NULL);
|
||||
if (!mEcoreEvas) return;
|
||||
}
|
||||
|
||||
void
|
||||
EvasApp::setup()
|
||||
{
|
||||
ecore_evas_data_set(mEcoreEvas, "app", this);
|
||||
ecore_evas_callback_resize_set(mEcoreEvas, _on_resize);
|
||||
ecore_evas_callback_delete_request_set(mEcoreEvas, _on_delete);
|
||||
ecore_event_handler_add(ECORE_EVENT_KEY_DOWN, on_key_down, this);
|
||||
ecore_evas_callback_pre_render_set(mEcoreEvas, on_pre_render);
|
||||
ecore_evas_callback_post_render_set(mEcoreEvas, on_post_render);
|
||||
|
||||
ecore_evas_show(mEcoreEvas);
|
||||
mEvas = ecore_evas_get(mEcoreEvas);
|
||||
mBackground = evas_object_rectangle_add(mEvas);
|
||||
evas_object_color_set(mBackground, 70, 70, 70, 255);
|
||||
evas_object_show(mBackground);
|
||||
}
|
||||
|
||||
void
|
||||
EvasApp::resize(int w, int h)
|
||||
{
|
||||
evas_object_resize(mBackground, w, h);
|
||||
mw = w;
|
||||
mh = h;
|
||||
}
|
||||
|
||||
void EvasApp::run()
|
||||
{
|
||||
resize(mw, mh);
|
||||
ecore_main_loop_begin();
|
||||
ecore_evas_shutdown();
|
||||
}
|
||||
|
||||
static bool isJsonFile(const char *filename) {
|
||||
const char *dot = strrchr(filename, '.');
|
||||
if(!dot || dot == filename) return false;
|
||||
return !strcmp(dot + 1, "json");
|
||||
}
|
||||
|
||||
std::vector<std::string>
|
||||
EvasApp::jsonFiles(const std::string &dirName, bool /*recurse*/)
|
||||
{
|
||||
DIR *d;
|
||||
struct dirent *dir;
|
||||
std::vector<std::string> result;
|
||||
d = opendir(dirName.c_str());
|
||||
if (d) {
|
||||
while ((dir = readdir(d)) != NULL) {
|
||||
if (isJsonFile(dir->d_name))
|
||||
result.push_back(dirName + dir->d_name);
|
||||
}
|
||||
closedir(d);
|
||||
}
|
||||
|
||||
std::sort(result.begin(), result.end(), [](auto & a, auto &b){return a < b;});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
80
example/evasapp.h
Normal file
80
example/evasapp.h
Normal file
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved.
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef EVASAPP_H
|
||||
#define EVASAPP_H
|
||||
|
||||
#ifndef EFL_BETA_API_SUPPORT
|
||||
#define EFL_BETA_API_SUPPORT
|
||||
#endif
|
||||
|
||||
#ifndef EFL_EO_API_SUPPORT
|
||||
#define EFL_EO_API_SUPPORT
|
||||
#endif
|
||||
|
||||
#include <Eo.h>
|
||||
#include <Efl.h>
|
||||
#include <Evas.h>
|
||||
#include <Ecore.h>
|
||||
#include <Ecore_Evas.h>
|
||||
#include <Ecore_Input.h>
|
||||
#include<vector>
|
||||
#include<string>
|
||||
|
||||
|
||||
typedef void (*appCb)(void *userData, void *extra);
|
||||
class EvasApp
|
||||
{
|
||||
public:
|
||||
EvasApp(int w, int h);
|
||||
void setup();
|
||||
void resize(int w, int h);
|
||||
int width() const{ return mw;}
|
||||
int height() const{ return mh;}
|
||||
void run();
|
||||
Ecore_Evas * ee() const{return mEcoreEvas;}
|
||||
Evas * evas() const {return mEvas;}
|
||||
void addExitCb(appCb exitcb, void *data) {mExitCb = exitcb; mExitData = data;}
|
||||
void addResizeCb(appCb resizecb, void *data) {mResizeCb = resizecb; mResizeData = data;}
|
||||
void addKeyCb(appCb keycb, void *data) {mKeyCb = keycb; mKeyData = data;}
|
||||
void addRenderPreCb(appCb renderPrecb, void *data) {mRenderPreCb = renderPrecb; mRenderPreData = data;}
|
||||
void addRenderPostCb(appCb renderPostcb, void *data) {mRenderPostCb = renderPostcb; mRenderPostData = data;}
|
||||
void exit();
|
||||
static std::vector<std::string> jsonFiles(const std::string &dir, bool recurse=false);
|
||||
public:
|
||||
int mw{0};
|
||||
int mh{0};
|
||||
Ecore_Evas *mEcoreEvas{nullptr};
|
||||
Evas *mEvas{nullptr};
|
||||
Evas_Object *mBackground{nullptr};
|
||||
appCb mResizeCb{nullptr};
|
||||
void *mResizeData{nullptr};
|
||||
appCb mExitCb{nullptr};
|
||||
void *mExitData{nullptr};
|
||||
appCb mKeyCb{nullptr};
|
||||
void *mKeyData{nullptr};
|
||||
appCb mRenderPreCb{nullptr};
|
||||
void *mRenderPreData{nullptr};
|
||||
appCb mRenderPostCb{nullptr};
|
||||
void *mRenderPostData{nullptr};
|
||||
};
|
||||
#endif //EVASAPP_H
|
835
example/gif.h
Normal file
835
example/gif.h
Normal file
|
@ -0,0 +1,835 @@
|
|||
//
|
||||
// gif.h
|
||||
// by Charlie Tangora
|
||||
// Public domain.
|
||||
// Email me : ctangora -at- gmail -dot- com
|
||||
//
|
||||
// This file offers a simple, very limited way to create animated GIFs directly in code.
|
||||
//
|
||||
// Those looking for particular cleverness are likely to be disappointed; it's pretty
|
||||
// much a straight-ahead implementation of the GIF format with optional Floyd-Steinberg
|
||||
// dithering. (It does at least use delta encoding - only the changed portions of each
|
||||
// frame are saved.)
|
||||
//
|
||||
// So resulting files are often quite large. The hope is that it will be handy nonetheless
|
||||
// as a quick and easily-integrated way for programs to spit out animations.
|
||||
//
|
||||
// Only RGBA8 is currently supported as an input format. (The alpha is ignored.)
|
||||
//
|
||||
// If capturing a buffer with a bottom-left origin (such as OpenGL), define GIF_FLIP_VERT
|
||||
// to automatically flip the buffer data when writing the image (the buffer itself is
|
||||
// unchanged.
|
||||
//
|
||||
// USAGE:
|
||||
// Create a GifWriter struct. Pass it to GifBegin() to initialize and write the header.
|
||||
// Pass subsequent frames to GifWriteFrame().
|
||||
// Finally, call GifEnd() to close the file handle and free memory.
|
||||
//
|
||||
|
||||
#ifndef gif_h
|
||||
#define gif_h
|
||||
|
||||
#include <stdio.h> // for FILE*
|
||||
#include <string.h> // for memcpy and bzero
|
||||
#include <stdint.h> // for integer typedefs
|
||||
|
||||
// Define these macros to hook into a custom memory allocator.
|
||||
// TEMP_MALLOC and TEMP_FREE will only be called in stack fashion - frees in the reverse order of mallocs
|
||||
// and any temp memory allocated by a function will be freed before it exits.
|
||||
// MALLOC and FREE are used only by GifBegin and GifEnd respectively (to allocate a buffer the size of the image, which
|
||||
// is used to find changed pixels for delta-encoding.)
|
||||
|
||||
#ifndef GIF_TEMP_MALLOC
|
||||
#include <stdlib.h>
|
||||
#define GIF_TEMP_MALLOC malloc
|
||||
#endif
|
||||
|
||||
#ifndef GIF_TEMP_FREE
|
||||
#include <stdlib.h>
|
||||
#define GIF_TEMP_FREE free
|
||||
#endif
|
||||
|
||||
#ifndef GIF_MALLOC
|
||||
#include <stdlib.h>
|
||||
#define GIF_MALLOC malloc
|
||||
#endif
|
||||
|
||||
#ifndef GIF_FREE
|
||||
#include <stdlib.h>
|
||||
#define GIF_FREE free
|
||||
#endif
|
||||
|
||||
const int kGifTransIndex = 0;
|
||||
|
||||
struct GifPalette
|
||||
{
|
||||
int bitDepth;
|
||||
|
||||
uint8_t r[256];
|
||||
uint8_t g[256];
|
||||
uint8_t b[256];
|
||||
|
||||
// k-d tree over RGB space, organized in heap fashion
|
||||
// i.e. left child of node i is node i*2, right child is node i*2+1
|
||||
// nodes 256-511 are implicitly the leaves, containing a color
|
||||
uint8_t treeSplitElt[255];
|
||||
uint8_t treeSplit[255];
|
||||
};
|
||||
|
||||
// max, min, and abs functions
|
||||
int GifIMax(int l, int r) { return l>r?l:r; }
|
||||
int GifIMin(int l, int r) { return l<r?l:r; }
|
||||
int GifIAbs(int i) { return i<0?-i:i; }
|
||||
|
||||
// walks the k-d tree to pick the palette entry for a desired color.
|
||||
// Takes as in/out parameters the current best color and its error -
|
||||
// only changes them if it finds a better color in its subtree.
|
||||
// this is the major hotspot in the code at the moment.
|
||||
void GifGetClosestPaletteColor(GifPalette* pPal, int r, int g, int b, int& bestInd, int& bestDiff, int treeRoot = 1)
|
||||
{
|
||||
// base case, reached the bottom of the tree
|
||||
if(treeRoot > (1<<pPal->bitDepth)-1)
|
||||
{
|
||||
int ind = treeRoot-(1<<pPal->bitDepth);
|
||||
if(ind == kGifTransIndex) return;
|
||||
|
||||
// check whether this color is better than the current winner
|
||||
int r_err = r - ((int32_t)pPal->r[ind]);
|
||||
int g_err = g - ((int32_t)pPal->g[ind]);
|
||||
int b_err = b - ((int32_t)pPal->b[ind]);
|
||||
int diff = GifIAbs(r_err)+GifIAbs(g_err)+GifIAbs(b_err);
|
||||
|
||||
if(diff < bestDiff)
|
||||
{
|
||||
bestInd = ind;
|
||||
bestDiff = diff;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// take the appropriate color (r, g, or b) for this node of the k-d tree
|
||||
int comps[3]; comps[0] = r; comps[1] = g; comps[2] = b;
|
||||
int splitComp = comps[pPal->treeSplitElt[treeRoot]];
|
||||
|
||||
int splitPos = pPal->treeSplit[treeRoot];
|
||||
if(splitPos > splitComp)
|
||||
{
|
||||
// check the left subtree
|
||||
GifGetClosestPaletteColor(pPal, r, g, b, bestInd, bestDiff, treeRoot*2);
|
||||
if( bestDiff > splitPos - splitComp )
|
||||
{
|
||||
// cannot prove there's not a better value in the right subtree, check that too
|
||||
GifGetClosestPaletteColor(pPal, r, g, b, bestInd, bestDiff, treeRoot*2+1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
GifGetClosestPaletteColor(pPal, r, g, b, bestInd, bestDiff, treeRoot*2+1);
|
||||
if( bestDiff > splitComp - splitPos )
|
||||
{
|
||||
GifGetClosestPaletteColor(pPal, r, g, b, bestInd, bestDiff, treeRoot*2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GifSwapPixels(uint8_t* image, int pixA, int pixB)
|
||||
{
|
||||
uint8_t rA = image[pixA*4];
|
||||
uint8_t gA = image[pixA*4+1];
|
||||
uint8_t bA = image[pixA*4+2];
|
||||
uint8_t aA = image[pixA*4+3];
|
||||
|
||||
uint8_t rB = image[pixB*4];
|
||||
uint8_t gB = image[pixB*4+1];
|
||||
uint8_t bB = image[pixB*4+2];
|
||||
uint8_t aB = image[pixA*4+3];
|
||||
|
||||
image[pixA*4] = rB;
|
||||
image[pixA*4+1] = gB;
|
||||
image[pixA*4+2] = bB;
|
||||
image[pixA*4+3] = aB;
|
||||
|
||||
image[pixB*4] = rA;
|
||||
image[pixB*4+1] = gA;
|
||||
image[pixB*4+2] = bA;
|
||||
image[pixB*4+3] = aA;
|
||||
}
|
||||
|
||||
// just the partition operation from quicksort
|
||||
int GifPartition(uint8_t* image, const int left, const int right, const int elt, int pivotIndex)
|
||||
{
|
||||
const int pivotValue = image[(pivotIndex)*4+elt];
|
||||
GifSwapPixels(image, pivotIndex, right-1);
|
||||
int storeIndex = left;
|
||||
bool split = 0;
|
||||
for(int ii=left; ii<right-1; ++ii)
|
||||
{
|
||||
int arrayVal = image[ii*4+elt];
|
||||
if( arrayVal < pivotValue )
|
||||
{
|
||||
GifSwapPixels(image, ii, storeIndex);
|
||||
++storeIndex;
|
||||
}
|
||||
else if( arrayVal == pivotValue )
|
||||
{
|
||||
if(split)
|
||||
{
|
||||
GifSwapPixels(image, ii, storeIndex);
|
||||
++storeIndex;
|
||||
}
|
||||
split = !split;
|
||||
}
|
||||
}
|
||||
GifSwapPixels(image, storeIndex, right-1);
|
||||
return storeIndex;
|
||||
}
|
||||
|
||||
// Perform an incomplete sort, finding all elements above and below the desired median
|
||||
void GifPartitionByMedian(uint8_t* image, int left, int right, int com, int neededCenter)
|
||||
{
|
||||
if(left < right-1)
|
||||
{
|
||||
int pivotIndex = left + (right-left)/2;
|
||||
|
||||
pivotIndex = GifPartition(image, left, right, com, pivotIndex);
|
||||
|
||||
// Only "sort" the section of the array that contains the median
|
||||
if(pivotIndex > neededCenter)
|
||||
GifPartitionByMedian(image, left, pivotIndex, com, neededCenter);
|
||||
|
||||
if(pivotIndex < neededCenter)
|
||||
GifPartitionByMedian(image, pivotIndex+1, right, com, neededCenter);
|
||||
}
|
||||
}
|
||||
|
||||
// Builds a palette by creating a balanced k-d tree of all pixels in the image
|
||||
void GifSplitPalette(uint8_t* image, int numPixels, int firstElt, int lastElt, int splitElt, int splitDist, int treeNode, bool buildForDither, GifPalette* pal)
|
||||
{
|
||||
if(lastElt <= firstElt || numPixels == 0)
|
||||
return;
|
||||
|
||||
// base case, bottom of the tree
|
||||
if(lastElt == firstElt+1)
|
||||
{
|
||||
if(buildForDither)
|
||||
{
|
||||
// Dithering needs at least one color as dark as anything
|
||||
// in the image and at least one brightest color -
|
||||
// otherwise it builds up error and produces strange artifacts
|
||||
if( firstElt == 1 )
|
||||
{
|
||||
// special case: the darkest color in the image
|
||||
uint32_t r=255, g=255, b=255;
|
||||
for(int ii=0; ii<numPixels; ++ii)
|
||||
{
|
||||
r = (uint32_t)GifIMin((int32_t)r, image[ii * 4 + 0]);
|
||||
g = (uint32_t)GifIMin((int32_t)g, image[ii * 4 + 1]);
|
||||
b = (uint32_t)GifIMin((int32_t)b, image[ii * 4 + 2]);
|
||||
}
|
||||
|
||||
pal->r[firstElt] = (uint8_t)r;
|
||||
pal->g[firstElt] = (uint8_t)g;
|
||||
pal->b[firstElt] = (uint8_t)b;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if( firstElt == (1 << pal->bitDepth)-1 )
|
||||
{
|
||||
// special case: the lightest color in the image
|
||||
uint32_t r=0, g=0, b=0;
|
||||
for(int ii=0; ii<numPixels; ++ii)
|
||||
{
|
||||
r = (uint32_t)GifIMax((int32_t)r, image[ii * 4 + 0]);
|
||||
g = (uint32_t)GifIMax((int32_t)g, image[ii * 4 + 1]);
|
||||
b = (uint32_t)GifIMax((int32_t)b, image[ii * 4 + 2]);
|
||||
}
|
||||
|
||||
pal->r[firstElt] = (uint8_t)r;
|
||||
pal->g[firstElt] = (uint8_t)g;
|
||||
pal->b[firstElt] = (uint8_t)b;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// otherwise, take the average of all colors in this subcube
|
||||
uint64_t r=0, g=0, b=0;
|
||||
for(int ii=0; ii<numPixels; ++ii)
|
||||
{
|
||||
r += image[ii*4+0];
|
||||
g += image[ii*4+1];
|
||||
b += image[ii*4+2];
|
||||
}
|
||||
|
||||
r += (uint64_t)numPixels / 2; // round to nearest
|
||||
g += (uint64_t)numPixels / 2;
|
||||
b += (uint64_t)numPixels / 2;
|
||||
|
||||
r /= (uint64_t)numPixels;
|
||||
g /= (uint64_t)numPixels;
|
||||
b /= (uint64_t)numPixels;
|
||||
|
||||
pal->r[firstElt] = (uint8_t)r;
|
||||
pal->g[firstElt] = (uint8_t)g;
|
||||
pal->b[firstElt] = (uint8_t)b;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Find the axis with the largest range
|
||||
int minR = 255, maxR = 0;
|
||||
int minG = 255, maxG = 0;
|
||||
int minB = 255, maxB = 0;
|
||||
for(int ii=0; ii<numPixels; ++ii)
|
||||
{
|
||||
int r = image[ii*4+0];
|
||||
int g = image[ii*4+1];
|
||||
int b = image[ii*4+2];
|
||||
|
||||
if(r > maxR) maxR = r;
|
||||
if(r < minR) minR = r;
|
||||
|
||||
if(g > maxG) maxG = g;
|
||||
if(g < minG) minG = g;
|
||||
|
||||
if(b > maxB) maxB = b;
|
||||
if(b < minB) minB = b;
|
||||
}
|
||||
|
||||
int rRange = maxR - minR;
|
||||
int gRange = maxG - minG;
|
||||
int bRange = maxB - minB;
|
||||
|
||||
// and split along that axis. (incidentally, this means this isn't a "proper" k-d tree but I don't know what else to call it)
|
||||
int splitCom = 1;
|
||||
if(bRange > gRange) splitCom = 2;
|
||||
if(rRange > bRange && rRange > gRange) splitCom = 0;
|
||||
|
||||
int subPixelsA = numPixels * (splitElt - firstElt) / (lastElt - firstElt);
|
||||
int subPixelsB = numPixels-subPixelsA;
|
||||
|
||||
GifPartitionByMedian(image, 0, numPixels, splitCom, subPixelsA);
|
||||
|
||||
pal->treeSplitElt[treeNode] = (uint8_t)splitCom;
|
||||
pal->treeSplit[treeNode] = image[subPixelsA*4+splitCom];
|
||||
|
||||
GifSplitPalette(image, subPixelsA, firstElt, splitElt, splitElt-splitDist, splitDist/2, treeNode*2, buildForDither, pal);
|
||||
GifSplitPalette(image+subPixelsA*4, subPixelsB, splitElt, lastElt, splitElt+splitDist, splitDist/2, treeNode*2+1, buildForDither, pal);
|
||||
}
|
||||
|
||||
// Finds all pixels that have changed from the previous image and
|
||||
// moves them to the fromt of th buffer.
|
||||
// This allows us to build a palette optimized for the colors of the
|
||||
// changed pixels only.
|
||||
int GifPickChangedPixels( const uint8_t* lastFrame, uint8_t* frame, int numPixels )
|
||||
{
|
||||
int numChanged = 0;
|
||||
uint8_t* writeIter = frame;
|
||||
|
||||
for (int ii=0; ii<numPixels; ++ii)
|
||||
{
|
||||
if(lastFrame[0] != frame[0] ||
|
||||
lastFrame[1] != frame[1] ||
|
||||
lastFrame[2] != frame[2])
|
||||
{
|
||||
writeIter[0] = frame[0];
|
||||
writeIter[1] = frame[1];
|
||||
writeIter[2] = frame[2];
|
||||
++numChanged;
|
||||
writeIter += 4;
|
||||
}
|
||||
lastFrame += 4;
|
||||
frame += 4;
|
||||
}
|
||||
|
||||
return numChanged;
|
||||
}
|
||||
|
||||
// Creates a palette by placing all the image pixels in a k-d tree and then averaging the blocks at the bottom.
|
||||
// This is known as the "modified median split" technique
|
||||
void GifMakePalette( const uint8_t* lastFrame, const uint8_t* nextFrame, uint32_t width, uint32_t height, int bitDepth, bool buildForDither, GifPalette* pPal )
|
||||
{
|
||||
pPal->bitDepth = bitDepth;
|
||||
|
||||
// SplitPalette is destructive (it sorts the pixels by color) so
|
||||
// we must create a copy of the image for it to destroy
|
||||
size_t imageSize = (size_t)(width * height * 4 * sizeof(uint8_t));
|
||||
uint8_t* destroyableImage = (uint8_t*)GIF_TEMP_MALLOC(imageSize);
|
||||
memcpy(destroyableImage, nextFrame, imageSize);
|
||||
|
||||
int numPixels = (int)(width * height);
|
||||
if(lastFrame)
|
||||
numPixels = GifPickChangedPixels(lastFrame, destroyableImage, numPixels);
|
||||
|
||||
const int lastElt = 1 << bitDepth;
|
||||
const int splitElt = lastElt/2;
|
||||
const int splitDist = splitElt/2;
|
||||
|
||||
GifSplitPalette(destroyableImage, numPixels, 1, lastElt, splitElt, splitDist, 1, buildForDither, pPal);
|
||||
|
||||
GIF_TEMP_FREE(destroyableImage);
|
||||
|
||||
// add the bottom node for the transparency index
|
||||
pPal->treeSplit[1 << (bitDepth-1)] = 0;
|
||||
pPal->treeSplitElt[1 << (bitDepth-1)] = 0;
|
||||
|
||||
pPal->r[0] = pPal->g[0] = pPal->b[0] = 0;
|
||||
}
|
||||
|
||||
// Implements Floyd-Steinberg dithering, writes palette value to alpha
|
||||
void GifDitherImage( const uint8_t* lastFrame, const uint8_t* nextFrame, uint8_t* outFrame, uint32_t width, uint32_t height, GifPalette* pPal )
|
||||
{
|
||||
int numPixels = (int)(width * height);
|
||||
|
||||
// quantPixels initially holds color*256 for all pixels
|
||||
// The extra 8 bits of precision allow for sub-single-color error values
|
||||
// to be propagated
|
||||
int32_t *quantPixels = (int32_t *)GIF_TEMP_MALLOC(sizeof(int32_t) * (size_t)numPixels * 4);
|
||||
|
||||
for( int ii=0; ii<numPixels*4; ++ii )
|
||||
{
|
||||
uint8_t pix = nextFrame[ii];
|
||||
int32_t pix16 = int32_t(pix) * 256;
|
||||
quantPixels[ii] = pix16;
|
||||
}
|
||||
|
||||
for( uint32_t yy=0; yy<height; ++yy )
|
||||
{
|
||||
for( uint32_t xx=0; xx<width; ++xx )
|
||||
{
|
||||
int32_t* nextPix = quantPixels + 4*(yy*width+xx);
|
||||
const uint8_t* lastPix = lastFrame? lastFrame + 4*(yy*width+xx) : NULL;
|
||||
|
||||
// Compute the colors we want (rounding to nearest)
|
||||
int32_t rr = (nextPix[0] + 127) / 256;
|
||||
int32_t gg = (nextPix[1] + 127) / 256;
|
||||
int32_t bb = (nextPix[2] + 127) / 256;
|
||||
|
||||
// if it happens that we want the color from last frame, then just write out
|
||||
// a transparent pixel
|
||||
if( lastFrame &&
|
||||
lastPix[0] == rr &&
|
||||
lastPix[1] == gg &&
|
||||
lastPix[2] == bb )
|
||||
{
|
||||
nextPix[0] = rr;
|
||||
nextPix[1] = gg;
|
||||
nextPix[2] = bb;
|
||||
nextPix[3] = kGifTransIndex;
|
||||
continue;
|
||||
}
|
||||
|
||||
int32_t bestDiff = 1000000;
|
||||
int32_t bestInd = kGifTransIndex;
|
||||
|
||||
// Search the palete
|
||||
GifGetClosestPaletteColor(pPal, rr, gg, bb, bestInd, bestDiff);
|
||||
|
||||
// Write the result to the temp buffer
|
||||
int32_t r_err = nextPix[0] - int32_t(pPal->r[bestInd]) * 256;
|
||||
int32_t g_err = nextPix[1] - int32_t(pPal->g[bestInd]) * 256;
|
||||
int32_t b_err = nextPix[2] - int32_t(pPal->b[bestInd]) * 256;
|
||||
|
||||
nextPix[0] = pPal->r[bestInd];
|
||||
nextPix[1] = pPal->g[bestInd];
|
||||
nextPix[2] = pPal->b[bestInd];
|
||||
nextPix[3] = bestInd;
|
||||
|
||||
// Propagate the error to the four adjacent locations
|
||||
// that we haven't touched yet
|
||||
int quantloc_7 = (int)(yy * width + xx + 1);
|
||||
int quantloc_3 = (int)(yy * width + width + xx - 1);
|
||||
int quantloc_5 = (int)(yy * width + width + xx);
|
||||
int quantloc_1 = (int)(yy * width + width + xx + 1);
|
||||
|
||||
if(quantloc_7 < numPixels)
|
||||
{
|
||||
int32_t* pix7 = quantPixels+4*quantloc_7;
|
||||
pix7[0] += GifIMax( -pix7[0], r_err * 7 / 16 );
|
||||
pix7[1] += GifIMax( -pix7[1], g_err * 7 / 16 );
|
||||
pix7[2] += GifIMax( -pix7[2], b_err * 7 / 16 );
|
||||
}
|
||||
|
||||
if(quantloc_3 < numPixels)
|
||||
{
|
||||
int32_t* pix3 = quantPixels+4*quantloc_3;
|
||||
pix3[0] += GifIMax( -pix3[0], r_err * 3 / 16 );
|
||||
pix3[1] += GifIMax( -pix3[1], g_err * 3 / 16 );
|
||||
pix3[2] += GifIMax( -pix3[2], b_err * 3 / 16 );
|
||||
}
|
||||
|
||||
if(quantloc_5 < numPixels)
|
||||
{
|
||||
int32_t* pix5 = quantPixels+4*quantloc_5;
|
||||
pix5[0] += GifIMax( -pix5[0], r_err * 5 / 16 );
|
||||
pix5[1] += GifIMax( -pix5[1], g_err * 5 / 16 );
|
||||
pix5[2] += GifIMax( -pix5[2], b_err * 5 / 16 );
|
||||
}
|
||||
|
||||
if(quantloc_1 < numPixels)
|
||||
{
|
||||
int32_t* pix1 = quantPixels+4*quantloc_1;
|
||||
pix1[0] += GifIMax( -pix1[0], r_err / 16 );
|
||||
pix1[1] += GifIMax( -pix1[1], g_err / 16 );
|
||||
pix1[2] += GifIMax( -pix1[2], b_err / 16 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Copy the palettized result to the output buffer
|
||||
for( int ii=0; ii<numPixels*4; ++ii )
|
||||
{
|
||||
outFrame[ii] = (uint8_t)quantPixels[ii];
|
||||
}
|
||||
|
||||
GIF_TEMP_FREE(quantPixels);
|
||||
}
|
||||
|
||||
// Picks palette colors for the image using simple thresholding, no dithering
|
||||
void GifThresholdImage( const uint8_t* lastFrame, const uint8_t* nextFrame, uint8_t* outFrame, uint32_t width, uint32_t height, GifPalette* pPal )
|
||||
{
|
||||
uint32_t numPixels = width*height;
|
||||
for( uint32_t ii=0; ii<numPixels; ++ii )
|
||||
{
|
||||
// if a previous color is available, and it matches the current color,
|
||||
// set the pixel to transparent
|
||||
if(lastFrame &&
|
||||
lastFrame[0] == nextFrame[0] &&
|
||||
lastFrame[1] == nextFrame[1] &&
|
||||
lastFrame[2] == nextFrame[2])
|
||||
{
|
||||
outFrame[0] = lastFrame[0];
|
||||
outFrame[1] = lastFrame[1];
|
||||
outFrame[2] = lastFrame[2];
|
||||
outFrame[3] = kGifTransIndex;
|
||||
}
|
||||
else
|
||||
{
|
||||
// palettize the pixel
|
||||
int32_t bestDiff = 1000000;
|
||||
int32_t bestInd = 1;
|
||||
GifGetClosestPaletteColor(pPal, nextFrame[0], nextFrame[1], nextFrame[2], bestInd, bestDiff);
|
||||
|
||||
// Write the resulting color to the output buffer
|
||||
outFrame[0] = pPal->r[bestInd];
|
||||
outFrame[1] = pPal->g[bestInd];
|
||||
outFrame[2] = pPal->b[bestInd];
|
||||
outFrame[3] = (uint8_t)bestInd;
|
||||
}
|
||||
|
||||
if(lastFrame) lastFrame += 4;
|
||||
outFrame += 4;
|
||||
nextFrame += 4;
|
||||
}
|
||||
}
|
||||
|
||||
// Simple structure to write out the LZW-compressed portion of the image
|
||||
// one bit at a time
|
||||
struct GifBitStatus
|
||||
{
|
||||
uint8_t bitIndex; // how many bits in the partial byte written so far
|
||||
uint8_t byte; // current partial byte
|
||||
|
||||
uint32_t chunkIndex;
|
||||
uint8_t chunk[256]; // bytes are written in here until we have 256 of them, then written to the file
|
||||
};
|
||||
|
||||
// insert a single bit
|
||||
void GifWriteBit( GifBitStatus& stat, uint32_t bit )
|
||||
{
|
||||
bit = bit & 1;
|
||||
bit = bit << stat.bitIndex;
|
||||
stat.byte |= bit;
|
||||
|
||||
++stat.bitIndex;
|
||||
if( stat.bitIndex > 7 )
|
||||
{
|
||||
// move the newly-finished byte to the chunk buffer
|
||||
stat.chunk[stat.chunkIndex++] = stat.byte;
|
||||
// and start a new byte
|
||||
stat.bitIndex = 0;
|
||||
stat.byte = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// write all bytes so far to the file
|
||||
void GifWriteChunk( FILE* f, GifBitStatus& stat )
|
||||
{
|
||||
fputc((int)stat.chunkIndex, f);
|
||||
fwrite(stat.chunk, 1, stat.chunkIndex, f);
|
||||
|
||||
stat.bitIndex = 0;
|
||||
stat.byte = 0;
|
||||
stat.chunkIndex = 0;
|
||||
}
|
||||
|
||||
void GifWriteCode( FILE* f, GifBitStatus& stat, uint32_t code, uint32_t length )
|
||||
{
|
||||
for( uint32_t ii=0; ii<length; ++ii )
|
||||
{
|
||||
GifWriteBit(stat, code);
|
||||
code = code >> 1;
|
||||
|
||||
if( stat.chunkIndex == 255 )
|
||||
{
|
||||
GifWriteChunk(f, stat);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The LZW dictionary is a 256-ary tree constructed as the file is encoded,
|
||||
// this is one node
|
||||
struct GifLzwNode
|
||||
{
|
||||
uint16_t m_next[256];
|
||||
};
|
||||
|
||||
// write a 256-color (8-bit) image palette to the file
|
||||
void GifWritePalette( const GifPalette* pPal, FILE* f )
|
||||
{
|
||||
fputc(0, f); // first color: transparency
|
||||
fputc(0, f);
|
||||
fputc(0, f);
|
||||
|
||||
for(int ii=1; ii<(1 << pPal->bitDepth); ++ii)
|
||||
{
|
||||
uint32_t r = pPal->r[ii];
|
||||
uint32_t g = pPal->g[ii];
|
||||
uint32_t b = pPal->b[ii];
|
||||
|
||||
fputc((int)r, f);
|
||||
fputc((int)g, f);
|
||||
fputc((int)b, f);
|
||||
}
|
||||
}
|
||||
|
||||
// write the image header, LZW-compress and write out the image
|
||||
void GifWriteLzwImage(FILE* f, uint8_t* image, uint32_t left, uint32_t top, uint32_t width, uint32_t height, uint32_t delay, GifPalette* pPal)
|
||||
{
|
||||
// graphics control extension
|
||||
fputc(0x21, f);
|
||||
fputc(0xf9, f);
|
||||
fputc(0x04, f);
|
||||
fputc(0x05, f); // leave prev frame in place, this frame has transparency
|
||||
fputc(delay & 0xff, f);
|
||||
fputc((delay >> 8) & 0xff, f);
|
||||
fputc(kGifTransIndex, f); // transparent color index
|
||||
fputc(0, f);
|
||||
|
||||
fputc(0x2c, f); // image descriptor block
|
||||
|
||||
fputc(left & 0xff, f); // corner of image in canvas space
|
||||
fputc((left >> 8) & 0xff, f);
|
||||
fputc(top & 0xff, f);
|
||||
fputc((top >> 8) & 0xff, f);
|
||||
|
||||
fputc(width & 0xff, f); // width and height of image
|
||||
fputc((width >> 8) & 0xff, f);
|
||||
fputc(height & 0xff, f);
|
||||
fputc((height >> 8) & 0xff, f);
|
||||
|
||||
//fputc(0, f); // no local color table, no transparency
|
||||
//fputc(0x80, f); // no local color table, but transparency
|
||||
|
||||
fputc(0x80 + pPal->bitDepth-1, f); // local color table present, 2 ^ bitDepth entries
|
||||
GifWritePalette(pPal, f);
|
||||
|
||||
const int minCodeSize = pPal->bitDepth;
|
||||
const uint32_t clearCode = 1 << pPal->bitDepth;
|
||||
|
||||
fputc(minCodeSize, f); // min code size 8 bits
|
||||
|
||||
GifLzwNode* codetree = (GifLzwNode*)GIF_TEMP_MALLOC(sizeof(GifLzwNode)*4096);
|
||||
|
||||
memset(codetree, 0, sizeof(GifLzwNode)*4096);
|
||||
int32_t curCode = -1;
|
||||
uint32_t codeSize = (uint32_t)minCodeSize + 1;
|
||||
uint32_t maxCode = clearCode+1;
|
||||
|
||||
GifBitStatus stat;
|
||||
stat.byte = 0;
|
||||
stat.bitIndex = 0;
|
||||
stat.chunkIndex = 0;
|
||||
|
||||
GifWriteCode(f, stat, clearCode, codeSize); // start with a fresh LZW dictionary
|
||||
|
||||
for(uint32_t yy=0; yy<height; ++yy)
|
||||
{
|
||||
for(uint32_t xx=0; xx<width; ++xx)
|
||||
{
|
||||
#ifdef GIF_FLIP_VERT
|
||||
// bottom-left origin image (such as an OpenGL capture)
|
||||
uint8_t nextValue = image[((height-1-yy)*width+xx)*4+3];
|
||||
#else
|
||||
// top-left origin
|
||||
uint8_t nextValue = image[(yy*width+xx)*4+3];
|
||||
#endif
|
||||
|
||||
// "loser mode" - no compression, every single code is followed immediately by a clear
|
||||
//WriteCode( f, stat, nextValue, codeSize );
|
||||
//WriteCode( f, stat, 256, codeSize );
|
||||
|
||||
if( curCode < 0 )
|
||||
{
|
||||
// first value in a new run
|
||||
curCode = nextValue;
|
||||
}
|
||||
else if( codetree[curCode].m_next[nextValue] )
|
||||
{
|
||||
// current run already in the dictionary
|
||||
curCode = codetree[curCode].m_next[nextValue];
|
||||
}
|
||||
else
|
||||
{
|
||||
// finish the current run, write a code
|
||||
GifWriteCode(f, stat, (uint32_t)curCode, codeSize);
|
||||
|
||||
// insert the new run into the dictionary
|
||||
codetree[curCode].m_next[nextValue] = (uint16_t)++maxCode;
|
||||
|
||||
if( maxCode >= (1ul << codeSize) )
|
||||
{
|
||||
// dictionary entry count has broken a size barrier,
|
||||
// we need more bits for codes
|
||||
codeSize++;
|
||||
}
|
||||
if( maxCode == 4095 )
|
||||
{
|
||||
// the dictionary is full, clear it out and begin anew
|
||||
GifWriteCode(f, stat, clearCode, codeSize); // clear tree
|
||||
|
||||
memset(codetree, 0, sizeof(GifLzwNode)*4096);
|
||||
codeSize = (uint32_t)(minCodeSize + 1);
|
||||
maxCode = clearCode+1;
|
||||
}
|
||||
|
||||
curCode = nextValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// compression footer
|
||||
GifWriteCode(f, stat, (uint32_t)curCode, codeSize);
|
||||
GifWriteCode(f, stat, clearCode, codeSize);
|
||||
GifWriteCode(f, stat, clearCode + 1, (uint32_t)minCodeSize + 1);
|
||||
|
||||
// write out the last partial chunk
|
||||
while( stat.bitIndex ) GifWriteBit(stat, 0);
|
||||
if( stat.chunkIndex ) GifWriteChunk(f, stat);
|
||||
|
||||
fputc(0, f); // image block terminator
|
||||
|
||||
GIF_TEMP_FREE(codetree);
|
||||
}
|
||||
|
||||
struct GifWriter
|
||||
{
|
||||
FILE* f;
|
||||
uint8_t* oldImage;
|
||||
bool firstFrame;
|
||||
};
|
||||
|
||||
// Creates a gif file.
|
||||
// The input GIFWriter is assumed to be uninitialized.
|
||||
// The delay value is the time between frames in hundredths of a second - note that not all viewers pay much attention to this value.
|
||||
bool GifBegin( GifWriter* writer, const char* filename, uint32_t width, uint32_t height, uint32_t delay, int32_t bitDepth = 8, bool dither = false )
|
||||
{
|
||||
(void)bitDepth; (void)dither; // Mute "Unused argument" warnings
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1400)
|
||||
writer->f = 0;
|
||||
fopen_s(&writer->f, filename, "wb");
|
||||
#else
|
||||
writer->f = fopen(filename, "wb");
|
||||
#endif
|
||||
if(!writer->f) return false;
|
||||
|
||||
writer->firstFrame = true;
|
||||
|
||||
// allocate
|
||||
writer->oldImage = (uint8_t*)GIF_MALLOC(width*height*4);
|
||||
|
||||
fputs("GIF89a", writer->f);
|
||||
|
||||
// screen descriptor
|
||||
fputc(width & 0xff, writer->f);
|
||||
fputc((width >> 8) & 0xff, writer->f);
|
||||
fputc(height & 0xff, writer->f);
|
||||
fputc((height >> 8) & 0xff, writer->f);
|
||||
|
||||
fputc(0xf0, writer->f); // there is an unsorted global color table of 2 entries
|
||||
fputc(0, writer->f); // background color
|
||||
fputc(0, writer->f); // pixels are square (we need to specify this because it's 1989)
|
||||
|
||||
// now the "global" palette (really just a dummy palette)
|
||||
// color 0: black
|
||||
fputc(0, writer->f);
|
||||
fputc(0, writer->f);
|
||||
fputc(0, writer->f);
|
||||
// color 1: also black
|
||||
fputc(0, writer->f);
|
||||
fputc(0, writer->f);
|
||||
fputc(0, writer->f);
|
||||
|
||||
if( delay != 0 )
|
||||
{
|
||||
// animation header
|
||||
fputc(0x21, writer->f); // extension
|
||||
fputc(0xff, writer->f); // application specific
|
||||
fputc(11, writer->f); // length 11
|
||||
fputs("NETSCAPE2.0", writer->f); // yes, really
|
||||
fputc(3, writer->f); // 3 bytes of NETSCAPE2.0 data
|
||||
|
||||
fputc(1, writer->f); // JUST BECAUSE
|
||||
fputc(0, writer->f); // loop infinitely (byte 0)
|
||||
fputc(0, writer->f); // loop infinitely (byte 1)
|
||||
|
||||
fputc(0, writer->f); // block terminator
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Writes out a new frame to a GIF in progress.
|
||||
// The GIFWriter should have been created by GIFBegin.
|
||||
// AFAIK, it is legal to use different bit depths for different frames of an image -
|
||||
// this may be handy to save bits in animations that don't change much.
|
||||
bool GifWriteFrame( GifWriter* writer, const uint8_t* image, uint32_t width, uint32_t height, uint32_t delay, int bitDepth = 8, bool dither = false )
|
||||
{
|
||||
if(!writer->f) return false;
|
||||
|
||||
const uint8_t* oldImage = writer->firstFrame? NULL : writer->oldImage;
|
||||
writer->firstFrame = false;
|
||||
|
||||
GifPalette pal;
|
||||
GifMakePalette((dither? NULL : oldImage), image, width, height, bitDepth, dither, &pal);
|
||||
|
||||
if(dither)
|
||||
GifDitherImage(oldImage, image, writer->oldImage, width, height, &pal);
|
||||
else
|
||||
GifThresholdImage(oldImage, image, writer->oldImage, width, height, &pal);
|
||||
|
||||
GifWriteLzwImage(writer->f, writer->oldImage, 0, 0, width, height, delay, &pal);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Writes the EOF code, closes the file handle, and frees temp memory used by a GIF.
|
||||
// Many if not most viewers will still display a GIF properly if the EOF code is missing,
|
||||
// but it's still a good idea to write it out.
|
||||
bool GifEnd( GifWriter* writer )
|
||||
{
|
||||
if(!writer->f) return false;
|
||||
|
||||
fputc(0x3b, writer->f); // end of file
|
||||
fclose(writer->f);
|
||||
GIF_FREE(writer->oldImage);
|
||||
|
||||
writer->f = NULL;
|
||||
writer->oldImage = NULL;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
178
example/lottie2gif.cpp
Normal file
178
example/lottie2gif.cpp
Normal file
|
@ -0,0 +1,178 @@
|
|||
#include "gif.h"
|
||||
#include <rlottie.h>
|
||||
|
||||
#include<iostream>
|
||||
#include<string>
|
||||
#include<vector>
|
||||
#include<array>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include<libgen.h>
|
||||
#else
|
||||
#include <windows.h>
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
class GifBuilder {
|
||||
public:
|
||||
explicit GifBuilder(const std::string &fileName , const uint32_t width,
|
||||
const uint32_t height, const int bgColor=0xffffffff, const uint32_t delay = 2)
|
||||
{
|
||||
GifBegin(&handle, fileName.c_str(), width, height, delay);
|
||||
bgColorR = (uint8_t) ((bgColor & 0xff0000) >> 16);
|
||||
bgColorG = (uint8_t) ((bgColor & 0x00ff00) >> 8);
|
||||
bgColorB = (uint8_t) ((bgColor & 0x0000ff));
|
||||
}
|
||||
~GifBuilder()
|
||||
{
|
||||
GifEnd(&handle);
|
||||
}
|
||||
void addFrame(rlottie::Surface &s, uint32_t delay = 2)
|
||||
{
|
||||
argbTorgba(s);
|
||||
GifWriteFrame(&handle,
|
||||
reinterpret_cast<uint8_t *>(s.buffer()),
|
||||
s.width(),
|
||||
s.height(),
|
||||
delay);
|
||||
}
|
||||
void argbTorgba(rlottie::Surface &s)
|
||||
{
|
||||
uint8_t *buffer = reinterpret_cast<uint8_t *>(s.buffer());
|
||||
uint32_t totalBytes = s.height() * s.bytesPerLine();
|
||||
|
||||
for (uint32_t i = 0; i < totalBytes; i += 4) {
|
||||
unsigned char a = buffer[i+3];
|
||||
// compute only if alpha is non zero
|
||||
if (a) {
|
||||
unsigned char r = buffer[i+2];
|
||||
unsigned char g = buffer[i+1];
|
||||
unsigned char b = buffer[i];
|
||||
|
||||
if (a != 255) { //un premultiply
|
||||
unsigned char r2 = (unsigned char) ((float) bgColorR * ((float) (255 - a) / 255));
|
||||
unsigned char g2 = (unsigned char) ((float) bgColorG * ((float) (255 - a) / 255));
|
||||
unsigned char b2 = (unsigned char) ((float) bgColorB * ((float) (255 - a) / 255));
|
||||
buffer[i] = r + r2;
|
||||
buffer[i+1] = g + g2;
|
||||
buffer[i+2] = b + b2;
|
||||
|
||||
} else {
|
||||
// only swizzle r and b
|
||||
buffer[i] = r;
|
||||
buffer[i+2] = b;
|
||||
}
|
||||
} else {
|
||||
buffer[i+2] = bgColorB;
|
||||
buffer[i+1] = bgColorG;
|
||||
buffer[i] = bgColorR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
GifWriter handle;
|
||||
uint8_t bgColorR, bgColorG, bgColorB;
|
||||
};
|
||||
|
||||
class App {
|
||||
public:
|
||||
int render(uint32_t w, uint32_t h)
|
||||
{
|
||||
auto player = rlottie::Animation::loadFromFile(fileName);
|
||||
if (!player) return help();
|
||||
|
||||
auto buffer = std::unique_ptr<uint32_t[]>(new uint32_t[w * h]);
|
||||
size_t frameCount = player->totalFrame();
|
||||
|
||||
GifBuilder builder(gifName.data(), w, h, bgColor);
|
||||
for (size_t i = 0; i < frameCount ; i++) {
|
||||
rlottie::Surface surface(buffer.get(), w, h, w * 4);
|
||||
player->renderSync(i, surface);
|
||||
builder.addFrame(surface);
|
||||
}
|
||||
return result();
|
||||
}
|
||||
|
||||
int setup(int argc, char **argv, size_t *width, size_t *height)
|
||||
{
|
||||
char *path{nullptr};
|
||||
|
||||
*width = *height = 200; //default gif size
|
||||
|
||||
if (argc > 1) path = argv[1];
|
||||
if (argc > 2) {
|
||||
char tmp[20];
|
||||
char *x = strstr(argv[2], "x");
|
||||
if (x) {
|
||||
snprintf(tmp, x - argv[2] + 1, "%s", argv[2]);
|
||||
*width = atoi(tmp);
|
||||
snprintf(tmp, sizeof(tmp), "%s", x + 1);
|
||||
*height = atoi(tmp);
|
||||
}
|
||||
}
|
||||
if (argc > 3) bgColor = strtol(argv[3], NULL, 16);
|
||||
|
||||
if (!path) return help();
|
||||
|
||||
std::array<char, 5000> memory;
|
||||
|
||||
#ifdef _WIN32
|
||||
path = _fullpath(memory.data(), path, memory.size());
|
||||
#else
|
||||
path = realpath(path, memory.data());
|
||||
#endif
|
||||
if (!path) return help();
|
||||
|
||||
fileName = std::string(path);
|
||||
|
||||
if (!jsonFile()) return help();
|
||||
|
||||
gifName = basename(fileName);
|
||||
gifName.append(".gif");
|
||||
return 0;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string basename(const std::string &str)
|
||||
{
|
||||
return str.substr(str.find_last_of("/\\") + 1);
|
||||
}
|
||||
|
||||
bool jsonFile() {
|
||||
std::string extn = ".json";
|
||||
if ( fileName.size() <= extn.size() ||
|
||||
fileName.substr(fileName.size()- extn.size()) != extn )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int result() {
|
||||
std::cout<<"Generated GIF file : "<<gifName<<std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int help() {
|
||||
std::cout<<"Usage: \n lottie2gif [lottieFileName] [Resolution] [bgColor]\n\nExamples: \n $ lottie2gif input.json\n $ lottie2gif input.json 200x200\n $ lottie2gif input.json 200x200 ff00ff\n\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
private:
|
||||
int bgColor = 0xffffffff;
|
||||
std::string fileName;
|
||||
std::string gifName;
|
||||
};
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
App app;
|
||||
size_t w, h;
|
||||
|
||||
if (app.setup(argc, argv, &w, &h)) return 1;
|
||||
|
||||
app.render(w, h);
|
||||
|
||||
return 0;
|
||||
}
|
160
example/lottieperf.cpp
Normal file
160
example/lottieperf.cpp
Normal file
|
@ -0,0 +1,160 @@
|
|||
#include <memory>
|
||||
#include <vector>
|
||||
#include <dirent.h>
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
#include <cstring>
|
||||
|
||||
#include <rlottie.h>
|
||||
|
||||
static bool isJsonFile(const char *filename) {
|
||||
const char *dot = strrchr(filename, '.');
|
||||
if(!dot || dot == filename) return false;
|
||||
return !strcmp(dot + 1, "json");
|
||||
}
|
||||
|
||||
static std::vector<std::string>
|
||||
jsonFiles(const std::string &dirName)
|
||||
{
|
||||
DIR *d;
|
||||
struct dirent *dir;
|
||||
std::vector<std::string> result;
|
||||
d = opendir(dirName.c_str());
|
||||
if (d) {
|
||||
while ((dir = readdir(d)) != NULL) {
|
||||
if (isJsonFile(dir->d_name))
|
||||
result.push_back(dirName + dir->d_name);
|
||||
}
|
||||
closedir(d);
|
||||
}
|
||||
|
||||
std::sort(result.begin(), result.end(), [](auto & a, auto &b){return a < b;});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
class Renderer
|
||||
{
|
||||
public:
|
||||
explicit Renderer(const std::string& filename)
|
||||
{
|
||||
_animation = rlottie::Animation::loadFromFile(filename);
|
||||
_frames = _animation->totalFrame();
|
||||
_buffer = std::make_unique<uint32_t[]>(100 * 100);
|
||||
_surface = rlottie::Surface(_buffer.get(), 100, 100, 100 * 4);
|
||||
}
|
||||
void render()
|
||||
{
|
||||
if (_cur >= _frames) _cur = 0;
|
||||
_animation->renderSync(_cur++, _surface);
|
||||
}
|
||||
void renderAsync()
|
||||
{
|
||||
if (_cur >= _frames) _cur = 0;
|
||||
_future = _animation->render(_cur++, _surface);
|
||||
}
|
||||
void get()
|
||||
{
|
||||
if (_future.valid()) _future.get();
|
||||
}
|
||||
private:
|
||||
std::unique_ptr<uint32_t[]> _buffer;
|
||||
std::unique_ptr<rlottie::Animation> _animation;
|
||||
size_t _frames{0};
|
||||
size_t _cur{0};
|
||||
rlottie::Surface _surface;
|
||||
std::future<rlottie::Surface> _future;
|
||||
};
|
||||
|
||||
class PerfTest
|
||||
{
|
||||
public:
|
||||
explicit PerfTest(size_t resourceCount, size_t iterations):
|
||||
_resourceCount(resourceCount), _iterations(iterations)
|
||||
{
|
||||
_resourceList = jsonFiles(std::string(DEMO_DIR));
|
||||
}
|
||||
void test(bool async)
|
||||
{
|
||||
setup();
|
||||
std::cout<<" Test Started : .... \n";
|
||||
auto start = std::chrono::high_resolution_clock::now();
|
||||
benchmark(async);
|
||||
std::chrono::duration<double> secs = std::chrono::high_resolution_clock::now() - start;
|
||||
std::chrono::duration<double, std::milli> millisecs = secs;
|
||||
std::cout<< " Test Finished.\n";
|
||||
std::cout<< " \nPerformance Report: \n\n";
|
||||
std::cout<< " \t Resource Rendered per Frame : "<< _resourceCount <<"\n";
|
||||
std::cout<< " \t Render Buffer Size : (100 X 100) \n";
|
||||
std::cout<< " \t Render Mode : "<< (async ? "Async" : "Sync")<<"\n";
|
||||
std::cout<< " \t Total Frames Rendered : "<< _iterations<<"\n";
|
||||
std::cout<< " \t Total Render Time : "<< secs.count()<<"sec\n";
|
||||
std::cout<< " \t Avrage Time per Resource : "<< millisecs.count() / (_iterations * _resourceCount)<<"ms\n";
|
||||
std::cout<< " \t Avrage Time Per Frame : "<< millisecs.count() / _iterations <<"ms\n";
|
||||
std::cout<< " \t FPS : "<< _iterations / secs.count() <<"fps\n\n";
|
||||
}
|
||||
private:
|
||||
void setup()
|
||||
{
|
||||
for (auto i = 0u; i < _resourceCount; i++) {
|
||||
auto index = i % _resourceList.size();
|
||||
_renderers.push_back(std::make_unique<Renderer>(_resourceList[index]));
|
||||
}
|
||||
}
|
||||
|
||||
void benchmark(bool async)
|
||||
{
|
||||
for (auto i = 0u; i < _iterations; i++) {
|
||||
if (async) {
|
||||
for (const auto &e : _renderers) e->renderAsync();
|
||||
for (const auto &e : _renderers) e->get();
|
||||
} else {
|
||||
for (const auto &e : _renderers) e->render();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
size_t _resourceCount;
|
||||
size_t _iterations;
|
||||
|
||||
std::vector<std::string> _resourceList;
|
||||
std::vector<std::unique_ptr<Renderer>> _renderers;
|
||||
};
|
||||
|
||||
static int help()
|
||||
{
|
||||
std::cout<<"\nUsage : ./perf [--sync] [-c] [resource count] [-i] [iteration count] \n";
|
||||
std::cout<<"\nExample : ./perf -c 50 -i 100 \n";
|
||||
std::cout<<"\n\t runs perf test for 100 iterations. renders 50 resource per iteration\n\n";
|
||||
return 0;
|
||||
}
|
||||
int
|
||||
main(int argc, char ** argv)
|
||||
{
|
||||
bool async = true;
|
||||
size_t resourceCount = 250;
|
||||
size_t iterations = 500;
|
||||
auto index = 0;
|
||||
|
||||
while (index < argc) {
|
||||
const char* option = argv[index];
|
||||
index++;
|
||||
if (!strcmp(option,"--help") || !strcmp(option,"-h")) {
|
||||
return help();
|
||||
} else if (!strcmp(option,"--sync")) {
|
||||
async = false;
|
||||
} else if (!strcmp(option,"-c")) {
|
||||
resourceCount = (index < argc) ? atoi(argv[index]) : resourceCount;
|
||||
index++;
|
||||
} else if (!strcmp(option,"-i")) {
|
||||
iterations = (index < argc) ? atoi(argv[index]) : iterations;
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
PerfTest obj(resourceCount, iterations);
|
||||
obj.test(async);
|
||||
return 0;
|
||||
}
|
228
example/lottieview.cpp
Normal file
228
example/lottieview.cpp
Normal file
|
@ -0,0 +1,228 @@
|
|||
/*
|
||||
* Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved.
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include"lottieview.h"
|
||||
|
||||
using namespace rlottie;
|
||||
|
||||
static void
|
||||
_image_update_cb(void *data, Evas_Object *obj EINA_UNUSED)
|
||||
{
|
||||
RenderStrategy *info = (RenderStrategy *)data;
|
||||
info->dataCb();
|
||||
}
|
||||
|
||||
void RenderStrategy::addCallback(){
|
||||
if (_useImage)
|
||||
evas_object_image_pixels_get_callback_set(_renderObject, _image_update_cb, this);
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
animator(void *data , double pos)
|
||||
{
|
||||
LottieView *view = static_cast<LottieView *>(data);
|
||||
|
||||
view->seek(pos);
|
||||
if (pos == 1.0) {
|
||||
view->mAnimator = NULL;
|
||||
view->finished();
|
||||
return EINA_FALSE;
|
||||
}
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
LottieView::LottieView(Evas *evas, Strategy s) {
|
||||
mPalying = false;
|
||||
mReverse = false;
|
||||
mRepeatCount = 0;
|
||||
mRepeatMode = LottieView::RepeatMode::Restart;
|
||||
mLoop = false;
|
||||
mSpeed = 1;
|
||||
|
||||
switch (s) {
|
||||
case Strategy::renderCpp: {
|
||||
mRenderDelegate = std::make_unique<RlottieRenderStrategy_CPP>(evas);
|
||||
break;
|
||||
}
|
||||
case Strategy::renderCppAsync: {
|
||||
mRenderDelegate = std::make_unique<RlottieRenderStrategy_CPP_ASYNC>(evas);
|
||||
break;
|
||||
}
|
||||
case Strategy::renderC: {
|
||||
mRenderDelegate = std::make_unique<RlottieRenderStrategy_C>(evas);
|
||||
break;
|
||||
}
|
||||
case Strategy::renderCAsync: {
|
||||
mRenderDelegate = std::make_unique<RlottieRenderStrategy_C_ASYNC>(evas);
|
||||
break;
|
||||
}
|
||||
case Strategy::eflVg: {
|
||||
mRenderDelegate = std::make_unique<EflVgRenderStrategy>(evas);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
mRenderDelegate = std::make_unique<RlottieRenderStrategy_CPP>(evas);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
LottieView::~LottieView()
|
||||
{
|
||||
if (mAnimator) ecore_animator_del(mAnimator);
|
||||
}
|
||||
|
||||
Evas_Object *LottieView::getImage() {
|
||||
return mRenderDelegate->renderObject();
|
||||
}
|
||||
|
||||
void LottieView::show()
|
||||
{
|
||||
mRenderDelegate->show();
|
||||
seek(0);
|
||||
}
|
||||
|
||||
void LottieView::hide()
|
||||
{
|
||||
mRenderDelegate->hide();
|
||||
}
|
||||
|
||||
void LottieView::seek(float pos)
|
||||
{
|
||||
if (!mRenderDelegate) return;
|
||||
|
||||
|
||||
mPos = mapProgress(pos);
|
||||
|
||||
// check if the pos maps to the current frame
|
||||
if (mCurFrame == mRenderDelegate->frameAtPos(mPos)) return;
|
||||
|
||||
mCurFrame = mRenderDelegate->frameAtPos(mPos);
|
||||
|
||||
mRenderDelegate->render(mCurFrame);
|
||||
}
|
||||
|
||||
float LottieView::getPos()
|
||||
{
|
||||
return mPos;
|
||||
}
|
||||
|
||||
void LottieView::setFilePath(const char *filePath)
|
||||
{
|
||||
mRenderDelegate->loadFromFile(filePath);
|
||||
}
|
||||
|
||||
void LottieView::loadFromData(const std::string &jsonData, const std::string &key, const std::string &resourcePath)
|
||||
{
|
||||
mRenderDelegate->loadFromData(jsonData, key, resourcePath);
|
||||
}
|
||||
|
||||
void LottieView::setSize(int w, int h)
|
||||
{
|
||||
mRenderDelegate->resize(w, h);
|
||||
}
|
||||
|
||||
void LottieView::setPos(int x, int y)
|
||||
{
|
||||
mRenderDelegate->setPos(x, y);
|
||||
}
|
||||
|
||||
void LottieView::finished()
|
||||
{
|
||||
restart();
|
||||
}
|
||||
|
||||
void LottieView::loop(bool loop)
|
||||
{
|
||||
mLoop = loop;
|
||||
}
|
||||
|
||||
void LottieView::setRepeatCount(int count)
|
||||
{
|
||||
mRepeatCount = count;
|
||||
}
|
||||
|
||||
void LottieView::setRepeatMode(LottieView::RepeatMode mode)
|
||||
{
|
||||
mRepeatMode = mode;
|
||||
}
|
||||
|
||||
void LottieView::play()
|
||||
{
|
||||
if (mAnimator) ecore_animator_del(mAnimator);
|
||||
mAnimator = ecore_animator_timeline_add(duration()/mSpeed, animator, this);
|
||||
mReverse = false;
|
||||
mCurCount = mRepeatCount;
|
||||
mPalying = true;
|
||||
}
|
||||
|
||||
void LottieView::play(const std::string &marker)
|
||||
{
|
||||
size_t totalframe = getTotalFrame();
|
||||
auto frame = mRenderDelegate->findFrameAtMarker(marker);
|
||||
|
||||
setMinProgress((float)std::get<0>(frame) / (float)totalframe);
|
||||
if (std::get<1>(frame) != 0)
|
||||
setMaxProgress((float)std::get<1>(frame) / (float)totalframe);
|
||||
|
||||
this->play();
|
||||
}
|
||||
|
||||
void LottieView::play(const std::string &startmarker, const std::string endmarker)
|
||||
{
|
||||
size_t totalframe = getTotalFrame();
|
||||
auto stframe = mRenderDelegate->findFrameAtMarker(startmarker);
|
||||
auto edframe = mRenderDelegate->findFrameAtMarker(endmarker);
|
||||
|
||||
setMinProgress((float)std::get<0>(stframe) / (float)totalframe);
|
||||
if (std::get<0>(edframe) != 0)
|
||||
setMaxProgress((float)std::get<0>(edframe) / (float)totalframe);
|
||||
|
||||
this->play();
|
||||
}
|
||||
|
||||
void LottieView::pause()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void LottieView::stop()
|
||||
{
|
||||
mPalying = false;
|
||||
if (mAnimator) {
|
||||
ecore_animator_del(mAnimator);
|
||||
mAnimator = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void LottieView::restart()
|
||||
{
|
||||
mCurCount--;
|
||||
if (mLoop || mRepeatCount) {
|
||||
if (mRepeatMode == LottieView::RepeatMode::Reverse)
|
||||
mReverse = !mReverse;
|
||||
else
|
||||
mReverse = false;
|
||||
|
||||
if (mAnimator) ecore_animator_del(mAnimator);
|
||||
mAnimator = ecore_animator_timeline_add(duration()/mSpeed, animator, this);
|
||||
}
|
||||
}
|
458
example/lottieview.h
Normal file
458
example/lottieview.h
Normal file
|
@ -0,0 +1,458 @@
|
|||
/*
|
||||
* Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved.
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef LOTTIEVIEW_H
|
||||
#define LOTTIEVIEW_H
|
||||
|
||||
#ifndef EFL_BETA_API_SUPPORT
|
||||
#define EFL_BETA_API_SUPPORT
|
||||
#endif
|
||||
|
||||
#ifndef EFL_EO_API_SUPPORT
|
||||
#define EFL_EO_API_SUPPORT
|
||||
#endif
|
||||
|
||||
#include <Eo.h>
|
||||
#include <Efl.h>
|
||||
#include <Evas.h>
|
||||
#include <Ecore.h>
|
||||
#include <Ecore_Evas.h>
|
||||
#include "rlottie.h"
|
||||
#include "rlottie_capi.h"
|
||||
#include<future>
|
||||
#include <cmath>
|
||||
#include <algorithm>
|
||||
|
||||
class RenderStrategy {
|
||||
public:
|
||||
virtual ~RenderStrategy() {
|
||||
evas_object_del(renderObject());
|
||||
}
|
||||
RenderStrategy(Evas_Object *obj, bool useImage = true):_renderObject(obj), _useImage(useImage){
|
||||
addCallback();
|
||||
}
|
||||
virtual rlottie::Animation *player() {return nullptr;}
|
||||
virtual void loadFromFile(const char *filePath) = 0;
|
||||
virtual void loadFromData(const std::string &jsonData, const std::string &key, const std::string &resourcePath) = 0;
|
||||
virtual size_t totalFrame() = 0;
|
||||
virtual double frameRate() = 0;
|
||||
virtual size_t frameAtPos(double pos) = 0;
|
||||
virtual double duration() = 0;
|
||||
void render(int frame) {
|
||||
_renderCount++;
|
||||
_redraw = renderRequest(frame);
|
||||
if (_redraw && _useImage)
|
||||
evas_object_image_pixels_dirty_set(renderObject(), EINA_TRUE);
|
||||
}
|
||||
void dataCb() {
|
||||
if (_redraw && _useImage) {
|
||||
evas_object_image_data_set(renderObject(), buffer());
|
||||
}
|
||||
_redraw = false;
|
||||
}
|
||||
virtual void resize(int width, int height) = 0;
|
||||
virtual void setPos(int x, int y) {evas_object_move(renderObject(), x, y);}
|
||||
typedef std::tuple<size_t, size_t> MarkerFrame;
|
||||
virtual MarkerFrame findFrameAtMarker(const std::string &markerName) = 0;
|
||||
void show() {evas_object_show(_renderObject);}
|
||||
void hide() {evas_object_hide(_renderObject);}
|
||||
void addCallback();
|
||||
Evas_Object* renderObject() const {return _renderObject;}
|
||||
size_t renderCount() const {return _renderCount;}
|
||||
protected:
|
||||
virtual bool renderRequest(int) = 0;
|
||||
virtual uint32_t* buffer() = 0;
|
||||
private:
|
||||
size_t _renderCount{0};
|
||||
bool _redraw{false};
|
||||
Evas_Object *_renderObject;
|
||||
bool _useImage{true};
|
||||
};
|
||||
|
||||
class CppApiBase : public RenderStrategy {
|
||||
public:
|
||||
CppApiBase(Evas_Object *renderObject): RenderStrategy(renderObject) {}
|
||||
rlottie::Animation *player() {return mPlayer.get();}
|
||||
void loadFromFile(const char *filePath)
|
||||
{
|
||||
mPlayer = rlottie::Animation::loadFromFile(filePath);
|
||||
|
||||
if (!mPlayer) {
|
||||
printf("load failed file %s\n", filePath);
|
||||
}
|
||||
}
|
||||
|
||||
void loadFromData(const std::string &jsonData, const std::string &key, const std::string &resourcePath)
|
||||
{
|
||||
mPlayer = rlottie::Animation::loadFromData(jsonData, key, resourcePath);
|
||||
|
||||
if (!mPlayer) {
|
||||
printf("load failed from data\n");
|
||||
}
|
||||
}
|
||||
|
||||
size_t totalFrame() {
|
||||
return mPlayer->totalFrame();
|
||||
|
||||
}
|
||||
double duration() {
|
||||
return mPlayer->duration();
|
||||
}
|
||||
|
||||
double frameRate() {
|
||||
return mPlayer->frameRate();
|
||||
}
|
||||
|
||||
size_t frameAtPos(double pos) {
|
||||
return mPlayer->frameAtPos(pos);
|
||||
}
|
||||
|
||||
MarkerFrame findFrameAtMarker(const std::string &markerName)
|
||||
{
|
||||
auto markerList = mPlayer->markers();
|
||||
auto marker = std::find_if(markerList.begin(), markerList.end()
|
||||
, [&markerName](const auto& e) {
|
||||
return std::get<0>(e) == markerName;
|
||||
});
|
||||
if (marker == markerList.end())
|
||||
return std::make_tuple(0, 0);
|
||||
return std::make_tuple(std::get<1>(*marker), std::get<2>(*marker));
|
||||
}
|
||||
|
||||
protected:
|
||||
std::unique_ptr<rlottie::Animation> mPlayer;
|
||||
};
|
||||
|
||||
class RlottieRenderStrategyCBase : public RenderStrategy {
|
||||
public:
|
||||
RlottieRenderStrategyCBase(Evas *evas):RenderStrategy(evas_object_image_filled_add(evas)) {
|
||||
evas_object_image_colorspace_set(renderObject(), EVAS_COLORSPACE_ARGB8888);
|
||||
evas_object_image_alpha_set(renderObject(), EINA_TRUE);
|
||||
}
|
||||
void resize(int width, int height) {
|
||||
evas_object_resize(renderObject(), width, height);
|
||||
evas_object_image_size_set(renderObject(), width, height);
|
||||
}
|
||||
};
|
||||
|
||||
class RlottieRenderStrategy : public CppApiBase {
|
||||
public:
|
||||
RlottieRenderStrategy(Evas *evas):CppApiBase(evas_object_image_filled_add(evas)) {
|
||||
evas_object_image_colorspace_set(renderObject(), EVAS_COLORSPACE_ARGB8888);
|
||||
evas_object_image_alpha_set(renderObject(), EINA_TRUE);
|
||||
}
|
||||
void resize(int width, int height) {
|
||||
evas_object_resize(renderObject(), width, height);
|
||||
evas_object_image_size_set(renderObject(), width, height);
|
||||
}
|
||||
};
|
||||
|
||||
class RlottieRenderStrategy_CPP : public RlottieRenderStrategy {
|
||||
public:
|
||||
RlottieRenderStrategy_CPP(Evas *evas):RlottieRenderStrategy(evas) {}
|
||||
|
||||
bool renderRequest(int frame) {
|
||||
int width , height;
|
||||
Evas_Object *image = renderObject();
|
||||
evas_object_image_size_get(image, &width, &height);
|
||||
mBuffer = (uint32_t *)evas_object_image_data_get(image, EINA_TRUE);
|
||||
size_t bytesperline = evas_object_image_stride_get(image);
|
||||
rlottie::Surface surface(mBuffer, width, height, bytesperline);
|
||||
mPlayer->renderSync(frame, surface);
|
||||
return true;
|
||||
}
|
||||
uint32_t* buffer() {
|
||||
return mBuffer;
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t * mBuffer;
|
||||
};
|
||||
|
||||
class RlottieRenderStrategy_CPP_ASYNC : public RlottieRenderStrategy {
|
||||
public:
|
||||
RlottieRenderStrategy_CPP_ASYNC(Evas *evas):RlottieRenderStrategy(evas) {}
|
||||
~RlottieRenderStrategy_CPP_ASYNC() {
|
||||
if (mRenderTask.valid())
|
||||
mRenderTask.get();
|
||||
}
|
||||
bool renderRequest(int frame) {
|
||||
//addCallback();
|
||||
if (mRenderTask.valid()) return true;
|
||||
int width , height;
|
||||
Evas_Object *image = renderObject();
|
||||
evas_object_image_size_get(image, &width, &height);
|
||||
auto buffer = (uint32_t *)evas_object_image_data_get(image, EINA_TRUE);
|
||||
size_t bytesperline = evas_object_image_stride_get(image);
|
||||
rlottie::Surface surface(buffer, width, height, bytesperline);
|
||||
mRenderTask = mPlayer->render(frame, surface);
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t* buffer() {
|
||||
auto surface = mRenderTask.get();
|
||||
return surface.buffer();
|
||||
}
|
||||
private:
|
||||
std::future<rlottie::Surface> mRenderTask;
|
||||
};
|
||||
|
||||
|
||||
class RlottieRenderStrategy_C : public RlottieRenderStrategyCBase {
|
||||
public:
|
||||
RlottieRenderStrategy_C(Evas *evas):RlottieRenderStrategyCBase(evas) {}
|
||||
~RlottieRenderStrategy_C() {
|
||||
if (mPlayer) lottie_animation_destroy(mPlayer);
|
||||
}
|
||||
void loadFromFile(const char *filePath)
|
||||
{
|
||||
mPlayer = lottie_animation_from_file(filePath);
|
||||
|
||||
if (!mPlayer) {
|
||||
printf("load failed file %s\n", filePath);
|
||||
}
|
||||
}
|
||||
|
||||
void loadFromData(const std::string &jsonData, const std::string &key, const std::string &resourcePath)
|
||||
{
|
||||
mPlayer = lottie_animation_from_data(jsonData.c_str(), key.c_str(), resourcePath.c_str());
|
||||
if (!mPlayer) {
|
||||
printf("load failed from data\n");
|
||||
}
|
||||
}
|
||||
|
||||
size_t totalFrame() {
|
||||
return lottie_animation_get_totalframe(mPlayer);
|
||||
|
||||
}
|
||||
|
||||
double frameRate() {
|
||||
return lottie_animation_get_framerate(mPlayer);
|
||||
}
|
||||
|
||||
size_t frameAtPos(double pos) {
|
||||
return lottie_animation_get_frame_at_pos(mPlayer, pos);
|
||||
}
|
||||
|
||||
double duration() {
|
||||
return lottie_animation_get_duration(mPlayer);
|
||||
}
|
||||
MarkerFrame findFrameAtMarker(const std::string &markerName)
|
||||
{
|
||||
printf("Can't not [%s] marker, CAPI isn't implements yet\n", markerName.c_str());
|
||||
return std::make_tuple(0, 0);
|
||||
}
|
||||
|
||||
bool renderRequest(int frame) {
|
||||
int width , height;
|
||||
Evas_Object *image = renderObject();
|
||||
evas_object_image_size_get(image, &width, &height);
|
||||
mBuffer = (uint32_t *)evas_object_image_data_get(image, EINA_TRUE);
|
||||
size_t bytesperline = evas_object_image_stride_get(image);
|
||||
lottie_animation_render(mPlayer, frame, mBuffer, width, height, bytesperline);
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t* buffer() {
|
||||
return mBuffer;
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t * mBuffer;
|
||||
protected:
|
||||
Lottie_Animation *mPlayer;
|
||||
};
|
||||
|
||||
class RlottieRenderStrategy_C_ASYNC : public RlottieRenderStrategy_C {
|
||||
public:
|
||||
RlottieRenderStrategy_C_ASYNC(Evas *evas):RlottieRenderStrategy_C(evas) {}
|
||||
~RlottieRenderStrategy_C_ASYNC() {
|
||||
if (mDirty) lottie_animation_render_flush(mPlayer);
|
||||
}
|
||||
bool renderRequest(int frame) {
|
||||
if (mDirty) return true;
|
||||
mDirty = true;
|
||||
Evas_Object *image = renderObject();
|
||||
evas_object_image_size_get(image, &mWidth, &mHeight);
|
||||
mBuffer = (uint32_t *)evas_object_image_data_get(image, EINA_TRUE);
|
||||
size_t bytesperline = evas_object_image_stride_get(image);
|
||||
lottie_animation_render_async(mPlayer, frame, mBuffer, mWidth, mHeight, bytesperline);
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t* buffer() {
|
||||
lottie_animation_render_flush(mPlayer);
|
||||
mDirty =false;
|
||||
return mBuffer;
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t * mBuffer;
|
||||
int mWidth;
|
||||
int mHeight;
|
||||
bool mDirty{false};
|
||||
};
|
||||
|
||||
enum class Strategy {
|
||||
renderCpp = 0,
|
||||
renderCppAsync,
|
||||
renderC,
|
||||
renderCAsync,
|
||||
eflVg
|
||||
};
|
||||
|
||||
class LottieView
|
||||
{
|
||||
public:
|
||||
enum class RepeatMode {
|
||||
Restart,
|
||||
Reverse
|
||||
};
|
||||
LottieView(Evas *evas, Strategy s = Strategy::renderCppAsync);
|
||||
~LottieView();
|
||||
rlottie::Animation *player(){return mRenderDelegate->player();}
|
||||
Evas_Object *getImage();
|
||||
void setSize(int w, int h);
|
||||
void setPos(int x, int y);
|
||||
void setFilePath(const char *filePath);
|
||||
void loadFromData(const std::string &jsonData, const std::string &key, const std::string &resourcePath="");
|
||||
void show();
|
||||
void hide();
|
||||
void loop(bool loop);
|
||||
void setSpeed(float speed) { mSpeed = speed;}
|
||||
void setRepeatCount(int count);
|
||||
void setRepeatMode(LottieView::RepeatMode mode);
|
||||
float getFrameRate() const { return mRenderDelegate->frameRate(); }
|
||||
long getTotalFrame() const { return mRenderDelegate->totalFrame(); }
|
||||
public:
|
||||
void seek(float pos);
|
||||
float getPos();
|
||||
void finished();
|
||||
void play();
|
||||
void play(const std::string &marker);
|
||||
void play(const std::string &startmarker, const std::string endmarker);
|
||||
void pause();
|
||||
void stop();
|
||||
void initializeBufferObject(Evas *evas);
|
||||
void setMinProgress(float progress)
|
||||
{
|
||||
//clamp it to [0,1]
|
||||
mMinProgress = progress;
|
||||
}
|
||||
void setMaxProgress(float progress)
|
||||
{
|
||||
//clamp it to [0,1]
|
||||
mMaxprogress = progress;
|
||||
}
|
||||
|
||||
size_t renderCount() const {
|
||||
return mRenderDelegate ? mRenderDelegate->renderCount() : 0;
|
||||
}
|
||||
private:
|
||||
float mapProgress(float progress) {
|
||||
//clamp it to the segment
|
||||
progress = (mMinProgress + (mMaxprogress - mMinProgress) * progress);
|
||||
|
||||
// currently playing and in reverse mode
|
||||
if (mPalying && mReverse)
|
||||
progress = mMaxprogress > mMinProgress ?
|
||||
mMaxprogress - progress : mMinProgress - progress;
|
||||
|
||||
|
||||
return progress;
|
||||
}
|
||||
float duration() const {
|
||||
// usually we run the animation for mPlayer->duration()
|
||||
// but now run animation for segmented duration.
|
||||
return mRenderDelegate->duration() * fabs(mMaxprogress - mMinProgress);
|
||||
}
|
||||
void createVgNode(LOTNode *node, Efl_VG *root);
|
||||
void update(const std::vector<LOTNode *> &);
|
||||
void updateTree(const LOTLayerNode *);
|
||||
void update(const LOTLayerNode *, Efl_VG *parent);
|
||||
void restart();
|
||||
public:
|
||||
int mRepeatCount;
|
||||
LottieView::RepeatMode mRepeatMode;
|
||||
size_t mCurFrame{UINT_MAX};
|
||||
Ecore_Animator *mAnimator{nullptr};
|
||||
bool mLoop;
|
||||
int mCurCount;
|
||||
bool mReverse;
|
||||
bool mPalying;
|
||||
float mSpeed;
|
||||
float mPos;
|
||||
//keep a segment of the animation default is [0, 1]
|
||||
float mMinProgress{0};
|
||||
float mMaxprogress{1};
|
||||
std::unique_ptr<RenderStrategy> mRenderDelegate;
|
||||
};
|
||||
|
||||
#include<assert.h>
|
||||
class EflVgRenderStrategy : public RenderStrategy {
|
||||
public:
|
||||
EflVgRenderStrategy(Evas *evas):RenderStrategy(evas_object_vg_add(evas), false) {}
|
||||
|
||||
void loadFromFile(const char *filePath) {
|
||||
evas_object_vg_file_set(renderObject(), filePath, NULL);
|
||||
}
|
||||
|
||||
void loadFromData(const std::string&, const std::string&, const std::string&) {
|
||||
assert(false);
|
||||
}
|
||||
|
||||
size_t totalFrame() {
|
||||
return evas_object_vg_animated_frame_count_get(renderObject()) - 1;
|
||||
}
|
||||
|
||||
double frameRate() {
|
||||
return (double)totalFrame() / evas_object_vg_animated_frame_duration_get(renderObject(), 0, 0);
|
||||
}
|
||||
|
||||
size_t frameAtPos(double pos) {
|
||||
return totalFrame() * pos;
|
||||
}
|
||||
|
||||
double duration() {
|
||||
return evas_object_vg_animated_frame_duration_get(renderObject(), 0, 0);
|
||||
}
|
||||
|
||||
void resize(int width, int height) {
|
||||
evas_object_resize(renderObject(), width, height);
|
||||
}
|
||||
|
||||
uint32_t *buffer() {
|
||||
assert(false);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool renderRequest(int frame) {
|
||||
evas_object_vg_animated_frame_set(renderObject(), frame);
|
||||
return false;
|
||||
}
|
||||
|
||||
MarkerFrame findFrameAtMarker(const std::string&) {
|
||||
return std::make_tuple(0, 0);
|
||||
}
|
||||
};
|
||||
|
||||
#endif //LOTTIEVIEW_H
|
260
example/lottieviewer.cpp
Normal file
260
example/lottieviewer.cpp
Normal file
|
@ -0,0 +1,260 @@
|
|||
/*
|
||||
* Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved.
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <Elementary.h>
|
||||
#include "lottieview.h"
|
||||
#include "evasapp.h"
|
||||
#include<iostream>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
#include <error.h>
|
||||
#include <algorithm>
|
||||
|
||||
using namespace std;
|
||||
|
||||
typedef struct _AppInfo AppInfo;
|
||||
struct _AppInfo {
|
||||
LottieView *view;
|
||||
Evas_Object *layout;
|
||||
Evas_Object *slider;
|
||||
Evas_Object *button;
|
||||
Ecore_Animator *animator;
|
||||
Eina_Bool autoPlaying;
|
||||
};
|
||||
|
||||
typedef struct _ItemData ItemData;
|
||||
struct _ItemData {
|
||||
int index;
|
||||
};
|
||||
|
||||
|
||||
std::vector<std::string> jsonFiles;
|
||||
bool renderMode = true;
|
||||
|
||||
static void
|
||||
_layout_del_cb(void *data, Evas *, Evas_Object *, void *)
|
||||
{
|
||||
AppInfo *info = (AppInfo *)data;
|
||||
if (info->view) delete info->view;
|
||||
ecore_animator_del(info->animator);
|
||||
free(info);
|
||||
}
|
||||
|
||||
static void
|
||||
_update_frame_info(AppInfo *info, double pos)
|
||||
{
|
||||
int frameNo = pos * info->view->getTotalFrame();
|
||||
char buf[64];
|
||||
|
||||
sprintf(buf, "%d / %ld", frameNo, info->view->getTotalFrame());
|
||||
elm_object_part_text_set(info->layout, "text", buf);
|
||||
}
|
||||
|
||||
static void
|
||||
_toggle_start_button(AppInfo *info)
|
||||
{
|
||||
if (!info->autoPlaying)
|
||||
{
|
||||
info->autoPlaying = EINA_TRUE;
|
||||
info->view->play();
|
||||
elm_object_text_set(info->button, "Stop");
|
||||
}
|
||||
else
|
||||
{
|
||||
info->autoPlaying = EINA_FALSE;
|
||||
info->view->stop();
|
||||
elm_object_text_set(info->button, "Start");
|
||||
}
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
_animator_cb(void *data)
|
||||
{
|
||||
AppInfo *info = (AppInfo *)data;
|
||||
|
||||
if (info && info->autoPlaying && info->view)
|
||||
{
|
||||
float pos = info->view->getPos();
|
||||
_update_frame_info(info, pos);
|
||||
elm_slider_value_set(info->slider, (double)pos);
|
||||
evas_object_image_pixels_dirty_set(info->view->getImage(), EINA_TRUE);
|
||||
if (pos >= 1.0)
|
||||
_toggle_start_button(info);
|
||||
}
|
||||
return ECORE_CALLBACK_RENEW;
|
||||
}
|
||||
|
||||
static void
|
||||
_slider_cb(void *data, Evas_Object *obj, void *event_info EINA_UNUSED)
|
||||
{
|
||||
double val = elm_slider_value_get(obj);
|
||||
AppInfo *info = (AppInfo *)data;
|
||||
|
||||
_update_frame_info(info, val);
|
||||
|
||||
if (!info->autoPlaying)
|
||||
{
|
||||
info->view->seek(val);
|
||||
evas_object_image_pixels_dirty_set(info->view->getImage(), EINA_TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_button_clicked_cb(void *data, Evas_Object */*obj*/, void */*event_info*/)
|
||||
{
|
||||
AppInfo *info = (AppInfo *)data;
|
||||
|
||||
_toggle_start_button(info);
|
||||
}
|
||||
|
||||
Evas_Object *
|
||||
create_layout(Evas_Object *parent, const char *file)
|
||||
{
|
||||
Evas_Object *layout, *slider, *image, *button;
|
||||
Ecore_Animator *animator;
|
||||
char buf[64];
|
||||
AppInfo *info = (AppInfo *)calloc(sizeof(AppInfo), 1);
|
||||
|
||||
//LAYOUT
|
||||
layout = elm_layout_add(parent);
|
||||
evas_object_show(layout);
|
||||
evas_object_size_hint_weight_set(layout, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
|
||||
|
||||
std::string edjPath = DEMO_DIR;
|
||||
edjPath +="layout.edj";
|
||||
|
||||
elm_layout_file_set(layout, edjPath.c_str(), "layout");
|
||||
|
||||
//LOTTIEVIEW
|
||||
LottieView *view = new LottieView(evas_object_evas_get(layout), Strategy::renderCppAsync);
|
||||
view->setFilePath(file);
|
||||
view->setSize(500, 500);
|
||||
|
||||
//IMAGE from LOTTIEVIEW
|
||||
image = view->getImage();
|
||||
evas_object_show(image);
|
||||
elm_object_part_content_set(layout, "lottie", image);
|
||||
|
||||
//SLIDER
|
||||
slider = elm_slider_add(layout);
|
||||
elm_object_part_content_set(layout, "slider", slider);
|
||||
elm_slider_step_set(slider, 0.01);
|
||||
evas_object_smart_callback_add(slider, "changed", _slider_cb, (void *)info);
|
||||
|
||||
button = elm_button_add(layout);
|
||||
elm_object_text_set(button, "Start");
|
||||
elm_object_part_content_set(layout, "button", button);
|
||||
evas_object_smart_callback_add(button, "clicked", _button_clicked_cb, (void *)info);
|
||||
|
||||
animator = ecore_animator_add(_animator_cb, info);
|
||||
|
||||
info->view = view;
|
||||
info->layout = layout;
|
||||
info->slider = slider;
|
||||
info->button = button;
|
||||
info->animator = animator;
|
||||
evas_object_event_callback_add(layout, EVAS_CALLBACK_DEL, _layout_del_cb, (void *)info);
|
||||
|
||||
sprintf(buf, "%d / %ld", 0, view->getTotalFrame());
|
||||
elm_object_part_text_set(layout, "text", buf);
|
||||
|
||||
view->seek(0.0);
|
||||
return layout;
|
||||
}
|
||||
|
||||
static void
|
||||
_gl_selected_cb(void *data, Evas_Object */*obj*/, void *event_info)
|
||||
{
|
||||
Evas_Object *nf = (Evas_Object *)data;
|
||||
Elm_Object_Item *it = (Elm_Object_Item *)event_info;
|
||||
elm_genlist_item_selected_set(it, EINA_FALSE);
|
||||
|
||||
Evas_Object *layout = create_layout(nf, jsonFiles[elm_genlist_item_index_get(it) - 1].c_str());
|
||||
elm_naviframe_item_push(nf, NULL, NULL, NULL, layout, NULL);
|
||||
}
|
||||
|
||||
static char *
|
||||
_gl_text_get(void *data, Evas_Object */*obj*/, const char */*part*/)
|
||||
{
|
||||
ItemData *id = (ItemData *) data;
|
||||
const char *ptr = strrchr(jsonFiles[id->index].c_str(), '/');
|
||||
int len = int(ptr + 1 - jsonFiles[id->index].c_str()); // +1 to include '/'
|
||||
return strdup(jsonFiles[id->index].substr(len).c_str());
|
||||
}
|
||||
|
||||
static void
|
||||
_gl_del(void */*data*/, Evas_Object */*obj*/)
|
||||
{
|
||||
}
|
||||
|
||||
EAPI_MAIN int
|
||||
elm_main(int argc EINA_UNUSED, char **argv EINA_UNUSED)
|
||||
{
|
||||
Evas_Object *win, *nf, *genlist;
|
||||
Elm_Genlist_Item_Class *itc = elm_genlist_item_class_new();
|
||||
ItemData *itemData;
|
||||
|
||||
|
||||
if (argc > 1) {
|
||||
if (!strcmp(argv[1], "--disable-render"))
|
||||
renderMode = false;
|
||||
}
|
||||
|
||||
//WIN
|
||||
elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED);
|
||||
win = elm_win_util_standard_add("lottie", "LottieViewer");
|
||||
elm_win_autodel_set(win, EINA_TRUE);
|
||||
evas_object_resize(win, 500, 700);
|
||||
evas_object_show(win);
|
||||
|
||||
//NAVIFRAME
|
||||
nf = elm_naviframe_add(win);
|
||||
evas_object_size_hint_weight_set(nf, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
|
||||
elm_win_resize_object_add(win, nf);
|
||||
evas_object_show(nf);
|
||||
|
||||
//GENLIST
|
||||
genlist = elm_genlist_add(nf);
|
||||
elm_genlist_mode_set(genlist, ELM_LIST_COMPRESS);
|
||||
evas_object_smart_callback_add(genlist, "selected", _gl_selected_cb, nf);
|
||||
|
||||
itc->item_style = "default";
|
||||
itc->func.text_get = _gl_text_get;
|
||||
itc->func.del = _gl_del;
|
||||
|
||||
jsonFiles = EvasApp::jsonFiles(DEMO_DIR);
|
||||
|
||||
for (uint32_t i = 0; i < jsonFiles.size(); i++) {
|
||||
itemData = (ItemData *)calloc(sizeof(ItemData), 1);
|
||||
itemData->index = i;
|
||||
elm_genlist_item_append(genlist, itc, (void *)itemData, NULL, ELM_GENLIST_ITEM_NONE, NULL, NULL);
|
||||
}
|
||||
|
||||
elm_naviframe_item_push(nf, "Lottie Viewer", NULL, NULL, genlist, NULL);
|
||||
|
||||
elm_run();
|
||||
|
||||
return 0;
|
||||
}
|
||||
ELM_MAIN()
|
170
example/lottieviewtest.cpp
Normal file
170
example/lottieviewtest.cpp
Normal file
|
@ -0,0 +1,170 @@
|
|||
/*
|
||||
* Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved.
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "evasapp.h"
|
||||
#include "lottieview.h"
|
||||
#include<iostream>
|
||||
#include <dirent.h>
|
||||
#include <stdio.h>
|
||||
#include <chrono>
|
||||
using namespace std;
|
||||
|
||||
static Eina_Bool onTestDone(void *data);
|
||||
/*
|
||||
* To check the frame rate with rendermode off run
|
||||
* ECORE_EVAS_FPS_DEBUG=1 ./lottieviewTest --disable-render
|
||||
*
|
||||
* To check the frame rate with render backend
|
||||
* ECORE_EVAS_FPS_DEBUG=1 ./lottieviewTest
|
||||
*
|
||||
*/
|
||||
|
||||
class LottieViewTest
|
||||
{
|
||||
public:
|
||||
LottieViewTest(EvasApp *app, Strategy st, double timeout) {
|
||||
mStartTime = std::chrono::high_resolution_clock::now();
|
||||
mStrategy = st;
|
||||
mApp = app;
|
||||
|
||||
if (timeout > 0) {
|
||||
ecore_timer_add(timeout, onTestDone, mApp);
|
||||
}
|
||||
// work around for 60fps
|
||||
ecore_animator_frametime_set(1.0f/120.0f);
|
||||
}
|
||||
|
||||
void show(int numberOfImage) {
|
||||
auto resource = EvasApp::jsonFiles(std::string(DEMO_DIR));
|
||||
|
||||
if (resource.empty()) return;
|
||||
|
||||
int count = numberOfImage;
|
||||
int colums = (int) ceil(sqrt(count));
|
||||
int offset = 3;
|
||||
int vw = (mApp->width() - (offset * colums))/colums;
|
||||
int vh = vw;
|
||||
int posx = offset;
|
||||
int posy = offset;
|
||||
int resourceSize = resource.size();
|
||||
for (int i = 0 ; i < numberOfImage; i++) {
|
||||
int index = i % resourceSize;
|
||||
std::unique_ptr<LottieView> view(new LottieView(mApp->evas(), mStrategy));
|
||||
view->setFilePath(resource[index].c_str());
|
||||
view->setPos(posx, posy);
|
||||
view->setSize(vw, vh);
|
||||
view->show();
|
||||
view->play();
|
||||
view->loop(true);
|
||||
//view->setRepeatMode(LottieView::RepeatMode::Reverse);
|
||||
posx += vw+offset;
|
||||
if ((mApp->width() - posx) < vw) {
|
||||
posx = offset;
|
||||
posy = posy + vh + offset;
|
||||
}
|
||||
mViews.push_back(std::move(view));
|
||||
}
|
||||
}
|
||||
|
||||
~LottieViewTest() {
|
||||
const auto frames = mViews.empty() ? 0 : mViews[0]->renderCount();
|
||||
const double secs = std::chrono::duration<double>(std::chrono::high_resolution_clock::now() - mStartTime).count();
|
||||
std::cout<<"\tTestTime : "<< secs<<" sec \n\tTotalFrames : "<<frames<<"\n\tFramesPerSecond : "<< frames / secs <<" fps\n";
|
||||
}
|
||||
|
||||
static int help() {
|
||||
printf("Usage ./lottieviewTest [-s] [strategy] [-t] [timeout] [-c] [count]\n");
|
||||
printf("\n \t-t : timeout duration in seconds\n");
|
||||
printf("\n \t-c : number of resource in the grid\n");
|
||||
printf("\n \t-s : Rendering Strategy\n");
|
||||
printf("\t\t 0 - Test Lottie SYNC Renderer with CPP API\n");
|
||||
printf("\t\t 1 - Test Lottie ASYNC Renderer with CPP API\n");
|
||||
printf("\t\t 2 - Test Lottie SYNC Renderer with C API\n");
|
||||
printf("\t\t 3 - Test Lottie ASYNC Renderer with C API\n");
|
||||
printf("\t\t 4 - Test Lottie Tree Api using Efl VG Render\n");
|
||||
printf(" Default : ./lottieviewTest -s 1 \n");
|
||||
return 0;
|
||||
}
|
||||
public:
|
||||
EvasApp *mApp;
|
||||
Strategy mStrategy;
|
||||
std::vector<std::unique_ptr<LottieView>> mViews;
|
||||
std::chrono::high_resolution_clock::time_point mStartTime;
|
||||
};
|
||||
|
||||
static void
|
||||
onExitCb(void *data, void */*extra*/)
|
||||
{
|
||||
LottieViewTest *view = (LottieViewTest *)data;
|
||||
delete view;
|
||||
}
|
||||
|
||||
|
||||
static Eina_Bool
|
||||
onTestDone(void *data)
|
||||
{
|
||||
EvasApp *app = (EvasApp *)data;
|
||||
app->exit();
|
||||
return ECORE_CALLBACK_CANCEL;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
Strategy st = Strategy::renderCppAsync;
|
||||
auto index = 0;
|
||||
double timeOut = 0;
|
||||
size_t itemCount = 250;
|
||||
while (index < argc) {
|
||||
const char* option = argv[index];
|
||||
index++;
|
||||
if (!strcmp(option,"--help") || !strcmp(option,"-h")) {
|
||||
return LottieViewTest::help();
|
||||
} else if (!strcmp(option,"-s")) {
|
||||
st = (index < argc) ? static_cast<Strategy>(atoi(argv[index])) : Strategy::renderCppAsync;
|
||||
index++;
|
||||
} else if (!strcmp(option,"-t")) {
|
||||
timeOut = (index < argc) ? atoi(argv[index]) : 10;
|
||||
index++;
|
||||
} else if (!strcmp(option,"-c")) {
|
||||
itemCount = (index < argc) ? atoi(argv[index]) : 10;
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
EvasApp *app = new EvasApp(800, 800);
|
||||
app->setup();
|
||||
|
||||
LottieViewTest *view = new LottieViewTest(app, st, timeOut);
|
||||
view->show(itemCount);
|
||||
|
||||
app->addExitCb(onExitCb, view);
|
||||
|
||||
app->run();
|
||||
delete app;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
74
example/meson.build
Normal file
74
example/meson.build
Normal file
|
@ -0,0 +1,74 @@
|
|||
|
||||
override_default = ['warning_level=2', 'werror=false']
|
||||
|
||||
common_source = files('evasapp.cpp')
|
||||
common_source += files('lottieview.cpp')
|
||||
|
||||
demo_sources = files('demo.cpp')
|
||||
demo_sources += common_source
|
||||
|
||||
executable('lottie2gif',
|
||||
'lottie2gif.cpp',
|
||||
include_directories : inc,
|
||||
override_options : override_default,
|
||||
link_with : rlottie_lib)
|
||||
|
||||
if host_machine.system() != 'windows'
|
||||
executable('perf',
|
||||
'lottieperf.cpp',
|
||||
include_directories : inc,
|
||||
override_options : override_default,
|
||||
link_with : rlottie_lib)
|
||||
endif
|
||||
|
||||
demo_dep = dependency('elementary', required : false, disabler : true)
|
||||
|
||||
executable('demo',
|
||||
demo_sources,
|
||||
include_directories : inc,
|
||||
override_options : override_default,
|
||||
link_with : rlottie_lib,
|
||||
dependencies : demo_dep)
|
||||
|
||||
|
||||
demo_marker_sources = files('demo_marker.cpp')
|
||||
demo_marker_sources += common_source
|
||||
|
||||
executable('demo_marker',
|
||||
demo_marker_sources,
|
||||
include_directories : inc,
|
||||
override_options : override_default,
|
||||
link_with : rlottie_lib,
|
||||
dependencies : demo_dep)
|
||||
|
||||
lottieview_test_src = files('lottieviewtest.cpp')
|
||||
lottieview_test_src += common_source
|
||||
|
||||
executable('lottieviewTest',
|
||||
lottieview_test_src,
|
||||
include_directories : inc,
|
||||
override_options : override_default,
|
||||
link_with : rlottie_lib,
|
||||
dependencies : demo_dep)
|
||||
|
||||
uxsample_test_src = files('uxsampletest.cpp')
|
||||
uxsample_test_src += common_source
|
||||
|
||||
executable('uxsampleTest',
|
||||
uxsample_test_src,
|
||||
include_directories : inc,
|
||||
override_options : override_default,
|
||||
link_with : rlottie_lib,
|
||||
dependencies : demo_dep)
|
||||
|
||||
lottieviewer_sources = files('lottieviewer.cpp')
|
||||
lottieviewer_sources += common_source
|
||||
|
||||
executable('lottieviewer',
|
||||
lottieviewer_sources,
|
||||
include_directories : inc,
|
||||
override_options : override_default,
|
||||
link_with : rlottie_lib,
|
||||
dependencies : demo_dep)
|
||||
|
||||
|
130
example/pathtest.cpp
Normal file
130
example/pathtest.cpp
Normal file
|
@ -0,0 +1,130 @@
|
|||
/*
|
||||
* Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved.
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "evasapp.h"
|
||||
#include"vpath.h"
|
||||
#include<iostream>
|
||||
using namespace std;
|
||||
|
||||
EvasApp *APP;
|
||||
|
||||
static void
|
||||
_on_resize(Ecore_Evas *ee)
|
||||
{
|
||||
int w, h;
|
||||
ecore_evas_geometry_get(ee, NULL, NULL, &w, &h);
|
||||
APP->resize(w, h);
|
||||
}
|
||||
|
||||
class PathTest
|
||||
{
|
||||
public:
|
||||
PathTest(EvasApp *app) {
|
||||
mApp = app;
|
||||
mShape = evas_vg_shape_add(mApp->root());
|
||||
}
|
||||
void setColor(int r, int g, int b, int a) {
|
||||
evas_vg_node_color_set(mShape, r, g, b, a);
|
||||
}
|
||||
|
||||
void setStrokeColor(int r, int g, int b, int a) {
|
||||
evas_vg_shape_stroke_color_set(mShape, r, g, b, a);
|
||||
}
|
||||
|
||||
void setStrokeWidth(int w) {
|
||||
evas_vg_shape_stroke_width_set(mShape, w);
|
||||
}
|
||||
|
||||
void setPath(const VPath &path) {
|
||||
Efl_VG *shape = mShape;
|
||||
evas_vg_shape_reset(shape);
|
||||
const std::vector<VPath::Element> &elm = path.elements();
|
||||
const std::vector<VPointF> &pts = path.points();
|
||||
int i=0;
|
||||
for (auto e : elm) {
|
||||
switch(e) {
|
||||
case VPath::Element::MoveTo:
|
||||
{
|
||||
VPointF p = pts[i++];
|
||||
evas_vg_shape_append_move_to(shape, p.x(), p.y());
|
||||
break;
|
||||
}
|
||||
case VPath::Element::LineTo:
|
||||
{
|
||||
VPointF p = pts[i++];
|
||||
evas_vg_shape_append_line_to(shape, p.x(), p.y());
|
||||
break;
|
||||
}
|
||||
case VPath::Element::CubicTo:
|
||||
{
|
||||
VPointF p = pts[i++];
|
||||
VPointF p1 = pts[i++];
|
||||
VPointF p2 = pts[i++];
|
||||
evas_vg_shape_append_cubic_to(shape, p.x(), p.y(), p1.x(), p1.y(), p2.x(), p2.y());
|
||||
break;
|
||||
}
|
||||
case VPath::Element::Close:
|
||||
{
|
||||
evas_vg_shape_append_close(shape);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
EvasApp *mApp;
|
||||
Efl_VG *mShape;
|
||||
};
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
APP = new EvasApp(800, 800);
|
||||
ecore_evas_callback_resize_set(APP->mEcoreEvas, _on_resize);
|
||||
APP->setup();
|
||||
|
||||
VPath path;
|
||||
path.addRoundRect(VRectF(100, 100, 200, 200), 20, 20, VPath::Direction::CCW);
|
||||
path.addCircle(50, 50, 20, VPath::Direction::CCW);
|
||||
|
||||
path.addOval(VRectF(300, 100, 100, 50), VPath::Direction::CCW);
|
||||
|
||||
path.addPolystar(15.0, 106.0, 34.0, 0.0, 150,
|
||||
150, 231.0, 88.0, VPath::Direction::CW);
|
||||
|
||||
PathTest test(APP);
|
||||
test.setPath(path);
|
||||
test.setColor(255, 0, 0, 255);
|
||||
test.setStrokeColor(200, 200, 0, 200);
|
||||
test.setStrokeWidth(5);
|
||||
|
||||
|
||||
APP->run();
|
||||
delete APP;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
1
example/resource/1643-exploding-star.json
Normal file
1
example/resource/1643-exploding-star.json
Normal file
File diff suppressed because one or more lines are too long
1
example/resource/1667-firework.json
Normal file
1
example/resource/1667-firework.json
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
example/resource/29056-nepenthe-illustration.json
Normal file
1
example/resource/29056-nepenthe-illustration.json
Normal file
File diff suppressed because one or more lines are too long
1
example/resource/360º_degree.json
Normal file
1
example/resource/360º_degree.json
Normal file
File diff suppressed because one or more lines are too long
1
example/resource/3d.json
Normal file
1
example/resource/3d.json
Normal file
|
@ -0,0 +1 @@
|
|||
{"v":"5.2.1","fr":60,"ip":0,"op":60,"w":500,"h":500,"nm":"Comp 1","ddd":1,"assets":[],"layers":[{"ddd":1,"ind":1,"ty":4,"nm":"Shape Layer 3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"rx":{"a":0,"k":0,"ix":8},"ry":{"a":0,"k":0,"ix":9},"rz":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":0,"s":[0],"e":[360]},{"t":55}],"ix":10},"or":{"a":0,"k":[0,0,0],"ix":7},"p":{"a":0,"k":[75,384,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"rc","d":1,"s":{"a":0,"k":[100,100],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.075893886387,0.175385013223,0.921568632126,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":0,"op":60,"st":0,"bm":0},{"ddd":1,"ind":2,"ty":4,"nm":"Shape Layer 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"rx":{"a":0,"k":0,"ix":8},"ry":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":0,"s":[0],"e":[360]},{"t":55}],"ix":9},"rz":{"a":0,"k":0,"ix":10},"or":{"a":0,"k":[0,0,0],"ix":7},"p":{"a":0,"k":[76,234,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"rc","d":1,"s":{"a":0,"k":[100,100],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.025943866,0.945098042488,0.134079754353,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":0,"op":60,"st":0,"bm":0},{"ddd":1,"ind":3,"ty":4,"nm":"Shape Layer 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"rx":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":0,"s":[0],"e":[360]},{"t":55}],"ix":8},"ry":{"a":0,"k":0,"ix":9},"rz":{"a":0,"k":0,"ix":10},"or":{"a":0,"k":[0,0,0],"ix":7},"p":{"a":0,"k":[76,72,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"rc","d":1,"s":{"a":0,"k":[100,100],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":0,"op":60,"st":0,"bm":0}],"markers":[]}
|
1
example/resource/4479-fireworks.json
Normal file
1
example/resource/4479-fireworks.json
Normal file
File diff suppressed because one or more lines are too long
1
example/resource/5317-fireworkds.json
Normal file
1
example/resource/5317-fireworkds.json
Normal file
File diff suppressed because one or more lines are too long
1
example/resource/5344-honey-sack-hud.json
Normal file
1
example/resource/5344-honey-sack-hud.json
Normal file
File diff suppressed because one or more lines are too long
1
example/resource/Indicators1.json
Normal file
1
example/resource/Indicators1.json
Normal file
File diff suppressed because one or more lines are too long
1
example/resource/ModernPictogramsForLottie_LoudMute.json
Normal file
1
example/resource/ModernPictogramsForLottie_LoudMute.json
Normal file
File diff suppressed because one or more lines are too long
1
example/resource/StickAndBall.json
Normal file
1
example/resource/StickAndBall.json
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
example/resource/_alarm.json
Normal file
1
example/resource/_alarm.json
Normal file
File diff suppressed because one or more lines are too long
1
example/resource/a_cup_of_coffee.json
Normal file
1
example/resource/a_cup_of_coffee.json
Normal file
File diff suppressed because one or more lines are too long
1
example/resource/a_mountain.json
Normal file
1
example/resource/a_mountain.json
Normal file
File diff suppressed because one or more lines are too long
1
example/resource/abstract_circle.json
Normal file
1
example/resource/abstract_circle.json
Normal file
|
@ -0,0 +1 @@
|
|||
{"v":"5.1.16","fr":15,"ip":0,"op":51,"w":500,"h":500,"nm":"El 28","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Circle Abstract","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":49,"s":[100],"e":[0]},{"t":51}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[250.316,250.684,0],"ix":2},"a":{"a":0,"k":[280,0,0],"ix":1},"s":{"a":0,"k":[225,225,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[145,145],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.190695878571,0.889764404297,0.972549019608,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.583]},"o":{"x":[0.01],"y":[0.006]},"n":["0p833_0p583_0p01_0p006"],"t":22.2,"s":[3],"e":[0]},{"t":49.2001953125}],"ix":5},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[236,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.99,0.99],"y":[0.997,0.997]},"o":{"x":[1,1],"y":[1,1]},"n":["0p99_0p997_1_1","0p99_0p997_1_1"],"t":0,"s":[0,0],"e":[50,50]},{"i":{"x":[0.833,0.833],"y":[0.676,0.676]},"o":{"x":[0.01,0.01],"y":[0.043,0.043]},"n":["0p833_0p676_0p01_0p043","0p833_0p676_0p01_0p043"],"t":6,"s":[50,50],"e":[75,75]},{"t":49.2001953125}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"rp","c":{"a":1,"k":[{"i":{"x":[0.99],"y":[0.985]},"o":{"x":[1],"y":[2.692]},"n":["0p99_0p985_1_2p692"],"t":0,"s":[0],"e":[18]},{"i":{"x":[0.833],"y":[0.288]},"o":{"x":[0.01],"y":[-0.02]},"n":["0p833_0p288_0p01_-0p02"],"t":21,"s":[18],"e":[0]},{"t":49.2001953125}],"ix":1},"o":{"a":0,"k":5,"ix":2},"m":1,"ix":2,"tr":{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[280,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":20,"ix":4},"so":{"a":0,"k":100,"ix":5},"eo":{"a":0,"k":100,"ix":6},"nm":"Transform"},"nm":"Repeater 1","mn":"ADBE Vector Filter - Repeater","hd":false}],"ip":0,"op":51,"st":0,"bm":0}],"markers":[]}
|
1
example/resource/acrobatics.json
Normal file
1
example/resource/acrobatics.json
Normal file
File diff suppressed because one or more lines are too long
1
example/resource/anubis.json
Normal file
1
example/resource/anubis.json
Normal file
File diff suppressed because one or more lines are too long
1
example/resource/ao.json
Normal file
1
example/resource/ao.json
Normal file
|
@ -0,0 +1 @@
|
|||
{"v":"5.2.1","fr":60,"ip":0,"op":60,"w":500,"h":500,"nm":"Comp 1","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[250,250,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"rc","d":1,"s":{"a":0,"k":[100,100],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ind":2,"ty":"sh","ix":3,"ks":{"a":0,"k":{"i":[[-89.47,0],[0,-89.47],[89.47,0],[0,89.47]],"o":[[89.47,0],[0,89.47],[-89.47,0],[0,-89.47]],"v":[[0,-162],[162,0],[0,162],[-162,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"ml2":{"a":0,"k":4,"ix":8},"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false}],"ip":0,"op":60,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Shape Layer 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.562,"y":0.562},"o":{"x":0.167,"y":0.167},"n":"0p562_0p562_0p167_0p167","t":8,"s":[250,88,0],"e":[412,250,0],"to":[89.4701232910156,0,0],"ti":[0,-89.4701232910156,0]},{"i":{"x":0.656,"y":0.656},"o":{"x":0.311,"y":0.311},"n":"0p656_0p656_0p311_0p311","t":38,"s":[412,250,0],"e":[250,412,0],"to":[0,89.4701232910156,0],"ti":[89.4701232910156,0,0]},{"i":{"x":0.689,"y":0.689},"o":{"x":0.343,"y":0.343},"n":"0p689_0p689_0p343_0p343","t":68,"s":[250,412,0],"e":[88,250,0],"to":[-89.4701232910156,0,0],"ti":[0,89.4701232910156,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.437,"y":0.437},"n":"0p833_0p833_0p437_0p437","t":98,"s":[88,250,0],"e":[250,88,0],"to":[0,-89.4701232910156,0],"ti":[-89.4701232910156,0,0]},{"t":128}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":1,"shapes":[{"ty":"rc","d":1,"s":{"a":0,"k":[100,100],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"ml2":{"a":0,"k":4,"ix":8},"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false}],"ip":0,"op":60,"st":0,"bm":0}],"markers":[]}
|
1
example/resource/balloons_with_string.json
Normal file
1
example/resource/balloons_with_string.json
Normal file
File diff suppressed because one or more lines are too long
1
example/resource/bell.json
Normal file
1
example/resource/bell.json
Normal file
File diff suppressed because one or more lines are too long
1
example/resource/birth_stone_logo.json
Normal file
1
example/resource/birth_stone_logo.json
Normal file
|
@ -0,0 +1 @@
|
|||
{"v":"5.2.1","fr":29.9700012207031,"ip":0,"op":120.0000048877,"w":150,"h":120,"nm":"logo 2","ddd":1,"assets":[],"layers":[{"ddd":0,"ind":2,"ty":4,"nm":"Shape Layer 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[98,45.5,0],"ix":2},"a":{"a":0,"k":[-23,-14.5,0],"ix":1},"s":{"a":0,"k":[-100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[19.25,-19.25],[0,0],[0,0]],"o":[[0,0],[0,0],[-20.25,20.25],[0,0],[0,0]],"v":[[19.5,-14],[-12.5,-45.25],[-51.25,-42.25],[-55.75,-5.25],[-23,28.75]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gs","o":{"a":0,"k":100,"ix":9},"w":{"a":0,"k":8,"ix":10},"g":{"p":3,"k":{"a":0,"k":[0,0.584,0.894,0.929,0.5,0.692,0.733,0.965,1,0.8,0.573,1],"ix":8}},"s":{"a":0,"k":[-64.303,-9.492],"ix":4},"e":{"a":0,"k":[23.721,-13.33],"ix":5},"t":1,"lc":2,"lj":2,"nm":"Gradient Stroke 1","mn":"ADBE Vector Graphic - G-Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":100,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"n":["0p667_1_0p333_0"],"t":30,"s":[100],"e":[0]},{"t":60.0000024438501}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":120.0000048877,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Shape Layer 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[75,60,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[22.75,-19.25],[0,0],[0,0]],"o":[[0,0],[0,0],[-19.75,19.75],[0,0],[0,0]],"v":[[19.5,-14],[-12.5,-45.25],[-51.25,-42.25],[-55.75,-5.25],[-23,28.75]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gs","o":{"a":0,"k":100,"ix":9},"w":{"a":0,"k":8,"ix":10},"g":{"p":3,"k":{"a":0,"k":[0,1,0.788,0.6,0.5,0.902,0.682,0.798,1,0.804,0.576,0.996],"ix":8}},"s":{"a":0,"k":[-64.303,-9.492],"ix":4},"e":{"a":0,"k":[23.721,-13.33],"ix":5},"t":1,"lc":2,"lj":2,"nm":"Gradient Stroke 1","mn":"ADBE Vector Graphic - G-Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":100,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"n":["0p667_1_0p333_0"],"t":0,"s":[100],"e":[0]},{"t":30.0000012219251}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":120.0000048877,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Shape Layer 3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[75.5,103,0],"ix":2},"a":{"a":0,"k":[0,42.5,0],"ix":1},"s":{"a":0,"k":[91.956,91.956,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[18.648,18.648],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.8,0.572549019608,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,42.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":100,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"n":["0p667_1_0p333_0"],"t":60,"s":[100],"e":[0]},{"t":89.0000036250443}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":120.0000048877,"st":0,"bm":0}],"markers":[]}
|
1
example/resource/bounching_ball.json
Normal file
1
example/resource/bounching_ball.json
Normal file
File diff suppressed because one or more lines are too long
1
example/resource/browser.json
Normal file
1
example/resource/browser.json
Normal file
File diff suppressed because one or more lines are too long
1
example/resource/confetti.json
Normal file
1
example/resource/confetti.json
Normal file
File diff suppressed because one or more lines are too long
1
example/resource/cooking.json
Normal file
1
example/resource/cooking.json
Normal file
File diff suppressed because one or more lines are too long
1
example/resource/dna.json
Normal file
1
example/resource/dna.json
Normal file
File diff suppressed because one or more lines are too long
1
example/resource/done.json
Normal file
1
example/resource/done.json
Normal file
|
@ -0,0 +1 @@
|
|||
{"v":"4.11.1","fr":29.9700012207031,"ip":0,"op":76.0000030955435,"w":70,"h":70,"nm":"Comp 1","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[35,35,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"n":["0p667_1_0p333_0","0p667_1_0p333_0","0p667_1_0p333_0"],"t":33,"s":[0,0,100],"e":[120,120,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"n":["0p667_1_0p333_0","0p667_1_0p333_0","0p667_1_0p333_0"],"t":46,"s":[120,120,100],"e":[100,100,100]},{"t":52.0000021180034}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-7,1.438],[-2.656,5.781],[7.422,-4.297]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"n":["0p667_1_0p333_0"],"t":33,"s":[0],"e":[100]},{"t":52.0000021180034}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":450.000018328876,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Shape Layer 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[35,35,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"n":["0p667_1_0p333_0","0p667_1_0p333_0","0p667_1_0p333_0"],"t":18,"s":[0,0,100],"e":[120,120,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"n":["0p667_1_0p333_0","0p667_1_0p333_0","0p667_1_0p333_0"],"t":33,"s":[120,120,100],"e":[80,80,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"n":["0p667_1_0p333_0","0p667_1_0p333_0","0p667_1_0p333_0"],"t":41,"s":[80,80,100],"e":[110,110,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"n":["0p667_1_0p333_0","0p667_1_0p333_0","0p667_1_0p333_0"],"t":49,"s":[110,110,100],"e":[100,100,100]},{"t":52.0000021180034}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[13.015,0],[0,-13.015],[-13.015,0],[0,13.015]],"o":[[-13.015,0],[0,13.015],[13.015,0],[0,-13.015]],"v":[[0,-23.566],[-23.566,0],[0,23.566],[23.566,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.898039215686,0.898039215686,0.898039215686,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"ix":5},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0.760784313725,0.2,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[105.535,105.535],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":450.000018328876,"st":0,"bm":0}]}
|
1
example/resource/dynamic_path_test.json
Normal file
1
example/resource/dynamic_path_test.json
Normal file
|
@ -0,0 +1 @@
|
|||
{"v":"5.1.17","fr":29.9700012207031,"ip":0,"op":150.000006109625,"w":300,"h":300,"nm":"Comp 1","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[150,150,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"n":["0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167"],"t":20,"s":[135,135],"e":[116,116]},{"t":137.000005580124}],"ix":2},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":20,"s":[24,25],"e":[57,52],"to":[5.5,4.5],"ti":[-5.5,-4.5]},{"t":129.000005254278}],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":0,"s":[0],"e":[54]},{"t":149.000006068894}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"n":["0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167"],"t":0,"s":[100,100],"e":[50,50]},{"t":40.0000016292334}],"ix":2},"p":{"a":0,"k":[-26,-37],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.145327582955,0.057777773589,0.866666674614,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 2","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"sr","sy":1,"d":1,"pt":{"a":0,"k":5,"ix":3},"p":{"a":0,"k":[26,-54],"ix":4},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":110,"s":[0],"e":[184]},{"t":149.000006068894}],"ix":5},"ir":{"a":0,"k":30,"ix":6},"is":{"a":0,"k":27,"ix":8},"or":{"a":0,"k":59,"ix":7},"os":{"a":0,"k":73,"ix":9},"ix":5,"nm":"Polystar Path 1","mn":"ADBE Vector Shape - Star","hd":false},{"ty":"fl","c":{"a":0,"k":[0.07993286103,0.716212213039,0.766274511814,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 3","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":0,"op":150.000006109625,"st":0,"bm":0}],"markers":[]}
|
1
example/resource/dynamic_property.json
Normal file
1
example/resource/dynamic_property.json
Normal file
File diff suppressed because one or more lines are too long
1
example/resource/eid_mubarak.json
Normal file
1
example/resource/eid_mubarak.json
Normal file
File diff suppressed because one or more lines are too long
1
example/resource/emoji_shock.json
Normal file
1
example/resource/emoji_shock.json
Normal file
File diff suppressed because one or more lines are too long
1
example/resource/emoji_wink.json
Normal file
1
example/resource/emoji_wink.json
Normal file
File diff suppressed because one or more lines are too long
1
example/resource/file_transfer.json
Normal file
1
example/resource/file_transfer.json
Normal file
File diff suppressed because one or more lines are too long
1
example/resource/fingerprint_success.json
Normal file
1
example/resource/fingerprint_success.json
Normal file
File diff suppressed because one or more lines are too long
1
example/resource/funky_chicken.json
Normal file
1
example/resource/funky_chicken.json
Normal file
File diff suppressed because one or more lines are too long
1
example/resource/gears.json
Normal file
1
example/resource/gears.json
Normal file
File diff suppressed because one or more lines are too long
1
example/resource/gears_or_settings.json
Normal file
1
example/resource/gears_or_settings.json
Normal file
File diff suppressed because one or more lines are too long
1
example/resource/glow_loading.json
Normal file
1
example/resource/glow_loading.json
Normal file
File diff suppressed because one or more lines are too long
1
example/resource/gradient_animated_background.json
Normal file
1
example/resource/gradient_animated_background.json
Normal file
|
@ -0,0 +1 @@
|
|||
{"v":"4.6.10","fr":15,"ip":0,"op":155,"w":1080,"h":1920,"nm":"background","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 1","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[540,960,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[1160,880]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":0},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect"},{"ty":"st","c":{"a":0,"k":[0.9960784,0.7843137,0.145098,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":6},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke"},{"ty":"gf","o":{"a":0,"k":100},"r":1,"g":{"p":3,"k":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":0,"s":[0,0.511,0.89,0.283,0.5,0.334,0.873,0.583,1,0.156,0.857,0.882],"e":[0,0.726,0.283,0.89,0.5,0.441,0.356,0.886,1,0.156,0.429,0.882]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":31,"s":[0,0.726,0.283,0.89,0.5,0.441,0.356,0.886,1,0.156,0.429,0.882],"e":[0,0.89,0.283,0.283,0.5,0.886,0.553,0.219,1,0.882,0.823,0.156]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":61,"s":[0,0.89,0.283,0.283,0.5,0.886,0.553,0.219,1,0.882,0.823,0.156],"e":[0,0,0.312,0.737,0.5,0.078,0.597,0.754,1,0.156,0.882,0.771]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":91,"s":[0,0,0.312,0.737,0.5,0.078,0.597,0.754,1,0.156,0.882,0.771],"e":[0,0.51,0.89,0.282,0.5,0.333,0.873,0.582,1,0.157,0.855,0.882]},{"t":120}]}},"s":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":0,"s":[-430.769,-404.573],"e":[23.726,-364.48],"to":[75.7491683959961,6.68213844299316],"ti":[-123.915840148926,-8.51547145843506]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":31,"s":[23.726,-364.48],"e":[312.726,-353.48],"to":[123.915840148926,8.51547145843506],"ti":[-1.00208830833435,-1.83333337306976]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":61,"s":[312.726,-353.48],"e":[29.739,-353.48],"to":[1.00208830833435,1.83333337306976],"ti":[120.055290222168,0.60746711492538]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":91,"s":[29.739,-353.48],"e":[-407.606,-357.125],"to":[-120.055290222168,-0.60746711492538],"ti":[72.8907089233398,0.60746711492538]},{"t":120}]},"e":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":0,"s":[374.412,342.611],"e":[22.822,357.191],"to":[-58.5984153747559,2.42986845970154],"ti":[132.520950317383,-7.89707231521606]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":31,"s":[22.822,357.191],"e":[-420.714,389.994],"to":[-132.520950317383,7.89707231521606],"ti":[-4.68509674072266,-7.89707231521606]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":61,"s":[-420.714,389.994],"e":[50.932,404.573],"to":[4.68509674072266,7.89707231521606],"ti":[-132.918350219727,4.25226974487305]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":91,"s":[50.932,404.573],"e":[376.797,364.48],"to":[132.918350219727,-4.25226974487305],"ti":[-54.3107261657715,6.68213844299316]},{"t":120}]},"t":1,"nm":"Gradient Fill 1","mn":"ADBE Vector Graphic - G-Fill"},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[93.29,219.491],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group"}],"ip":0,"op":155,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":2,"ty":1,"nm":"Deep Red Solid 1","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[540,960,0]},"a":{"a":0,"k":[540,960,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"sw":1080,"sh":1920,"sc":"#be2a2a","ip":0,"op":155,"st":0,"bm":0,"sr":1}]}
|
1
example/resource/gradient_sleepy_loader.json
Normal file
1
example/resource/gradient_sleepy_loader.json
Normal file
|
@ -0,0 +1 @@
|
|||
{"v":"5.1.8","fr":23.9759979248047,"ip":0,"op":240.999979140721,"w":300,"h":300,"nm":"SynthesisProto_Loader","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Layer 2 Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":0,"s":[-180],"e":[180]},{"t":239.999979227274}],"ix":10},"p":{"a":0,"k":[150.125,150,0],"ix":2},"a":{"a":0,"k":[533,533,0],"ix":1},"s":{"a":0,"k":[16,16,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[65.74,-27.805],[48.897,-48.895],[26.837,-63.449],[0,-71.877],[-27.805,-65.739],[-48.894,-48.896],[-63.449,-26.837],[-71.878,0],[-65.739,27.805],[-48.895,48.895],[-26.837,63.449],[0,71.878],[27.805,65.739],[48.896,48.896],[63.449,26.837],[71.877,0]],"o":[[-63.449,26.837],[-48.894,48.896],[-27.805,65.739],[0,71.878],[26.837,63.449],[48.897,48.895],[65.74,27.805],[71.877,0],[63.449,-26.837],[48.896,-48.896],[27.805,-65.739],[0,-71.877],[-26.837,-63.449],[-48.895,-48.895],[-65.739,-27.805],[-71.878,0]],"v":[[-207.395,-490.833],[-376.703,-376.703],[-490.833,-207.394],[-532.735,0],[-490.833,207.393],[-376.703,376.702],[-207.395,490.833],[0,532.735],[207.394,490.833],[376.702,376.702],[490.833,207.393],[532.738,0],[490.833,-207.394],[376.702,-376.703],[207.394,-490.833],[0,-532.738]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[65.201,65.2],[0,92.206],[-65.199,65.2],[-92.207,0],[-65.2,-65.2],[0,-92.206],[65.2,-65.201],[92.206,0]],"o":[[-65.199,-65.201],[0,-92.206],[65.201,-65.2],[92.206,0],[65.2,65.2],[0,92.206],[-65.2,65.2],[-92.207,0]],"v":[[-244.095,244.094],[-345.202,0],[-244.095,-244.094],[0,-345.202],[244.095,-244.094],[345.202,0],[244.095,244.094],[0,345.202]],"c":true},"ix":2},"nm":"Path 3","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gf","o":{"a":0,"k":100,"ix":10},"r":1,"g":{"p":3,"k":{"a":0,"k":[0,0.133,0.063,0.282,0.5,0.386,0.257,0.459,1,0.639,0.451,0.635],"ix":9}},"s":{"a":0,"k":[661,0],"ix":5},"e":{"a":0,"k":[-690,0],"ix":6},"t":1,"nm":"Gradient Fill 1","mn":"ADBE Vector Graphic - G-Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[533,533],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":1,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":720.999937595269,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Layer 1 Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":0,"s":[180],"e":[-180]},{"t":239.999979227274}],"ix":10},"p":{"a":0,"k":[150.125,150,0],"ix":2},"a":{"a":0,"k":[726,726,0],"ix":1},"s":{"a":0,"k":[16,16,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-400.378],[-400.379,0],[0,400.378],[400.378,0]],"o":[[0,400.378],[400.378,0],[0,-400.378],[-400.379,0]],"v":[[-724.948,0],[0,724.949],[724.948,0],[0,-724.949]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gf","o":{"a":0,"k":100,"ix":10},"r":1,"g":{"p":3,"k":{"a":0,"k":[0,0.133,0.063,0.282,0.5,0.386,0.257,0.459,1,0.639,0.451,0.635],"ix":9}},"s":{"a":0,"k":[200,0],"ix":5},"e":{"a":0,"k":[-608,0],"ix":6},"t":1,"nm":"Gradient Fill 1","mn":"ADBE Vector Graphic - G-Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[726,726],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":180,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":1,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":720.999937595269,"st":0,"bm":0}],"markers":[]}
|
1
example/resource/happy.json
Normal file
1
example/resource/happy.json
Normal file
File diff suppressed because one or more lines are too long
1
example/resource/heart.json
Normal file
1
example/resource/heart.json
Normal file
File diff suppressed because one or more lines are too long
1
example/resource/hourglass.json
Normal file
1
example/resource/hourglass.json
Normal file
File diff suppressed because one or more lines are too long
1
example/resource/image_embedded.json
Normal file
1
example/resource/image_embedded.json
Normal file
File diff suppressed because one or more lines are too long
1
example/resource/image_test.json
Normal file
1
example/resource/image_test.json
Normal file
|
@ -0,0 +1 @@
|
|||
{"v":"5.4.3","fr":60,"ip":0,"op":60,"w":800,"h":800,"nm":"test","ddd":0,"assets":[{"id":"image_0","w":200,"h":300,"u":"images/","p":"img_0.png","e":0}],"layers":[{"ddd":0,"ind":1,"ty":2,"nm":"img_0.png","cl":"png","refId":"image_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":0,"s":[0],"e":[56]},{"t":50}],"ix":10},"p":{"a":0,"k":[400,400,0],"ix":2},"a":{"a":0,"k":[100,150,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"n":["0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167"],"t":0,"s":[99,99,100],"e":[152,152,100]},{"t":50}],"ix":6}},"ao":0,"ip":0,"op":60,"st":0,"bm":0}],"markers":[]}
|
BIN
example/resource/images/img_0.png
Normal file
BIN
example/resource/images/img_0.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 99 KiB |
1
example/resource/imprint.json
Normal file
1
example/resource/imprint.json
Normal file
File diff suppressed because one or more lines are too long
1
example/resource/insta_camera.json
Normal file
1
example/resource/insta_camera.json
Normal file
File diff suppressed because one or more lines are too long
1
example/resource/intelia_logo_animation.json
Normal file
1
example/resource/intelia_logo_animation.json
Normal file
File diff suppressed because one or more lines are too long
1
example/resource/it's_lunch_time!.json
Normal file
1
example/resource/it's_lunch_time!.json
Normal file
File diff suppressed because one or more lines are too long
1
example/resource/jolly_walker.json
Normal file
1
example/resource/jolly_walker.json
Normal file
File diff suppressed because one or more lines are too long
93
example/resource/layout.edc
Normal file
93
example/resource/layout.edc
Normal file
|
@ -0,0 +1,93 @@
|
|||
collections {
|
||||
group { "layout";
|
||||
parts {
|
||||
rect { "bg";
|
||||
desc { "default";
|
||||
color: 225 225 225 225;
|
||||
}
|
||||
}
|
||||
spacer { "lottie_base";
|
||||
desc { "default";
|
||||
rel1.to_y: "text";
|
||||
rel1.relative: 0.0 1.0;
|
||||
rel2.to_y: "slider";
|
||||
rel2.relative: 1.0 0.0;
|
||||
}
|
||||
}
|
||||
swallow { "lottie";
|
||||
desc { "default";
|
||||
rel1.to: "lottie_base";
|
||||
rel2.to: "lottie_base";
|
||||
}
|
||||
}
|
||||
text { "text";
|
||||
desc { "default";
|
||||
rel1.relative: 1.0 0.0;
|
||||
rel2.relative: 1.0 0.0;
|
||||
rel1.offset: -20 20;
|
||||
rel2.offset: -20 20;
|
||||
align: 1.0 0.0;
|
||||
color: 0 0 0 255;
|
||||
min: 200 30;
|
||||
text {
|
||||
font: "arial";
|
||||
size: 25;
|
||||
align: 1.0 0.5;
|
||||
}
|
||||
}
|
||||
}
|
||||
swallow { "slider";
|
||||
desc { "default";
|
||||
min: 0 100;
|
||||
max: -1 100;
|
||||
align: 0.5 1.0;
|
||||
rel1.to_x: "left_pad";
|
||||
rel1.relative: 1.0 1.0;
|
||||
rel2.to_x: "button_left_pad";
|
||||
rel2.relative: 0.0 1.0;
|
||||
fixed: 0 1;
|
||||
}
|
||||
}
|
||||
spacer { "left_pad";
|
||||
desc { "default";
|
||||
fixed: 1 0;
|
||||
min: 20 0;
|
||||
align: 0.0 0.5;
|
||||
rel2.relative: 0.0 0.0;
|
||||
}
|
||||
}
|
||||
spacer { "right_pad";
|
||||
desc { "default";
|
||||
fixed: 1 0;
|
||||
min: 20 0;
|
||||
align: 1.0 0.5;
|
||||
rel1.relative: 1.0 0.0;
|
||||
}
|
||||
}
|
||||
swallow { "button";
|
||||
desc { "default";
|
||||
fixed: 1 1;
|
||||
min: 80 55;
|
||||
align: 1.0 0.5;
|
||||
rel1.to_x: "right_pad";
|
||||
rel1.to_y: "slider";
|
||||
rel1.relative: 0.0 0.5;
|
||||
rel2.to_x: "right_pad";
|
||||
rel2.to_y: "slider";
|
||||
rel2.relative: 0.0 0.5;
|
||||
}
|
||||
}
|
||||
spacer { "button_left_pad";
|
||||
desc { "default";
|
||||
fixed: 1 0;
|
||||
min: 20 0;
|
||||
align: 1.0 0.5;
|
||||
rel1.to_x: "button";
|
||||
rel1.relative: 0.0 0.0;
|
||||
rel2.to_x: "button";
|
||||
rel2.relative: 0.0 1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
BIN
example/resource/layout.edj
Normal file
BIN
example/resource/layout.edj
Normal file
Binary file not shown.
1
example/resource/leap_frog_loader.json
Normal file
1
example/resource/leap_frog_loader.json
Normal file
File diff suppressed because one or more lines are too long
1
example/resource/like.json
Normal file
1
example/resource/like.json
Normal file
File diff suppressed because one or more lines are too long
1
example/resource/loader.json
Normal file
1
example/resource/loader.json
Normal file
File diff suppressed because one or more lines are too long
1
example/resource/loader_4.json
Normal file
1
example/resource/loader_4.json
Normal file
|
@ -0,0 +1 @@
|
|||
{"v":"4.6.9","fr":29.9700012207031,"ip":0,"op":34.0000013848484,"w":800,"h":600,"nm":"Loader","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":2,"ty":4,"nm":"Shape Layer 2","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[400,300,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[36.812,0],[0,-19.33],[-19.33,0],[-37.125,0],[0,-19.33],[19.33,0]],"o":[[-19.33,0],[0,19.33],[36.688,0],[19.33,0],[0,19.33],[-37.25,0]],"v":[[-44.844,-35],[-79.844,0],[-44.844,35],[44.844,-35],[79.844,0],[44.844,35]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"st","c":{"a":0,"k":[0.105882,0.105882,0.105882,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":12},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke"},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group"},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"n":["0_1_0p167_0p167"],"t":5.834,"s":[0],"e":[20]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":17.11,"s":[20],"e":[20]},{"i":{"x":[0.611],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"n":["0p611_1_0p167_0p167"],"t":23.334,"s":[20],"e":[40]},{"t":35.0000014255792}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"n":["0_1_0p167_0p167"],"t":0,"s":[12],"e":[32]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":11.666,"s":[32],"e":[32]},{"i":{"x":[0.5],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"n":["0p5_1_0p167_0p167"],"t":17.11,"s":[32],"e":[53]},{"t":29.1662511879657}],"ix":2},"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"n":["0p667_1_0p167_0p167"],"t":0,"s":[-22],"e":[82.925]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"n":["0p667_1_0p167_0p167"],"t":17.11,"s":[82.925],"e":[193]},{"t":35.0000014255792}],"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim"}],"ip":0,"op":300.00001221925,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":3,"ty":4,"nm":"Shape Layer 1","ks":{"o":{"a":0,"k":25},"r":{"a":0,"k":0},"p":{"a":0,"k":[400,300,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[36.812,0],[0,-19.33],[-19.33,0],[-37.125,0],[0,-19.33],[19.33,0]],"o":[[-19.33,0],[0,19.33],[36.688,0],[19.33,0],[0,19.33],[-37.25,0]],"v":[[-44.844,-35],[-79.844,0],[-44.844,35],[44.844,-35],[79.844,0],[44.844,35]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"st","c":{"a":0,"k":[0.105882,0.105882,0.105882,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":12},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke"},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group"}],"ip":0,"op":300.00001221925,"st":0,"bm":0,"sr":1}]}
|
1
example/resource/loader_animation.json
Normal file
1
example/resource/loader_animation.json
Normal file
File diff suppressed because one or more lines are too long
1
example/resource/loading.json
Normal file
1
example/resource/loading.json
Normal file
File diff suppressed because one or more lines are too long
1
example/resource/loading_.json
Normal file
1
example/resource/loading_.json
Normal file
File diff suppressed because one or more lines are too long
1
example/resource/loading_animation.json
Normal file
1
example/resource/loading_animation.json
Normal file
File diff suppressed because one or more lines are too long
1
example/resource/loading_rectangles.json
Normal file
1
example/resource/loading_rectangles.json
Normal file
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue