Merge commit '73411266c1bf07eb0b659102c3376a3739629ff7' as 'external/rlottie'

This commit is contained in:
Leon Styhre 2022-01-06 22:59:15 +01:00
commit deb6dced0f
298 changed files with 65788 additions and 0 deletions

BIN
external/rlottie/.Gifs/1.gif vendored Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

BIN
external/rlottie/.Gifs/2.gif vendored Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 848 KiB

BIN
external/rlottie/.Gifs/logo.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
external/rlottie/.Gifs/rlottie.xcf vendored Normal file

Binary file not shown.

23
external/rlottie/.appveyor.yml vendored Normal file
View 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
external/rlottie/.clang-format vendored Normal file
View 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
external/rlottie/.gitignore vendored Normal file
View file

@ -0,0 +1,13 @@
build
*.creator*
*.config
*.files
*.includes
html
latex
*.swp
tmp
.cproject
.project
.vs
**/*.DS_Store

22
external/rlottie/.travis.yml vendored Normal file
View 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
external/rlottie/AUTHORS vendored Normal file
View 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
external/rlottie/CMakeLists.txt vendored Normal file
View 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
external/rlottie/COPYING vendored Normal file
View 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
external/rlottie/README.md vendored Normal file
View 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
external/rlottie/arm_build.sh vendored Executable file
View 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
external/rlottie/arm_cross.txt vendored Normal file
View 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
external/rlottie/cmake/config.h.in vendored Normal file
View 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

View 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
external/rlottie/example/CMakeLists.txt vendored Normal file
View 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
external/rlottie/example/demo.cpp vendored Normal file
View 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;
}

View 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
external/rlottie/example/evasapp.cpp vendored Normal file
View 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
external/rlottie/example/evasapp.h vendored Normal file
View 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
external/rlottie/example/gif.h vendored Normal file
View 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
external/rlottie/example/lottie2gif.cpp vendored Normal file
View 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
external/rlottie/example/lottieperf.cpp vendored Normal file
View 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
external/rlottie/example/lottieview.cpp vendored Normal file
View 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
external/rlottie/example/lottieview.h vendored Normal file
View 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

View 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()

View 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
external/rlottie/example/meson.build vendored Normal file
View 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
external/rlottie/example/pathtest.cpp vendored Normal file
View 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;
}

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

View 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":[]}

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

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

View 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":[]}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View 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":[]}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View 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":[]}

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

View 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}]}

View 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":[]}

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

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View 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}]}

View 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":[]}

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

View 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":[]}

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

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

View 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;
}
}
}
}
}

Binary file not shown.

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

View 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}]}

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

Some files were not shown because too many files have changed in this diff Show more