325 changed files with 78447 additions and 0 deletions
|
After Width: | Height: | Size: 1.5 MiB |
|
After Width: | Height: | Size: 848 KiB |
|
After Width: | Height: | Size: 11 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
@ -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 "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars64.bat" |
||||
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 |
||||
@ -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 |
||||
... |
||||
|
||||
@ -0,0 +1,14 @@
|
||||
build |
||||
*.creator* |
||||
*.config |
||||
*.files |
||||
*.includes |
||||
html |
||||
latex |
||||
*.swp |
||||
tmp |
||||
.cproject |
||||
.project |
||||
.vs |
||||
**/*.DS_Store |
||||
builddir_wasm |
||||
@ -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 |
||||
@ -0,0 +1,18 @@
|
||||
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> |
||||
Anatoly Korniltsev <korniltsev.anatoly@gmail.com> |
||||
Александр Першин <a.pershin@corp.mail.ru> |
||||
Anton Sergeev <antonsergeev88@gmail.com> |
||||
HyunGu Lee <start3a@gmail.com> |
||||
ChaeLin Shin <chaelinshin96@gmail.com> |
||||
Seungjae Yoon <artium59@gmail.com> |
||||
@ -0,0 +1,208 @@
|
||||
cmake_minimum_required( VERSION 3.16 ) |
||||
|
||||
#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 |
||||
PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/inc> |
||||
PRIVATE |
||||
"${CMAKE_CURRENT_BINARY_DIR}" |
||||
) |
||||
|
||||
#declare common target compilation options |
||||
if(MSVC) |
||||
target_compile_options(rlottie |
||||
PUBLIC |
||||
PRIVATE |
||||
/std:c++14 |
||||
/EHs-c- # disable exceptions |
||||
/GR- # disable RTTI |
||||
/W3 |
||||
) |
||||
else() |
||||
target_compile_options(rlottie |
||||
PUBLIC |
||||
PRIVATE |
||||
-std=c++14 |
||||
-fno-exceptions |
||||
-fno-unwind-tables |
||||
-fno-asynchronous-unwind-tables |
||||
-fno-rtti |
||||
-Wall |
||||
-fvisibility=hidden |
||||
-Wnon-virtual-dtor |
||||
-Woverloaded-virtual |
||||
-Wno-unused-parameter |
||||
) |
||||
endif() |
||||
|
||||
if (WIN32 AND NOT BUILD_SHARED_LIBS) |
||||
target_compile_definitions(rlottie PUBLIC -DRLOTTIE_BUILD=0) |
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT") |
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd") |
||||
endif() |
||||
|
||||
#declare dependancy |
||||
set( CMAKE_THREAD_PREFER_PTHREAD TRUE ) |
||||
find_package( Threads ) |
||||
|
||||
if(WIN32) |
||||
set( OSSPEC_LIBS Shlwapi ) |
||||
endif() |
||||
|
||||
target_link_libraries(rlottie |
||||
PUBLIC |
||||
"${CMAKE_THREAD_LIBS_INIT}" |
||||
${OSSPEC_LIBS} |
||||
) |
||||
|
||||
if (NOT APPLE AND NOT WIN32) |
||||
target_link_libraries(rlottie |
||||
PRIVATE |
||||
"-Wl,--version-script=${CMAKE_CURRENT_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" |
||||
) |
||||
elseif(NOT MSVC) |
||||
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) |
||||
@ -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 |
||||
|
||||
@ -0,0 +1,11 @@
|
||||
Source: https://github.com/Samsung/rlottie |
||||
Revision: ea06d2f29ba01b8d06c00a838d107f5e484ae59b |
||||
Imported: 2026-10-05 |
||||
|
||||
Local CMake changes: |
||||
- Minimum version 3.16, matching ChatGUI and compatible with CMake 4. |
||||
- Link Shlwapi by library name so MinGW resolves its import library. |
||||
|
||||
Build from tools/chatgui: |
||||
cmake -S rlottie_src -B rlottie_build -G Ninja -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=ON |
||||
cmake --build rlottie_build --target rlottie --parallel 4 |
||||
@ -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/ |
||||
@ -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' |
||||
@ -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 |
||||
@ -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) |
||||
@ -0,0 +1,17 @@
|
||||
add_executable(lottie2gif "lottie2gif.cpp") |
||||
|
||||
if(MSVC) |
||||
target_compile_options(lottie2gif |
||||
PRIVATE |
||||
/std:c++14) |
||||
else() |
||||
target_compile_options(lottie2gif |
||||
PRIVATE |
||||
-std=c++14) |
||||
endif() |
||||
|
||||
target_link_libraries(lottie2gif rlottie) |
||||
|
||||
target_include_directories(lottie2gif |
||||
PRIVATE |
||||
"${CMAKE_CURRENT_LIST_DIR}/../inc/") |
||||
@ -0,0 +1,261 @@
|
||||
/*
|
||||
* 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->player()->setValue<rlottie::Property::TrimEnd>("Shape Layer 2.Trim Paths 1", |
||||
[](const rlottie::FrameInfo& info) { |
||||
return rlottie::Point(0, 30); |
||||
}); |
||||
} |
||||
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; |
||||
} |
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -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; |
||||
} |
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -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 isLottiefile(const char *filename) { |
||||
const char *dot = strrchr(filename, '.'); |
||||
if(!dot || dot == filename) return false; |
||||
return !strcmp(dot + 1, "json") || !strcmp(dot + 1, "lottie"); |
||||
} |
||||
|
||||
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 (isLottiefile(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; |
||||
} |
||||
|
||||
@ -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
|
||||
@ -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 |
||||
@ -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; |
||||
} |
||||
@ -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; |
||||
} |
||||
@ -0,0 +1,227 @@
|
||||
/*
|
||||
* 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); |
||||
} |
||||
} |
||||
@ -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
|
||||
@ -0,0 +1,259 @@
|
||||
/*
|
||||
* 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) |
||||
{ |
||||
long currFrameNo = info->view->mCurFrame; |
||||
long totalFrameNo = info->view->getTotalFrame(); |
||||
|
||||
char buf[64]; |
||||
sprintf(buf, "%ld (total: %ld)", currFrameNo, totalFrameNo); |
||||
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); |
||||
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; |
||||
|
||||
if (!info->autoPlaying) |
||||
{ |
||||
info->view->seek(val); |
||||
evas_object_image_pixels_dirty_set(info->view->getImage(), EINA_TRUE); |
||||
} |
||||
|
||||
_update_frame_info(info); |
||||
} |
||||
|
||||
static void |
||||
_button_clicked_cb(void *data, Evas_Object */*obj*/, void */*event_info*/) |
||||
{ |
||||
AppInfo *info = (AppInfo *)data; |
||||
if (info->view->getPos() >= 1.0f) info->view->mPos = 0.0f; |
||||
_toggle_start_button(info); |
||||
} |
||||
|
||||
Evas_Object * |
||||
create_layout(Evas_Object *parent, const char *file) |
||||
{ |
||||
Evas_Object *layout, *slider, *image, *button; |
||||
Ecore_Animator *animator; |
||||
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); |
||||
|
||||
view->seek(0.0); |
||||
_update_frame_info(info); |
||||
|
||||
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() |
||||
@ -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; |
||||
} |
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -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) |
||||
|
||||
|
||||
@ -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
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
@ -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
@ -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
@ -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
@ -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
@ -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}]} |
||||
@ -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
@ -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}]} |
||||
@ -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
@ -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":[]} |
||||
|
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
@ -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
@ -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}]} |
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue