dm 7 years ago
parent
commit
011100b850
100 changed files with 15464 additions and 339 deletions
  1. 7 0
      .gitignore
  2. 124 0
      ae-movie/CMakeLists.txt
  3. 26 0
      ae-movie/LICENSE
  4. 5 0
      ae-movie/README.md
  5. 40 0
      ae-movie/include/movie/movie.h
  6. 37 0
      ae-movie/include/movie/movie.hpp
  7. 562 0
      ae-movie/include/movie/movie_composition.h
  8. 69 0
      ae-movie/include/movie/movie_config.h
  9. 436 0
      ae-movie/include/movie/movie_data.h
  10. 92 0
      ae-movie/include/movie/movie_instance.h
  11. 455 0
      ae-movie/include/movie/movie_providers.h
  12. 144 0
      ae-movie/include/movie/movie_render.h
  13. 145 0
      ae-movie/include/movie/movie_resource.h
  14. 50 0
      ae-movie/include/movie/movie_skeleton.h
  15. 219 0
      ae-movie/include/movie/movie_type.h
  16. 51 0
      ae-movie/include/movie/movie_typedef.h
  17. 36 0
      ae-movie/include/movie/movie_version.h
  18. 231 0
      ae-movie/src/movie_bezier.c
  19. 71 0
      ae-movie/src/movie_bezier.h
  20. 4712 0
      ae-movie/src/movie_composition.c
  21. 2846 0
      ae-movie/src/movie_data.c
  22. 54 0
      ae-movie/src/movie_debug.h
  23. 236 0
      ae-movie/src/movie_instance.c
  24. 483 0
      ae-movie/src/movie_math.c
  25. 119 0
      ae-movie/src/movie_math.h
  26. 105 0
      ae-movie/src/movie_memory.h
  27. 208 0
      ae-movie/src/movie_providers.c
  28. 179 0
      ae-movie/src/movie_skeleton.c
  29. 156 0
      ae-movie/src/movie_stream.c
  30. 100 0
      ae-movie/src/movie_stream.h
  31. 505 0
      ae-movie/src/movie_struct.h
  32. 1567 0
      ae-movie/src/movie_transformation.c
  33. 220 0
      ae-movie/src/movie_transformation.h
  34. BIN
      examples/HelloViewerAE/data/HelloViewerAE.exe
  35. 2 2
      examples/HelloViewerAE/proj.android/AndroidManifest.xml
  36. 1 1
      examples/HelloViewerAE/proj.android/build-run.bat
  37. 1 1
      examples/HelloViewerAE/proj.android/build-run.sh
  38. 1 1
      examples/HelloViewerAE/proj.android/build.gradle
  39. 0 0
      examples/HelloViewerAE/proj.android/gradle/wrapper/gradle-wrapper.jar
  40. 0 0
      examples/HelloViewerAE/proj.android/gradle/wrapper/gradle-wrapper.properties
  41. 0 0
      examples/HelloViewerAE/proj.android/gradlew
  42. 0 0
      examples/HelloViewerAE/proj.android/gradlew.bat
  43. 0 0
      examples/HelloViewerAE/proj.android/jni/Android.mk
  44. 0 0
      examples/HelloViewerAE/proj.android/jni/Application.mk
  45. 1 1
      examples/HelloViewerAE/proj.android/jni/src/Android.mk
  46. 0 0
      examples/HelloViewerAE/proj.android/res/drawable-hdpi/ic_launcher.png
  47. 0 0
      examples/HelloViewerAE/proj.android/res/drawable-mdpi/ic_launcher.png
  48. 0 0
      examples/HelloViewerAE/proj.android/res/drawable-xhdpi/ic_launcher.png
  49. 0 0
      examples/HelloViewerAE/proj.android/res/drawable-xxhdpi/ic_launcher.png
  50. 0 0
      examples/HelloViewerAE/proj.android/res/layout/main.xml
  51. 1 1
      examples/HelloViewerAE/proj.android/res/values/strings.xml
  52. 5 0
      examples/HelloViewerAE/proj.android/settings.gradle
  53. 1 1
      examples/HelloViewerAE/proj.android/src/org/oxygine/HelloViewerAE/MainActivity.java
  54. 54 0
      examples/HelloViewerAE/proj.cmake/CMakeLists.txt
  55. 1 1
      examples/HelloViewerAE/proj.cmake/build_emsc.bat
  56. 1 1
      examples/HelloViewerAE/proj.cmake/build_emsc_release.bat
  57. 1 1
      examples/HelloViewerAE/proj.cmake/run.sh
  58. 0 0
      examples/HelloViewerAE/proj.ios/HelloViewerAE/HelloViewerAE_ios-Info.plist
  59. 0 0
      examples/HelloViewerAE/proj.ios/HelloViewerAE/HelloViewerAE_ios-Prefix.pch
  60. 0 0
      examples/HelloViewerAE/proj.ios/HelloViewerAE/Images.xcassets/AppIcon.appiconset/Contents.json
  61. 0 0
      examples/HelloViewerAE/proj.ios/HelloViewerAE/Images.xcassets/LaunchImage.launchimage/Contents.json
  62. 0 0
      examples/HelloViewerAE/proj.ios/HelloViewerAE/LaunchImage.launchimage/Contents.json
  63. 0 0
      examples/HelloViewerAE/proj.ios/HelloViewerAE/LaunchScreen.storyboard
  64. 28 28
      examples/HelloViewerAE/proj.ios/HelloViewerAE_ios.xcodeproj/project.pbxproj
  65. 0 0
      examples/HelloViewerAE/proj.macosx/HelloViewerAE/HelloViewerAE_macosx-Prefix.pch
  66. 0 0
      examples/HelloViewerAE/proj.macosx/HelloViewerAE/Images.xcassets/AppIcon.appiconset/Contents.json
  67. 0 0
      examples/HelloViewerAE/proj.macosx/HelloViewerAE_macosx-Info.plist
  68. 32 32
      examples/HelloViewerAE/proj.macosx/HelloViewerAE_macosx.xcodeproj/project.pbxproj
  69. 2 2
      examples/HelloViewerAE/proj.win32/HelloViewerAE.sln
  70. 7 7
      examples/HelloViewerAE/proj.win32/HelloViewerAE.vcxproj
  71. 0 0
      examples/HelloViewerAE/proj.win32/HelloViewerAE.vcxproj.filters
  72. 0 0
      examples/HelloViewerAE/proj.win32/HelloViewerAE.vcxproj.user
  73. 390 0
      examples/HelloViewerAE/src/AEMovieWork.cpp
  74. 21 0
      examples/HelloViewerAE/src/AEMovieWork.h
  75. 496 0
      examples/HelloViewerAE/src/example.cpp
  76. 1 2
      examples/HelloViewerAE/src/example.h
  77. 62 7
      examples/HelloViewerAE/src/main.cpp
  78. 5 0
      examples/HelloViewerAE/src/test.cpp
  79. 60 0
      examples/HelloViewerAE/src/test.h
  80. 0 239
      examples/data/fonts/main.fnt
  81. BIN
      examples/data/fonts/main_0.png
  82. BIN
      examples/data/images/anim.png
  83. BIN
      examples/data/images/button.png
  84. 0 11
      examples/data/res.xml
  85. BIN
      examples/exported/Knight/Knight.aem
  86. 0 0
      examples/exported/Knight/Knight.aem.log
  87. BIN
      examples/exported/Knight/images/Sprite_Player_body.png
  88. BIN
      examples/exported/Knight/images/Sprite_Player_head.png
  89. BIN
      examples/exported/Knight/images/Sprite_Player_left_apple_eye.png
  90. BIN
      examples/exported/Knight/images/Sprite_Player_left_eyebrow.png
  91. BIN
      examples/exported/Knight/images/Sprite_Player_left_eyelash.png
  92. BIN
      examples/exported/Knight/images/Sprite_Player_left_hand.png
  93. BIN
      examples/exported/Knight/images/Sprite_Player_left_hand_bg.png
  94. BIN
      examples/exported/Knight/images/Sprite_Player_left_leg.png
  95. BIN
      examples/exported/Knight/images/Sprite_Player_left_leg_bg.png
  96. BIN
      examples/exported/Knight/images/Sprite_Player_right_apple_eye.png
  97. BIN
      examples/exported/Knight/images/Sprite_Player_right_eyebrow.png
  98. BIN
      examples/exported/Knight/images/Sprite_Player_right_eyelash.png
  99. BIN
      examples/exported/Knight/images/Sprite_Player_right_hand.png
  100. BIN
      examples/exported/Knight/images/Sprite_Player_right_hand_bg.png

+ 7 - 0
.gitignore

@@ -1 +1,8 @@
 *.dll
 *.dll
+examples/HelloAE/proj.cmake/build/
+examples/HelloViewerAE/proj.cmake/build/
+examples/AE/
+export/2/
+export/temp/
+*.pyc
+examples/HelloViewerAE/data/viewer.log

+ 124 - 0
ae-movie/CMakeLists.txt

@@ -0,0 +1,124 @@
+cmake_minimum_required(VERSION 3.0)
+
+PROJECT(movie)
+
+if(${CMAKE_CXX_COMPILER_ID} STREQUAL Clang)
+  set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Werror")
+elseif(${CMAKE_CXX_COMPILER_ID} STREQUAL AppleClang)
+  set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Werror")
+elseif(${CMAKE_CXX_COMPILER_ID} STREQUAL GNU)
+  set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Werror")
+elseif(${CMAKE_CXX_COMPILER_ID} STREQUAL Intel)
+  set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Werror")
+elseif(${CMAKE_CXX_COMPILER_ID} STREQUAL MSVC)
+  set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall /WX")
+  set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /wd4710")
+  set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /wd4738")
+endif()
+
+OPTION(LIBMOVIE_EXTERNAL_BUILD  "LIBMOVIE_EXTERNAL_BUILD"  OFF)
+OPTION(LIBMOVIE_EXAMPLES_BUILD  "LIBMOVIE_EXAMPLES_BUILD"  ON)
+
+IF( NOT LIBMOVIE_EXTERNAL_BUILD )
+    SET( CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/lib/${CMAKE_GENERATOR} )
+    SET( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/bin/${CMAKE_GENERATOR} )
+ENDIF()
+
+MACRO( ADD_FILTER group_name )
+	SOURCE_GROUP( ${group_name} FILES ${ARGN} )
+	SET( SRC_FILES ${SRC_FILES} ${ARGN} )
+ENDMACRO()
+
+SET( INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include )
+SET( SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src )
+
+ADD_FILTER(
+public
+	${INCLUDE_DIR}/movie/movie.h
+    ${INCLUDE_DIR}/movie/movie.hpp
+    ${INCLUDE_DIR}/movie/movie_node.h
+    ${INCLUDE_DIR}/movie/movie_data.h
+    ${INCLUDE_DIR}/movie/movie_instance.h
+    ${INCLUDE_DIR}/movie/movie_resource.h
+    ${INCLUDE_DIR}/movie/movie_skeleton.h
+    ${INCLUDE_DIR}/movie/movie_type.h
+    ${INCLUDE_DIR}/movie/movie_typedef.h
+    ${INCLUDE_DIR}/movie/movie_config.h    
+)
+
+ADD_FILTER(
+source
+	${SOURCE_DIR}/movie_data.c
+    ${SOURCE_DIR}/movie_instance.c
+    ${SOURCE_DIR}/movie_math.c
+    ${SOURCE_DIR}/movie_math.h
+    ${SOURCE_DIR}/movie_memory.h
+    ${SOURCE_DIR}/movie_node.c
+    ${SOURCE_DIR}/movie_skeleton.c
+    ${SOURCE_DIR}/movie_stream.c
+    ${SOURCE_DIR}/movie_stream.h
+    ${SOURCE_DIR}/movie_struct.h
+    ${SOURCE_DIR}/movie_transformation.c
+    ${SOURCE_DIR}/movie_transformation.h
+    ${SOURCE_DIR}/movie_debug.h
+)
+
+INCLUDE_DIRECTORIES( ${PROJECT_NAME} ${INCLUDE_DIR} ) 
+
+ADD_LIBRARY( ${PROJECT_NAME} STATIC ${SRC_FILES} )
+
+if( LIBMOVIE_EXAMPLES_BUILD )
+    SET( EXAMPLES_DIR ${CMAKE_CURRENT_SOURCE_DIR}/examples )
+
+    set(
+    sandbox_SOURCES
+        ${EXAMPLES_DIR}/sandbox/sandbox.c
+    )
+
+    INCLUDE_DIRECTORIES( sandbox ${INCLUDE_DIR} )
+    
+    ADD_DEFINITIONS(-D_CRT_SECURE_NO_WARNINGS)
+
+    ADD_EXECUTABLE( sandbox ${sandbox_SOURCES} )
+
+    TARGET_LINK_LIBRARIES( sandbox movie )
+    
+    set(
+    test1_SOURCES
+        ${EXAMPLES_DIR}/test/common.c
+        ${EXAMPLES_DIR}/test/common.h
+        ${EXAMPLES_DIR}/test/test1.c
+    )
+
+    INCLUDE_DIRECTORIES( test1 ${INCLUDE_DIR} )
+
+    ADD_EXECUTABLE( test1 ${test1_SOURCES} )
+
+    TARGET_LINK_LIBRARIES( test1 movie )    
+    
+    set(
+    test2_SOURCES
+        ${EXAMPLES_DIR}/test/common.c
+        ${EXAMPLES_DIR}/test/common.h
+        ${EXAMPLES_DIR}/test/test2.c
+    )
+
+    INCLUDE_DIRECTORIES( test2 ${INCLUDE_DIR} )
+
+    ADD_EXECUTABLE( test2 ${test2_SOURCES} )
+
+    TARGET_LINK_LIBRARIES( test2 movie )
+    
+    set(
+    test3_SOURCES
+        ${EXAMPLES_DIR}/test/common.c
+        ${EXAMPLES_DIR}/test/common.h
+        ${EXAMPLES_DIR}/test/test3.c
+    )
+
+    INCLUDE_DIRECTORIES( test3 ${INCLUDE_DIR} )
+
+    ADD_EXECUTABLE( test3 ${test3_SOURCES} )
+
+    TARGET_LINK_LIBRARIES( test3 movie )    
+endif()

+ 26 - 0
ae-movie/LICENSE

@@ -0,0 +1,26 @@
+libMOVIE Software License v1.0
+
+Copyright (c) 2016-2017, Yuriy Levchenko <[email protected]>
+All rights reserved.
+
+You are granted a perpetual, non-exclusive, non-sublicensable, and
+non-transferable license to use, install, execute, and perform the libMOVIE
+software and derivative works solely for personal or internal
+use. Without the written permission of Yuriy Levchenko, you may not (a) modify, translate,
+adapt, or develop new applications using the libMOVIE or otherwise
+create derivative works or improvements of the libMOVIE or (b) remove,
+delete, alter, or obscure any trademarks or any copyright, trademark, patent,
+or other intellectual property or proprietary rights notices on or in the
+Software, including any copy thereof. Redistributions in binary or source
+form must include this license and terms.
+
+THIS SOFTWARE IS PROVIDED BY YURIY LEVCHENKO "AS IS" AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+EVENT SHALL YURIY LEVCHENKO BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION,
+OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ 5 - 0
ae-movie/README.md

@@ -0,0 +1,5 @@
+Framework for render After Effects composition
+
+|         | Linux  | Mac OS | Windows |
+| ------- | ------ | ------ | ------- |
+| master  | ![Travis-CI](https://travis-ci.org/irov/libmovie.svg?branch=master) | ![Travis-CI](https://travis-ci.org/irov/libmovie.svg?branch=master) | ![AppVeyor](https://ci.appveyor.com/api/projects/status/s0yio92rsujopyug?svg=true) |

+ 40 - 0
ae-movie/include/movie/movie.h

@@ -0,0 +1,40 @@
+/******************************************************************************
+* libMOVIE Software License v1.0
+*
+* Copyright (c) 2016-2018, Yuriy Levchenko <[email protected]>
+* All rights reserved.
+*
+* You are granted a perpetual, non-exclusive, non-sublicensable, and
+* non-transferable license to use, install, execute, and perform the libMOVIE
+* software and derivative works solely for personal or internal
+* use. Without the written permission of Yuriy Levchenko, you may not (a) modify, translate,
+* adapt, or develop new applications using the libMOVIE or otherwise
+* create derivative works or improvements of the libMOVIE or (b) remove,
+* delete, alter, or obscure any trademarks or any copyright, trademark, patent,
+* or other intellectual property or proprietary rights notices on or in the
+* Software, including any copy thereof. Redistributions in binary or source
+* form must include this license and terms.
+*
+* THIS SOFTWARE IS PROVIDED BY YURIY LEVCHENKO "AS IS" AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+* EVENT SHALL YURIY LEVCHENKO BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION,
+* OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF
+* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+#ifndef MOVIE_H_
+#define MOVIE_H_
+
+#include "movie_version.h"
+#include "movie_type.h"
+#include "movie_instance.h"
+#include "movie_data.h"
+#include "movie_resource.h"
+#include "movie_composition.h"
+
+#endif

+ 37 - 0
ae-movie/include/movie/movie.hpp

@@ -0,0 +1,37 @@
+/******************************************************************************
+* libMOVIE Software License v1.0
+*
+* Copyright (c) 2016-2018, Yuriy Levchenko <[email protected]>
+* All rights reserved.
+*
+* You are granted a perpetual, non-exclusive, non-sublicensable, and
+* non-transferable license to use, install, execute, and perform the libMOVIE
+* software and derivative works solely for personal or internal
+* use. Without the written permission of Yuriy Levchenko, you may not (a) modify, translate,
+* adapt, or develop new applications using the libMOVIE or otherwise
+* create derivative works or improvements of the libMOVIE or (b) remove,
+* delete, alter, or obscure any trademarks or any copyright, trademark, patent,
+* or other intellectual property or proprietary rights notices on or in the
+* Software, including any copy thereof. Redistributions in binary or source
+* form must include this license and terms.
+*
+* THIS SOFTWARE IS PROVIDED BY YURIY LEVCHENKO "AS IS" AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+* EVENT SHALL YURIY LEVCHENKO BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION,
+* OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF
+* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+#ifndef MOVIE_HPP_
+#define MOVIE_HPP_
+
+extern "C" {
+#include "movie.h"
+}
+
+#endif

+ 562 - 0
ae-movie/include/movie/movie_composition.h

@@ -0,0 +1,562 @@
+/******************************************************************************
+* libMOVIE Software License v1.0
+*
+* Copyright (c) 2016-2018, Yuriy Levchenko <[email protected]>
+* All rights reserved.
+*
+* You are granted a perpetual, non-exclusive, non-sublicensable, and
+* non-transferable license to use, install, execute, and perform the libMOVIE
+* software and derivative works solely for personal or internal
+* use. Without the written permission of Yuriy Levchenko, you may not (a) modify, translate,
+* adapt, or develop new applications using the libMOVIE or otherwise
+* create derivative works or improvements of the libMOVIE or (b) remove,
+* delete, alter, or obscure any trademarks or any copyright, trademark, patent,
+* or other intellectual property or proprietary rights notices on or in the
+* Software, including any copy thereof. Redistributions in binary or source
+* form must include this license and terms.
+*
+* THIS SOFTWARE IS PROVIDED BY YURIY LEVCHENKO "AS IS" AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+* EVENT SHALL YURIY LEVCHENKO BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION,
+* OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF
+* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+#ifndef MOVIE_NODE_H_
+#define MOVIE_NODE_H_
+
+#include "movie_type.h"
+#include "movie_typedef.h"
+#include "movie_instance.h"
+#include "movie_data.h"
+#include "movie_render.h"
+#include "movie_providers.h"
+
+/**
+@addtogroup compositions
+@{
+*/
+
+/**
+@brief Allocate a composition in memory.
+@param [in] _movieData Resource holding movie data.
+@param [in] _compositionData Resource holding composition data.
+@param [in] _interpolate If TRUE, composition will be interpolated.
+@param [in] _providers Set of callbacks which provide data used during playback.
+@param [in] _userdata Link to the object that will hold the data providers give.
+@return A composition or AE_NULL if failed.
+*/
+const aeMovieComposition * ae_create_movie_composition( const aeMovieData * _movieData, const aeMovieCompositionData * _compositionData, ae_bool_t _interpolate, const aeMovieCompositionProviders * _providers, ae_userdata_t _userdata );
+
+/**
+@brief Release a composition from memory.
+@param [in] _composition Composition.
+*/
+ae_void_t ae_delete_movie_composition( const aeMovieComposition * _composition );
+
+/**
+@brief get composition data from composition.
+@param [in] _composition Composition.
+*/
+const aeMovieCompositionData * ae_get_movie_composition_composition_data( const aeMovieComposition * _composition );
+
+/**
+@brief Get composition anchor point.
+@param [in] _composition Composition.
+@param [out] _point point.
+@return TRUE if successful
+*/
+ae_bool_t ae_get_movie_composition_anchor_point( const aeMovieComposition * _composition, ae_vector3_t _point );
+
+typedef struct aeMovieCompositionRenderInfo
+{
+    ae_uint32_t max_render_node;
+    ae_uint32_t max_vertex_count;
+    ae_uint32_t max_index_count;
+} aeMovieCompositionRenderInfo;
+
+/**
+@param [in] _composition Composition.
+@return Maximum number of render meshes you will ever get during a full ae_compute_movie_mesh() cycle.
+*/
+ae_void_t ae_calculate_movie_composition_render_info( const aeMovieComposition * _composition, aeMovieCompositionRenderInfo * _info );
+
+/**
+@brief Set whether a composition is looped or not.
+@param [in] _composition Composition.
+@param [in] _loop If TRUE, playback will be looped.
+*/
+ae_void_t ae_set_movie_composition_loop( const aeMovieComposition * _composition, ae_bool_t _loop );
+
+/**
+@param [in] _composition Composition.
+@return TRUE if composition playback is looped.
+*/
+ae_bool_t ae_get_movie_composition_loop( const aeMovieComposition * _composition );
+
+/**
+@param [in] _composition Composition.
+@return TRUE if composition playback is interpolated.
+*/
+ae_bool_t ae_get_movie_composition_interpolate( const aeMovieComposition * _composition );
+
+/**
+@brief Set playback area of a composition in milliseconds.
+@param [in] _composition Composition.
+@param [in] _begin Begin time.
+@param [in] _end End time.
+@return TRUE if successful.
+*/
+ae_bool_t ae_set_movie_composition_work_area( const aeMovieComposition * _composition, ae_time_t _begin, ae_time_t _end );
+
+/**
+@brief Restore playback area of a composition to whole-length.
+@param [in] _composition Composition.
+*/
+ae_void_t ae_remove_movie_composition_work_area( const aeMovieComposition * _composition );
+
+/**
+@brief Start playback.
+@param [in] _composition Composition.
+@param [in] _time Starting time.
+*/
+ae_void_t ae_play_movie_composition( const aeMovieComposition * _composition, ae_time_t _time );
+
+/**
+@brief Stop playback.
+@param [in] _composition Composition.
+*/
+ae_void_t ae_stop_movie_composition( const aeMovieComposition * _composition );
+
+/**
+@brief Pause playback.
+@param [in] _composition Composition.
+*/
+ae_void_t ae_pause_movie_composition( const aeMovieComposition * _composition );
+
+/**
+@brief Resume playback.
+@param [in] _composition Composition.
+*/
+ae_void_t ae_resume_movie_composition( const aeMovieComposition * _composition );
+
+/**
+@brief Play till the end of the loop area and stop, even if playback is looped.
+@param [in] _composition Composition.
+@param [in] _skip If TRUE, skip to the end of current animation loop.
+*/
+ae_void_t ae_interrupt_movie_composition( const aeMovieComposition * _composition, ae_bool_t _skip );
+
+/**
+@param [in] _composition Composition.
+@return TRUE if the composition is playing.
+*/
+ae_bool_t ae_is_play_movie_composition( const aeMovieComposition * _composition );
+
+/**
+@param [in] _composition Composition.
+@return TRUE if the composition is paused.
+*/
+ae_bool_t ae_is_pause_movie_composition( const aeMovieComposition * _composition );
+
+/**
+@param [in] _composition Composition.
+@return TRUE if the composition has been interrupted.
+*/
+ae_bool_t ae_is_interrupt_movie_composition( const aeMovieComposition * _composition );
+
+/**
+@brief Set composition playback to the specified position in milliseconds.
+@param [in] _composition Composition.
+@param [in] _timing Position.
+*/
+ae_void_t ae_set_movie_composition_time( const aeMovieComposition * _composition, ae_time_t _timing );
+
+
+const ae_char_t * ae_get_movie_composition_name( const aeMovieComposition * _composition );
+
+/**
+@brief Get composition current playback position in milliseconds.
+@param [in] _composition Composition.
+@return Position.
+*/
+ae_time_t ae_get_movie_composition_time( const aeMovieComposition * _composition );
+
+/**
+@brief Get composition duration in milliseconds.
+@param [in] _composition Composition.
+@return Duration.
+*/
+ae_time_t ae_get_movie_composition_duration( const aeMovieComposition * _composition );
+
+/**
+@brief Get composition loop area in milliseconds.
+@param [in] _composition Composition.
+@param [out] _in Begin time.
+@param [out] _out End time.
+*/
+ae_void_t ae_get_movie_composition_in_out_loop( const aeMovieComposition * _composition, ae_time_t * _in, ae_time_t * _out );
+
+/**
+@brief Update composition nodes and state. Call this from your application update() loop.
+@param [in] _composition Composition.
+@param [in] _timing Time offset since the last update in milliseconds.
+*/
+ae_bool_t ae_update_movie_composition( const aeMovieComposition * _composition, ae_time_t _timing );
+
+// compositions
+/// @}
+
+/**
+@addtogroup slots
+@{
+*/
+
+/**
+@brief Set user data for a slot.
+@param [in] _composition Composition.
+@param [in] _name Slot name.
+@param [in] _userdata Data pointer.
+@return TRUE if successful.
+*/
+ae_bool_t ae_set_movie_composition_slot_userdata( const aeMovieComposition * _composition, const ae_char_t * _name, ae_userdata_t _userdata );
+
+/**
+@brief Search for a slot by the given name.
+@param [in] _composition Composition.
+@param [in] _slotName Slot name.
+@return Pointer to the slot or AE_NULL if not found.
+*/
+ae_userdata_t ae_get_movie_composition_slot_userdata( const aeMovieComposition * _composition, const ae_char_t * _name );
+
+/**
+@brief Check for a slot by the given name.
+@param [in] _composition Composition.
+@param [in] _name Slot name.
+@return TRUE if found.
+*/
+ae_bool_t ae_has_movie_composition_slot( const aeMovieComposition * _composition, const ae_char_t * _name );
+
+/**
+@brief Remove user data from the slot.
+@param [in] _composition Composition.
+@param [in] _name Slot name.
+@return Pointer to data that was assigned to this slot prior to removal.
+*/
+ae_userdata_t ae_remove_movie_composition_slot( const aeMovieComposition * _composition, const ae_char_t * _name );
+
+// slots
+/// @}
+
+/**
+@brief get camera user data from composition.
+@param [in] _composition Composition.
+@return Pointer to the data referenced by the camera linked to the composition.
+*/
+ae_userdata_t ae_get_movie_composition_camera_userdata( const aeMovieComposition * _composition );
+
+// slots
+/// @}
+
+
+/**
+@addtogroup sockets
+@{
+*/
+
+/**
+@brief Search for a socket by the given name.
+@param [in] _composition Composition.
+@param [in] _slotName Socket name.
+@param [out] _polygon Socket shape.
+@return TRUE if found.
+*/
+ae_bool_t ae_get_movie_composition_socket( const aeMovieComposition * _composition, const ae_char_t * _slotName, const ae_polygon_t ** _polygon );
+
+// sockets
+/// @}
+
+
+
+/**
+@addtogroup compositions
+@{
+*/
+
+/**
+@brief Compute rendering data at the current playback time.
+@param [in] _composition Composition.
+@param [in] _iterator Index of the render mesh to update, can start from zero, will increase automatically inside.
+@param [out] _vertices Pointer to render mesh.
+@return TRUE if there are still meshes to compute in the next iteration, FALSE if finished.
+*/
+ae_bool_t ae_compute_movie_mesh( const aeMovieComposition * _composition, ae_uint32_t * _iterator, aeMovieRenderMesh * _vertices );
+
+/**
+@param [in] _composition Composition.
+@return Number of meshes at the current playback time.
+*/
+uint32_t ae_get_movie_render_mesh_count( const aeMovieComposition * _composition );
+
+
+/**
+@brief test exist node.
+@param [in] _composition Composition.
+@param [in] _layerName Node name.
+@param [in] _type Node type.
+@return TRUE if the node is found.
+*/
+ae_bool_t ae_has_movie_composition_node( const aeMovieComposition * _composition, const ae_char_t * _layerName, aeMovieLayerTypeEnum _type );
+
+/**
+@brief Get node active time range in milliseconds.
+Returns interval on which node is active, i.e. being played, rendered, etc.
+@param [in] _composition Composition.
+@param [in] _layerName Node name.
+@param [in] _type Node type.
+@param [out] _in Begin time.
+@param [out] _out End time.
+@return TRUE if the node is found.
+*/
+ae_bool_t ae_get_movie_composition_node_in_out_time( const aeMovieComposition * _composition, const ae_char_t * _layerName, aeMovieLayerTypeEnum _type, ae_time_t * _in, ae_time_t * _out );
+
+
+ae_void_t ae_set_movie_composition_nodes_enable( const aeMovieComposition * _composition, const ae_char_t * _layerName, aeMovieLayerTypeEnum _type, ae_bool_t _enable );
+
+/**
+@brief Toggle layer usage.
+@param [in] _composition Composition.
+@param [in] _layerName Node name.
+@param [in] _type Node type.
+@param [in] _enable If TRUE, enable usage.
+@return TRUE if the node is found.
+*/
+ae_bool_t ae_set_movie_composition_node_enable( const aeMovieComposition * _composition, const ae_char_t * _layerName, aeMovieLayerTypeEnum _type, ae_bool_t _enable );
+
+/**
+@brief Query whether the given node is active or not.
+@param [in] _composition Composition.
+@param [in] _layerName Node name.
+@param [in] _type Node type.
+@param [out] _enable TRUE if enabled.
+@return TRUE if the node is found.
+*/
+ae_bool_t ae_get_movie_composition_node_enable( const aeMovieComposition * _composition, const ae_char_t * _layerName, aeMovieLayerTypeEnum _type, ae_bool_t * _enable );
+
+/**
+@brief test exist node.
+@param [in] _composition Composition.
+@param [in] _layerName Node name.
+@param [in] _type Node type.
+@return TRUE if the node is found.
+*/
+ae_bool_t ae_has_movie_composition_node_any( const aeMovieComposition * _composition, const ae_char_t * _layerName );
+
+/**
+@brief Get node active time range in milliseconds.
+Returns interval on which node is active, i.e. being played, rendered, etc.
+@param [in] _composition Composition.
+@param [in] _layerName Node name.
+@param [in] _type Node type.
+@param [out] _in Begin time.
+@param [out] _out End time.
+@return TRUE if the node is found.
+*/
+ae_bool_t ae_get_movie_composition_node_in_out_time_any( const aeMovieComposition * _composition, const ae_char_t * _layerName, ae_time_t * _in, ae_time_t * _out );
+
+
+ae_void_t ae_set_movie_composition_nodes_enable_any( const aeMovieComposition * _composition, const ae_char_t * _layerName, ae_bool_t _enable );
+
+/**
+@brief Toggle layer usage.
+@param [in] _composition Composition.
+@param [in] _layerName Node name.
+@param [in] _type Node type.
+@param [in] _enable If TRUE, enable usage.
+@return TRUE if the node is found.
+*/
+ae_bool_t ae_set_movie_composition_node_enable_any( const aeMovieComposition * _composition, const ae_char_t * _layerName, ae_bool_t _enable );
+
+/**
+@brief Query whether the given node is active or not.
+@param [in] _composition Composition.
+@param [in] _layerName Node name.
+@param [in] _type Node type.
+@param [out] _enable TRUE if enabled.
+@return TRUE if the node is found.
+*/
+ae_bool_t ae_get_movie_composition_node_enable_any( const aeMovieComposition * _composition, const ae_char_t * _layerName, ae_bool_t * _enable );
+
+
+// compositions
+/// @}
+
+
+
+/**
+@addtogroup subcompositions
+@{
+*/
+
+ae_bool_t ae_has_movie_sub_composition( const aeMovieComposition * _composition, const ae_char_t * _name );
+
+/**
+@brief Search for a sub-composition by name.
+@param [in] _composition Composition.
+@param [in] _name Name of a sub-composition to search for.
+@return Pointer to the sub-composition or AE_NULL if not found.
+*/
+const aeMovieSubComposition * ae_get_movie_sub_composition( const aeMovieComposition * _composition, const ae_char_t * _name );
+
+
+typedef ae_bool_t( *ae_movie_sub_composition_visitor_t )(const aeMovieComposition * _compositionData, ae_uint32_t _index, const ae_char_t * _name, const aeMovieSubComposition * _subcomposition, ae_userdata_t _ud);
+
+ae_bool_t ae_visit_movie_sub_composition( const aeMovieComposition * _composition, ae_movie_sub_composition_visitor_t _visitor, ae_userdata_t _ud );
+
+/**
+@brief Get name of a sub-composition.
+@param [in] _subcomposition Sub-composition.
+@return Name.
+*/
+const ae_char_t * ae_get_movie_sub_composition_name( const aeMovieSubComposition * _subcomposition );
+
+/**
+@brief Get sub-composition loop area in milliseconds.
+@param [in] _subcomposition Sub-composition.
+@param [out] _in Begin time.
+@param [out] _out End time.
+*/
+ae_void_t ae_get_movie_sub_composition_in_out_loop( const aeMovieSubComposition * _subcomposition, ae_time_t * _in, ae_time_t * _out );
+
+/**
+@brief Start playback.
+@param [in] _composition Composition.
+@param [in] _subcomposition Sub-composition.
+@param [in] _time Start time in milliseconds.
+@return TRUE if successful.
+*/
+ae_bool_t ae_play_movie_sub_composition( const aeMovieComposition * _composition, const aeMovieSubComposition * _subcomposition, ae_time_t _time );
+
+/**
+@brief Stop playback.
+@param [in] _composition Composition.
+@param [in] _subcomposition Sub-composition.
+@return TRUE if successful.
+*/
+ae_bool_t ae_stop_movie_sub_composition( const aeMovieComposition * _composition, const aeMovieSubComposition * _subcomposition );
+
+/**
+@brief Pause playback.
+@param [in] _composition Composition.
+@param [in] _subcomposition Sub-composition.
+@return TRUE if successful.
+*/
+ae_bool_t ae_pause_movie_sub_composition( const aeMovieComposition * _composition, const aeMovieSubComposition * _subcomposition );
+
+/**
+@brief Resume playback.
+@param [in] _composition Composition.
+@param [in] _subcomposition Sub-composition.
+@return TRUE if successful.
+*/
+ae_bool_t ae_resume_movie_sub_composition( const aeMovieComposition * _composition, const aeMovieSubComposition * _subcomposition );
+
+/**
+@brief Play till the end of the loop area and stop, even if playback is looped.
+@param [in] _composition Composition.
+@param [in] _subcomposition Sub-composition.
+@param [in] _skip If TRUE, skip to the end of current animation loop.
+*/
+ae_void_t ae_interrupt_movie_sub_composition( const aeMovieComposition * _composition, const aeMovieSubComposition * _subcomposition, ae_bool_t _skip );
+
+/**
+@param [in] _subcomposition Sub-composition.
+@return TRUE if the sub-composition is playing.
+*/
+ae_bool_t ae_is_play_movie_sub_composition( const aeMovieSubComposition * _subcomposition );
+
+/**
+@param [in] _subcomposition Sub-composition.
+@return TRUE if the sub-composition is paused.
+*/
+ae_bool_t ae_is_pause_movie_sub_composition( const aeMovieSubComposition * _subcomposition );
+
+/**
+@param [in] _subcomposition Sub-composition.
+@return TRUE if the sub-composition has been interrupted.
+*/
+ae_bool_t ae_is_interrupt_movie_sub_composition( const aeMovieSubComposition * _subcomposition );
+
+/**
+@brief Set sub-composition playback to the specified position in milliseconds.
+@param [in] _composition Composition.
+@param [in] _subcomposition Sub-composition.
+@param [in] _timing Position.
+*/
+ae_void_t ae_set_movie_sub_composition_time( const aeMovieComposition * _composition, const aeMovieSubComposition * _subcomposition, ae_time_t _timing );
+
+/**
+@brief Get current playback position of a sub-composition in milliseconds.
+@param [in] _subcomposition Sub-composition.
+@return Time.
+*/
+ae_time_t ae_get_movie_sub_composition_time( const aeMovieSubComposition * _subcomposition );
+
+/**
+@brief Set whether a sub-composition is looped or not.
+@param [in] _subcomposition Sub-composition.
+@param [in] _loop If TRUE, playback will be looped.
+*/
+ae_void_t ae_set_movie_sub_composition_loop( const aeMovieSubComposition * _subcomposition, ae_bool_t _loop );
+
+/**
+@param [in] _subcomposition Sub-composition.
+@return TRUE if sub-composition playback is looped.
+*/
+ae_bool_t ae_get_movie_sub_composition_loop( const aeMovieSubComposition * _subcomposition );
+
+/**
+@brief Set whether a sub-composition is enable or not.
+@param [in] _subcomposition Sub-composition.
+@param [in] _loop If TRUE, playback will be looped.
+*/
+ae_void_t ae_set_movie_sub_composition_enable( const aeMovieSubComposition * _subcomposition, ae_bool_t _enable );
+
+/**
+@param [in] _subcomposition Sub-composition.
+@return TRUE if sub-composition playback is enable.
+*/
+ae_bool_t ae_get_movie_sub_composition_enable( const aeMovieSubComposition * _subcomposition );
+
+/**
+@brief Set playback area of a sub-composition in milliseconds.
+@param [in] _composition Composition.
+@param [in] _subcomposition Sub-composition.
+@param [in] _begin Begin time.
+@param [in] _end End time.
+@return TRUE if successful.
+*/
+ae_bool_t ae_set_movie_sub_composition_work_area( const aeMovieComposition * _composition, const aeMovieSubComposition * _subcomposition, ae_time_t _begin, ae_time_t _end );
+
+/**
+@brief Restore playback area of a sub-composition to whole-length.
+@param [in] _composition Composition.
+@param [in] _subcomposition Sub-composition.
+*/
+ae_void_t ae_remove_movie_sub_composition_work_area( const aeMovieComposition * _composition, const aeMovieSubComposition * _subcomposition );
+
+/**
+@brief get composition data from subcomposition.
+@param [in] _subcomposition SubComposition.
+*/
+const aeMovieCompositionData * ae_get_movie_sub_composition_composition_data( const aeMovieSubComposition * _subcomposition );
+
+// subcompositions
+/// @}
+
+#endif

+ 69 - 0
ae-movie/include/movie/movie_config.h

@@ -0,0 +1,69 @@
+/******************************************************************************
+* libMOVIE Software License v1.0
+*
+* Copyright (c) 2016-2018, Yuriy Levchenko <[email protected]>
+* All rights reserved.
+*
+* You are granted a perpetual, non-exclusive, non-sublicensable, and
+* non-transferable license to use, install, execute, and perform the libMOVIE
+* software and derivative works solely for personal or internal
+* use. Without the written permission of Yuriy Levchenko, you may not (a) modify, translate,
+* adapt, or develop new applications using the libMOVIE or otherwise
+* create derivative works or improvements of the libMOVIE or (b) remove,
+* delete, alter, or obscure any trademarks or any copyright, trademark, patent,
+* or other intellectual property or proprietary rights notices on or in the
+* Software, including any copy thereof. Redistributions in binary or source
+* form must include this license and terms.
+*
+* THIS SOFTWARE IS PROVIDED BY YURIY LEVCHENKO "AS IS" AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+* EVENT SHALL YURIY LEVCHENKO BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION,
+* OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF
+* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+#ifndef MOVIE_CONFIG_H_
+#define MOVIE_CONFIG_H_
+
+#ifndef NDEBUG
+#   ifndef AE_MOVIE_NO_DEBUG
+#	    define AE_MOVIE_DEBUG
+#	endif
+#endif
+
+#ifndef AE_TIME_DEFINE
+#   define AE_TIME_SECOND
+#endif
+
+#ifdef AE_TIME_SECOND
+#   define AE_TIME_OUTSCALE( T ) (T)
+#   define AE_TIME_INSCALE( T ) (T)
+#elif AE_TIME_MILLISECOND
+#   define AE_TIME_OUTSCALE( T ) (T * 1000.f)
+#   define AE_TIME_INSCALE( T ) (T * 0.001f)
+#endif
+
+#define AE_CALLBACK static
+#define AE_INTERNAL inline static
+
+#define AE_UNUSED(Var) ((ae_void_t)Var)
+
+#ifndef AE_MOVIE_BEZIER_MAX_QUALITY
+#   define AE_MOVIE_BEZIER_MAX_QUALITY (10U)
+#endif
+
+#ifndef AE_MOVIE_BEZIER_WARP_BASE_GRID
+#   define AE_MOVIE_BEZIER_WARP_BASE_GRID (7U)
+#endif 
+
+
+#ifndef AE_MOVIE_LAYER_MAX_OPTIONS
+#   define AE_MOVIE_LAYER_MAX_OPTIONS (8U)
+#endif
+
+#endif

+ 436 - 0
ae-movie/include/movie/movie_data.h

@@ -0,0 +1,436 @@
+/******************************************************************************
+* libMOVIE Software License v1.0
+*
+* Copyright (c) 2016-2018, Yuriy Levchenko <[email protected]>
+* All rights reserved.
+*
+* You are granted a perpetual, non-exclusive, non-sublicensable, and
+* non-transferable license to use, install, execute, and perform the libMOVIE
+* software and derivative works solely for personal or internal
+* use. Without the written permission of Yuriy Levchenko, you may not (a) modify, translate,
+* adapt, or develop new applications using the libMOVIE or otherwise
+* create derivative works or improvements of the libMOVIE or (b) remove,
+* delete, alter, or obscure any trademarks or any copyright, trademark, patent,
+* or other intellectual property or proprietary rights notices on or in the
+* Software, including any copy thereof. Redistributions in binary or source
+* form must include this license and terms.
+*
+* THIS SOFTWARE IS PROVIDED BY YURIY LEVCHENKO "AS IS" AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+* EVENT SHALL YURIY LEVCHENKO BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION,
+* OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF
+* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+#ifndef MOVIE_DATA_H_
+#define MOVIE_DATA_H_
+
+#include "movie_type.h"
+#include "movie_typedef.h"
+#include "movie_instance.h"
+
+/**
+@addtogroup data_types
+@{
+*/
+
+/*
+ case AE_MOVIE_LAYER_TYPE_MOVIE:
+ case AE_MOVIE_LAYER_TYPE_SPRITE:
+ case AE_MOVIE_LAYER_TYPE_TEXT:
+ case AE_MOVIE_LAYER_TYPE_EVENT:
+ case AE_MOVIE_LAYER_TYPE_SOCKET:
+ case AE_MOVIE_LAYER_TYPE_SHAPE:
+ case AE_MOVIE_LAYER_TYPE_SLOT:
+ case AE_MOVIE_LAYER_TYPE_NULL:
+ case AE_MOVIE_LAYER_TYPE_SCENE_EFFECT:
+ case AE_MOVIE_LAYER_TYPE_SOLID:
+ case AE_MOVIE_LAYER_TYPE_SEQUENCE:
+ case AE_MOVIE_LAYER_TYPE_VIDEO:
+ case AE_MOVIE_LAYER_TYPE_SOUND:
+ case AE_MOVIE_LAYER_TYPE_PARTICLE:
+ case AE_MOVIE_LAYER_TYPE_IMAGE:
+ case AE_MOVIE_LAYER_TYPE_SUB_MOVIE:
+ */
+
+typedef enum aeMovieLayerTypeEnum
+{
+    AE_MOVIE_LAYER_TYPE_MOVIE = 1,
+    AE_MOVIE_LAYER_TYPE_SPRITE = 4,
+    AE_MOVIE_LAYER_TYPE_TEXT = 5,
+    AE_MOVIE_LAYER_TYPE_EVENT = 7,
+    AE_MOVIE_LAYER_TYPE_SOCKET = 8,
+    AE_MOVIE_LAYER_TYPE_SHAPE = 9,
+    AE_MOVIE_LAYER_TYPE_SLOT = 11,
+    AE_MOVIE_LAYER_TYPE_NULL = 12,
+    AE_MOVIE_LAYER_TYPE_SCENE_EFFECT = 13,
+    AE_MOVIE_LAYER_TYPE_SOLID = 14,
+    AE_MOVIE_LAYER_TYPE_SEQUENCE = 15,
+    AE_MOVIE_LAYER_TYPE_VIDEO = 16,
+    AE_MOVIE_LAYER_TYPE_SOUND = 17,
+    AE_MOVIE_LAYER_TYPE_PARTICLE = 18,
+    AE_MOVIE_LAYER_TYPE_IMAGE = 20,
+    AE_MOVIE_LAYER_TYPE_SUB_MOVIE = 21,
+} aeMovieLayerTypeEnum;
+
+typedef enum aeMovieCompositionFlag
+{
+    AE_MOVIE_COMPOSITION_LOOP_SEGMENT = 0x00000001,
+    AE_MOVIE_COMPOSITION_ANCHOR_POINT = 0x00000002,
+    AE_MOVIE_COMPOSITION_OFFSET_POINT = 0x00000004,
+    AE_MOVIE_COMPOSITION_BOUNDS = 0x00000008,
+    AE_MOVIE_COMPOSITION_CAMERA = 0x00000010,
+} aeMovieCompositionFlag;
+
+// data_types
+/// @}
+
+/**
+@addtogroup data
+@{
+*/
+
+typedef struct aeMovieDataCacheUVAvailableCallbackData
+{
+	ae_uint32_t dummy;
+} aeMovieDataCacheUVAvailableCallbackData;
+
+typedef struct aeMovieDataCacheUVProviderCallbackData
+{
+    const aeMovieResource * resource;
+
+    ae_uint32_t vertex_count;
+    const ae_vector2_t * uvs;
+} aeMovieDataCacheUVProviderCallbackData;
+
+typedef struct aeMovieDataCacheUVDeleterCallbackData
+{
+    ae_userdata_t uv_cache_userdata;
+} aeMovieDataCacheUVDeleterCallbackData;
+
+/**
+@brief Callback to allocate a new resource given by the descriptor.
+@param [in] _resource Description of the resource to load.
+@param [in] _data Object which will hold the resource reference after loading.
+@return Reference to the created resource.
+*/
+typedef ae_bool_t( *ae_movie_data_callback_resource_provider_t )(const aeMovieResource * _resource, ae_userdataptr_t _rd, ae_userdata_t _ud);
+typedef ae_void_t( *ae_movie_data_callback_resource_deleter_t )(aeMovieResourceTypeEnum _type, ae_userdata_t _data, ae_userdata_t _ud);
+
+typedef ae_bool_t( *ae_movie_data_callback_cache_uv_available_t )(const aeMovieDataCacheUVAvailableCallbackData * _callbackData, ae_userdata_t _ud);
+typedef ae_bool_t( *ae_movie_data_callback_cache_uv_provider_t )(const aeMovieDataCacheUVProviderCallbackData * _callbackData, ae_userdataptr_t _rd, ae_userdata_t _ud);
+typedef ae_void_t( *ae_movie_data_callback_cache_uv_deleter_t )(const aeMovieDataCacheUVDeleterCallbackData * _callbackData, ae_userdata_t _ud);
+
+typedef struct aeMovieDataProviders
+{
+    ae_movie_data_callback_resource_provider_t resource_provider;
+    ae_movie_data_callback_resource_deleter_t resource_deleter;
+
+	ae_movie_data_callback_cache_uv_available_t cache_uv_available;
+    ae_movie_data_callback_cache_uv_provider_t cache_uv_provider;
+    ae_movie_data_callback_cache_uv_deleter_t cache_uv_deleter;
+} aeMovieDataProviders;
+
+ae_void_t ae_clear_movie_data_providers( aeMovieDataProviders * _providers );
+
+/**
+@brief Allocate a data structure to load movie file into.
+@param [in] _instance Instance.
+@return Pointer to the created structure.
+*/
+aeMovieData * ae_create_movie_data( const aeMovieInstance * _instance, const aeMovieDataProviders * _providers, ae_userdata_t _userdata );
+
+/**
+@brief Release data.
+@param [in] _movieData Data.
+*/
+ae_void_t ae_delete_movie_data( const aeMovieData * _movieData );
+
+/**
+@brief Create a stream to load the data from the given data pointer.
+@param [in] _instance Instance.
+@param [in] _read,_copy User pointers to utility functions.
+@param [in] _userdata Object to use in above callbacks to read data from.
+@return Pointer to the stream.
+*/
+aeMovieStream * ae_create_movie_stream( const aeMovieInstance * _instance, ae_movie_stream_memory_read_t _read, ae_movie_stream_memory_copy_t _copy, ae_userdata_t _userdata );
+
+/**
+@brief Create a stream to load the data from the given data pointer.
+@param [in] _instance Instance.
+@param [in] _read,_copy User pointers to utility functions.
+@param [in] _userdata Object to use in above callbacks to read data from.
+@return Pointer to the stream.
+*/
+aeMovieStream * ae_create_movie_stream_memory( const aeMovieInstance * _instance, ae_constvoidptr_t _buffer, ae_movie_stream_memory_copy_t _copy, ae_userdata_t _userdata );
+
+
+/**
+@brief Release stream.
+@param [in] _stream Stream.
+*/
+ae_void_t ae_delete_movie_stream( const aeMovieStream * _stream );
+
+/**
+@brief Fills movie data structure and loads resources through provider.
+@param [in] _stream Object to load from.
+@param [in] _major major version.
+@param [in] _minor minor version.
+@return TRUE if successful.
+*/
+ae_result_t ae_check_movie_data( aeMovieStream * _stream, ae_uint32_t * _major, ae_uint32_t * _minor );
+
+/**
+@brief get sdk version
+@return version.
+*/
+ae_uint32_t ae_get_movie_sdk_major_version( void );
+ae_uint32_t ae_get_movie_sdk_minor_version( void );
+/**
+@brief get result string info
+@param [in] _result code
+@return string info.
+*/
+const ae_char_t * ae_get_result_string_info( ae_result_t _result );
+
+/**
+@brief Fills movie data structure and loads resources through provider.
+@param [in] _movieData Data structure to fill.
+@param [in] _stream Object to load from.
+@param [in] _major major version.
+@param [in] _minor minor version.
+@return TRUE if successful.
+*/
+ae_result_t ae_load_movie_data( aeMovieData * _movieData, aeMovieStream * _stream, ae_uint32_t * _major, ae_uint32_t * _minor );
+
+/**
+@param [in] _movieData Data.
+@return NAME movie data
+*/
+const ae_char_t * ae_get_movie_name( const aeMovieData * _movieData );
+
+/**
+@param [in] _movieData Data.
+@return TRUE if content is common store
+*/
+ae_bool_t ae_is_movie_common_store( const aeMovieData * _movieData );
+
+/**
+@brief Search for composition data by the given name.
+@param [in] _movieData Data.
+@param [in] _name Composition name.
+@return TRUE is composition exist.
+*/
+ae_bool_t ae_has_movie_composition_data( const aeMovieData * _movieData, const ae_char_t * _name );
+
+/**
+@brief Search for composition data by the given name.
+@param [in] _movieData Data.
+@param [in] _name Composition name.
+@return Pointer to the data or AE_NULL if not found.
+*/
+const aeMovieCompositionData * ae_get_movie_composition_data( const aeMovieData * _movieData, const ae_char_t * _name );
+
+typedef ae_bool_t( *ae_movie_layer_data_visitor_t )(const aeMovieCompositionData * _compositionData, const aeMovieLayerData * _layer, ae_userdata_t _ud);
+
+ae_bool_t ae_visit_movie_layer_data( const aeMovieData * _movieData, ae_movie_layer_data_visitor_t _visitor, ae_userdata_t _ud );
+
+/**
+@param [in] _layer Layer.
+@return Layer name.
+*/
+const ae_char_t * ae_get_movie_layer_data_name( const aeMovieLayerData * _layer );
+
+/**
+@param [in] _layer Layer.
+@return Layer type.
+*/
+aeMovieLayerTypeEnum ae_get_movie_layer_data_type( const aeMovieLayerData * _layer );
+
+/**
+@param [in] _layer Layer.
+@return TRUE if the layer is a track matte layer.
+*/
+ae_bool_t ae_is_movie_layer_data_track_mate( const aeMovieLayerData * _layer );
+
+/**
+@param [in] _layer Layer.
+@return TRUE if the layer data is three-dimensional.
+*/
+ae_bool_t ae_is_movie_layer_data_threeD( const aeMovieLayerData * _layer );
+
+/**
+@param [in] _layer Layer.
+@return TRUE if the layer data is incessantly.
+*/
+ae_bool_t ae_is_movie_layer_data_incessantly( const aeMovieLayerData * _layer );
+
+/**
+@param [in] _layer Layer.
+@param [in] _option option identity.
+@return TRUE if the layer has this option.
+*/
+ae_bool_t ae_has_movie_layer_data_option( const aeMovieLayerData * _layer, ae_uint32_t _option );
+
+ae_uint32_t ae_get_movie_layer_data_option_count( const aeMovieLayerData * _layer );
+ae_uint32_t ae_get_movie_layer_data_option( const aeMovieLayerData * _layer, ae_uint32_t _index );
+
+/**
+@param [in] _layer Layer.
+@return resource linked to the layer.
+*/
+const aeMovieResource * ae_get_movie_layer_data_resource( const aeMovieLayerData * _layer );
+
+/**
+@param [in] _layer Layer.
+@return Pointer to the data referenced by the resource linked to the layer.
+*/
+ae_userdata_t ae_get_movie_layer_data_resource_userdata( const aeMovieLayerData * _layer );
+
+/**
+@param [in] _layer Layer.
+@return Pointer to the data referenced by the resource linked to the layer.
+*/
+ae_bool_t ae_test_movie_layer_data_opacity_transparent( const aeMovieLayerData * _layer );
+
+/**
+@brief Get track matte type layer
+@param [in] _layer Layer.
+@return Layer track matte type.
+*/
+ae_track_matte_mode_t ae_get_movie_layer_data_track_matte_mode( const aeMovieLayerData * _layer );
+
+/**
+@brief Get blend mode layer
+@param [in] _layer Layer.
+@return Layer blend mode.
+*/
+ae_blend_mode_t ae_get_movie_layer_data_blend_mode( const aeMovieLayerData * _layer );
+
+
+/**
+@brief Get stretch layer
+@param [in] _layer Layer.
+@return stretch.
+*/
+ae_float_t ae_get_movie_layer_data_stretch( const aeMovieLayerData * _layer );
+
+/**
+@brief Get viewport layer
+@param [in] _layer Layer.
+@return viewport.
+*/
+const ae_viewport_t * ae_get_movie_layer_data_viewport( const aeMovieLayerData * _layer );
+
+
+/**
+@brief Get polygon for a socket layer
+@param [in] _layer Layer.
+@param [in] _frame frame of polygon.
+@param [out] _polygon Socket shape.
+@return TRUE if found.
+*/
+ae_bool_t ae_get_movie_layer_data_socket_polygon( const aeMovieLayerData * _layer, ae_uint32_t _frame, const ae_polygon_t ** _polygon );
+
+
+/**
+@param [in] _compositionData Composition data.
+@return Composition name.
+*/
+const ae_char_t * ae_get_movie_composition_data_name( const aeMovieCompositionData * _compositionData );
+
+
+/**
+@param [in] _compositionData Composition data.
+@return Composition width.
+*/
+ae_float_t ae_get_movie_composition_data_width( const aeMovieCompositionData * _compositionData );
+
+/**
+@param [in] _compositionData Composition data.
+@return Composition height.
+*/
+ae_float_t ae_get_movie_composition_data_height( const aeMovieCompositionData * _compositionData );
+
+/**
+@param [in] _compositionData Composition data.
+@return Composition duration in milliseconds.
+*/
+ae_time_t ae_get_movie_composition_data_duration( const aeMovieCompositionData * _compositionData );
+
+/**
+@param [in] _compositionData Composition data.
+@return Single frame duration in milliseconds.
+*/
+ae_time_t ae_get_movie_composition_data_frame_duration( const aeMovieCompositionData * _compositionData );
+
+/**
+@param [in] _compositionData Composition data.
+@return Total number of frames in the composition.
+*/
+ae_uint32_t ae_get_movie_composition_data_frame_count( const aeMovieCompositionData * _compositionData );
+
+/**
+@brief Get composition loop range in milliseconds.
+@param [in] _compositionData Composition data.
+@param [out] _in Begin time.
+@param [out] _out End time.
+*/
+ae_void_t ae_get_movie_composition_data_loop_segment( const aeMovieCompositionData * _compositionData, ae_time_t * _in, ae_time_t * _out );
+
+/**
+@param [in] _compositionData Composition data.
+@return ???
+*/
+ae_bool_t ae_is_movie_composition_data_master( const aeMovieCompositionData * _compositionData );
+
+/**
+@param [in] _movieData Data.
+@return Total number of compositions in the movie.
+*/
+ae_uint32_t ae_get_movie_composition_data_count( const aeMovieData * _movieData );
+
+/**
+@param [in] _movieData Data.
+@param [in] _index Composition index.
+@return Composition data under the given index.
+*/
+const aeMovieCompositionData * ae_get_movie_composition_data_by_index( const aeMovieData * _movieData, ae_uint32_t _index );
+
+/**
+@param [in] _compositionData Composition data.
+@return Total number of events.
+*/
+ae_uint32_t ae_get_movie_composition_data_event_count( const aeMovieCompositionData * _compositionData );
+
+/**
+@param [in] _compositionData Composition data.
+@param [in] _index Event index.
+@return Name of the event under the given index.
+*/
+const ae_char_t * ae_get_movie_composition_data_event_name( const aeMovieCompositionData * _compositionData, ae_uint32_t _index );
+
+// data
+/// @}
+
+/**
+@brief Has composition bounds.
+@param [in] _composition Composition.
+@return TRUE if has
+*/
+ae_bool_t ae_has_movie_composition_data_bounds( const aeMovieCompositionData * _compositionData );
+
+/**
+@brief Get composition bounds.
+@param [in] _composition Composition.
+@param [out] _bounds viewport.
+@return TRUE if successful
+*/
+ae_bool_t ae_get_movie_composition_data_bounds( const aeMovieCompositionData * _compositionData, ae_viewport_t * _bounds );
+
+#endif

+ 92 - 0
ae-movie/include/movie/movie_instance.h

@@ -0,0 +1,92 @@
+/******************************************************************************
+* libMOVIE Software License v1.0
+*
+* Copyright (c) 2016-2018, Yuriy Levchenko <[email protected]>
+* All rights reserved.
+*
+* You are granted a perpetual, non-exclusive, non-sublicensable, and
+* non-transferable license to use, install, execute, and perform the libMOVIE
+* software and derivative works solely for personal or internal
+* use. Without the written permission of Yuriy Levchenko, you may not (a) modify, translate,
+* adapt, or develop new applications using the libMOVIE or otherwise
+* create derivative works or improvements of the libMOVIE or (b) remove,
+* delete, alter, or obscure any trademarks or any copyright, trademark, patent,
+* or other intellectual property or proprietary rights notices on or in the
+* Software, including any copy thereof. Redistributions in binary or source
+* form must include this license and terms.
+*
+* THIS SOFTWARE IS PROVIDED BY YURIY LEVCHENKO "AS IS" AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+* EVENT SHALL YURIY LEVCHENKO BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION,
+* OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF
+* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+#ifndef MOVIE_INSTANCE_H_
+#define MOVIE_INSTANCE_H_
+
+#include "movie_type.h"
+#include "movie_typedef.h"
+
+/**
+@addtogroup instance
+@{
+*/
+
+#ifdef AE_MOVIE_MEMORY_DEBUG
+typedef ae_voidptr_t( *ae_movie_alloc_t )(ae_userdata_t _userdata, ae_size_t _size, const ae_char_t * _file, ae_uint32_t _line);
+typedef ae_voidptr_t( *ae_movie_alloc_n_t )(ae_userdata_t _userdata, ae_size_t _size, ae_size_t _n, const ae_char_t * _file, ae_uint32_t _line);
+#else
+typedef ae_voidptr_t( *ae_movie_alloc_t )(ae_userdata_t _userdata, ae_size_t _size);
+typedef ae_voidptr_t( *ae_movie_alloc_n_t )(ae_userdata_t _userdata, ae_size_t _size, ae_size_t _n);
+#endif
+
+typedef ae_void_t( *ae_movie_free_t )(ae_userdata_t _userdata, ae_constvoidptr_t _ptr);
+typedef ae_void_t( *ae_movie_free_n_t )(ae_userdata_t _userdata, ae_constvoidptr_t _ptr);
+
+typedef ae_int32_t( *ae_movie_strncmp_t )(ae_userdata_t _userdata, const ae_char_t * _src, const ae_char_t * _dst, ae_size_t _count);
+
+typedef enum
+{
+    AE_ERROR_INFO,
+    AE_ERROR_MEMORY,
+    AE_ERROR_STREAM,
+    AE_ERROR_WARNING,
+    AE_ERROR_UNSUPPORT,
+    AE_ERROR_ERROR,
+    AE_ERROR_INTERNAL,
+    AE_ERROR_CRITICAL,
+} aeMovieErrorCode;
+
+typedef ae_void_t( *ae_movie_logger_t )(ae_userdata_t _userdata, aeMovieErrorCode _code, const ae_char_t * _message, ...);
+
+/**
+@brief Create a new instance.
+@param [in] _alloc,_alloc_n,_free,_free_n,_strncmp,_logger User pointers to utility functions.
+@param [in] _data Usually pointer to the creating object.
+*/
+const aeMovieInstance * ae_create_movie_instance(
+    const ae_char_t * _hashkey,
+    ae_movie_alloc_t _alloc,
+    ae_movie_alloc_n_t _alloc_n,
+    ae_movie_free_t _free,
+    ae_movie_free_n_t _free_n,
+    ae_movie_strncmp_t _strncmp,
+    ae_movie_logger_t _logger,
+    ae_userdata_t _userdata );
+
+/**
+@brief Delete an existing instance.
+@param [in] _instance Instance.
+*/
+ae_void_t ae_delete_movie_instance( const aeMovieInstance * _instance );
+
+// instance
+/// @}
+
+#endif

+ 455 - 0
ae-movie/include/movie/movie_providers.h

@@ -0,0 +1,455 @@
+/******************************************************************************
+* libMOVIE Software License v1.0
+*
+* Copyright (c) 2016-2018, Yuriy Levchenko <[email protected]>
+* All rights reserved.
+*
+* You are granted a perpetual, non-exclusive, non-sublicensable, and
+* non-transferable license to use, install, execute, and perform the libMOVIE
+* software and derivative works solely for personal or internal
+* use. Without the written permission of Yuriy Levchenko, you may not (a) modify, translate,
+* adapt, or develop new applications using the libMOVIE or otherwise
+* create derivative works or improvements of the libMOVIE or (b) remove,
+* delete, alter, or obscure any trademarks or any copyright, trademark, patent,
+* or other intellectual property or proprietary rights notices on or in the
+* Software, including any copy thereof. Redistributions in binary or source
+* form must include this license and terms.
+*
+* THIS SOFTWARE IS PROVIDED BY YURIY LEVCHENKO "AS IS" AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+* EVENT SHALL YURIY LEVCHENKO BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION,
+* OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF
+* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+#ifndef MOVIE_PROVIDERS_H_
+#define MOVIE_PROVIDERS_H_
+
+#include "movie_type.h"
+#include "movie_render.h"
+
+/**
+@addtogroup providers
+@{
+*/
+
+/*
+ case AE_MOVIE_STATE_UPDATE_BEGIN:
+ case AE_MOVIE_STATE_UPDATE_PROCESS:
+ case AE_MOVIE_STATE_UPDATE_PAUSE:
+ case AE_MOVIE_STATE_UPDATE_RESUME:
+ case AE_MOVIE_STATE_UPDATE_STOP:
+ case AE_MOVIE_STATE_UPDATE_END:
+ case AE_MOVIE_STATE_UPDATE_SKIP:
+ */
+
+typedef enum
+{
+    AE_MOVIE_STATE_UPDATE_BEGIN = 0,
+    AE_MOVIE_STATE_UPDATE_PROCESS,
+    AE_MOVIE_STATE_UPDATE_PAUSE,
+    AE_MOVIE_STATE_UPDATE_RESUME,
+    AE_MOVIE_STATE_UPDATE_STOP,
+    AE_MOVIE_STATE_UPDATE_END,
+    AE_MOVIE_STATE_UPDATE_SKIP
+} aeMovieStateUpdateEnum;
+
+typedef struct aeMovieCameraProviderCallbackData
+{
+    /// @brief Camera name.
+    const ae_char_t * name;
+
+    /// @brief Field-of-view in degrees.
+    ae_float_t fov;
+
+    /// @brief Viewport width.
+    ae_float_t width;
+
+    /// @brief Viewport height.
+    ae_float_t height;
+
+    ae_vector3_t target;
+    ae_vector3_t position;
+    ae_quaternion_t quaternion;
+} aeMovieCameraProviderCallbackData;
+
+typedef struct aeMovieCameraDeleterCallbackData
+{
+    /// @brief Camera element data.
+    ae_userdata_t camera_userdata;
+
+    /// @brief Camera name.
+    const ae_char_t * name;
+} aeMovieCameraDeleterCallbackData;
+
+typedef struct aeMovieCameraUpdateCallbackData
+{
+    /// @brief Camera element data.
+    ae_userdata_t camera_userdata;
+
+    /// @brief Camera name.
+    const ae_char_t * name;
+
+    /// @brief Camera target.
+    ae_vector3_t target;
+
+    /// @brief Camera position.
+    ae_vector3_t position;
+
+    /// @brief Camera quaternion.
+    ae_quaternion_t quaternion;
+} aeMovieCameraUpdateCallbackData;
+
+typedef struct aeMovieNodeProviderCallbackData
+{
+    ae_uint32_t index;
+
+    const aeMovieLayerData * layer;
+
+    /// @brief if node incessantly timeline
+    ae_bool_t incessantly;
+
+    ae_bool_t immutable_matrix;
+
+    /// @brief Additional transform, e.g. for slots/sockets.
+    ae_matrix34_ptr_t matrix;
+
+    /// @brief Value from 0.0 to 1.0.
+    ae_color_t color;
+
+    /// @brief Value from 0.0 to 1.0.
+    ae_color_channel_t opacity;
+
+    /// @brief Value from 0.0 to 1.0.
+    ae_float_t volume;
+
+    /// @brief Pointer to track matte layer, should be used to create user track matte structure inside provider.
+    const aeMovieLayerData * track_matte_layer;
+} aeMovieNodeProviderCallbackData;
+
+typedef struct aeMovieNodeDeleterCallbackData
+{
+    ae_uint32_t index;
+
+    ae_userdata_t element_userdata;
+    const aeMovieLayerData * layer;
+
+    const aeMovieLayerData * track_matte_layer;
+} aeMovieNodeDeleterCallbackData;
+
+typedef struct aeMovieNodeUpdateCallbackData
+{
+    ae_uint32_t index;
+
+    ae_userdata_t element_userdata;
+    const aeMovieLayerData * layer;
+
+    ae_bool_t loop;
+    ae_bool_t interrupt;
+    aeMovieStateUpdateEnum state;
+    ae_time_t offset;
+
+    ae_bool_t immutable_matrix;
+
+    /// @brief Additional transform, e.g. for slots/sockets.
+    ae_matrix34_ptr_t matrix;
+
+    ae_bool_t immutable_color;
+
+    /// @brief Value from 0.0 to 1.0.
+    ae_color_t color;
+
+    /// @brief Value from 0.0 to 1.0.
+    ae_color_channel_t opacity;
+
+    /// @brief Value from 0.0 to 1.0.
+    ae_float_t volume;
+} aeMovieNodeUpdateCallbackData;
+
+typedef struct aeMovieTrackMatteProviderCallbackData
+{
+    ae_uint32_t index;
+
+    ae_userdata_t element_userdata;
+    const aeMovieLayerData * layer;
+
+    ae_bool_t loop;
+    ae_time_t offset;
+
+    ae_bool_t immutable_matrix;
+
+    /// @brief Additional transform, e.g. for slots/sockets.
+    ae_matrix34_ptr_t matrix;
+
+    ae_bool_t immutable_color;
+
+    /// @brief Value from 0.0 to 1.0.
+    ae_color_t color;
+
+    /// @brief Value from 0.0 to 1.0.
+    ae_color_channel_t opacity;
+
+    aeMovieRenderMesh * mesh;
+
+    ae_track_matte_mode_t track_matte_mode;
+} aeMovieTrackMatteProviderCallbackData;
+
+typedef struct aeMovieTrackMatteUpdateCallbackData
+{
+    ae_uint32_t index;
+
+    ae_userdata_t element_userdata;
+    const aeMovieLayerData * layer;
+
+    ae_bool_t interrupt;
+    ae_bool_t loop;
+    aeMovieStateUpdateEnum state;
+    ae_time_t offset;
+
+    ae_bool_t immutable_matrix;
+
+    /// @brief Additional transform, e.g. for slots/sockets.
+    ae_matrix34_ptr_t matrix;
+
+    ae_bool_t immutable_color;
+
+    /// @brief Value from 0.0 to 1.0.
+    ae_color_t color;
+
+    /// @brief Value from 0.0 to 1.0.
+    ae_color_channel_t opacity;
+
+    aeMovieRenderMesh * mesh;
+
+    ae_userdata_t track_matte_userdata;
+} aeMovieTrackMatteUpdateCallbackData;
+
+typedef struct aeMovieTrackMatteDeleterCallbackData
+{
+    ae_uint32_t index;
+
+    ae_userdata_t element_userdata;
+    const aeMovieLayerData * layer;
+
+    ae_userdata_t track_matte_userdata;
+} aeMovieTrackMatteDeleterCallbackData;
+
+typedef struct aeMovieShaderProviderCallbackData
+{
+    ae_string_t name;
+    ae_string_t description;
+    ae_uint32_t version;
+    ae_uint32_t flags;
+
+    ae_uint32_t parameter_count;
+    ae_string_t parameter_names[32];
+    ae_string_t parameter_uniforms[32];
+    ae_uint8_t parameter_types[32];
+    ae_float_t parameter_values[32];
+    ae_color_t parameter_colors[32];
+    ae_float_t parameter_scales[32];
+} aeMovieShaderProviderCallbackData;
+
+typedef struct aeMovieShaderPropertyUpdateCallbackData
+{
+    ae_uint32_t index;
+
+    ae_userdata_t element_userdata;
+
+    ae_string_t name;
+    ae_string_t uniform;
+    aeMovieShaderParameterTypeEnum type;
+
+    ae_color_t color;
+    ae_float_t value;
+    ae_float_t scale;
+} aeMovieShaderPropertyUpdateCallbackData;
+
+typedef struct aeMovieShaderDeleterCallbackData
+{
+    ae_uint32_t index;
+
+    ae_userdata_t element_userdata;
+
+    ae_string_t name;
+    ae_uint32_t version;
+} aeMovieShaderDeleterCallbackData;
+
+typedef struct aeMovieCompositionEventCallbackData
+{
+    ae_uint32_t index;
+
+    ae_userdata_t element_userdata;
+
+    /// @brief Name of the composition which sent the event.
+    const ae_char_t * name;
+
+    ae_bool_t immutable_matrix;
+
+    /// @brief Additional transform, e.g. for slots/sockets.
+    ae_matrix34_ptr_t matrix;
+
+    ae_bool_t immutable_color;
+
+    /// @brief Value from 0.0 to 1.0.
+    ae_color_t color;
+
+    /// @brief Value from 0.0 to 1.0.
+    ae_color_channel_t opacity;
+
+    ae_bool_t begin;
+} aeMovieCompositionEventCallbackData;
+
+typedef enum
+{
+    AE_MOVIE_COMPOSITION_PLAY = 0,
+    AE_MOVIE_COMPOSITION_STOP,
+    AE_MOVIE_COMPOSITION_PAUSE,
+    AE_MOVIE_COMPOSITION_RESUME,
+    AE_MOVIE_COMPOSITION_INTERRUPT,
+    AE_MOVIE_COMPOSITION_END,
+    AE_MOVIE_COMPOSITION_LOOP_END,
+} aeMovieCompositionStateEnum;
+
+typedef struct aeMovieCompositionStateCallbackData
+{
+    /// @brief New composition state.
+    aeMovieCompositionStateEnum state;
+} aeMovieCompositionStateCallbackData;
+
+typedef struct aeMovieCompositionExtraInterruptCallbackData
+{
+    ae_uint32_t dummy;
+} aeMovieCompositionExtraInterruptCallbackData;
+
+typedef struct aeMovieCompositionSceneEffectProviderCallbackData
+{
+    ae_uint32_t index;
+
+    ae_userdata_t element_userdata;
+
+    /// @brief Additional transform, e.g.
+    ae_vector2_t anchor_point;
+    ae_vector2_t position;
+    ae_vector2_t scale;
+    ae_quaternionzw_t quaternion;
+    ae_skew_t skew;
+
+    ae_color_t color;
+    ae_color_channel_t opacity;
+} aeMovieCompositionSceneEffectProviderCallbackData;
+
+typedef struct aeMovieCompositionSceneEffectDeleterCallbackData
+{
+    ae_userdata_t element_userdata;
+
+    ae_userdata_t scene_effect_userdata;
+} aeMovieCompositionSceneEffectDeleterCallbackData;
+
+typedef struct aeMovieCompositionSceneEffectUpdateCallbackData
+{
+    ae_userdata_t element_userdata;
+
+    /// @brief Additional transform, e.g.
+    ae_vector2_t anchor_point;
+    ae_vector2_t position;
+    ae_vector2_t scale;
+    ae_quaternionzw_t quaternion;
+    ae_skew_t skew;
+
+    ae_color_t color;
+    ae_color_channel_t opacity;
+
+    ae_userdata_t scene_effect_userdata;
+} aeMovieCompositionSceneEffectUpdateCallbackData;
+
+typedef struct aeMovieSubCompositionProviderCallbackData
+{
+    const aeMovieLayerData * layer;
+    const aeMovieCompositionData * composition_data;
+    const struct aeMovieCompositionAnimation * animation;
+} aeMovieSubCompositionProviderCallbackData;
+
+typedef struct aeMovieSubCompositionDeleterCallbackData
+{
+    ae_userdata_t subcomposition_userdata;
+} aeMovieSubCompositionDeleterCallbackData;
+
+typedef struct aeMovieSubCompositionStateCallbackData
+{
+    /// @brief New composition state.
+    aeMovieCompositionStateEnum state;
+
+    ae_userdata_t subcomposition_userdata;
+} aeMovieSubCompositionStateCallbackData;
+
+typedef ae_bool_t( *ae_movie_composition_callback_node_provider_t )(const aeMovieNodeProviderCallbackData * _callbackData, ae_userdataptr_t _nd, ae_userdata_t _ud);
+typedef ae_void_t( *ae_movie_composition_callback_node_deleter_t )(const aeMovieNodeDeleterCallbackData * _callbackData, ae_userdata_t _ud);
+typedef ae_void_t( *ae_movie_composition_callback_node_update_t )(const aeMovieNodeUpdateCallbackData * _callbackData, ae_userdata_t _ud);
+
+typedef ae_bool_t( *ae_movie_composition_callback_camera_provider_t )(const aeMovieCameraProviderCallbackData * _callbackData, ae_userdataptr_t _cd, ae_userdata_t _ud);
+typedef ae_void_t( *ae_movie_composition_callback_camera_deleter_t )(const aeMovieCameraDeleterCallbackData * _callbackData, ae_userdata_t _ud);
+typedef ae_void_t( *ae_movie_composition_callback_camera_update_t )(const aeMovieCameraUpdateCallbackData * _callbackData, ae_userdata_t _ud);
+
+typedef ae_bool_t( *ae_movie_composition_callback_track_matte_provider_t )(const aeMovieTrackMatteProviderCallbackData * _callbackData, ae_userdataptr_t _tmd, ae_userdata_t _ud);
+typedef ae_void_t( *ae_movie_composition_callback_track_matte_deleter_t )(const aeMovieTrackMatteDeleterCallbackData * _callbackData, ae_userdata_t _ud);
+typedef ae_void_t( *ae_movie_composition_callback_track_matte_update_t )(const aeMovieTrackMatteUpdateCallbackData * _callbackData, ae_userdata_t _ud);
+
+typedef ae_bool_t( *ae_movie_composition_callback_shader_provider_t )(const aeMovieShaderProviderCallbackData * _callbackData, ae_userdataptr_t _sd, ae_userdata_t _ud);
+typedef ae_void_t( *ae_movie_composition_callback_shader_deleter_t )(const aeMovieShaderDeleterCallbackData * _callbackData, ae_userdata_t _ud);
+typedef ae_void_t( *ae_movie_composition_callback_shader_property_update_t )(const aeMovieShaderPropertyUpdateCallbackData * _callbackData, ae_userdata_t _ud);
+
+typedef ae_void_t( *ae_movie_composition_callback_composition_event_t )(const aeMovieCompositionEventCallbackData * _callbackData, ae_userdata_t _ud);
+typedef ae_void_t( *ae_movie_composition_callback_composition_state_t )(const aeMovieCompositionStateCallbackData * _callbackData, ae_userdata_t _ud);
+typedef ae_bool_t( *ae_movie_composition_callback_composition_extra_interrupt_t )(const aeMovieCompositionExtraInterruptCallbackData * _callbackData, ae_userdata_t _ud);
+
+typedef ae_bool_t( *ae_movie_composition_callback_scene_effect_provider_t )(const aeMovieCompositionSceneEffectProviderCallbackData * _callbackData, ae_userdataptr_t _sed, ae_userdata_t _ud);
+typedef ae_void_t( *ae_movie_composition_callback_scene_effect_deleter_t )(const aeMovieCompositionSceneEffectDeleterCallbackData * _callbackData, ae_userdata_t _ud);
+typedef ae_void_t( *ae_movie_composition_callback_scene_effect_update_t )(const aeMovieCompositionSceneEffectUpdateCallbackData * _callbackData, ae_userdata_t _ud);
+
+typedef ae_bool_t( *ae_movie_composition_callback_subcomposition_provider_t )(const aeMovieSubCompositionProviderCallbackData * _callbackData, ae_userdataptr_t _scd, ae_userdata_t _ud);
+typedef ae_void_t( *ae_movie_composition_callback_subcomposition_deleter_t )(const aeMovieSubCompositionDeleterCallbackData * _callbackData, ae_userdata_t _ud);
+typedef ae_void_t( *ae_movie_composition_callback_subcomposition_state_t )(const aeMovieSubCompositionStateCallbackData * _callbackData, ae_userdata_t _ud);
+
+typedef struct aeMovieCompositionProviders
+{
+    ae_movie_composition_callback_node_provider_t node_provider;
+    ae_movie_composition_callback_node_deleter_t node_deleter;
+    ae_movie_composition_callback_node_update_t node_update;
+
+    ae_movie_composition_callback_camera_provider_t camera_provider;
+    ae_movie_composition_callback_camera_deleter_t camera_deleter;
+    ae_movie_composition_callback_camera_update_t camera_update;
+
+    ae_movie_composition_callback_track_matte_provider_t track_matte_provider;
+    ae_movie_composition_callback_track_matte_deleter_t track_matte_deleter;
+    ae_movie_composition_callback_track_matte_update_t track_matte_update;
+
+    ae_movie_composition_callback_shader_provider_t shader_provider;
+    ae_movie_composition_callback_shader_deleter_t shader_deleter;
+    ae_movie_composition_callback_shader_property_update_t shader_property_update;
+
+    ae_movie_composition_callback_composition_event_t composition_event;
+    ae_movie_composition_callback_composition_state_t composition_state;
+    ae_movie_composition_callback_composition_extra_interrupt_t composition_extra_interrupt;
+
+    ae_movie_composition_callback_scene_effect_provider_t scene_effect_provider;
+    ae_movie_composition_callback_scene_effect_deleter_t scene_effect_deleter;
+    ae_movie_composition_callback_scene_effect_update_t scene_effect_update;
+
+    ae_movie_composition_callback_subcomposition_provider_t subcomposition_provider;
+    ae_movie_composition_callback_subcomposition_deleter_t subcomposition_deleter;
+    ae_movie_composition_callback_subcomposition_state_t subcomposition_state;
+} aeMovieCompositionProviders;
+
+ae_void_t ae_clear_movie_composition_providers( aeMovieCompositionProviders * _providers );
+
+// providers
+/// @}
+
+#endif

+ 144 - 0
ae-movie/include/movie/movie_render.h

@@ -0,0 +1,144 @@
+/******************************************************************************
+* libMOVIE Software License v1.0
+*
+* Copyright (c) 2016-2018, Yuriy Levchenko <[email protected]>
+* All rights reserved.
+*
+* You are granted a perpetual, non-exclusive, non-sublicensable, and
+* non-transferable license to use, install, execute, and perform the libMOVIE
+* software and derivative works solely for personal or internal
+* use. Without the written permission of Yuriy Levchenko, you may not (a) modify, translate,
+* adapt, or develop new applications using the libMOVIE or otherwise
+* create derivative works or improvements of the libMOVIE or (b) remove,
+* delete, alter, or obscure any trademarks or any copyright, trademark, patent,
+* or other intellectual property or proprietary rights notices on or in the
+* Software, including any copy thereof. Redistributions in binary or source
+* form must include this license and terms.
+*
+* THIS SOFTWARE IS PROVIDED BY YURIY LEVCHENKO "AS IS" AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+* EVENT SHALL YURIY LEVCHENKO BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION,
+* OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF
+* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+#ifndef MOVIE_RENDER_H_
+#define MOVIE_RENDER_H_
+
+#include "movie_type.h"
+#include "movie_data.h"
+
+/**
+@addtogroup render
+@{
+*/
+
+/**
+@brief Mesh used in render loop.
+
+Can be provided:
+<ul>
+<li>By ae_compute_movie_mesh().</li>
+<li>As a part of track matte data structure,
+which is in turn created and updated inside
+user-provided callbacks (see \link #ae_movie_callback_node_provider_t node provider\endlink etc.).</li>
+</ul>
+*/
+typedef struct aeMovieRenderMesh
+{
+    /**
+    @brief Renderable type.
+    */
+    aeMovieLayerTypeEnum layer_type;
+
+    /**
+    @brief One of AE blend modes.
+    */
+    ae_blend_mode_t blend_mode;
+
+    /**
+    @brief Type of the resource associated with the mesh.
+    */
+    aeMovieResourceTypeEnum resource_type;
+
+    /**
+    @brief Pointer to the resource data.
+    */
+    ae_userdata_t resource_userdata;
+
+    /**
+    @brief Number of vertices.
+    */
+    ae_uint32_t vertexCount;
+
+    /**
+    @brief Number of indices.
+    */
+    ae_uint32_t indexCount;
+
+    /**
+    @brief Vertex positions.
+    */
+    ae_vector3_t position[AE_MOVIE_MAX_VERTICES];
+
+    /**
+    @brief Texture coordinates.
+    */
+    ae_vector2_t uv[AE_MOVIE_MAX_VERTICES];
+
+    ae_userdata_t uv_cache_userdata;
+
+    /**
+    @brief Triangle indices.
+    */
+    const ae_uint16_t * indices;
+
+    /**
+    @name Color
+    @brief Usually used as a multiplier.
+    @{
+    */
+    ae_color_t color;
+    ae_color_channel_t opacity;
+    /// @}
+
+    /**
+    @brief Pointer to a user-provided camera structure.
+    */
+    ae_userdata_t camera_userdata;
+
+    ae_track_matte_mode_t track_matte_mode;
+
+    /**
+    @brief Pointer to a user-provided track matte structure.
+
+    Contains track matte layer data.
+    */
+    ae_userdata_t track_matte_userdata;
+
+    const ae_viewport_t * viewport;
+
+    /**
+    @brief Pointer to a user-provided shader structure.
+
+    Contains shader layer data.
+    */
+    ae_userdata_t shader_userdata;
+
+    /**
+    @brief Pointer to a user-provided node structure.
+
+    Contains data for track matte, slot, socket etc.
+    */
+    ae_userdata_t element_userdata;
+} aeMovieRenderMesh;
+
+// render
+/// @}
+
+#endif

+ 145 - 0
ae-movie/include/movie/movie_resource.h

@@ -0,0 +1,145 @@
+/******************************************************************************
+* libMOVIE Software License v1.0
+*
+* Copyright (c) 2016-2018, Yuriy Levchenko <[email protected]>
+* All rights reserved.
+*
+* You are granted a perpetual, non-exclusive, non-sublicensable, and
+* non-transferable license to use, install, execute, and perform the libMOVIE
+* software and derivative works solely for personal or internal
+* use. Without the written permission of Yuriy Levchenko, you may not (a) modify, translate,
+* adapt, or develop new applications using the libMOVIE or otherwise
+* create derivative works or improvements of the libMOVIE or (b) remove,
+* delete, alter, or obscure any trademarks or any copyright, trademark, patent,
+* or other intellectual property or proprietary rights notices on or in the
+* Software, including any copy thereof. Redistributions in binary or source
+* form must include this license and terms.
+*
+* THIS SOFTWARE IS PROVIDED BY YURIY LEVCHENKO "AS IS" AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+* EVENT SHALL YURIY LEVCHENKO BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION,
+* OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF
+* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+#ifndef MOVIE_RESOURCE_H_
+#define MOVIE_RESOURCE_H_
+
+#include "movie/movie_type.h"
+
+typedef struct aeMovieResourceSolid
+{
+    AE_MOVIE_RESOURCE_BASE();
+
+    ae_float_t width;
+    ae_float_t height;
+
+    ae_color_t color;
+} aeMovieResourceSolid;
+
+typedef enum
+{
+    AE_MOVIE_RESOURCE_VIDEO_PREMULTIPLIED = AE_BITWISE( 0 ),
+} ae_movie_resource_video_options;
+
+typedef struct aeMovieResourceVideo
+{
+    AE_MOVIE_RESOURCE_BASE();
+
+    ae_string_t path;
+    ae_uint32_t codec;
+
+    ae_uint32_t options;
+
+    ae_float_t base_width;
+    ae_float_t base_height;
+    ae_float_t trim_width;
+    ae_float_t trim_height;
+    ae_float_t offset_x;
+    ae_float_t offset_y;
+
+    ae_bool_t has_alpha_channel;
+    ae_time_t frameRate; //No TIMESCALE
+    ae_time_t duration; //No TIMESCALE
+
+    const struct aeMovieResourceVideoCache * cache;
+} aeMovieResourceVideo;
+
+typedef struct aeMovieResourceSound
+{
+    AE_MOVIE_RESOURCE_BASE();
+
+    ae_string_t path;
+    ae_uint32_t codec;
+
+    ae_time_t duration; //No TIMESCALE
+} aeMovieResourceSound;
+
+typedef enum
+{
+    AE_MOVIE_RESOURCE_IMAGE_PREMULTIPLIED = AE_BITWISE( 0 ),
+    AE_MOVIE_RESOURCE_IMAGE_TRIM = AE_BITWISE( 1 ),
+    AE_MOVIE_RESOURCE_IMAGE_TRACKMATTE = AE_BITWISE( 2 ),
+} ae_movie_resource_image_options;
+
+typedef struct aeMovieResourceImage
+{
+    AE_MOVIE_RESOURCE_BASE();
+
+    ae_string_t path;
+    ae_uint32_t codec;
+
+    ae_uint32_t options;
+
+    ae_float_t base_width;
+    ae_float_t base_height;
+    ae_float_t trim_width;
+    ae_float_t trim_height;
+    ae_float_t offset_x;
+    ae_float_t offset_y;
+
+    const ae_vector2_t * uvs;
+    const ae_vector2_t * bezier_warp_uvs[AE_MOVIE_BEZIER_MAX_QUALITY];
+    const ae_mesh_t * mesh;
+
+    const struct aeMovieResourceImage * atlas_image;
+    ae_bool_t atlas_rotate;
+
+    const struct aeMovieResourceImageCache * cache;
+} aeMovieResourceImage;
+
+typedef struct aeMovieResourceSequence
+{
+    AE_MOVIE_RESOURCE_BASE();
+
+    ae_time_t frameDurationInv; //No TIMESCALE
+
+    ae_uint32_t image_count;
+    const aeMovieResourceImage * const * images;
+} aeMovieResourceSequence;
+
+typedef struct aeMovieResourceParticle
+{
+    AE_MOVIE_RESOURCE_BASE();
+
+    ae_string_t path;
+    ae_uint32_t codec;
+
+    ae_uint32_t image_count;
+    const aeMovieResourceImage * const * images;
+} aeMovieResourceParticle;
+
+typedef struct aeMovieResourceSlot
+{
+    AE_MOVIE_RESOURCE_BASE();
+
+    ae_float_t width;
+    ae_float_t height;
+} aeMovieResourceSlot;
+
+#endif

+ 50 - 0
ae-movie/include/movie/movie_skeleton.h

@@ -0,0 +1,50 @@
+/******************************************************************************
+* libMOVIE Software License v1.0
+*
+* Copyright (c) 2016-2018, Yuriy Levchenko <[email protected]>
+* All rights reserved.
+*
+* You are granted a perpetual, non-exclusive, non-sublicensable, and
+* non-transferable license to use, install, execute, and perform the libMOVIE
+* software and derivative works solely for personal or internal
+* use. Without the written permission of Yuriy Levchenko, you may not (a) modify, translate,
+* adapt, or develop new applications using the libMOVIE or otherwise
+* create derivative works or improvements of the libMOVIE or (b) remove,
+* delete, alter, or obscure any trademarks or any copyright, trademark, patent,
+* or other intellectual property or proprietary rights notices on or in the
+* Software, including any copy thereof. Redistributions in binary or source
+* form must include this license and terms.
+*
+* THIS SOFTWARE IS PROVIDED BY YURIY LEVCHENKO "AS IS" AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+* EVENT SHALL YURIY LEVCHENKO BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION,
+* OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF
+* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+#ifndef MOVIE_SKELETON_H_
+#define MOVIE_SKELETON_H_
+
+#include "movie_type.h"
+#include "movie_instance.h"
+#include "movie_resource.h"
+#include "movie_data.h"
+
+typedef struct aeMovieSkeleton
+{
+    aeMovieComposition * base;
+
+    aeMovieComposition * animations[8];
+} aeMovieSkeleton;
+
+aeMovieSkeleton * ae_movie_create_skeleton( aeMovieComposition * _base );
+ae_bool_t ae_movie_skeleton_add_animation( aeMovieSkeleton * _skeleton, aeMovieComposition * _animation );
+
+ae_void_t ae_movie_destroy_skeleton( const aeMovieSkeleton * _skeleton );
+
+#endif

+ 219 - 0
ae-movie/include/movie/movie_type.h

@@ -0,0 +1,219 @@
+/******************************************************************************
+* libMOVIE Software License v1.0
+*
+* Copyright (c) 2016-2018, Yuriy Levchenko <[email protected]>
+* All rights reserved.
+*
+* You are granted a perpetual, non-exclusive, non-sublicensable, and
+* non-transferable license to use, install, execute, and perform the libMOVIE
+* software and derivative works solely for personal or internal
+* use. Without the written permission of Yuriy Levchenko, you may not (a) modify, translate,
+* adapt, or develop new applications using the libMOVIE or otherwise
+* create derivative works or improvements of the libMOVIE or (b) remove,
+* delete, alter, or obscure any trademarks or any copyright, trademark, patent,
+* or other intellectual property or proprietary rights notices on or in the
+* Software, including any copy thereof. Redistributions in binary or source
+* form must include this license and terms.
+*
+* THIS SOFTWARE IS PROVIDED BY YURIY LEVCHENKO "AS IS" AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+* EVENT SHALL YURIY LEVCHENKO BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION,
+* OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF
+* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+#ifndef MOVIE_TYPE_H_
+#define MOVIE_TYPE_H_
+
+#include <stdint.h>
+#include <stddef.h>
+
+#include "movie/movie_config.h"
+
+typedef void ae_void_t;
+typedef uint32_t ae_bool_t;
+typedef char ae_char_t;
+typedef uint8_t ae_uint8_t;
+typedef uint16_t ae_uint16_t;
+typedef uint32_t ae_uint32_t;
+typedef int32_t ae_int32_t;
+typedef size_t ae_size_t;
+typedef int32_t ae_enum_t;
+typedef float ae_float_t;
+typedef float ae_time_t;
+typedef ae_void_t * ae_voidptr_t;
+typedef ae_voidptr_t * ae_voidptrptr_t;
+typedef const ae_void_t * ae_constvoidptr_t;
+typedef ae_uint8_t * ae_byteptr_t;
+typedef const ae_uint8_t * ae_constbyteptr_t;
+typedef ae_voidptr_t ae_userdata_t;
+typedef ae_userdata_t * ae_userdataptr_t;
+
+typedef ae_char_t * ae_string_t;
+
+typedef ae_float_t ae_vector2_t[2];
+typedef ae_float_t ae_vector3_t[3];
+typedef ae_float_t ae_quaternionzw_t[2];
+typedef ae_float_t ae_quaternion_t[4];
+typedef ae_float_t ae_skew_t[3];
+typedef ae_float_t ae_matrix34_t[12];
+
+typedef const ae_float_t * ae_vector3_ptr_t;
+typedef const ae_float_t * ae_matrix34_ptr_t;
+typedef void( *ae_function_t )(void);
+
+static const ae_bool_t AE_TRUE = 1;
+static const ae_bool_t AE_FALSE = 0;
+static const ae_voidptr_t AE_NULLPTR = 0;
+static const ae_userdata_t AE_USERDATA_NULL = 0;
+static const ae_function_t AE_FUNCTION_NULL = 0;
+
+#define AE_BITWISE(X) (1 << X)
+#define AE_OPTION(A, B, C, D) ((A << 24) | (B << 16) | (C << 8) | D)
+
+typedef ae_float_t ae_color_channel_t;
+
+typedef struct
+{
+    ae_color_channel_t r;
+    ae_color_channel_t g;
+    ae_color_channel_t b;
+} ae_color_t;
+
+typedef struct
+{
+    ae_uint32_t point_count;
+    const ae_vector2_t * points;
+} ae_polygon_t;
+
+typedef struct
+{
+    ae_float_t begin_x;
+    ae_float_t begin_y;
+    ae_float_t end_x;
+    ae_float_t end_y;
+} ae_viewport_t;
+
+typedef struct
+{
+    ae_uint32_t vertex_count;
+    ae_uint32_t index_count;
+    const ae_vector2_t * positions;
+    const ae_vector2_t * uvs;
+    const ae_uint16_t * indices;
+} ae_mesh_t;
+
+typedef struct aeMovieStream aeMovieStream;
+
+#ifndef AE_MOVIE_MAX_LAYER_NAME
+#	define AE_MOVIE_MAX_LAYER_NAME 128U
+#endif
+
+#ifndef AE_MOVIE_MAX_COMPOSITION_NAME
+#	define AE_MOVIE_MAX_COMPOSITION_NAME 128U
+#endif
+
+#ifndef AE_MOVIE_MAX_VERTICES
+#	define AE_MOVIE_MAX_VERTICES 1024U
+#endif
+
+typedef enum
+{
+    AE_MOVIE_RESOURCE_NONE = 0,
+    AE_MOVIE_RESOURCE_SOLID = 4,
+    AE_MOVIE_RESOURCE_VIDEO = 5,
+    AE_MOVIE_RESOURCE_SOUND = 6,
+    AE_MOVIE_RESOURCE_IMAGE = 7,
+    AE_MOVIE_RESOURCE_SEQUENCE = 8,
+    AE_MOVIE_RESOURCE_PARTICLE = 9,
+    AE_MOVIE_RESOURCE_SLOT = 10,
+} aeMovieResourceTypeEnum;
+
+typedef enum
+{
+    AE_MOVIE_EXTENSION_SHADER_PARAMETER_SLIDER = 3,
+    AE_MOVIE_EXTENSION_SHADER_PARAMETER_ANGLE = 4,
+    AE_MOVIE_EXTENSION_SHADER_PARAMETER_COLOR = 5,
+    AE_MOVIE_EXTENSION_SHADER_PARAMETER_TIME = 6,
+} aeMovieShaderParameterTypeEnum;
+
+#define AE_MOVIE_RESOURCE_BASE()\
+	aeMovieResourceTypeEnum type;\
+    ae_string_t name;\
+	ae_voidptr_t userdata
+
+typedef struct aeMovieResource
+{
+    AE_MOVIE_RESOURCE_BASE();
+} aeMovieResource;
+
+typedef enum
+{
+    AE_MOVIE_BLEND_ADD = 1,
+    AE_MOVIE_BLEND_ALPHA_ADD,
+    AE_MOVIE_BLEND_CLASSIC_COLOR_BURN,
+    AE_MOVIE_BLEND_CLASSIC_COLOR_DODGE,
+    AE_MOVIE_BLEND_CLASSIC_DIFFERENCE,
+    AE_MOVIE_BLEND_COLOR,
+    AE_MOVIE_BLEND_COLOR_BURN,
+    AE_MOVIE_BLEND_COLOR_DODGE,
+    AE_MOVIE_BLEND_DANCING_DISSOLVE,
+    AE_MOVIE_BLEND_DARKEN,
+    AE_MOVIE_BLEND_DARKER_COLOR,
+    AE_MOVIE_BLEND_DIFFERENCE,
+    AE_MOVIE_BLEND_DISSOLVE,
+    AE_MOVIE_BLEND_EXCLUSION,
+    AE_MOVIE_BLEND_HARD_LIGHT,
+    AE_MOVIE_BLEND_HARD_MIX,
+    AE_MOVIE_BLEND_HUE,
+    AE_MOVIE_BLEND_LIGHTEN,
+    AE_MOVIE_BLEND_LIGHTER_COLOR,
+    AE_MOVIE_BLEND_LINEAR_BURN,
+    AE_MOVIE_BLEND_LINEAR_DODGE,
+    AE_MOVIE_BLEND_LINEAR_LIGHT,
+    AE_MOVIE_BLEND_LUMINESCENT_PREMUL,
+    AE_MOVIE_BLEND_LUMINOSITY,
+    AE_MOVIE_BLEND_MULTIPLY,
+    AE_MOVIE_BLEND_NORMAL,
+    AE_MOVIE_BLEND_OVERLAY,
+    AE_MOVIE_BLEND_PIN_LIGHT,
+    AE_MOVIE_BLEND_SATURATION,
+    AE_MOVIE_BLEND_SCREEN,
+    AE_MOVIE_BLEND_SILHOUETE_ALPHA,
+    AE_MOVIE_BLEND_SILHOUETTE_LUMA,
+    AE_MOVIE_BLEND_SOFT_LIGHT,
+    AE_MOVIE_BLEND_STENCIL_ALPHA,
+    AE_MOVIE_BLEND_STENCIL_LUMA,
+    AE_MOVIE_BLEND_VIVID_LIGHT,
+} ae_blend_mode_t;
+
+typedef enum
+{
+    AE_MOVIE_TRACK_MATTE_NONE = 0,
+    AE_MOVIE_TRACK_MATTE_ALPHA = 1,
+    AE_MOVIE_TRACK_MATTE_ALPHA_INVERTED = 2,
+    AE_MOVIE_TRACK_MATTE_LUMA = 3,
+    AE_MOVIE_TRACK_MATTE_LUMA_INVERTED = 4,
+} ae_track_matte_mode_t;
+
+typedef enum
+{
+    AE_RESULT_SUCCESSFUL = 0,
+    AE_RESULT_INVALID_MAGIC = -2,
+    AE_RESULT_INVALID_VERSION = -3,
+    AE_RESULT_INVALID_HASH = -4,
+    AE_RESULT_INVALID_STREAM = -5,
+    AE_RESULT_INVALID_DATA = -6,
+    AE_RESULT_INVALID_MEMORY = -7,
+    AE_RESULT_INTERNAL_ERROR = -8,
+} ae_result_t;
+
+typedef ae_size_t( *ae_movie_stream_memory_read_t )(ae_voidptr_t _data, ae_voidptr_t _buff, ae_size_t _carriage, ae_size_t _size);
+typedef ae_void_t( *ae_movie_stream_memory_copy_t )(ae_voidptr_t _data, ae_constvoidptr_t _src, ae_voidptr_t _dst, ae_size_t _size);
+
+#endif

+ 51 - 0
ae-movie/include/movie/movie_typedef.h

@@ -0,0 +1,51 @@
+/******************************************************************************
+* libMOVIE Software License v1.0
+*
+* Copyright (c) 2016-2018, Yuriy Levchenko <[email protected]>
+* All rights reserved.
+*
+* You are granted a perpetual, non-exclusive, non-sublicensable, and
+* non-transferable license to use, install, execute, and perform the libMOVIE
+* software and derivative works solely for personal or internal
+* use. Without the written permission of Yuriy Levchenko, you may not (a) modify, translate,
+* adapt, or develop new applications using the libMOVIE or otherwise
+* create derivative works or improvements of the libMOVIE or (b) remove,
+* delete, alter, or obscure any trademarks or any copyright, trademark, patent,
+* or other intellectual property or proprietary rights notices on or in the
+* Software, including any copy thereof. Redistributions in binary or source
+* form must include this license and terms.
+*
+* THIS SOFTWARE IS PROVIDED BY YURIY LEVCHENKO "AS IS" AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+* EVENT SHALL YURIY LEVCHENKO BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION,
+* OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF
+* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+#ifndef MOVIE_TYPEDEF_H_
+#define MOVIE_TYPEDEF_H_
+
+typedef struct aeMovieInstance aeMovieInstance;
+typedef struct aeMovieCompositionAnimation aeMovieCompositionAnimation;
+typedef struct aeMovieSubComposition aeMovieSubComposition;
+typedef struct aeMovieComposition aeMovieComposition;
+typedef struct aeMovieCompositionCamera aeMovieCompositionCamera;
+typedef struct aeMovieCompositionData aeMovieCompositionData;
+typedef struct aeMovieData aeMovieData;
+typedef struct aeMovieNode aeMovieNode;
+typedef struct aeMovieLayerData aeMovieLayerData;
+
+typedef struct aeMovieLayerExtensionTimeremap aeMovieLayerExtensionTimeremap;
+typedef struct aeMovieLayerExtensionMesh aeMovieLayerExtensionMesh;
+typedef struct aeMovieLayerExtensionBezierWarp aeMovieLayerExtensionBezierWarp;
+typedef struct aeMovieLayerExtensionShader aeMovieLayerExtensionShader;
+typedef struct aeMovieLayerExtensionViewport aeMovieLayerExtensionViewport;
+typedef struct aeMovieLayerExtensionPolygon aeMovieLayerExtensionPolygon;
+typedef struct aeMovieLayerExtensionVolume aeMovieLayerExtensionVolume;
+
+#endif

+ 36 - 0
ae-movie/include/movie/movie_version.h

@@ -0,0 +1,36 @@
+/******************************************************************************
+* libMOVIE Software License v1.0
+*
+* Copyright (c) 2016-2018, Yuriy Levchenko <[email protected]>
+* All rights reserved.
+*
+* You are granted a perpetual, non-exclusive, non-sublicensable, and
+* non-transferable license to use, install, execute, and perform the libMOVIE
+* software and derivative works solely for personal or internal
+* use. Without the written permission of Yuriy Levchenko, you may not (a) modify, translate,
+* adapt, or develop new applications using the libMOVIE or otherwise
+* create derivative works or improvements of the libMOVIE or (b) remove,
+* delete, alter, or obscure any trademarks or any copyright, trademark, patent,
+* or other intellectual property or proprietary rights notices on or in the
+* Software, including any copy thereof. Redistributions in binary or source
+* form must include this license and terms.
+*
+* THIS SOFTWARE IS PROVIDED BY YURIY LEVCHENKO "AS IS" AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+* EVENT SHALL YURIY LEVCHENKO BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION,
+* OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF
+* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+//////////////////////////////////////////////////////////////////////////
+#ifndef MOVIE_VERSION_H_
+#define MOVIE_VERSION_H_
+//////////////////////////////////////////////////////////////////////////
+#define AE_MOVIE_SDK_MAJOR_VERSION 17
+#define AE_MOVIE_SDK_MINOR_VERSION 5
+//////////////////////////////////////////////////////////////////////////
+#endif

+ 231 - 0
ae-movie/src/movie_bezier.c

@@ -0,0 +1,231 @@
+/******************************************************************************
+* libMOVIE Software License v1.0
+*
+* Copyright (c) 2016-2018, Yuriy Levchenko <[email protected]>
+* All rights reserved.
+*
+* You are granted a perpetual, non-exclusive, non-sublicensable, and
+* non-transferable license to use, install, execute, and perform the libMOVIE
+* software and derivative works solely for personal or internal
+* use. Without the written permission of Yuriy Levchenko, you may not (a) modify, translate,
+* adapt, or develop new applications using the libMOVIE or otherwise
+* create derivative works or improvements of the libMOVIE or (b) remove,
+* delete, alter, or obscure any trademarks or any copyright, trademark, patent,
+* or other intellectual property or proprietary rights notices on or in the
+* Software, including any copy thereof. Redistributions in binary or source
+* form must include this license and terms.
+*
+* THIS SOFTWARE IS PROVIDED BY YURIY LEVCHENKO "AS IS" AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+* EVENT SHALL YURIY LEVCHENKO BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION,
+* OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF
+* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+#include "movie_bezier.h"
+#include "movie_struct.h"
+#include "movie_math.h"
+
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __bezier_setup( ae_bezier_t * _bt, ae_float_t t )
+{
+    ae_float_t t2 = t * t;
+    ae_float_t t3 = t2 * t;
+
+    ae_float_t ti = 1.f - t;
+    ae_float_t ti2 = ti * ti;
+    ae_float_t ti3 = ti2 * ti;
+
+    _bt->ta = ti3;
+    _bt->tb = 3.f * t * ti2;
+    _bt->tc = 3.f * t2 * ti;
+    _bt->td = t3;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_float_t __bezier_point( ae_float_t a, ae_float_t b, ae_float_t c, ae_float_t d, const ae_bezier_t * _bt )
+{
+    return a * _bt->ta + b * _bt->tb + c * _bt->tc + d * _bt->td;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_float_t __bezier_warp_x( const aeMovieBezierWarp * _bezierWarp, const ae_bezier_t * _bu, const ae_bezier_t * _bv )
+{
+    const ae_vector2_t * corners = _bezierWarp->corners;
+    const ae_vector2_t * beziers = _bezierWarp->beziers;
+
+    ae_float_t x0 = beziers[0][0] + beziers[1][0] - corners[0][0];
+    ae_float_t x1 = beziers[2][0] + beziers[3][0] - corners[1][0];
+    ae_float_t x2 = beziers[4][0] + beziers[5][0] - corners[2][0];
+    ae_float_t x3 = beziers[6][0] + beziers[7][0] - corners[3][0];
+
+    ae_float_t bu0x = __bezier_point( corners[0][0], beziers[0][0], beziers[7][0], corners[3][0], _bv );
+    ae_float_t bu1x = __bezier_point( beziers[1][0], x0, x3, beziers[6][0], _bv );
+    ae_float_t bu2x = __bezier_point( beziers[2][0], x1, x2, beziers[5][0], _bv );
+    ae_float_t bu3x = __bezier_point( corners[1][0], beziers[3][0], beziers[4][0], corners[2][0], _bv );
+
+    ae_float_t x = __bezier_point( bu0x, bu1x, bu2x, bu3x, _bu );
+
+    return x;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_float_t __bezier_warp_y( const aeMovieBezierWarp * _bezierWarp, const ae_bezier_t * _bu, const ae_bezier_t * _bv )
+{
+    const ae_vector2_t * corners = _bezierWarp->corners;
+    const ae_vector2_t * beziers = _bezierWarp->beziers;
+
+    ae_float_t x0 = beziers[0][1] + beziers[1][1] - corners[0][1];
+    ae_float_t x1 = beziers[2][1] + beziers[3][1] - corners[1][1];
+    ae_float_t x2 = beziers[4][1] + beziers[5][1] - corners[2][1];
+    ae_float_t x3 = beziers[6][1] + beziers[7][1] - corners[3][1];
+
+    ae_float_t bu0x = __bezier_point( corners[0][1], beziers[0][1], beziers[7][1], corners[3][1], _bv );
+    ae_float_t bu1x = __bezier_point( beziers[1][1], x0, x3, beziers[6][1], _bv );
+    ae_float_t bu2x = __bezier_point( beziers[2][1], x1, x2, beziers[5][1], _bv );
+    ae_float_t bu3x = __bezier_point( corners[1][1], beziers[3][1], beziers[4][1], corners[2][1], _bv );
+
+    ae_float_t y = __bezier_point( bu0x, bu1x, bu2x, bu3x, _bu );
+
+    return y;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_float_t __get_bezier_warp_grid_invf( ae_uint32_t _quality )
+{
+    ae_uint32_t line_count = get_bezier_warp_line_count( _quality );
+    ae_float_t grid_invf = 1.f / (ae_float_t)(line_count - 1);
+
+    return grid_invf;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __make_bezier_warp_vertices( const aeMovieInstance * _instance, ae_uint32_t _quality, const aeMovieBezierWarp * _bezierWarp, const ae_matrix34_t _matrix, aeMovieRenderMesh * _render )
+{
+    ae_uint32_t line_count = get_bezier_warp_line_count( _quality );
+    ae_float_t grid_invf = __get_bezier_warp_grid_invf( _quality );
+
+    _render->vertexCount = get_bezier_warp_vertex_count( _quality );
+    _render->indexCount = get_bezier_warp_index_count( _quality );
+
+    ae_float_t du = 0.f;
+    ae_float_t dv = 0.f;
+
+    ae_vector3_t * positions = _render->position;
+
+    ae_uint32_t v = 0;
+    for( ; v != line_count; ++v )
+    {
+        ae_bezier_t bv;
+        __bezier_setup( &bv, dv );
+
+        ae_uint32_t u = 0;
+        for( ; u != line_count; ++u )
+        {
+            ae_bezier_t bu;
+            __bezier_setup( &bu, du );
+
+            ae_float_t x = __bezier_warp_x( _bezierWarp, &bu, &bv );
+            ae_float_t y = __bezier_warp_y( _bezierWarp, &bu, &bv );
+
+            ae_mul_v3_xy_m34( *positions++, x, y, _matrix );
+
+            du += grid_invf;
+        }
+
+        du = 0.f;
+        dv += grid_invf;
+    }
+
+    _render->indices = _instance->bezier_warp_indices[_quality];
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __setup_bezier_corners( aeMovieBezierWarp * _bezier, const ae_vector2_t * _current, const ae_vector2_t * _next, ae_float_t _t )
+{
+    ae_linerp_f2( _bezier->corners[0], _current[0], _next[0], _t );
+    ae_linerp_f2( _bezier->corners[1], _current[1], _next[1], _t );
+    ae_linerp_f2( _bezier->corners[2], _current[2], _next[2], _t );
+    ae_linerp_f2( _bezier->corners[3], _current[3], _next[3], _t );
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __setup_bezier_beziers( aeMovieBezierWarp * _bezier, const ae_vector2_t * _current, const ae_vector2_t * _next, ae_float_t _t )
+{
+    ae_linerp_f2( _bezier->beziers[0], _current[0], _next[0], _t );
+    ae_linerp_f2( _bezier->beziers[1], _current[1], _next[1], _t );
+    ae_linerp_f2( _bezier->beziers[2], _current[2], _next[2], _t );
+    ae_linerp_f2( _bezier->beziers[3], _current[3], _next[3], _t );
+    ae_linerp_f2( _bezier->beziers[4], _current[4], _next[4], _t );
+    ae_linerp_f2( _bezier->beziers[5], _current[5], _next[5], _t );
+    ae_linerp_f2( _bezier->beziers[6], _current[6], _next[6], _t );
+    ae_linerp_f2( _bezier->beziers[7], _current[7], _next[7], _t );
+}
+//////////////////////////////////////////////////////////////////////////
+ae_void_t make_layer_bezier_warp_vertices( const aeMovieInstance * _instance, const aeMovieLayerExtensionBezierWarp * _layerBezierWarp, ae_uint32_t _frame, ae_bool_t _interpolate, ae_float_t _t, const ae_matrix34_t _matrix, const ae_vector2_t * _uvs, aeMovieRenderMesh * _render )
+{
+    ae_uint32_t bezier_warp_quality = _layerBezierWarp->quality;
+
+    if( _layerBezierWarp->immutable == AE_TRUE )
+    {
+        __make_bezier_warp_vertices( _instance, bezier_warp_quality, &_layerBezierWarp->immutable_bezier_warp, _matrix, _render );
+    }
+    else
+    {
+        if( _interpolate == AE_FALSE )
+        {
+            const aeMovieBezierWarp * bezier_warp = _layerBezierWarp->bezier_warps + _frame;
+
+            __make_bezier_warp_vertices( _instance, bezier_warp_quality, bezier_warp, _matrix, _render );
+        }
+        else
+        {
+            const aeMovieBezierWarp * bezier_warp_frame_current = _layerBezierWarp->bezier_warps + _frame + 0;
+            const aeMovieBezierWarp * bezier_warp_frame_next = _layerBezierWarp->bezier_warps + _frame + 1;
+
+            aeMovieBezierWarp bezierWarp;
+
+            const ae_vector2_t * current_corners = bezier_warp_frame_current->corners;
+            const ae_vector2_t * next_corners = bezier_warp_frame_next->corners;
+            __setup_bezier_corners( &bezierWarp, current_corners, next_corners, _t );
+
+            const ae_vector2_t * current_beziers = bezier_warp_frame_current->beziers;
+            const ae_vector2_t * next_beziers = bezier_warp_frame_next->beziers;
+            __setup_bezier_beziers( &bezierWarp, current_beziers, next_beziers, _t );
+
+            __make_bezier_warp_vertices( _instance, bezier_warp_quality, &bezierWarp, _matrix, _render );
+        }
+    }
+
+    ae_uint32_t vertex_count = get_bezier_warp_vertex_count( bezier_warp_quality );
+
+    const ae_vector2_t * bezier_warp_uvs = _instance->bezier_warp_uvs[bezier_warp_quality];
+
+    if( _uvs == AE_NULLPTR )
+    {
+        ae_uint32_t vertex_index = 0;
+        for( ; vertex_index != vertex_count; ++vertex_index )
+        {
+            ae_copy_v2( _render->uv[vertex_index], bezier_warp_uvs[vertex_index] );
+        }
+    }
+    else
+    {
+        ae_float_t bx = _uvs[0][0];
+        ae_float_t by = _uvs[0][1];
+
+        ae_float_t ux = _uvs[1][0] - _uvs[0][0];
+        ae_float_t uy = _uvs[1][1] - _uvs[0][1];
+
+        ae_float_t vx = _uvs[2][0] - _uvs[1][0];
+        ae_float_t vy = _uvs[2][1] - _uvs[1][1];
+
+        ae_uint32_t vertex_index = 0;
+        for( ; vertex_index != vertex_count; ++vertex_index )
+        {
+            ae_float_t u = bezier_warp_uvs[vertex_index][0];
+            ae_float_t v = bezier_warp_uvs[vertex_index][1];
+
+            _render->uv[vertex_index][0] = bx + ux * u + vx * v;
+            _render->uv[vertex_index][1] = by + uy * u + vy * v;
+        }
+    }
+}

+ 71 - 0
ae-movie/src/movie_bezier.h

@@ -0,0 +1,71 @@
+/******************************************************************************
+* libMOVIE Software License v1.0
+*
+* Copyright (c) 2016-2018, Yuriy Levchenko <[email protected]>
+* All rights reserved.
+*
+* You are granted a perpetual, non-exclusive, non-sublicensable, and
+* non-transferable license to use, install, execute, and perform the libMOVIE
+* software and derivative works solely for personal or internal
+* use. Without the written permission of Yuriy Levchenko, you may not (a) modify, translate,
+* adapt, or develop new applications using the libMOVIE or otherwise
+* create derivative works or improvements of the libMOVIE or (b) remove,
+* delete, alter, or obscure any trademarks or any copyright, trademark, patent,
+* or other intellectual property or proprietary rights notices on or in the
+* Software, including any copy thereof. Redistributions in binary or source
+* form must include this license and terms.
+*
+* THIS SOFTWARE IS PROVIDED BY YURIY LEVCHENKO "AS IS" AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+* EVENT SHALL YURIY LEVCHENKO BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION,
+* OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF
+* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+#ifndef MOVIE_BEZIER_H_
+#define MOVIE_BEZIER_H_
+
+#include "movie/movie_type.h"
+#include "movie/movie_config.h"
+#include "movie/movie_composition.h"
+
+typedef struct ae_bezier_t
+{
+    ae_float_t ta;
+    ae_float_t tb;
+    ae_float_t tc;
+    ae_float_t td;
+} ae_bezier_t;
+
+
+AE_INTERNAL ae_uint32_t get_bezier_warp_line_count( ae_uint32_t _quality )
+{
+    ae_uint32_t line_count = AE_MOVIE_BEZIER_WARP_BASE_GRID + _quality * 2;
+
+    return line_count;
+}
+
+AE_INTERNAL ae_uint32_t get_bezier_warp_vertex_count( ae_uint32_t _quality )
+{
+    ae_uint32_t line_count = get_bezier_warp_line_count( _quality );
+    ae_uint32_t vertex_count = line_count * line_count;
+
+    return vertex_count;
+}
+
+AE_INTERNAL ae_uint32_t get_bezier_warp_index_count( ae_uint32_t _quality )
+{
+    ae_uint32_t line_count = get_bezier_warp_line_count( _quality );
+    ae_uint32_t index_count = (line_count - 1) * (line_count - 1) * 6;
+
+    return index_count;
+}
+
+ae_void_t make_layer_bezier_warp_vertices( const struct aeMovieInstance * _instance, const struct aeMovieLayerExtensionBezierWarp * _layerBezierWarp, ae_uint32_t _frame, ae_bool_t _interpolate, ae_float_t _t, const ae_matrix34_t _matrix, const ae_vector2_t * _uvs, aeMovieRenderMesh * _render );
+
+#endif

+ 4712 - 0
ae-movie/src/movie_composition.c

@@ -0,0 +1,4712 @@
+/******************************************************************************
+* libMOVIE Software License v1.0
+*
+* Copyright (c) 2016-2018, Yuriy Levchenko <[email protected]>
+* All rights reserved.
+*
+* You are granted a perpetual, non-exclusive, non-sublicensable, and
+* non-transferable license to use, install, execute, and perform the libMOVIE
+* software and derivative works solely for personal or internal
+* use. Without the written permission of Yuriy Levchenko, you may not (a) modify, translate,
+* adapt, or develop new applications using the libMOVIE or otherwise
+* create derivative works or improvements of the libMOVIE or (b) remove,
+* delete, alter, or obscure any trademarks or any copyright, trademark, patent,
+* or other intellectual property or proprietary rights notices on or in the
+* Software, including any copy thereof. Redistributions in binary or source
+* form must include this license and terms.
+*
+* THIS SOFTWARE IS PROVIDED BY YURIY LEVCHENKO "AS IS" AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+* EVENT SHALL YURIY LEVCHENKO BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION,
+* OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF
+* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+#include "movie/movie_composition.h"
+#include "movie/movie_resource.h"
+
+#include "movie_bezier.h"
+#include "movie_transformation.h"
+#include "movie_memory.h"
+#include "movie_math.h"
+#include "movie_debug.h"
+
+#include "movie_struct.h"
+
+#ifndef AE_MOVIE_FRAME_EPSILON
+#define AE_MOVIE_FRAME_EPSILON 0.01f
+#endif
+
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_uint32_t __get_composition_update_revision( const aeMovieComposition * _composition )
+{
+    ae_uint32_t update_revision = *_composition->update_revision;
+
+    return update_revision;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_uint32_t __inc_composition_update_revision( const aeMovieComposition * _composition )
+{
+    ae_uint32_t update_revision = ++(*_composition->update_revision);
+
+    return update_revision;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __make_mesh_vertices( const ae_mesh_t * _mesh, const ae_matrix34_t _matrix, const ae_vector2_t * _uvs, aeMovieRenderMesh * _render )
+{
+    _render->vertexCount = _mesh->vertex_count;
+    _render->indexCount = _mesh->index_count;
+
+    ae_uint32_t vertex_count = _mesh->vertex_count;
+
+    ae_uint32_t vertex_index = 0;
+    for( ; vertex_index != vertex_count; ++vertex_index )
+    {
+        ae_mul_v3_v2_m34( _render->position[vertex_index], _mesh->positions[vertex_index], _matrix );
+    }
+
+    if( _uvs == AE_NULLPTR )
+    {
+        for( vertex_index = 0; vertex_index != vertex_count; ++vertex_index )
+        {
+            ae_copy_v2( _render->uv[vertex_index], _mesh->uvs[vertex_index] );
+        }
+    }
+    else
+    {
+        ae_float_t bx = _uvs[0][0];
+        ae_float_t by = _uvs[0][1];
+
+        ae_float_t ux = _uvs[1][0] - _uvs[0][0];
+        ae_float_t uy = _uvs[1][1] - _uvs[0][1];
+
+        ae_float_t vx = _uvs[2][0] - _uvs[1][0];
+        ae_float_t vy = _uvs[2][1] - _uvs[1][1];
+
+        for( vertex_index = 0; vertex_index != vertex_count; ++vertex_index )
+        {
+            ae_float_t u = _mesh->uvs[vertex_index][0];
+            ae_float_t v = _mesh->uvs[vertex_index][1];
+            
+            _render->uv[vertex_index][0] = bx + ux * u + vx * v;
+            _render->uv[vertex_index][1] = by + uy * u + vy * v;
+        } 
+    }
+
+    _render->indices = _mesh->indices;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __make_layer_sprite_vertices( const aeMovieInstance * _instance, ae_float_t _offset_x, ae_float_t _offset_y, ae_float_t _width, ae_float_t _height, const ae_matrix34_t _matrix, const ae_vector2_t * _uv, aeMovieRenderMesh * _render )
+{
+    ae_vector2_t v_position[4];
+
+    ae_float_t * v = &v_position[0][0];
+
+    *v++ = _offset_x + _width * 0.f;
+    *v++ = _offset_y + _height * 0.f;
+    *v++ = _offset_x + _width * 1.f;
+    *v++ = _offset_y + _height * 0.f;
+    *v++ = _offset_x + _width * 1.f;
+    *v++ = _offset_y + _height * 1.f;
+    *v++ = _offset_x + _width * 0.f;
+    *v++ = _offset_y + _height * 1.f;
+
+    _render->vertexCount = 4;
+    _render->indexCount = 6;
+
+    ae_mul_v3_v2_m34( _render->position[0], v_position[0], _matrix );
+    ae_mul_v3_v2_m34( _render->position[1], v_position[1], _matrix );
+    ae_mul_v3_v2_m34( _render->position[2], v_position[2], _matrix );
+    ae_mul_v3_v2_m34( _render->position[3], v_position[3], _matrix );
+
+    ae_copy_v2( _render->uv[0], _uv[0] );
+    ae_copy_v2( _render->uv[1], _uv[1] );
+    ae_copy_v2( _render->uv[2], _uv[2] );
+    ae_copy_v2( _render->uv[3], _uv[3] );
+
+    _render->indices = _instance->sprite_indices;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __make_layer_mesh_vertices( const aeMovieLayerExtensionMesh * _extensionMesh, ae_uint32_t _frame, const ae_matrix34_t _matrix, const ae_vector2_t * _uvs, aeMovieRenderMesh * _render )
+{
+    const ae_mesh_t * mesh = (_extensionMesh->immutable == AE_TRUE) ? &_extensionMesh->immutable_mesh : (_extensionMesh->meshes + _frame);
+
+    __make_mesh_vertices( mesh, _matrix, _uvs, _render );
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_float_t __compute_movie_property_value( const struct aeMoviePropertyValue * _property, ae_uint32_t _frame, ae_bool_t _interpolate, ae_float_t _t )
+{
+    if( _property->immutable == AE_TRUE )
+    {
+        return _property->immutable_value;
+    }
+
+    if( _interpolate == AE_FALSE )
+    {
+        ae_float_t value = _property->values[_frame];
+
+        return value;
+    }
+
+    ae_float_t value0 = _property->values[_frame + 0];
+    ae_float_t value1 = _property->values[_frame + 1];
+
+    ae_float_t valuef = ae_linerp_f1( value0, value1, _t );
+
+    return valuef;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_color_channel_t __compute_movie_property_color_channel( const struct aeMoviePropertyColorChannel * _property, ae_uint32_t _frame, ae_bool_t _interpolate, ae_float_t t )
+{
+    if( _property->immutable == AE_TRUE )
+    {
+        return _property->immutable_value;
+    }
+
+    if( _interpolate == AE_FALSE )
+    {
+        ae_color_channel_t c = _property->values[_frame];
+
+        return c;
+    }
+
+    ae_color_channel_t c0 = _property->values[_frame + 0];
+    ae_color_channel_t c1 = _property->values[_frame + 1];
+
+    ae_color_channel_t cf = ae_linerp_f1( c0, c1, t );
+
+    return cf;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_uint32_t __compute_movie_node_frame( const aeMovieNode * _node, ae_float_t * _t )
+{
+    ae_uint32_t frame = _node->current_frame;
+    *_t = _node->current_frame_t;
+
+    return frame;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __compute_movie_render_mesh( const aeMovieComposition * _composition, const aeMovieNode * _node, aeMovieRenderMesh * _render, ae_bool_t _interpolate, ae_bool_t _trackmatte )
+{
+    const aeMovieData * movie_data = _composition->movie_data;
+    const aeMovieInstance * instance = movie_data->instance;
+    const aeMovieLayerData * layer = _node->layer;
+    const aeMovieResource * resource = layer->resource;
+
+    aeMovieLayerTypeEnum layer_type = layer->type;
+
+    _render->layer_type = layer_type;
+
+    _render->blend_mode = _node->blend_mode;
+
+    if( resource != AE_NULLPTR )
+    {
+        _render->resource_type = resource->type;
+        _render->resource_userdata = resource->userdata;
+    }
+    else
+    {
+        _render->resource_type = AE_MOVIE_RESOURCE_NONE;
+        _render->resource_userdata = AE_NULLPTR;
+    }
+
+    _render->camera_userdata = _node->camera_userdata;
+    _render->element_userdata = _node->element_userdata;
+    _render->shader_userdata = _node->shader_userdata;
+
+    _render->viewport = _node->viewport;
+
+    if( _node->track_matte_node != AE_NULLPTR && _node->track_matte_node->active == AE_TRUE )
+    {
+        _render->track_matte_mode = layer->track_matte_mode;
+        _render->track_matte_userdata = _node->track_matte_node->track_matte_userdata;
+    }
+    else
+    {
+        _render->track_matte_mode = AE_MOVIE_TRACK_MATTE_NONE;
+        _render->track_matte_userdata = AE_NULLPTR;
+    }
+
+    _render->uv_cache_userdata = AE_NULLPTR;
+
+    ae_float_t t_frame = 0.f;
+    ae_uint32_t frame = __compute_movie_node_frame( _node, &t_frame );
+
+    switch( layer_type )
+    {
+    case AE_MOVIE_LAYER_TYPE_SHAPE:
+        {
+            __make_layer_mesh_vertices( layer->extensions->mesh, frame, _node->matrix, AE_NULLPTR, _render );
+
+            _render->color = _node->color;
+            _render->opacity = _node->opacity;
+        }break;
+    case AE_MOVIE_LAYER_TYPE_SOLID:
+        {
+            aeMovieResourceSolid * resource_solid = (aeMovieResourceSolid *)resource;
+
+            if( layer->extensions->mesh != AE_NULLPTR )
+            {
+                __make_layer_mesh_vertices( layer->extensions->mesh, frame, _node->matrix, AE_NULLPTR, _render );
+            }
+            else if( layer->extensions->bezier_warp != AE_NULLPTR )
+            {
+                make_layer_bezier_warp_vertices( instance, layer->extensions->bezier_warp, frame, _interpolate, t_frame, _node->matrix, AE_NULLPTR, _render );
+            }
+            else
+            {
+                ae_float_t width = resource_solid->width;
+                ae_float_t height = resource_solid->height;
+
+                __make_layer_sprite_vertices( instance, 0.f, 0.f, width, height, _node->matrix, instance->sprite_uv, _render );
+            }
+
+            _render->color.r = _node->color.r * resource_solid->color.r;
+            _render->color.g = _node->color.g * resource_solid->color.g;
+            _render->color.b = _node->color.b * resource_solid->color.b;
+            _render->opacity = _node->opacity;
+        }break;
+    case AE_MOVIE_LAYER_TYPE_SEQUENCE:
+        {
+            aeMovieResourceSequence * resource_sequence = (aeMovieResourceSequence *)resource;
+
+            ae_uint32_t frame_sequence;
+
+            if( layer->extensions->timeremap != AE_NULLPTR )
+            {
+                ae_float_t time = layer->extensions->timeremap->times[frame];
+
+                frame_sequence = (ae_uint32_t)(time * resource_sequence->frameDurationInv);
+            }
+            else
+            {
+                if( layer->reverse_time == AE_TRUE )
+                {
+                    frame_sequence = (ae_uint32_t)((_node->out_time - _node->in_time - (layer->start_time + _node->current_time)) * resource_sequence->frameDurationInv);
+                }
+                else
+                {
+                    frame_sequence = (ae_uint32_t)((layer->start_time + _node->current_time) * resource_sequence->frameDurationInv);
+                }
+            }
+
+            frame_sequence %= resource_sequence->image_count;
+
+            const aeMovieResourceImage * resource_image = resource_sequence->images[frame_sequence];
+
+            _render->resource_type = resource_image->type;
+            _render->resource_userdata = resource_image->userdata;
+
+            if( layer->extensions->mesh != AE_NULLPTR )
+            {
+                __make_layer_mesh_vertices( layer->extensions->mesh, frame, _node->matrix, resource_image->uvs, _render );
+
+                if( layer->cache != AE_NULLPTR )
+                {
+                    if( layer->extensions->mesh->immutable == AE_TRUE )
+                    {
+                        _render->uv_cache_userdata = layer->cache->immutable_mesh_uv_cache_userdata;
+                    }
+                    else
+                    {
+                        _render->uv_cache_userdata = layer->cache->mesh_uv_cache_userdata[frame];
+                    }
+                }
+            }
+            else if( layer->extensions->bezier_warp != AE_NULLPTR )
+            {
+                make_layer_bezier_warp_vertices( instance, layer->extensions->bezier_warp, frame, _interpolate, t_frame, _node->matrix, resource_image->uvs, _render );
+
+                if( resource_image->cache != AE_NULLPTR )
+                {
+                    _render->uv_cache_userdata = resource_image->cache->bezier_warp_uv_cache_userdata[layer->extensions->bezier_warp->quality];
+                }
+            }
+            else if( resource_image->mesh != AE_NULLPTR && _trackmatte == AE_FALSE )
+            {
+                __make_mesh_vertices( resource_image->mesh, _node->matrix, resource_image->uvs, _render );
+
+                if( resource_image->cache != AE_NULLPTR )
+                {
+                    _render->uv_cache_userdata = resource_image->cache->mesh_uv_cache_userdata;
+                }
+            }
+            else
+            {
+                ae_float_t offset_x = resource_image->offset_x;
+                ae_float_t offset_y = resource_image->offset_y;
+
+                ae_float_t width = resource_image->trim_width;
+                ae_float_t height = resource_image->trim_height;
+
+                __make_layer_sprite_vertices( instance, offset_x, offset_y, width, height, _node->matrix, resource_image->uvs, _render );
+
+                if( resource_image->cache != AE_NULLPTR )
+                {
+                    _render->uv_cache_userdata = resource_image->cache->uv_cache_userdata;
+                }
+            }
+
+            _render->color = _node->color;
+            _render->opacity = _node->opacity;
+        }break;
+    case AE_MOVIE_LAYER_TYPE_VIDEO:
+        {
+            aeMovieResourceVideo * resource_video = (aeMovieResourceVideo *)resource;
+
+            if( layer->extensions->mesh != AE_NULLPTR )
+            {
+                __make_layer_mesh_vertices( layer->extensions->mesh, frame, _node->matrix, AE_NULLPTR, _render );
+
+                if( layer->cache != AE_NULLPTR )
+                {
+                    if( layer->extensions->mesh->immutable == AE_TRUE )
+                    {
+                        _render->uv_cache_userdata = layer->cache->immutable_mesh_uv_cache_userdata;
+                    }
+                    else
+                    {
+                        _render->uv_cache_userdata = layer->cache->mesh_uv_cache_userdata[frame];
+                    }
+                }
+            }
+            else if( layer->extensions->bezier_warp != AE_NULLPTR )
+            {
+                make_layer_bezier_warp_vertices( instance, layer->extensions->bezier_warp, frame, _interpolate, t_frame, _node->matrix, AE_NULLPTR, _render );
+
+                if( resource_video->cache != AE_NULLPTR )
+                {
+                    _render->uv_cache_userdata = resource_video->cache->bezier_warp_uv_cache_userdata[layer->extensions->bezier_warp->quality];
+                }
+            }
+            else
+            {
+                ae_float_t offset_x = resource_video->offset_x;
+                ae_float_t offset_y = resource_video->offset_y;
+
+                ae_float_t width = resource_video->trim_width;
+                ae_float_t height = resource_video->trim_height;
+
+                __make_layer_sprite_vertices( instance, offset_x, offset_y, width, height, _node->matrix, instance->sprite_uv, _render );
+
+                if( resource_video->cache != AE_NULLPTR )
+                {
+                    _render->uv_cache_userdata = resource_video->cache->uv_cache_userdata;
+                }
+            }
+
+            _render->color = _node->color;
+            _render->opacity = _node->opacity;
+        }break;
+    case AE_MOVIE_LAYER_TYPE_IMAGE:
+        {
+            aeMovieResourceImage * resource_image = (aeMovieResourceImage *)resource;
+
+            if( layer->extensions->mesh != AE_NULLPTR )
+            {
+                __make_layer_mesh_vertices( layer->extensions->mesh, frame, _node->matrix, resource_image->uvs, _render );
+
+                if( layer->cache != AE_NULLPTR )
+                {
+                    if( layer->extensions->mesh->immutable == AE_TRUE )
+                    {
+                        _render->uv_cache_userdata = layer->cache->immutable_mesh_uv_cache_userdata;
+                    }
+                    else
+                    {
+                        _render->uv_cache_userdata = layer->cache->mesh_uv_cache_userdata[frame];
+                    }
+                }
+            }
+            else if( layer->extensions->bezier_warp != AE_NULLPTR )
+            {
+                make_layer_bezier_warp_vertices( instance, layer->extensions->bezier_warp, frame, _interpolate, t_frame, _node->matrix, resource_image->uvs, _render );
+
+                if( resource_image->cache != AE_NULLPTR )
+                {
+                    _render->uv_cache_userdata = resource_image->cache->bezier_warp_uv_cache_userdata[layer->extensions->bezier_warp->quality];
+                }
+            }
+            else if( resource_image->mesh != AE_NULLPTR && _trackmatte == AE_FALSE )
+            {
+                __make_mesh_vertices( resource_image->mesh, _node->matrix, resource_image->uvs, _render );
+
+                if( resource_image->cache != AE_NULLPTR )
+                {
+                    _render->uv_cache_userdata = resource_image->cache->mesh_uv_cache_userdata;
+                }
+            }
+            else
+            {
+                ae_float_t offset_x = resource_image->offset_x;
+                ae_float_t offset_y = resource_image->offset_y;
+
+                ae_float_t width = resource_image->trim_width;
+                ae_float_t height = resource_image->trim_height;
+
+                __make_layer_sprite_vertices( instance, offset_x, offset_y, width, height, _node->matrix, resource_image->uvs, _render );
+
+                if( resource_image->cache != AE_NULLPTR )
+                {
+                    _render->uv_cache_userdata = resource_image->cache->uv_cache_userdata;
+                }
+            }
+
+            _render->color = _node->color;
+            _render->opacity = _node->opacity;
+        }break;
+    default:
+        {
+            _render->vertexCount = 0;
+            _render->indexCount = 0;
+
+            _render->color = _node->color;
+            _render->opacity = _node->opacity;
+        }break;
+    }
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL aeMovieNode * __find_node_by_layer( aeMovieNode * _nodes, ae_uint32_t _begin, ae_uint32_t _end, const aeMovieLayerData * _layer )
+{
+    aeMovieNode * it_node = _nodes + _begin;
+    aeMovieNode * it_node_end = _nodes + _end;
+    for( ; it_node != it_node_end; ++it_node )
+    {
+        aeMovieNode * node = it_node;
+
+        const aeMovieLayerData * node_layer = node->layer;
+
+        if( node_layer == _layer )
+        {
+            return node;
+        }
+    }
+
+    return AE_NULLPTR;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL const aeMovieLayerData * __find_layer_by_index( const aeMovieCompositionData * _compositionData, ae_uint32_t _index )
+{
+    const aeMovieLayerData * it_layer = _compositionData->layers;
+    const aeMovieLayerData * it_layer_end = _compositionData->layers + _compositionData->layer_count;
+    for( ; it_layer != it_layer_end; ++it_layer )
+    {
+        const aeMovieLayerData * layer = it_layer;
+
+        ae_uint32_t layer_index = layer->index;
+
+        if( layer_index == _index )
+        {
+            return layer;
+        }
+    }
+
+    return AE_NULLPTR;
+}
+//////////////////////////////////////////////////////////////////////////
+#ifdef AE_MOVIE_DEBUG
+AE_INTERNAL ae_bool_t __test_error_composition_layer_frame( const aeMovieInstance * _instance, const aeMovieCompositionData * _compositionData, const aeMovieLayerData * _layerData, ae_uint32_t _frameId, const ae_char_t * _msg )
+{
+    if( _frameId >= _layerData->frame_count )
+    {
+        _instance->logger( _instance->instance_userdata
+            , AE_ERROR_INTERNAL
+            , "composition '%s' layer '%s' - %s\n"
+            , _compositionData->name
+            , _layerData->name
+            , _msg
+        );
+
+        return AE_FALSE;
+    }
+
+    return AE_TRUE;
+}
+#endif
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_uint32_t __get_movie_frame_time( const struct aeMovieCompositionAnimation * _animation, const struct aeMovieNode * _node, ae_bool_t _interpolate, ae_float_t * _t )
+{
+    ae_float_t animation_time = _animation->time;
+
+    const aeMovieLayerData * layer = _node->layer;
+
+    ae_float_t frameDurationInv = layer->composition_data->frameDurationInv;
+
+    ae_float_t current_time = animation_time - _node->in_time + _node->start_time;
+
+    ae_float_t frame_time = current_time * _node->stretchInv * frameDurationInv;
+
+    if( frame_time < 0.f )
+    {
+        frame_time = 0.f;
+    }
+
+    ae_uint32_t frame_relative = (ae_uint32_t)frame_time;
+
+    if( frame_relative >= layer->frame_count )
+    {
+        frame_relative = layer->frame_count - 1;
+
+        *_t = 0.f;
+
+        return frame_relative;
+    }
+
+    if( _interpolate == AE_TRUE )
+    {
+        ae_float_t t_relative = ae_fractional_f( frame_time );
+
+        *_t = t_relative;
+    }
+    else
+    {
+        *_t = 0.f;
+    }
+
+    return frame_relative;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __update_movie_composition_node_matrix( aeMovieNode * _node, ae_uint32_t _revision, const aeMovieComposition * _composition, const aeMovieCompositionData * _compositionData, const aeMovieCompositionAnimation * _animation, const aeMovieSubComposition * _subcomposition, ae_uint32_t _frameId, ae_bool_t _interpolate, ae_float_t _t )
+{
+    if( _node->update_revision == _revision )
+    {
+        return;
+    }
+
+    const aeMovieLayerData * node_layer = _node->layer;
+
+#ifdef AE_MOVIE_DEBUG	
+    if( __test_error_composition_layer_frame( _composition->movie_data->instance
+        , _compositionData
+        , node_layer
+        , _frameId
+        , "__update_movie_composition_node_matrix frame id out count"
+    ) == AE_FALSE )
+    {
+        return;
+    }
+#endif
+
+#ifdef AE_MOVIE_SAFE
+    if( _frameId >= node_layer->frame_count )
+    {
+        return;
+    }
+#endif
+
+    const struct aeMovieLayerTransformation * layer_transformation = node_layer->transformation;
+
+    ae_color_channel_t local_r = ae_movie_make_layer_color_r( layer_transformation, _frameId, _interpolate, _t );
+    ae_color_channel_t local_g = ae_movie_make_layer_color_g( layer_transformation, _frameId, _interpolate, _t );
+    ae_color_channel_t local_b = ae_movie_make_layer_color_b( layer_transformation, _frameId, _interpolate, _t );
+
+    ae_color_channel_t local_opacity = ae_movie_make_layer_opacity( layer_transformation, _frameId, _interpolate, _t );
+
+    if( node_layer->extensions->volume != AE_NULLPTR )
+    {
+        const struct aeMoviePropertyValue * property_volume = node_layer->extensions->volume->property_volume;
+
+        ae_float_t volume = __compute_movie_property_value( property_volume, _frameId, _interpolate, _t );
+
+        _node->volume = volume;
+    }
+
+    aeMovieNode * node_relative = _node->relative_node;
+
+    if( node_relative == AE_NULLPTR )
+    {
+        ae_movie_make_layer_matrix( _node->matrix, layer_transformation, _interpolate, _frameId, _t );
+
+        if( node_layer->subcomposition_data != AE_NULLPTR )
+        {
+            _node->composition_color.r = local_r;
+            _node->composition_color.g = local_g;
+            _node->composition_color.b = local_b;
+
+            _node->composition_opacity = local_opacity;
+        }
+        else
+        {
+            _node->composition_color.r = 1.f;
+            _node->composition_color.g = 1.f;
+            _node->composition_color.b = 1.f;
+
+            _node->composition_opacity = 1.f;
+        }
+
+        _node->color.r = local_r;
+        _node->color.g = local_g;
+        _node->color.b = local_b;
+
+        _node->opacity = local_opacity;
+        
+        _node->transparent = ae_equal_f_z( _node->opacity );
+
+        return;
+    }
+
+    if( _subcomposition == node_relative->subcomposition )
+    {
+        const aeMovieLayerData * node_relative_relative = node_relative->layer;
+
+        ae_float_t t_relative = 0.f;
+        ae_uint32_t frame_relative = __get_movie_frame_time( _animation, node_relative, _composition->interpolate, &t_relative );
+
+        ae_bool_t interpolate_relative = (frame_relative + 1 == node_relative_relative->frame_count) ? AE_FALSE : _interpolate;
+
+        __update_movie_composition_node_matrix( node_relative, _revision, _composition, _compositionData, _animation, _subcomposition, frame_relative, interpolate_relative, t_relative );
+    }
+
+    if( (layer_transformation->identity_property_mask & AE_MOVIE_PROPERTY_TRANSFORM_SUPER_ALL) == AE_MOVIE_PROPERTY_TRANSFORM_SUPER_ALL )
+    {
+        ae_copy_m34( _node->matrix, node_relative->matrix );
+    }
+    else
+    {
+        ae_matrix34_t local_matrix;
+        ae_movie_make_layer_matrix( local_matrix, layer_transformation, _interpolate, _frameId, _t );
+
+        ae_mul_m34_m34_r( _node->matrix, local_matrix, node_relative->matrix );
+    }
+
+    if( node_layer->subcomposition_data != AE_NULLPTR )
+    {
+        _node->composition_color.r = node_relative->composition_color.r * local_r;
+        _node->composition_color.g = node_relative->composition_color.g * local_g;
+        _node->composition_color.b = node_relative->composition_color.b * local_b;
+
+        _node->composition_opacity = node_relative->composition_opacity * local_opacity;
+    }
+    else
+    {
+        _node->composition_color.r = node_relative->composition_color.r;
+        _node->composition_color.g = node_relative->composition_color.g;
+        _node->composition_color.b = node_relative->composition_color.b;
+
+        _node->composition_opacity = node_relative->composition_opacity;
+    }
+
+    _node->color.r = node_relative->composition_color.r * local_r;
+    _node->color.g = node_relative->composition_color.g * local_g;
+    _node->color.b = node_relative->composition_color.b * local_b;
+
+    _node->opacity = node_relative->composition_opacity * local_opacity;
+
+    _node->transparent = ae_equal_f_z( _node->opacity );
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __update_movie_composition_node_shader( aeMovieNode * _node, ae_uint32_t _revision, const aeMovieComposition * _composition, const aeMovieCompositionData * _compositionData, ae_uint32_t _frameId, ae_bool_t _interpolate, ae_float_t _t )
+{
+    AE_UNUSED( _compositionData );
+
+    if( _node->update_revision == _revision )
+    {
+        return;
+    }
+
+    const aeMovieLayerData * node_layer = _node->layer;
+
+#ifdef AE_MOVIE_DEBUG	
+    if( __test_error_composition_layer_frame( _composition->movie_data->instance
+        , _compositionData
+        , node_layer
+        , _frameId
+        , "__update_movie_composition_node_shader frame id out count"
+    ) == AE_FALSE )
+    {
+        return;
+    }
+#endif
+
+#ifdef AE_MOVIE_SAFE
+    if( _frameId >= node_layer->frame_count )
+    {
+        return;
+    }
+#endif
+
+    const aeMovieLayerExtensionShader * shader = node_layer->extensions->shader;
+
+    const struct aeMovieLayerShaderParameter ** it_parameter = shader->parameters;
+    const struct aeMovieLayerShaderParameter ** it_parameter_end = shader->parameters + shader->parameter_count;
+
+    ae_uint32_t index = 0;
+
+    for( ;
+        it_parameter != it_parameter_end;
+        ++it_parameter )
+    {
+        const struct aeMovieLayerShaderParameter * parameter = *it_parameter;
+
+        aeMovieShaderParameterTypeEnum parameter_type = parameter->type;
+
+        switch( parameter_type )
+        {
+        case AE_MOVIE_EXTENSION_SHADER_PARAMETER_SLIDER:
+            {
+                const struct aeMovieLayerShaderParameterSlider * parameter_slider = (const struct aeMovieLayerShaderParameterSlider *)parameter;
+
+                ae_float_t value = __compute_movie_property_value( parameter_slider->property_value, _frameId, _interpolate, _t );
+
+                aeMovieShaderPropertyUpdateCallbackData callbackData;
+                callbackData.index = index;
+                callbackData.element_userdata = _node->shader_userdata;
+                callbackData.name = parameter_slider->name;
+                callbackData.uniform = parameter_slider->uniform;
+                callbackData.type = parameter_slider->type;
+                callbackData.color.r = 1.f;
+                callbackData.color.g = 1.f;
+                callbackData.color.b = 1.f;
+                callbackData.value = value;
+                callbackData.scale = 1.f;
+
+                (*_composition->providers.shader_property_update)(&callbackData, _composition->provider_userdata);
+            }break;
+        case AE_MOVIE_EXTENSION_SHADER_PARAMETER_ANGLE:
+            {
+                const struct aeMovieLayerShaderParameterAngle * parameter_angle = (const struct aeMovieLayerShaderParameterAngle *)parameter;
+
+                ae_float_t value = __compute_movie_property_value( parameter_angle->property_value, _frameId, _interpolate, _t );
+
+                aeMovieShaderPropertyUpdateCallbackData callbackData;
+                callbackData.index = index;
+                callbackData.element_userdata = _node->shader_userdata;
+                callbackData.name = parameter_angle->name;
+                callbackData.uniform = parameter_angle->uniform;
+                callbackData.type = parameter_angle->type;
+                callbackData.color.r = 1.f;
+                callbackData.color.g = 1.f;
+                callbackData.color.b = 1.f;
+                callbackData.value = value;
+                callbackData.scale = 1.f;
+
+                (*_composition->providers.shader_property_update)(&callbackData, _composition->provider_userdata);
+            }break;
+        case AE_MOVIE_EXTENSION_SHADER_PARAMETER_COLOR:
+            {
+                const struct aeMovieLayerShaderParameterColor * parameter_color = (const struct aeMovieLayerShaderParameterColor *)parameter;
+
+                const struct aeMoviePropertyColor * property_color = parameter_color->property_color;
+
+                ae_color_channel_t color_r = __compute_movie_property_color_channel( property_color->color_channel_r, _frameId, _interpolate, _t );
+                ae_color_channel_t color_g = __compute_movie_property_color_channel( property_color->color_channel_g, _frameId, _interpolate, _t );
+                ae_color_channel_t color_b = __compute_movie_property_color_channel( property_color->color_channel_b, _frameId, _interpolate, _t );
+
+                aeMovieShaderPropertyUpdateCallbackData callbackData;
+                callbackData.index = index;
+                callbackData.element_userdata = _node->shader_userdata;
+                callbackData.name = parameter_color->name;
+                callbackData.uniform = parameter_color->uniform;
+                callbackData.type = parameter_color->type;
+                callbackData.color.r = color_r;
+                callbackData.color.g = color_g;
+                callbackData.color.b = color_b;
+                callbackData.value = 0.f;
+                callbackData.scale = 1.f;
+
+                (*_composition->providers.shader_property_update)(&callbackData, _composition->provider_userdata);
+            }break;
+        case AE_MOVIE_EXTENSION_SHADER_PARAMETER_TIME:
+            {
+                const struct aeMovieLayerShaderParameterTime * parameter_time = (const struct aeMovieLayerShaderParameterTime *)parameter;
+
+                aeMovieShaderPropertyUpdateCallbackData callbackData;
+                callbackData.index = index;
+                callbackData.element_userdata = _node->shader_userdata;
+                callbackData.name = parameter_time->name;
+                callbackData.uniform = parameter_time->uniform;
+                callbackData.type = parameter_time->type;
+                callbackData.color.r = 1.f;
+                callbackData.color.g = 1.f;
+                callbackData.color.b = 1.f;
+                callbackData.value = 0.f;
+                callbackData.scale = parameter_time->scale;
+
+                (*_composition->providers.shader_property_update)(&callbackData, _composition->provider_userdata);
+            }break;
+        }
+
+        ++index;
+    }
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_uint32_t __get_movie_composition_data_node_count( const aeMovieCompositionData * _compositionData )
+{
+    ae_uint32_t count = _compositionData->layer_count;
+
+    const aeMovieLayerData * it_layer = _compositionData->layers;
+    const aeMovieLayerData * it_layer_end = _compositionData->layers + _compositionData->layer_count;
+    for( ; it_layer != it_layer_end; ++it_layer )
+    {
+        const aeMovieLayerData * layer = it_layer;
+
+        aeMovieLayerTypeEnum layer_type = layer->type;
+
+        switch( layer_type )
+        {
+        case AE_MOVIE_LAYER_TYPE_MOVIE:
+        case AE_MOVIE_LAYER_TYPE_SUB_MOVIE:
+            {
+                ae_uint32_t movie_layer_count = __get_movie_composition_data_node_count( layer->subcomposition_data );
+
+                count += movie_layer_count;
+            }break;
+        default:
+            {
+            }break;
+        }
+    }
+
+    return count;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_bool_t __setup_movie_node_track_matte( aeMovieNode * _nodes, ae_uint32_t * _iterator, const aeMovieCompositionData * _compositionData, aeMovieNode * _trackMatte )
+{
+    const aeMovieLayerData * it_layer = _compositionData->layers;
+    const aeMovieLayerData * it_layer_end = _compositionData->layers + _compositionData->layer_count;
+    for( ; it_layer != it_layer_end; ++it_layer )
+    {
+        const aeMovieLayerData * layer = it_layer;
+
+        aeMovieNode * node = _nodes + ((*_iterator)++);
+
+        aeMovieLayerTypeEnum layer_type = node->layer->type;
+
+        if( _trackMatte == AE_NULLPTR )
+        {
+            if( layer->has_track_matte == AE_TRUE )
+            {
+                switch( layer_type )
+                {
+                case AE_MOVIE_LAYER_TYPE_MOVIE:
+                case AE_MOVIE_LAYER_TYPE_SUB_MOVIE:
+                    {
+                        ae_uint32_t sub_composition_node_count = __get_movie_composition_data_node_count( node->layer->subcomposition_data );
+
+                        aeMovieNode * track_matte_node = _nodes + (*_iterator) + sub_composition_node_count;
+
+                        node->track_matte_node = track_matte_node;
+                        node->track_matte_userdata = AE_NULLPTR;
+                    }break;
+                default:
+                    {
+                        aeMovieNode * track_matte_node = _nodes + (*_iterator);
+
+                        node->track_matte_node = track_matte_node;
+                        node->track_matte_userdata = AE_NULLPTR;
+                    }break;
+                }
+            }
+            else
+            {
+                node->track_matte_node = AE_NULLPTR;
+                node->track_matte_userdata = AE_NULLPTR;
+            }
+        }
+        else
+        {
+            if( layer->has_track_matte == AE_TRUE )
+            {
+                return AE_FALSE;
+            }
+            else
+            {
+                node->track_matte_node = _trackMatte;
+                node->track_matte_userdata = AE_NULLPTR;
+            }
+        }
+
+        switch( layer_type )
+        {
+        case AE_MOVIE_LAYER_TYPE_MOVIE:
+        case AE_MOVIE_LAYER_TYPE_SUB_MOVIE:
+            {
+                if( __setup_movie_node_track_matte( _nodes, _iterator, layer->subcomposition_data, node->track_matte_node ) == AE_FALSE )
+                {
+                    return AE_FALSE;
+                }
+            }break;
+        default:
+            {
+            }break;
+        }
+    }
+
+    return AE_TRUE;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_bool_t __setup_movie_node_track_matte2( aeMovieComposition * _composition )
+{
+    uint32_t enumerator = 0U;
+
+    aeMovieNode * it_node = _composition->nodes;
+    aeMovieNode * it_node_end = _composition->nodes + _composition->node_count;
+    for( ; it_node != it_node_end; ++it_node, ++enumerator )
+    {
+        aeMovieNode * node = it_node;
+
+        if( node->ignore == AE_TRUE )
+        {
+            continue;
+        }
+
+        const aeMovieLayerData * layer = node->layer;
+
+        if( layer->is_track_matte == AE_TRUE )
+        {
+            aeMovieRenderMesh mesh;
+            __compute_movie_render_mesh( _composition, node, &mesh, _composition->interpolate, AE_TRUE );
+
+            aeMovieTrackMatteProviderCallbackData callbackData;
+            callbackData.index = enumerator;
+            callbackData.element_userdata = node->element_userdata;
+            callbackData.layer = layer;
+            callbackData.loop = AE_FALSE;
+            callbackData.offset = AE_TIME_OUTSCALE( node->start_time );
+            callbackData.immutable_matrix = node->immutable_matrix;
+            callbackData.matrix = node->matrix;
+            callbackData.immutable_color = node->immutable_color;
+            callbackData.color = node->color;
+            callbackData.opacity = node->opacity;
+            callbackData.mesh = &mesh;
+            callbackData.track_matte_mode = layer->track_matte_mode;
+
+            ae_userdata_t track_matte_userdata = AE_USERDATA_NULL;
+            if( (*_composition->providers.track_matte_provider)(&callbackData, &track_matte_userdata, _composition->provider_userdata) == AE_FALSE )
+            {
+                return AE_FALSE;
+            }
+
+            node->track_matte_userdata = track_matte_userdata;
+        }
+        else
+        {
+            node->track_matte_userdata = AE_NULLPTR;
+        }
+    }
+
+    return AE_TRUE;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_bool_t __setup_movie_composition_scene_effect( aeMovieComposition * _composition )
+{
+    _composition->scene_effect_node = AE_NULLPTR;
+    _composition->scene_effect_userdata = AE_NULLPTR;
+
+    ae_uint32_t enumerator = 0U;
+
+    aeMovieNode * it_node = _composition->nodes;
+    aeMovieNode * it_node_end = _composition->nodes + _composition->node_count;
+    for( ; it_node != it_node_end; ++it_node, ++enumerator )
+    {
+        aeMovieNode * node = it_node;
+
+        if( node->ignore == AE_TRUE )
+        {
+            continue;
+        }
+
+        const aeMovieLayerData * layer = node->layer;
+
+        if( layer->type != AE_MOVIE_LAYER_TYPE_SCENE_EFFECT )
+        {
+            continue;
+        }
+
+        _composition->scene_effect_node = node;
+
+        const aeMovieLayerTransformation2D * transformation2d = (const aeMovieLayerTransformation2D *)layer->transformation;
+
+        aeMovieCompositionSceneEffectProviderCallbackData callbackData;
+        callbackData.index = enumerator;
+        callbackData.element_userdata = node->element_userdata;
+
+        ae_movie_make_layer_transformation2d_fixed( callbackData.anchor_point, callbackData.position, callbackData.scale, callbackData.quaternion, callbackData.skew, transformation2d, 0 );
+        ae_movie_make_layer_transformation_color_fixed( &callbackData.color, &callbackData.opacity, layer->transformation, 0 );
+
+        ae_userdata_t scene_effect_userdata = AE_USERDATA_NULL;
+        if( (*_composition->providers.scene_effect_provider)(&callbackData, &scene_effect_userdata, _composition->provider_userdata) == AE_FALSE )
+        {
+            return AE_FALSE;
+        }
+
+        _composition->scene_effect_userdata = scene_effect_userdata;
+
+        break;
+    }
+
+    return AE_TRUE;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_uint32_t __get_movie_subcomposition_count( const aeMovieComposition * _composition )
+{
+    ae_uint32_t count = 0;
+
+    aeMovieNode * it_node = _composition->nodes;
+    aeMovieNode * it_node_end = _composition->nodes + _composition->node_count;
+    for( ; it_node != it_node_end; ++it_node )
+    {
+        aeMovieNode * node = it_node;
+
+        if( node->ignore == AE_TRUE )
+        {
+            continue;
+        }
+
+        const aeMovieLayerData * layer = node->layer;
+
+        if( layer->type != AE_MOVIE_LAYER_TYPE_SUB_MOVIE )
+        {
+            continue;
+        }
+
+        ++count;
+    }
+
+    return count;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_bool_t __setup_movie_subcomposition2( aeMovieComposition * _composition, ae_uint32_t * _node_iterator, aeMovieSubComposition * _subcompositions, ae_uint32_t * _subcomposition_iterator, const aeMovieCompositionData * _compositionData, const aeMovieSubComposition * _subcomposition )
+{
+    const aeMovieLayerData * it_layer = _compositionData->layers;
+    const aeMovieLayerData * it_layer_end = _compositionData->layers + _compositionData->layer_count;
+    for( ; it_layer != it_layer_end; ++it_layer )
+    {
+        const aeMovieLayerData * layer = it_layer;
+
+        aeMovieNode * node = _composition->nodes + ((*_node_iterator)++);
+
+        node->subcomposition = _subcomposition;
+
+        const aeMovieLayerData * node_layer = node->layer;
+
+        aeMovieLayerTypeEnum layer_type = node_layer->type;
+
+        switch( layer_type )
+        {
+        case AE_MOVIE_LAYER_TYPE_MOVIE:
+            {
+                if( __setup_movie_subcomposition2( _composition, _node_iterator, _subcompositions, _subcomposition_iterator, layer->subcomposition_data, _subcomposition ) == AE_FALSE )
+                {
+                    return AE_FALSE;
+                }
+            }break;
+        case AE_MOVIE_LAYER_TYPE_SUB_MOVIE:
+            {
+                aeMovieSubComposition * subcomposition = _subcompositions + ((*_subcomposition_iterator)++);
+
+                subcomposition->layer = layer;
+                subcomposition->composition_data = layer->composition_data;
+                subcomposition->subcomposition_data = layer->subcomposition_data;
+
+                aeMovieCompositionAnimation * animation = AE_NEW( _composition->movie_data->instance, aeMovieCompositionAnimation );
+
+                AE_MOVIE_PANIC_MEMORY( animation, AE_FALSE );
+
+                animation->enable = AE_TRUE;
+                animation->play = AE_FALSE;
+                animation->pause = AE_FALSE;
+                animation->interrupt = AE_FALSE;
+
+                animation->loop = AE_FALSE;
+
+                animation->time = 0.f;
+
+                const aeMovieCompositionData * sub_composition_data = layer->subcomposition_data;
+
+                animation->loop_segment_begin = sub_composition_data->loop_segment[0];
+                animation->loop_segment_end = sub_composition_data->loop_segment[1];
+
+                animation->work_area_begin = 0.f;
+                animation->work_area_end = sub_composition_data->duration;
+
+                subcomposition->animation = animation;
+
+                aeMovieSubCompositionProviderCallbackData callbackData;
+                callbackData.layer = subcomposition->layer;
+                callbackData.composition_data = subcomposition->composition_data;
+                callbackData.animation = subcomposition->animation;
+
+                ae_userdata_t subcomposition_userdata = AE_USERDATA_NULL;
+                if( (*_composition->providers.subcomposition_provider)(&callbackData, &subcomposition_userdata, _composition->provider_userdata) == AE_FALSE )
+                {
+                    return AE_FALSE;
+                }
+
+                subcomposition->subcomposition_userdata = subcomposition_userdata;
+
+                if( __setup_movie_subcomposition2( _composition, _node_iterator, _subcompositions, _subcomposition_iterator, layer->subcomposition_data, subcomposition ) == AE_FALSE )
+                {
+                    return AE_FALSE;
+                }
+            }break;
+        default:
+            {
+            }break;
+        }
+    }
+
+    return AE_TRUE;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_bool_t __setup_movie_subcomposition( aeMovieComposition * _composition )
+{
+    ae_uint32_t subcomposition_count = __get_movie_subcomposition_count( _composition );
+
+    if( subcomposition_count == 0U )
+    {
+        _composition->subcomposition_count = 0U;
+        _composition->subcompositions = AE_NULLPTR;
+
+        return AE_TRUE;
+    }
+
+    aeMovieSubComposition * subcompositions = AE_NEWN( _composition->movie_data->instance, aeMovieSubComposition, subcomposition_count );
+
+    AE_MOVIE_PANIC_MEMORY( subcompositions, AE_FALSE );
+
+    ae_uint32_t node_iterator = 0U;
+    ae_uint32_t subcomposition_iterator = 0U;
+
+    if( __setup_movie_subcomposition2( _composition, &node_iterator, subcompositions, &subcomposition_iterator, _composition->composition_data, AE_NULLPTR ) == AE_FALSE )
+    {
+        return AE_FALSE;
+    }
+
+    _composition->subcomposition_count = subcomposition_count;
+    _composition->subcompositions = subcompositions;
+
+    return AE_TRUE;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __setup_movie_node_initialize( aeMovieNode * _nodes, uint32_t _count )
+{
+    aeMovieNode *it_node = _nodes;
+    aeMovieNode *it_node_end = _nodes + _count;
+    for( ; it_node != it_node_end; ++it_node )
+    {
+        aeMovieNode * node = it_node;
+
+        node->subcomposition = AE_NULLPTR;
+        node->volume = 1.f;
+    }
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __setup_movie_node_relative( aeMovieNode * _nodes, ae_uint32_t * _iterator, const aeMovieCompositionData * _compositionData, aeMovieNode * _parent )
+{
+    ae_uint32_t begin_index = *_iterator;
+
+    const aeMovieLayerData *it_layer = _compositionData->layers;
+    const aeMovieLayerData *it_layer_end = _compositionData->layers + _compositionData->layer_count;
+    for( ; it_layer != it_layer_end; ++it_layer )
+    {
+        const aeMovieLayerData * layer = it_layer;
+
+        aeMovieNode * node = _nodes + ((*_iterator)++);
+
+        node->layer = layer;
+        node->update_revision = 0;
+
+        node->active = AE_FALSE;
+        node->ignore = AE_FALSE;
+        node->enable = AE_TRUE;
+        node->animate = AE_MOVIE_NODE_ANIMATE_STATIC;
+
+        if( layer->parent_index == 0 )
+        {
+            node->relative_node = _parent;
+        }
+
+        node->current_time = 0.f;
+        node->current_frame = 0;
+        node->current_frame_t = 0.f;
+
+        switch( layer->type )
+        {
+        case AE_MOVIE_LAYER_TYPE_MOVIE:
+        case AE_MOVIE_LAYER_TYPE_SUB_MOVIE:
+            {
+                __setup_movie_node_relative( _nodes, _iterator, layer->subcomposition_data, node );
+            }break;
+        default:
+            {
+            }break;
+        }
+    }
+
+    ae_uint32_t end_index = *_iterator;
+
+    const aeMovieLayerData *it_layer2 = _compositionData->layers;
+    const aeMovieLayerData *it_layer2_end = _compositionData->layers + _compositionData->layer_count;
+    for( ; it_layer2 != it_layer2_end; ++it_layer2 )
+    {
+        const aeMovieLayerData * layer = it_layer2;
+
+        ae_uint32_t parent_index = layer->parent_index;
+
+        if( parent_index == 0 )
+        {
+            continue;
+        }
+
+        aeMovieNode * node = __find_node_by_layer( _nodes, begin_index, end_index, layer );
+
+        const aeMovieLayerData * parent_layer = __find_layer_by_index( _compositionData, parent_index );
+
+        aeMovieNode * parent_node = __find_node_by_layer( _nodes, begin_index, end_index, parent_layer );
+
+        node->relative_node = parent_node;
+    }
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_bool_t __is_layer_super_immutable_transform( const aeMovieLayerData * _layer )
+{
+    const struct aeMovieLayerTransformation * layer_transformation = _layer->transformation;
+
+    return (layer_transformation->immutable_property_mask & AE_MOVIE_PROPERTY_TRANSFORM_SUPER_ALL) == AE_MOVIE_PROPERTY_TRANSFORM_SUPER_ALL;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_bool_t __is_node_super_immutable_transform( const aeMovieNode * _node )
+{
+    const aeMovieLayerData * node_layer = _node->layer;
+
+    ae_bool_t super_immutable = __is_layer_super_immutable_transform( node_layer );
+
+    if( super_immutable == AE_FALSE )
+    {
+        return AE_FALSE;
+    }
+
+    struct aeMovieNode * relative_node = _node->relative_node;
+
+    if( relative_node == AE_NULLPTR )
+    {
+        return AE_TRUE;
+    }    
+
+    ae_bool_t parent_super_immutable = __is_node_super_immutable_transform( relative_node );
+
+    return parent_super_immutable;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __setup_movie_node_transform_immutable( aeMovieComposition * _composition )
+{
+    aeMovieNode* it_node = _composition->nodes;
+    aeMovieNode* it_node_end = _composition->nodes + _composition->node_count;
+    for( ; it_node != it_node_end; ++it_node )
+    {
+        aeMovieNode * node = it_node;
+
+        ae_bool_t immutable_transform =  __is_node_super_immutable_transform( node );
+
+        node->immutable_matrix = immutable_transform;
+    }
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_bool_t __is_layer_super_immutable_color( const aeMovieLayerData * _layer )
+{
+    const struct aeMovieLayerTransformation * layer_transformation = _layer->transformation;
+
+    return (layer_transformation->immutable_property_mask & AE_MOVIE_PROPERTY_COLOR_SUPER_ALL) == AE_MOVIE_PROPERTY_COLOR_SUPER_ALL;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_bool_t __is_node_super_immutable_color( const aeMovieNode * _node )
+{
+    const aeMovieLayerData * node_layer = _node->layer;
+
+    ae_bool_t super_immutable = __is_layer_super_immutable_color( node_layer );
+
+    if( super_immutable == AE_FALSE )
+    {
+        return AE_FALSE;
+    }
+
+    struct aeMovieNode * relative_node = _node->relative_node;
+
+    if( relative_node == AE_NULLPTR )
+    {
+        return AE_TRUE;
+    }
+
+    ae_bool_t parent_super_immutable = __is_node_super_immutable_color( relative_node );
+
+    return parent_super_immutable;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __setup_movie_node_color_immutable( aeMovieComposition * _composition )
+{
+    aeMovieNode* it_node = _composition->nodes;
+    aeMovieNode* it_node_end = _composition->nodes + _composition->node_count;
+    for( ; it_node != it_node_end; ++it_node )
+    {
+        aeMovieNode * node = it_node;
+
+        ae_bool_t immutable_color = __is_node_super_immutable_color( node );
+
+        node->immutable_color = immutable_color;
+    }
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __setup_movie_node_time( aeMovieNode * _nodes, ae_uint32_t * _iterator, const aeMovieCompositionData * _compositionData, const aeMovieNode * _parent, ae_float_t _stretch, ae_float_t _startTime )
+{
+    const aeMovieLayerData *it_layer = _compositionData->layers;
+    const aeMovieLayerData *it_layer_end = _compositionData->layers + _compositionData->layer_count;
+    for( ; it_layer != it_layer_end; ++it_layer )
+    {
+        const aeMovieLayerData * layer = it_layer;
+
+        aeMovieNode * node = _nodes + ((*_iterator)++);
+
+        if( _parent == AE_NULLPTR )
+        {
+            node->start_time = 0.f;
+            node->in_time = layer->in_time;
+            node->out_time = layer->out_time;
+        }
+        else
+        {
+            ae_float_t layer_in = layer->in_time * _stretch - _startTime;
+            ae_float_t parent_in = _parent->in_time;
+
+            if( parent_in > layer_in )
+            {
+                node->start_time = parent_in - layer_in;
+                node->in_time = parent_in;
+            }
+            else
+            {
+                node->start_time = 0.f;
+                node->in_time = layer_in;
+            }
+
+            ae_float_t layer_out = layer->out_time * _stretch - _startTime;
+            ae_float_t parent_out = _parent->out_time;
+
+            if( node->subcomposition == _parent->subcomposition )
+            {
+                node->out_time = ae_min_f_f( layer_out, parent_out );
+            }
+            else
+            {
+                node->out_time = layer->out_time;
+            }
+
+            if( node->out_time <= 0.f || node->out_time < node->in_time )
+            {
+                node->in_time = 0.f;
+                node->out_time = 0.f;
+                node->ignore = AE_TRUE;
+            }
+        }
+
+        ae_float_t to_stretch = _stretch * layer->stretch;
+
+        switch( layer->type )
+        {
+        case AE_MOVIE_LAYER_TYPE_MOVIE:
+        case AE_MOVIE_LAYER_TYPE_SUB_MOVIE:
+            {
+                node->stretchInv = 1.f / _stretch;
+
+                ae_float_t to_startTime = _startTime + layer->start_time - layer->in_time;
+
+                __setup_movie_node_time( _nodes, _iterator, layer->subcomposition_data, node, to_stretch, to_startTime );
+            }break;
+        default:
+            {
+                node->stretchInv = 1.f / to_stretch;
+            }break;
+        }
+    }
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __setup_movie_node_incessantly( aeMovieComposition * _composition )
+{
+    const aeMovieCompositionData * composition_data = _composition->composition_data;
+    ae_time_t duration = composition_data->duration;
+
+    aeMovieNode *it_node = _composition->nodes;
+    aeMovieNode *it_node_end = _composition->nodes + _composition->node_count;
+    for( ; it_node != it_node_end; ++it_node )
+    {
+        aeMovieNode * node = it_node;
+
+        const aeMovieLayerData * layer = node->layer;
+
+        if( layer->type == AE_MOVIE_LAYER_TYPE_SUB_MOVIE )
+        {
+            node->incessantly = AE_TRUE;
+
+            continue;
+        }
+
+        if( ae_has_movie_layer_data_option( layer, AE_OPTION( 'l', 'o', 'o', 'p' ) ) == AE_TRUE )
+        {
+            node->incessantly = AE_TRUE;
+
+            continue;
+        }
+
+        if( layer->trimmed_time == AE_FALSE &&
+            ae_equal_f_z( node->start_time ) == AE_TRUE &&
+            ae_equal_f_z( node->in_time ) == AE_TRUE &&
+            ae_equal_f_f( node->out_time, duration ) == AE_TRUE )
+        {
+            node->incessantly = AE_TRUE;
+        }
+        else
+        {
+            node->incessantly = AE_FALSE;
+        }
+    }
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __setup_movie_node_incessantly2( aeMovieNode * _nodes, ae_uint32_t * _iterator, const aeMovieCompositionData * _compositionData, ae_bool_t _incessantly )
+{
+    const aeMovieLayerData *it_layer = _compositionData->layers;
+    const aeMovieLayerData *it_layer_end = _compositionData->layers + _compositionData->layer_count;
+    for( ; it_layer != it_layer_end; ++it_layer )
+    {
+        const aeMovieLayerData * layer = it_layer;
+
+        aeMovieNode * node = _nodes + ((*_iterator)++);
+
+        if( _incessantly == AE_TRUE )
+        {
+            node->incessantly = AE_TRUE;
+        }
+
+        switch( layer->type )
+        {
+        case AE_MOVIE_LAYER_TYPE_MOVIE:
+        case AE_MOVIE_LAYER_TYPE_SUB_MOVIE:
+            {
+                ae_bool_t layer_incessantly = ae_is_movie_layer_data_incessantly( layer );
+
+                if( _incessantly == AE_TRUE )
+                {
+                    layer_incessantly = AE_TRUE;
+                }
+
+                __setup_movie_node_incessantly2( _nodes, _iterator, layer->subcomposition_data, layer_incessantly );
+            }break;
+        default:
+            {
+            }break;
+        }
+    }
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __setup_movie_node_blend_mode( aeMovieNode * _nodes, ae_uint32_t * _iterator, const aeMovieCompositionData * _compositionData, const aeMovieNode * _parent, ae_blend_mode_t _blendMode )
+{
+    AE_UNUSED( _parent ); //TODO
+
+    const aeMovieLayerData *it_layer = _compositionData->layers;
+    const aeMovieLayerData *it_layer_end = _compositionData->layers + _compositionData->layer_count;
+    for( ; it_layer != it_layer_end; ++it_layer )
+    {
+        const aeMovieLayerData * layer = it_layer;
+
+        aeMovieNode * node = _nodes + ((*_iterator)++);
+
+        if( _blendMode != AE_MOVIE_BLEND_NORMAL )
+        {
+            node->blend_mode = _blendMode;
+        }
+        else
+        {
+            node->blend_mode = layer->blend_mode;
+        }
+
+        ae_blend_mode_t composition_blend_mode = AE_MOVIE_BLEND_NORMAL;
+
+        if( layer->subcomposition_data != AE_NULLPTR )
+        {
+            composition_blend_mode = node->blend_mode;
+        }
+
+        switch( layer->type )
+        {
+        case AE_MOVIE_LAYER_TYPE_MOVIE:
+        case AE_MOVIE_LAYER_TYPE_SUB_MOVIE:
+            {
+                __setup_movie_node_blend_mode( _nodes, _iterator, layer->subcomposition_data, node, composition_blend_mode );
+            }break;
+        default:
+            {
+            }break;
+        }
+    }
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __setup_movie_node_camera2( aeMovieComposition * _composition, ae_uint32_t * _iterator, const aeMovieCompositionData * _compositionData, ae_userdata_t _userdata )
+{
+    const aeMovieLayerData *it_layer = _compositionData->layers;
+    const aeMovieLayerData *it_layer_end = _compositionData->layers + _compositionData->layer_count;
+    for( ; it_layer != it_layer_end; ++it_layer )
+    {
+        const aeMovieLayerData * layer = it_layer;
+
+        aeMovieNode * node = _composition->nodes + ((*_iterator)++);
+
+        if( layer->threeD == AE_TRUE )
+        {
+            node->camera_userdata = _composition->camera_userdata;
+        }
+        else
+        {
+            node->camera_userdata = _userdata;
+        }
+
+        switch( layer->type )
+        {
+        case AE_MOVIE_LAYER_TYPE_SUB_MOVIE:
+        case AE_MOVIE_LAYER_TYPE_MOVIE:
+            {
+                __setup_movie_node_camera2( _composition, _iterator, layer->subcomposition_data, node->camera_userdata );
+            }break;
+        default:
+            {
+            }break;
+        }
+    }
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_bool_t __setup_movie_node_camera( aeMovieComposition * _composition )
+{
+    const aeMovieCompositionData * composition_data = _composition->composition_data;
+
+    if( composition_data->camera == AE_NULLPTR )
+    {
+        _composition->camera_userdata = AE_NULLPTR;
+
+        aeMovieNode *it_node = _composition->nodes;
+        aeMovieNode *it_node_end = _composition->nodes + _composition->node_count;
+        for( ; it_node != it_node_end; ++it_node )
+        {
+            aeMovieNode * node = it_node;
+
+            node->camera_userdata = AE_NULLPTR;
+        }
+
+        return AE_TRUE;
+    }
+
+    const aeMovieCompositionCamera * camera = composition_data->camera;
+
+    ae_float_t width = composition_data->width;
+    ae_float_t height = composition_data->height;
+
+    aeMovieCameraProviderCallbackData callbackData;
+    callbackData.name = composition_data->name;
+    callbackData.fov = camera->fov;
+    callbackData.width = width;
+    callbackData.height = height;
+
+    ae_movie_make_camera_transformation( callbackData.target, callbackData.position, callbackData.quaternion, camera, 0, AE_FALSE, 0.f );
+
+    ae_userdata_t camera_userdata = AE_USERDATA_NULL;
+    if( (*_composition->providers.camera_provider)(&callbackData, &camera_userdata, _composition->provider_userdata) == AE_FALSE )
+    {
+        return AE_FALSE;
+    }
+
+    _composition->camera_userdata = camera_userdata;
+
+    ae_uint32_t node_camera_iterator = 0U;
+    __setup_movie_node_camera2( _composition, &node_camera_iterator, composition_data, AE_NULLPTR );
+
+    return AE_TRUE;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __setup_movie_node_viewport2( aeMovieComposition * _composition, ae_uint32_t * _iterator, const aeMovieCompositionData * _compositionData, const ae_viewport_t * _viewport )
+{
+    const aeMovieLayerData *it_layer = _compositionData->layers;
+    const aeMovieLayerData *it_layer_end = _compositionData->layers + _compositionData->layer_count;
+    for( ; it_layer != it_layer_end; ++it_layer )
+    {
+        const aeMovieLayerData * layer = it_layer;
+
+        aeMovieNode * node = _composition->nodes + ((*_iterator)++);
+
+        if( layer->extensions->viewport != AE_NULLPTR )
+        {
+            node->viewport = &layer->extensions->viewport->viewport;
+        }
+        else
+        {
+            node->viewport = _viewport;
+        }
+
+        switch( layer->type )
+        {
+        case AE_MOVIE_LAYER_TYPE_SUB_MOVIE:
+        case AE_MOVIE_LAYER_TYPE_MOVIE:
+            {
+                __setup_movie_node_viewport2( _composition, _iterator, layer->subcomposition_data, node->viewport );
+            }break;
+        default:
+            {
+            }break;
+        }
+    }
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __setup_movie_node_viewport( aeMovieComposition * _composition )
+{
+    const aeMovieCompositionData * composition_data = _composition->composition_data;
+
+    ae_uint32_t node_camera_iterator = 0U;
+    __setup_movie_node_viewport2( _composition, &node_camera_iterator, composition_data, AE_NULLPTR );
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __setup_movie_node_matrix2( const aeMovieComposition * _composition, const aeMovieCompositionData * _compositionData, const aeMovieCompositionAnimation * _animation, const aeMovieSubComposition * _subcomposition )
+{
+    ae_uint32_t update_revision = __get_composition_update_revision( _composition );
+
+    aeMovieNode *it_node = _composition->nodes;
+    aeMovieNode *it_node_end = _composition->nodes + _composition->node_count;
+    for( ; it_node != it_node_end; ++it_node )
+    {
+        aeMovieNode * node = it_node;
+
+        if( node->subcomposition != _subcomposition )
+        {
+            continue;
+        }
+
+        const aeMovieLayerData * node_layer = node->layer;
+
+        ae_float_t t = 0.f;
+        ae_uint32_t frameId = __get_movie_frame_time( _animation, node, _composition->interpolate, &t );
+
+        ae_bool_t node_interpolate = (frameId + 1 == node_layer->frame_count) ? AE_FALSE : _composition->interpolate;
+
+        if( (node_layer->transformation->identity_property_mask & AE_MOVIE_PROPERTY_TRANSFORM_SUPER_ALL) == AE_MOVIE_PROPERTY_TRANSFORM_SUPER_ALL )
+        { 
+            ae_ident_m34( node->matrix );
+        }
+
+        __update_movie_composition_node_matrix( node, update_revision, _composition, _compositionData, _animation, _subcomposition, frameId, node_interpolate, t );
+    }
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __setup_movie_node_matrix( const aeMovieComposition * _composition )
+{
+    const aeMovieCompositionData * composition_data = _composition->composition_data;
+    const aeMovieCompositionAnimation * animation = _composition->animation;
+
+    __setup_movie_node_matrix2( _composition, composition_data, animation, AE_NULLPTR );
+
+    const aeMovieSubComposition *it_subcomposition = _composition->subcompositions;
+    const aeMovieSubComposition *it_subcomposition_end = _composition->subcompositions + _composition->subcomposition_count;
+
+    for( ; it_subcomposition != it_subcomposition_end; ++it_subcomposition )
+    {
+        const aeMovieSubComposition * subcomposition = it_subcomposition;
+
+        const aeMovieCompositionData * subcomposition_composition_data = subcomposition->composition_data;
+        aeMovieCompositionAnimation * subcomposition_animation = subcomposition->animation;
+
+        __setup_movie_node_matrix2( _composition, subcomposition_composition_data, subcomposition_animation, subcomposition );
+    }
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_bool_t __setup_movie_node_shader( aeMovieComposition * _composition )
+{
+    aeMovieNode* it_node = _composition->nodes;
+    aeMovieNode* it_node_end = _composition->nodes + _composition->node_count;
+    for( ; it_node != it_node_end; ++it_node )
+    {
+        aeMovieNode * node = it_node;
+
+        const aeMovieLayerData * layer = node->layer;
+
+        if( layer->extensions->shader == AE_NULLPTR )
+        {
+            node->shader_userdata = AE_NULLPTR;
+
+            continue;
+        }
+
+        const aeMovieLayerExtensionShader * shader = layer->extensions->shader;
+
+        aeMovieShaderProviderCallbackData callbackData;
+        callbackData.name = shader->name;
+        callbackData.description = shader->description;
+        callbackData.version = shader->version;
+        callbackData.flags = shader->flags;
+        callbackData.parameter_count = shader->parameter_count;
+
+        const struct aeMovieLayerShaderParameter ** it_parameter = shader->parameters;
+        const struct aeMovieLayerShaderParameter ** it_parameter_end = shader->parameters + shader->parameter_count;
+
+        ae_uint32_t paremeter_index = 0;
+
+        for( ;
+            it_parameter != it_parameter_end;
+            ++it_parameter )
+        {
+            const struct aeMovieLayerShaderParameter * parameter = *it_parameter;
+
+            callbackData.parameter_names[paremeter_index] = parameter->name;
+            callbackData.parameter_uniforms[paremeter_index] = parameter->uniform;
+            callbackData.parameter_types[paremeter_index] = parameter->type;
+
+            switch( parameter->type )
+            {
+            case AE_MOVIE_EXTENSION_SHADER_PARAMETER_SLIDER:
+                {
+                    const struct aeMovieLayerShaderParameterSlider * parameter_slider = (const struct aeMovieLayerShaderParameterSlider *)parameter;
+
+                    ae_float_t value = __compute_movie_property_value( parameter_slider->property_value, 0, AE_FALSE, 0.f );
+
+                    callbackData.parameter_values[paremeter_index] = value;
+
+                    ae_color_t color_white;
+                    color_white.r = 1.f;
+                    color_white.g = 1.f;
+                    color_white.b = 1.f;
+                    callbackData.parameter_colors[paremeter_index] = color_white;
+
+                    callbackData.parameter_scales[paremeter_index] = 1.f;
+                }break;
+            case AE_MOVIE_EXTENSION_SHADER_PARAMETER_ANGLE:
+                {
+                    const struct aeMovieLayerShaderParameterAngle * parameter_angle = (const struct aeMovieLayerShaderParameterAngle *)parameter;
+
+                    ae_float_t value = __compute_movie_property_value( parameter_angle->property_value, 0, AE_FALSE, 0.f );
+
+                    callbackData.parameter_values[paremeter_index] = value;
+
+                    ae_color_t color_white;
+                    color_white.r = 1.f;
+                    color_white.g = 1.f;
+                    color_white.b = 1.f;
+                    callbackData.parameter_colors[paremeter_index] = color_white;
+
+                    callbackData.parameter_scales[paremeter_index] = 1.f;
+                }break;
+            case AE_MOVIE_EXTENSION_SHADER_PARAMETER_COLOR:
+                {
+                    const struct aeMovieLayerShaderParameterColor * parameter_color = (const struct aeMovieLayerShaderParameterColor *)parameter;
+
+                    const struct aeMoviePropertyColor * property_color = parameter_color->property_color;
+
+                    ae_color_channel_t color_r = __compute_movie_property_color_channel( property_color->color_channel_r, 0, AE_FALSE, 0.f );
+                    ae_color_channel_t color_g = __compute_movie_property_color_channel( property_color->color_channel_g, 0, AE_FALSE, 0.f );
+                    ae_color_channel_t color_b = __compute_movie_property_color_channel( property_color->color_channel_b, 0, AE_FALSE, 0.f );
+
+                    callbackData.parameter_values[paremeter_index] = 0.f;
+
+                    ae_color_t color_value;
+                    color_value.r = color_r;
+                    color_value.g = color_g;
+                    color_value.b = color_b;
+                    callbackData.parameter_colors[paremeter_index] = color_value;
+
+                    callbackData.parameter_scales[paremeter_index] = 1.f;
+                }break;
+            case AE_MOVIE_EXTENSION_SHADER_PARAMETER_TIME:
+                {
+                    const struct aeMovieLayerShaderParameterTime * parameter_time = (const struct aeMovieLayerShaderParameterTime *)parameter;
+
+                    callbackData.parameter_values[paremeter_index] = 0.f;
+
+                    ae_color_t color_white;
+                    color_white.r = 1.f;
+                    color_white.g = 1.f;
+                    color_white.b = 1.f;
+                    callbackData.parameter_colors[paremeter_index] = color_white;
+
+                    callbackData.parameter_scales[paremeter_index] = parameter_time->scale;
+                }break;
+            }
+
+            ++paremeter_index;
+        }
+
+        ae_userdata_t shader_userdata = AE_USERDATA_NULL;
+        if( (*_composition->providers.shader_provider)(&callbackData, &shader_userdata, _composition->provider_userdata) == AE_FALSE )
+        {
+            return AE_FALSE;
+        }
+
+        node->shader_userdata = shader_userdata;
+    }
+
+    return AE_TRUE;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_bool_t __setup_movie_composition_element( aeMovieComposition * _composition )
+{
+    ae_uint32_t enumerator = 0U;
+
+    aeMovieNode* it_node = _composition->nodes;
+    aeMovieNode* it_node_end = _composition->nodes + _composition->node_count;
+    for( ; it_node != it_node_end; ++it_node, ++enumerator )
+    {
+        aeMovieNode * node = it_node;
+
+        const aeMovieLayerData * track_matte_layer = node->track_matte_node == AE_NULLPTR ? AE_NULLPTR : node->track_matte_node->layer;
+
+        aeMovieNodeProviderCallbackData callbackData;
+        callbackData.index = enumerator;
+        callbackData.layer = node->layer;
+        callbackData.incessantly = node->incessantly;
+        callbackData.immutable_matrix = node->immutable_matrix;
+        callbackData.matrix = node->matrix;
+        callbackData.color = node->color;
+        callbackData.opacity = node->opacity;
+        callbackData.volume = node->volume;
+        callbackData.track_matte_layer = track_matte_layer;
+
+        ae_userdata_t element_userdata = AE_USERDATA_NULL;
+        if( (*_composition->providers.node_provider)(&callbackData, &element_userdata, _composition->provider_userdata) == AE_FALSE )
+        {
+            return AE_FALSE;
+        }
+
+        node->element_userdata = element_userdata;
+    }
+
+    return AE_TRUE;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __setup_movie_composition_active( aeMovieComposition * _composition )
+{
+    aeMovieNode *it_node = _composition->nodes;
+    aeMovieNode *it_node_end = _composition->nodes + _composition->node_count;
+    for( ; it_node != it_node_end; ++it_node )
+    {
+        aeMovieNode * node = it_node;
+
+        if( node->ignore == AE_TRUE )
+        {
+            continue;
+        }
+
+        if( ae_equal_f_z( node->in_time ) == AE_TRUE )
+        {
+            node->active = AE_TRUE;
+        }
+    }
+}
+//////////////////////////////////////////////////////////////////////////
+const aeMovieComposition * ae_create_movie_composition( const aeMovieData * _movieData, const aeMovieCompositionData * _compositionData, ae_bool_t _interpolate, const aeMovieCompositionProviders * _providers, ae_userdata_t _userdata )
+{
+    aeMovieComposition * composition = AE_NEW( _movieData->instance, aeMovieComposition );
+
+    AE_MOVIE_PANIC_MEMORY( composition, AE_NULLPTR );
+
+    composition->movie_data = _movieData;
+    composition->composition_data = _compositionData;
+
+    aeMovieCompositionAnimation * animation = AE_NEW( _movieData->instance, aeMovieCompositionAnimation );
+
+    AE_MOVIE_PANIC_MEMORY( animation, AE_NULLPTR );
+
+    animation->enable = AE_TRUE;
+    animation->play = AE_FALSE;
+    animation->pause = AE_FALSE;
+    animation->interrupt = AE_FALSE;
+    animation->loop = AE_FALSE;
+
+    animation->time = 0.f;
+    animation->loop_segment_begin = _compositionData->loop_segment[0];
+    animation->loop_segment_end = _compositionData->loop_segment[1];
+    animation->work_area_begin = 0.f;
+    animation->work_area_end = _compositionData->duration;
+
+    composition->animation = animation;
+
+    ae_uint32_t * update_revision = AE_NEW( _movieData->instance, ae_uint32_t );
+
+    AE_MOVIE_PANIC_MEMORY( update_revision, AE_NULLPTR );
+
+    *update_revision = 0;
+
+    composition->update_revision = update_revision;
+
+    composition->interpolate = _interpolate;
+
+    ae_uint32_t node_count = __get_movie_composition_data_node_count( _compositionData );
+
+    composition->node_count = node_count;
+
+    aeMovieNode * nodes = AE_NEWN( _movieData->instance, aeMovieNode, node_count );
+
+    AE_MOVIE_PANIC_MEMORY( nodes, AE_NULLPTR );
+
+    __setup_movie_node_initialize( nodes, node_count );
+
+    composition->nodes = nodes;
+
+    composition->providers = *_providers;
+    composition->provider_userdata = _userdata;
+
+    ae_uint32_t node_relative_iterator = 0U;
+    __setup_movie_node_relative( composition->nodes, &node_relative_iterator, _compositionData, AE_NULLPTR );
+
+    __setup_movie_node_transform_immutable( composition );
+    __setup_movie_node_color_immutable( composition );
+
+    if( __setup_movie_subcomposition( composition ) == AE_FALSE )
+    {
+        return AE_NULLPTR;
+    }
+
+    ae_uint32_t node_time_iterator = 0U;
+    __setup_movie_node_time( composition->nodes, &node_time_iterator, _compositionData, AE_NULLPTR, 1.f, 0.f );
+
+    __setup_movie_node_incessantly( composition );
+
+    ae_uint32_t node_incessantly2_iterator = 0U;
+    __setup_movie_node_incessantly2( composition->nodes, &node_incessantly2_iterator, _compositionData, AE_FALSE );
+
+    ae_uint32_t node_blend_mode_iterator = 0U;
+    __setup_movie_node_blend_mode( composition->nodes, &node_blend_mode_iterator, _compositionData, AE_NULLPTR, AE_MOVIE_BLEND_NORMAL );
+
+    __inc_composition_update_revision( composition );
+
+    if( __setup_movie_node_camera( composition ) == AE_FALSE )
+    {
+        return AE_NULLPTR;
+    }
+
+    __setup_movie_node_matrix( composition );
+
+    __setup_movie_node_viewport( composition );
+
+    __setup_movie_composition_active( composition );
+
+    ae_uint32_t node_track_matte_iterator = 0;
+    if( __setup_movie_node_track_matte( composition->nodes, &node_track_matte_iterator, _compositionData, AE_NULLPTR ) == AE_FALSE )
+    {
+        return AE_NULLPTR;
+    }
+
+    if( __setup_movie_node_shader( composition ) == AE_FALSE )
+    {
+        return AE_NULLPTR;
+    }
+
+    if( __setup_movie_composition_element( composition ) == AE_FALSE )
+    {
+        return AE_NULLPTR;
+    }
+
+    if( __setup_movie_node_track_matte2( composition ) == AE_FALSE )
+    {
+        return AE_NULLPTR;
+    }
+
+    if( __setup_movie_composition_scene_effect( composition ) == AE_FALSE )
+    {
+        return AE_NULLPTR;
+    }
+
+    return composition;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __delete_nodes( const aeMovieComposition * _composition )
+{
+    ae_uint32_t enumerator = 0U;
+
+    const aeMovieNode *it_node = _composition->nodes;
+    const aeMovieNode *it_node_end = _composition->nodes + _composition->node_count;
+    for( ; it_node != it_node_end; ++it_node, ++enumerator )
+    {
+        const aeMovieNode * node = it_node;
+
+        const aeMovieLayerData * layer = node->layer;
+
+        if( node->shader_userdata != AE_NULLPTR )
+        {
+            aeMovieShaderDeleterCallbackData callbackData;
+            callbackData.index = enumerator;
+            callbackData.element_userdata = node->shader_userdata;
+            callbackData.name = layer->extensions->shader->name;
+            callbackData.version = layer->extensions->shader->version;
+
+            (*_composition->providers.shader_deleter)(&callbackData, _composition->provider_userdata);
+        }
+
+        if( layer->is_track_matte == AE_TRUE )
+        {
+            aeMovieTrackMatteDeleterCallbackData callbackData;
+            callbackData.index = enumerator;
+            callbackData.element_userdata = node->element_userdata;
+            callbackData.layer = layer;
+            callbackData.track_matte_userdata = node->track_matte_userdata;
+
+            (*_composition->providers.track_matte_deleter)(&callbackData, _composition->provider_userdata);
+        }
+
+        const aeMovieLayerData * track_matte_layer = node->track_matte_node == AE_NULLPTR ? AE_NULLPTR : node->track_matte_node->layer;
+
+        aeMovieNodeDeleterCallbackData callbackData;
+        callbackData.index = enumerator;
+        callbackData.element_userdata = node->element_userdata;
+        callbackData.layer = layer;
+        callbackData.track_matte_layer = track_matte_layer;
+
+        (*_composition->providers.node_deleter)(&callbackData, _composition->provider_userdata);
+    }
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __delete_camera( const aeMovieComposition * _composition )
+{
+    if( _composition->camera_userdata == AE_NULLPTR )
+    {
+        return;
+    }
+
+    const aeMovieCompositionData * composition_data = _composition->composition_data;
+    const aeMovieCompositionCamera * camera = composition_data->camera;
+
+    aeMovieCameraDeleterCallbackData callbackData;
+    callbackData.name = camera->name;
+    callbackData.camera_userdata = _composition->camera_userdata;
+
+    (*_composition->providers.camera_deleter)(&callbackData, _composition->provider_userdata);
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __delete_scene_effect( const aeMovieComposition * _composition )
+{
+    if( _composition->scene_effect_node == AE_NULLPTR )
+    {
+        return;
+    }
+
+    aeMovieNode * scene_effect_node = _composition->scene_effect_node;
+
+    aeMovieCompositionSceneEffectDeleterCallbackData callbackData;
+    callbackData.element_userdata = scene_effect_node->element_userdata;
+    callbackData.scene_effect_userdata = _composition->scene_effect_userdata;
+
+    (*_composition->providers.scene_effect_deleter)(&callbackData, _composition->provider_userdata);
+}
+//////////////////////////////////////////////////////////////////////////
+ae_void_t ae_delete_movie_composition( const aeMovieComposition * _composition )
+{
+    __delete_nodes( _composition );
+    __delete_camera( _composition );
+    __delete_scene_effect( _composition );
+
+    const aeMovieInstance * instance = _composition->movie_data->instance;
+
+    const aeMovieSubComposition *it_subcomposition = _composition->subcompositions;
+    const aeMovieSubComposition *it_subcomposition_end = _composition->subcompositions + _composition->subcomposition_count;
+    for( ; it_subcomposition != it_subcomposition_end; ++it_subcomposition )
+    {
+        const aeMovieSubComposition * subcomposition = it_subcomposition;
+
+        aeMovieSubCompositionDeleterCallbackData callbackData;
+        callbackData.subcomposition_userdata = subcomposition->subcomposition_userdata;
+
+        (*_composition->providers.subcomposition_deleter)(&callbackData, _composition->provider_userdata);  
+
+        AE_DELETE( instance, subcomposition->animation );
+    }
+
+    AE_DELETEN( instance, _composition->subcompositions );
+
+    AE_DELETEN( instance, _composition->nodes );
+
+    AE_DELETE( instance, _composition->animation );
+
+    AE_DELETE( instance, _composition->update_revision );
+
+    AE_DELETE( instance, _composition );
+}
+//////////////////////////////////////////////////////////////////////////
+const aeMovieCompositionData * ae_get_movie_composition_composition_data( const aeMovieComposition * _composition )
+{
+    const aeMovieCompositionData * composition_data = _composition->composition_data;
+
+    return composition_data;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_bool_t ae_get_movie_composition_anchor_point( const aeMovieComposition * _composition, ae_vector3_t _point )
+{
+    const aeMovieCompositionData * composition_data = _composition->composition_data;
+
+    if( composition_data->flags & AE_MOVIE_COMPOSITION_ANCHOR_POINT )
+    {
+        _point[0] = composition_data->anchor_point[0];
+        _point[1] = composition_data->anchor_point[1];
+        _point[2] = composition_data->anchor_point[2];
+
+        return AE_TRUE;
+    }
+
+    return AE_FALSE;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_uint32_t __mesh_max_vertex_count( const aeMovieLayerExtensionMesh * _mesh, ae_uint32_t _count )
+{
+    if( _mesh->immutable == AE_TRUE )
+    {
+        return _mesh->immutable_mesh.vertex_count;
+    }
+
+    ae_uint32_t max_vertex_count = 0U;
+
+    const ae_mesh_t * it_mesh = _mesh->meshes;
+    const ae_mesh_t * it_mesh_end = _mesh->meshes + _count;
+    for( ; it_mesh != it_mesh_end; ++it_mesh )
+    {
+        const ae_mesh_t * mesh = it_mesh;
+
+        if( max_vertex_count < mesh->vertex_count )
+        {
+            max_vertex_count = mesh->vertex_count;
+        }
+    }
+
+    return max_vertex_count;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_uint32_t __mesh_max_index_count( const aeMovieLayerExtensionMesh * _mesh, ae_uint32_t _count )
+{
+    if( _mesh->immutable == AE_TRUE )
+    {
+        return _mesh->immutable_mesh.index_count;
+    }
+
+    ae_uint32_t max_index_count = 0U;
+
+    const ae_mesh_t * it_mesh = _mesh->meshes;
+    const ae_mesh_t * it_mesh_end = _mesh->meshes + _count;
+    for( ; it_mesh != it_mesh_end; ++it_mesh )
+    {
+        const ae_mesh_t * mesh = it_mesh;
+
+        if( max_index_count < mesh->index_count )
+        {
+            max_index_count = mesh->index_count;
+        }
+    }
+
+    return max_index_count;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_uint32_t __resource_sequence_images_max_vertex_count( const aeMovieResourceSequence * _resource_sequence )
+{
+    ae_uint32_t max_vertex_count = 0U;
+
+    const aeMovieResourceImage * const * it_image = _resource_sequence->images;
+    const aeMovieResourceImage * const * it_image_end = _resource_sequence->images + _resource_sequence->image_count;
+    for( ; it_image != it_image_end; ++it_image )
+    {
+        const aeMovieResourceImage * image = *it_image;
+
+        const ae_mesh_t * mesh = image->mesh;
+
+        if( mesh == AE_NULLPTR )
+        {
+            if( max_vertex_count < 6 )
+            {
+                max_vertex_count = 6;
+            }
+        }
+        else
+        {
+            if( max_vertex_count < mesh->vertex_count )
+            {
+                max_vertex_count = mesh->vertex_count;
+            }
+        }
+    }
+
+    return max_vertex_count;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_uint32_t __resource_sequence_images_max_index_count( const aeMovieResourceSequence * _resource_sequence )
+{
+    ae_uint32_t max_index_count = 0U;
+
+    const aeMovieResourceImage * const * it_image = _resource_sequence->images;
+    const aeMovieResourceImage * const * it_image_end = _resource_sequence->images + _resource_sequence->image_count;
+    for( ; it_image != it_image_end; ++it_image )
+    {
+        const aeMovieResourceImage * image = *it_image;
+
+        const ae_mesh_t * mesh = image->mesh;
+
+        if( mesh == AE_NULLPTR )
+        {
+            if( max_index_count < 6 )
+            {
+                max_index_count = 6;
+            }
+        }
+        else
+        {
+            if( max_index_count < mesh->index_count )
+            {
+                max_index_count = mesh->index_count;
+            }
+        }
+    }
+
+    return max_index_count;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_void_t ae_calculate_movie_composition_render_info( const aeMovieComposition * _composition, aeMovieCompositionRenderInfo * _info )
+{
+    _info->max_render_node = 0U;
+    _info->max_vertex_count = 0U;
+    _info->max_index_count = 0U;
+
+    ae_uint32_t node_count = _composition->node_count;
+
+    ae_uint32_t iterator = 0U;
+    for( ; iterator != node_count; ++iterator )
+    {
+        const aeMovieNode * node = _composition->nodes + iterator;
+
+        const aeMovieLayerData * layer = node->layer;
+
+        if( layer->renderable == AE_FALSE )
+        {
+            continue;
+        }
+
+        ++_info->max_render_node;
+
+        aeMovieLayerTypeEnum layer_type = layer->type;
+        const aeMovieResource * layer_resource = layer->resource;
+
+        switch( layer_type )
+        {
+        case AE_MOVIE_LAYER_TYPE_SHAPE:
+            {
+                _info->max_vertex_count += __mesh_max_vertex_count( layer->extensions->mesh, layer->frame_count );
+                _info->max_index_count += __mesh_max_index_count( layer->extensions->mesh, layer->frame_count );
+            }break;
+        case AE_MOVIE_LAYER_TYPE_SOLID:
+            {
+                //aeMovieResourceSolid * resource_solid = (aeMovieResourceSolid *)resource;
+
+                if( layer->extensions->mesh != AE_NULLPTR )
+                {
+                    _info->max_vertex_count += __mesh_max_vertex_count( layer->extensions->mesh, layer->frame_count );
+                    _info->max_index_count += __mesh_max_index_count( layer->extensions->mesh, layer->frame_count );
+                }
+                else if( layer->extensions->bezier_warp != AE_NULLPTR )
+                {
+                    _info->max_vertex_count += get_bezier_warp_vertex_count( layer->extensions->bezier_warp->quality );
+                    _info->max_index_count += get_bezier_warp_index_count( layer->extensions->bezier_warp->quality );
+                }
+                else
+                {
+                    _info->max_vertex_count += 4U;
+                    _info->max_index_count += 6U;
+                }
+            }break;
+        case AE_MOVIE_LAYER_TYPE_SEQUENCE:
+            {
+                aeMovieResourceSequence * resource_sequence = (aeMovieResourceSequence *)layer_resource;
+
+                if( layer->extensions->mesh != AE_NULLPTR )
+                {
+                    _info->max_vertex_count += __mesh_max_vertex_count( layer->extensions->mesh, layer->frame_count );
+                    _info->max_index_count += __mesh_max_index_count( layer->extensions->mesh, layer->frame_count );
+                }
+                else if( layer->extensions->bezier_warp != AE_NULLPTR )
+                {
+                    _info->max_vertex_count += get_bezier_warp_vertex_count( layer->extensions->bezier_warp->quality );
+                    _info->max_index_count += get_bezier_warp_index_count( layer->extensions->bezier_warp->quality );
+                }
+                else
+                {
+                    _info->max_vertex_count += __resource_sequence_images_max_vertex_count( resource_sequence );
+                    _info->max_index_count += __resource_sequence_images_max_index_count( resource_sequence );
+                }
+            }break;
+        case AE_MOVIE_LAYER_TYPE_VIDEO:
+            {
+                //aeMovieResourceVideo * resource_video = (aeMovieResourceVideo *)resource;
+
+                if( layer->extensions->mesh != AE_NULLPTR )
+                {
+                    _info->max_vertex_count += __mesh_max_vertex_count( layer->extensions->mesh, layer->frame_count );
+                    _info->max_index_count += __mesh_max_index_count( layer->extensions->mesh, layer->frame_count );
+                }
+                else if( layer->extensions->bezier_warp != AE_NULLPTR )
+                {
+                    _info->max_vertex_count += get_bezier_warp_vertex_count( layer->extensions->bezier_warp->quality );
+                    _info->max_index_count += get_bezier_warp_index_count( layer->extensions->bezier_warp->quality );
+                }
+                else
+                {
+                    _info->max_vertex_count += 4U;
+                    _info->max_index_count += 6U;
+                }
+            }break;
+        case AE_MOVIE_LAYER_TYPE_IMAGE:
+            {
+                aeMovieResourceImage * resource_image = (aeMovieResourceImage *)layer_resource;
+
+                if( layer->extensions->mesh != AE_NULLPTR )
+                {
+                    _info->max_vertex_count += __mesh_max_vertex_count( layer->extensions->mesh, layer->frame_count );
+                    _info->max_index_count += __mesh_max_index_count( layer->extensions->mesh, layer->frame_count );
+                }
+                else if( layer->extensions->bezier_warp != AE_NULLPTR )
+                {
+                    _info->max_vertex_count += get_bezier_warp_vertex_count( layer->extensions->bezier_warp->quality );
+                    _info->max_index_count += get_bezier_warp_index_count( layer->extensions->bezier_warp->quality );
+                }
+                else if( resource_image->mesh != AE_NULLPTR )
+                {
+                    const ae_mesh_t * mesh = resource_image->mesh;
+
+                    _info->max_vertex_count += mesh->vertex_count;
+                    _info->max_index_count += mesh->index_count;
+                }
+                else
+                {
+                    _info->max_vertex_count += 4U;
+                    _info->max_index_count += 6U;
+                }
+            }break;
+        default:
+            {
+            }break;
+        }
+    }
+}
+//////////////////////////////////////////////////////////////////////////
+ae_void_t ae_set_movie_composition_loop( const aeMovieComposition * _composition, ae_bool_t _loop )
+{
+    aeMovieCompositionAnimation * animation = _composition->animation;
+
+    animation->loop = _loop;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_bool_t ae_get_movie_composition_loop( const  aeMovieComposition * _composition )
+{
+    const aeMovieCompositionAnimation * animation = _composition->animation;
+
+    ae_bool_t loop = animation->loop;
+
+    return loop;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_bool_t ae_get_movie_composition_interpolate( const aeMovieComposition * _composition )
+{
+    ae_bool_t interpolate = _composition->interpolate;
+
+    return interpolate;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_bool_t ae_is_play_movie_composition( const aeMovieComposition * _composition )
+{
+    const aeMovieCompositionAnimation * animation = _composition->animation;
+
+    ae_bool_t play = animation->play;
+
+    return play;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_bool_t ae_is_pause_movie_composition( const aeMovieComposition * _composition )
+{
+    const aeMovieCompositionAnimation * animation = _composition->animation;
+
+    ae_bool_t pause = animation->pause;
+
+    return pause;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_bool_t ae_is_interrupt_movie_composition( const aeMovieComposition * _composition )
+{
+    const aeMovieCompositionAnimation * animation = _composition->animation;
+
+    ae_bool_t interrupt = animation->interrupt;
+
+    return interrupt;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __notify_stop_nodies( const aeMovieComposition * _composition, const aeMovieCompositionData * _compositionData, aeMovieCompositionAnimation * _animation, const aeMovieSubComposition * _subcomposition )
+{
+    __setup_movie_node_matrix2( _composition, _compositionData, _animation, _subcomposition );
+
+    ae_uint32_t enumerator = 0U;
+
+    aeMovieNode *it_node = _composition->nodes;
+    aeMovieNode *it_node_end = _composition->nodes + _composition->node_count;
+    for( ; it_node != it_node_end; ++it_node, ++enumerator )
+    {
+        aeMovieNode * node = it_node;
+
+        if( node->subcomposition != _subcomposition )
+        {
+            continue;
+        }
+
+        const aeMovieLayerData * layer = node->layer;
+
+        if( layer->is_track_matte == AE_TRUE )
+        {
+            if( node->animate != AE_MOVIE_NODE_ANIMATE_STATIC && node->animate != AE_MOVIE_NODE_ANIMATE_END )
+            {
+                aeMovieRenderMesh mesh;
+                __compute_movie_render_mesh( _composition, node, &mesh, _composition->interpolate, AE_TRUE );
+
+                aeMovieTrackMatteUpdateCallbackData callbackData;
+                callbackData.index = enumerator;
+                callbackData.element_userdata = node->element_userdata;
+                callbackData.layer = layer;
+                callbackData.loop = _animation->loop;
+                callbackData.state = AE_MOVIE_STATE_UPDATE_STOP;
+                callbackData.offset = AE_TIME_OUTSCALE( 0.f );
+                callbackData.immutable_matrix = node->immutable_matrix;
+                callbackData.matrix = node->matrix;
+                callbackData.immutable_color = node->immutable_color;
+                callbackData.color = node->color;
+                callbackData.opacity = node->opacity;
+                callbackData.mesh = &mesh;
+                callbackData.track_matte_userdata = node->track_matte_userdata;
+
+                (*_composition->providers.track_matte_update)(&callbackData, _composition->provider_userdata);
+
+                node->animate = AE_MOVIE_NODE_ANIMATE_STATIC;
+            }
+        }
+        else
+        {
+            if( node->animate != AE_MOVIE_NODE_ANIMATE_STATIC && node->animate != AE_MOVIE_NODE_ANIMATE_END )
+            {
+                aeMovieNodeUpdateCallbackData callbackData;
+                callbackData.index = enumerator;
+                callbackData.element_userdata = node->element_userdata;
+                callbackData.layer = layer;
+                callbackData.loop = _animation->loop;
+                callbackData.state = AE_MOVIE_STATE_UPDATE_STOP;
+                callbackData.offset = AE_TIME_OUTSCALE( 0.f );
+                callbackData.immutable_matrix = node->immutable_matrix;
+                callbackData.matrix = node->matrix;
+                callbackData.immutable_color = node->immutable_color;
+                callbackData.color = node->color;
+                callbackData.opacity = node->opacity;
+                callbackData.volume = node->volume;
+
+                (*_composition->providers.node_update)(&callbackData, _composition->provider_userdata);
+
+                node->animate = AE_MOVIE_NODE_ANIMATE_STATIC;
+            }
+        }
+    }
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __notify_stop_nodies2( const aeMovieComposition * _composition )
+{
+    __notify_stop_nodies( _composition, _composition->composition_data, _composition->animation, AE_NULLPTR );
+
+    const aeMovieSubComposition *it_subcomposition = _composition->subcompositions;
+    const aeMovieSubComposition *it_subcomposition_end = _composition->subcompositions + _composition->subcomposition_count;
+    for( ; it_subcomposition != it_subcomposition_end; ++it_subcomposition )
+    {
+        const aeMovieSubComposition * subcomposition = it_subcomposition;
+
+        __notify_stop_nodies( _composition, subcomposition->composition_data, subcomposition->animation, subcomposition );
+    }
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __notify_pause_nodies( const aeMovieComposition * _composition, const aeMovieCompositionData * _compositionData, aeMovieCompositionAnimation * _animation, const aeMovieSubComposition * _subcomposition )
+{
+    __setup_movie_node_matrix2( _composition, _compositionData, _animation, _subcomposition );
+
+    ae_uint32_t enumerator = 0U;
+
+    aeMovieNode *it_node = _composition->nodes;
+    aeMovieNode *it_node_end = _composition->nodes + _composition->node_count;
+    for( ; it_node != it_node_end; ++it_node, ++enumerator )
+    {
+        aeMovieNode * node = it_node;
+
+        if( node->subcomposition != _subcomposition )
+        {
+            continue;
+        }
+
+        const aeMovieLayerData * layer = node->layer;
+
+        if( layer->is_track_matte == AE_TRUE )
+        {
+            if( node->animate != AE_MOVIE_NODE_ANIMATE_STATIC && node->animate != AE_MOVIE_NODE_ANIMATE_END )
+            {
+                aeMovieRenderMesh mesh;
+                __compute_movie_render_mesh( _composition, node, &mesh, _composition->interpolate, AE_TRUE );
+
+                aeMovieTrackMatteUpdateCallbackData callbackData;
+                callbackData.index = enumerator;
+                callbackData.element_userdata = node->element_userdata;
+                callbackData.layer = layer;
+                callbackData.loop = _animation->loop;
+                callbackData.state = AE_MOVIE_STATE_UPDATE_PAUSE;
+                callbackData.offset = AE_TIME_OUTSCALE( node->current_time );
+                callbackData.immutable_matrix = node->immutable_matrix;
+                callbackData.matrix = node->matrix;
+                callbackData.immutable_color = node->immutable_color;
+                callbackData.color = node->color;
+                callbackData.opacity = node->opacity;
+                callbackData.mesh = &mesh;
+                callbackData.track_matte_userdata = node->track_matte_userdata;
+
+                (*_composition->providers.track_matte_update)(&callbackData, _composition->provider_userdata);
+            }
+        }
+        else
+        {
+            if( node->animate != AE_MOVIE_NODE_ANIMATE_STATIC && node->animate != AE_MOVIE_NODE_ANIMATE_END )
+            {
+                aeMovieNodeUpdateCallbackData callbackData;
+                callbackData.index = enumerator;
+                callbackData.element_userdata = node->element_userdata;
+                callbackData.layer = layer;
+                callbackData.loop = _animation->loop;
+                callbackData.state = AE_MOVIE_STATE_UPDATE_PAUSE;
+                callbackData.offset = AE_TIME_OUTSCALE( node->current_time );
+                callbackData.immutable_matrix = node->immutable_matrix;
+                callbackData.matrix = node->matrix;
+                callbackData.immutable_color = node->immutable_color;
+                callbackData.color = node->color;
+                callbackData.opacity = node->opacity;
+                callbackData.volume = node->volume;
+
+                (*_composition->providers.node_update)(&callbackData, _composition->provider_userdata);
+            }
+        }
+    }
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __notify_pause_nodies2( const aeMovieComposition * _composition )
+{
+    __notify_pause_nodies( _composition, _composition->composition_data, _composition->animation, AE_NULLPTR );
+
+    const aeMovieSubComposition *it_subcomposition = _composition->subcompositions;
+    const aeMovieSubComposition *it_subcomposition_end = _composition->subcompositions + _composition->subcomposition_count;
+    for( ; it_subcomposition != it_subcomposition_end; ++it_subcomposition )
+    {
+        const aeMovieSubComposition * subcomposition = it_subcomposition;
+
+        __notify_pause_nodies( _composition, subcomposition->composition_data, subcomposition->animation, subcomposition );
+    }
+}
+//////////////////////////////////////////////////////////////////////////
+ae_void_t ae_pause_movie_composition( const aeMovieComposition * _composition )
+{
+    aeMovieCompositionAnimation * animation = _composition->animation;
+
+    if( animation->play == AE_FALSE )
+    {
+        return;
+    }
+
+    if( animation->pause == AE_TRUE )
+    {
+        return;
+    }
+
+    animation->pause = AE_TRUE;
+
+    __notify_pause_nodies2( _composition );
+	
+    aeMovieCompositionStateCallbackData callbackData;
+    callbackData.state = AE_MOVIE_COMPOSITION_PAUSE;
+
+    (*_composition->providers.composition_state)(&callbackData, _composition->provider_userdata);
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __notify_resume_nodies( const aeMovieComposition * _composition, const aeMovieCompositionData * _compositionData, aeMovieCompositionAnimation * _animation, const aeMovieSubComposition * _subcomposition )
+{
+    __setup_movie_node_matrix2( _composition, _compositionData, _animation, _subcomposition );
+
+    ae_uint32_t enumerator = 0U;
+
+    aeMovieNode *it_node = _composition->nodes;
+    aeMovieNode *it_node_end = _composition->nodes + _composition->node_count;
+    for( ; it_node != it_node_end; ++it_node, ++enumerator )
+    {
+        aeMovieNode * node = it_node;
+
+        if( node->subcomposition != _subcomposition )
+        {
+            continue;
+        }
+
+        const aeMovieLayerData * layer = node->layer;
+
+        if( layer->is_track_matte == AE_TRUE )
+        {
+            if( node->animate != AE_MOVIE_NODE_ANIMATE_STATIC && node->animate != AE_MOVIE_NODE_ANIMATE_END )
+            {
+                aeMovieRenderMesh mesh;
+                __compute_movie_render_mesh( _composition, node, &mesh, _composition->interpolate, AE_TRUE );
+
+                aeMovieTrackMatteUpdateCallbackData callbackData;
+                callbackData.index = enumerator;
+                callbackData.element_userdata = node->element_userdata;
+                callbackData.layer = layer;
+                callbackData.loop = _animation->loop;
+                callbackData.state = AE_MOVIE_STATE_UPDATE_RESUME;
+                callbackData.offset = AE_TIME_OUTSCALE( node->current_time );
+                callbackData.immutable_matrix = node->immutable_matrix;
+                callbackData.matrix = node->matrix;
+                callbackData.immutable_color = node->immutable_color;
+                callbackData.color = node->color;
+                callbackData.opacity = node->opacity;
+                callbackData.mesh = &mesh;
+                callbackData.track_matte_userdata = node->track_matte_userdata;
+
+                (*_composition->providers.track_matte_update)(&callbackData, _composition->provider_userdata);
+            }
+        }
+        else
+        {
+            if( node->animate != AE_MOVIE_NODE_ANIMATE_STATIC && node->animate != AE_MOVIE_NODE_ANIMATE_END )
+            {
+                aeMovieNodeUpdateCallbackData callbackData;
+                callbackData.index = enumerator;
+                callbackData.element_userdata = node->element_userdata;
+                callbackData.layer = layer;
+                callbackData.loop = _animation->loop;
+                callbackData.state = AE_MOVIE_STATE_UPDATE_RESUME;
+                callbackData.offset = AE_TIME_OUTSCALE( node->current_time );
+                callbackData.immutable_matrix = node->immutable_matrix;
+                callbackData.matrix = node->matrix;
+                callbackData.immutable_color = node->immutable_color;
+                callbackData.color = node->color;
+                callbackData.opacity = node->opacity;
+                callbackData.volume = node->volume;
+
+                (*_composition->providers.node_update)(&callbackData, _composition->provider_userdata);
+            }
+        }
+    }
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __notify_resume_nodies2( const aeMovieComposition * _composition )
+{
+    __notify_resume_nodies( _composition, _composition->composition_data, _composition->animation, AE_NULLPTR );
+
+    const aeMovieSubComposition *it_subcomposition = _composition->subcompositions;
+    const aeMovieSubComposition *it_subcomposition_end = _composition->subcompositions + _composition->subcomposition_count;
+    for( ; it_subcomposition != it_subcomposition_end; ++it_subcomposition )
+    {
+        const aeMovieSubComposition * subcomposition = it_subcomposition;
+
+        __notify_resume_nodies( _composition, subcomposition->composition_data, subcomposition->animation, subcomposition );
+    }
+}
+//////////////////////////////////////////////////////////////////////////
+ae_void_t ae_resume_movie_composition( const aeMovieComposition * _composition )
+{
+    aeMovieCompositionAnimation * animation = _composition->animation;
+
+    if( animation->play == AE_FALSE )
+    {
+        return;
+    }
+
+    if( animation->pause == AE_FALSE )
+    {
+        return;
+    }
+
+    animation->pause = AE_FALSE;
+
+    __notify_resume_nodies2( _composition );
+
+    aeMovieCompositionStateCallbackData callbackData;
+    callbackData.state = AE_MOVIE_COMPOSITION_RESUME;
+
+    (*_composition->providers.composition_state)(&callbackData, _composition->provider_userdata);
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_float_t __get_animation_loop_work_begin( const aeMovieCompositionAnimation * _animation )
+{
+    ae_bool_t loop = _animation->loop;
+
+    if( loop == AE_TRUE )
+    {
+        ae_float_t work_begin = ae_max_f_f( _animation->loop_segment_begin, _animation->work_area_begin );
+
+        return work_begin;
+    }
+    else
+    {
+        ae_float_t work_begin = _animation->work_area_begin;
+
+        return work_begin;
+    }
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_float_t __get_animation_loop_work_end( const aeMovieCompositionAnimation * _animation )
+{
+    ae_bool_t loop = _animation->loop;
+
+    if( loop == AE_TRUE )
+    {
+        ae_float_t work_end = ae_min_f_f( _animation->loop_segment_end, _animation->work_area_end );
+
+        return work_end;
+    }
+    else
+    {
+        ae_float_t work_end = _animation->work_area_end;
+
+        return work_end;
+    }
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __update_movie_composition_node_normal_state( const aeMovieComposition * _composition, const aeMovieCompositionAnimation * _animation, aeMovieNode * _node, ae_uint32_t _index, ae_bool_t _loop, ae_bool_t _begin, ae_float_t _time )
+{
+    if( _node->element_userdata == AE_NULLPTR )
+    {
+        return;
+    }
+
+    const aeMovieLayerData * layer = _node->layer;
+
+    aeMovieNodeUpdateCallbackData callbackData;
+    callbackData.index = _index;
+    callbackData.element_userdata = _node->element_userdata;
+    callbackData.layer = layer;
+    callbackData.interrupt = _animation->interrupt;
+    callbackData.loop = _loop;
+    callbackData.immutable_matrix = _node->immutable_matrix;
+    callbackData.matrix = _node->matrix;
+    callbackData.immutable_color = _node->immutable_color;
+    callbackData.color = _node->color;
+    callbackData.opacity = _node->opacity;
+    callbackData.volume = _node->volume;
+
+
+    if( _begin == AE_TRUE )
+    {
+        if( _node->animate == AE_MOVIE_NODE_ANIMATE_STATIC || _node->animate == AE_MOVIE_NODE_ANIMATE_END )
+        {
+            _node->animate = AE_MOVIE_NODE_ANIMATE_BEGIN;
+
+            callbackData.state = AE_MOVIE_STATE_UPDATE_BEGIN;
+
+            ae_float_t offset = layer->start_time + _time - _node->in_time;
+
+            if( offset < 0.f )
+            {
+                offset = 0.f;
+            }
+            else if( offset > layer->composition_data->duration )
+            {
+                offset = layer->composition_data->duration;
+            }
+
+            callbackData.offset = AE_TIME_OUTSCALE( offset );
+
+            (*_composition->providers.node_update)(&callbackData, _composition->provider_userdata);
+        }
+        else
+        {
+            _node->animate = AE_MOVIE_NODE_ANIMATE_PROCESS;
+
+            callbackData.state = AE_MOVIE_STATE_UPDATE_PROCESS;
+            callbackData.offset = AE_TIME_OUTSCALE( 0.f );
+
+            (*_composition->providers.node_update)(&callbackData, _composition->provider_userdata);
+        }
+    }
+    else
+    {
+        if( _node->animate == AE_MOVIE_NODE_ANIMATE_PROCESS || _node->animate == AE_MOVIE_NODE_ANIMATE_BEGIN )
+        {
+            _node->animate = AE_MOVIE_NODE_ANIMATE_END;
+
+            callbackData.state = AE_MOVIE_STATE_UPDATE_END;
+
+            callbackData.offset = AE_TIME_OUTSCALE( 0.f );
+
+            (*_composition->providers.node_update)(&callbackData, _composition->provider_userdata);
+        }
+        else
+        {
+            _node->animate = AE_MOVIE_NODE_ANIMATE_STATIC;
+
+            callbackData.state = AE_MOVIE_STATE_UPDATE_SKIP;
+
+            (*_composition->providers.node_update)(&callbackData, _composition->provider_userdata);
+        }
+    }
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __update_movie_composition_node_track_matte_state( const aeMovieComposition * _composition, const aeMovieCompositionAnimation * _animation, aeMovieNode * _node, ae_uint32_t _index, ae_bool_t _loop, ae_bool_t _begin, ae_float_t _time, ae_bool_t _interpolate )
+{
+    const aeMovieLayerData * layer = _node->layer;
+
+    aeMovieLayerTypeEnum layer_type = layer->type;
+
+    switch( layer_type )
+    {
+    case AE_MOVIE_LAYER_TYPE_MOVIE:
+        {
+            return;
+        }break;
+    default:
+        {
+        }break;
+    }
+
+    aeMovieRenderMesh mesh;
+    __compute_movie_render_mesh( _composition, _node, &mesh, _interpolate, AE_TRUE );
+
+    aeMovieTrackMatteUpdateCallbackData callbackData;
+    callbackData.index = _index;
+    callbackData.element_userdata = _node->element_userdata;
+    callbackData.layer = layer;
+    callbackData.interrupt = _animation->interrupt;
+    callbackData.loop = _loop;
+
+    ae_float_t offset = layer->start_time + _time - _node->in_time;
+
+    if( offset < 0.f )
+    {
+        offset = 0.f;
+    }
+    else if( offset > layer->composition_data->duration )
+    {
+        offset = layer->composition_data->duration;
+    }
+
+    callbackData.offset = AE_TIME_OUTSCALE( offset );
+    callbackData.immutable_matrix = _node->immutable_matrix;
+    callbackData.matrix = _node->matrix;
+    callbackData.immutable_color = _node->immutable_color;
+    callbackData.color = _node->color;
+    callbackData.opacity = 0.f;
+    callbackData.mesh = &mesh;
+    callbackData.track_matte_userdata = _node->track_matte_userdata;
+
+    if( _begin == AE_TRUE )
+    {
+        if( _node->animate == AE_MOVIE_NODE_ANIMATE_STATIC || _node->animate == AE_MOVIE_NODE_ANIMATE_END )
+        {
+            _node->animate = AE_MOVIE_NODE_ANIMATE_BEGIN;
+
+            callbackData.state = AE_MOVIE_STATE_UPDATE_BEGIN;
+
+            (*_composition->providers.track_matte_update)(&callbackData, _composition->provider_userdata);
+        }
+        else
+        {
+            _node->animate = AE_MOVIE_NODE_ANIMATE_PROCESS;
+
+            callbackData.state = AE_MOVIE_STATE_UPDATE_PROCESS;
+			
+            (*_composition->providers.track_matte_update)(&callbackData, _composition->provider_userdata);
+        }
+    }
+    else
+    {
+        if( _node->animate == AE_MOVIE_NODE_ANIMATE_PROCESS || _node->animate == AE_MOVIE_NODE_ANIMATE_BEGIN )
+        {
+            _node->animate = AE_MOVIE_NODE_ANIMATE_END;
+
+            callbackData.state = AE_MOVIE_STATE_UPDATE_END;
+            
+            (*_composition->providers.track_matte_update)(&callbackData, _composition->provider_userdata);
+        }
+        else
+        {
+            _node->animate = AE_MOVIE_NODE_ANIMATE_STATIC;
+        }
+    }
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __update_movie_composition_node_state( const aeMovieComposition * _composition, const aeMovieCompositionAnimation * _animation, aeMovieNode * _node, ae_uint32_t _index, ae_bool_t _loop, ae_bool_t _begin, ae_float_t _time, ae_bool_t _interpolate )
+{
+    if( _node->layer->is_track_matte == AE_TRUE )
+    {
+        __update_movie_composition_node_track_matte_state( _composition, _animation, _node, _index, _loop, _begin, _time, _interpolate );
+    }
+    else
+    {
+        __update_movie_composition_node_normal_state( _composition, _animation, _node, _index, _loop, _begin, _time );
+    }
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __update_node( const aeMovieComposition * _composition, const aeMovieCompositionData * _compositionData, const aeMovieCompositionAnimation * _animation, const aeMovieSubComposition * _subcomposition, aeMovieNode * _node, ae_uint32_t _index, ae_uint32_t _revision, ae_float_t _time, ae_uint32_t _frameId, ae_float_t _t, ae_bool_t _loop, ae_bool_t _interpolate, ae_bool_t _begin )
+{
+    const aeMovieLayerData * node_layer = _node->layer;
+
+#ifdef AE_MOVIE_DEBUG	
+    if( __test_error_composition_layer_frame( _composition->movie_data->instance
+        , _compositionData
+        , node_layer
+        , _frameId
+        , "__update_node frame id out count"
+    ) == AE_FALSE )
+    {
+        return;
+    }
+#endif
+
+#ifdef AE_MOVIE_SAFE
+    if( _frameId >= node_layer->frame_count )
+    {
+        return;
+    }
+#endif    
+
+    ae_bool_t node_interpolate = (_frameId + 1 == node_layer->frame_count) ? AE_FALSE : _interpolate;
+
+    __update_movie_composition_node_matrix( _node, _revision, _composition, _compositionData, _animation, _subcomposition, _frameId, node_interpolate, _t );
+
+    if( _node->shader_userdata != AE_NULLPTR )
+    {
+        __update_movie_composition_node_shader( _node, _revision, _composition, _compositionData, _frameId, node_interpolate, _t );
+    }
+
+    __update_movie_composition_node_state( _composition, _animation, _node, _index, _loop, _begin, _time, node_interpolate );
+
+    _node->update_revision = _revision;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __update_movie_scene_effect( const aeMovieComposition * _composition, const aeMovieCompositionAnimation * _animation )
+{
+    aeMovieNode * scene_effect_node = _composition->scene_effect_node;
+
+    if( scene_effect_node == AE_NULLPTR )
+    {
+        return;
+    }
+
+    const aeMovieLayerData * layer = scene_effect_node->layer;
+
+    const aeMovieLayerTransformation2D * transformation2d = (const aeMovieLayerTransformation2D *)layer->transformation;
+
+    ae_float_t frameDurationInv = layer->composition_data->frameDurationInv;
+
+    ae_float_t current_time = _animation->time - scene_effect_node->in_time + scene_effect_node->start_time;
+    ae_float_t frame_time = current_time * scene_effect_node->stretchInv * frameDurationInv;
+
+    ae_uint32_t frameId = (ae_uint32_t)frame_time;
+
+    aeMovieCompositionSceneEffectUpdateCallbackData callbackData;
+    callbackData.element_userdata = scene_effect_node->element_userdata;
+
+    ae_bool_t composition_interpolate = _composition->interpolate;
+
+    if( composition_interpolate == AE_TRUE )
+    {
+        ae_float_t t = ae_fractional_f( frame_time );
+
+        ae_movie_make_layer_transformation2d_interpolate( callbackData.anchor_point, callbackData.position, callbackData.scale, callbackData.quaternion, callbackData.skew, transformation2d, frameId, t );
+        ae_movie_make_layer_transformation_color_interpolate( &callbackData.color, &callbackData.opacity, layer->transformation, frameId, t );
+    }
+    else
+    {
+        ae_movie_make_layer_transformation2d_fixed( callbackData.anchor_point, callbackData.position, callbackData.scale, callbackData.quaternion, callbackData.skew, transformation2d, frameId );
+        ae_movie_make_layer_transformation_color_fixed( &callbackData.color, &callbackData.opacity, layer->transformation, frameId );
+    }
+
+    callbackData.scene_effect_userdata = _composition->scene_effect_userdata;
+
+    (*_composition->providers.scene_effect_update)(&callbackData, _composition->provider_userdata);
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __refresh_movie_composition_matrix( const aeMovieComposition * _composition, const aeMovieCompositionData * _compositionData, const aeMovieCompositionAnimation * _animation, const aeMovieSubComposition * _subcomposition )
+{
+    ae_uint32_t update_revision = __get_composition_update_revision( _composition );
+
+    ae_bool_t composition_interpolate = _composition->interpolate;
+
+    aeMovieNode *it_node = _composition->nodes;
+    aeMovieNode *it_node_end = _composition->nodes + _composition->node_count;
+    for( ; it_node != it_node_end; ++it_node )
+    {
+        aeMovieNode * node = it_node;
+
+        if( node->ignore == AE_TRUE )
+        {
+            continue;
+        }
+
+        if( node->active == AE_FALSE )
+        {
+            continue;
+        }
+
+        if( node->subcomposition != _subcomposition )
+        {
+            continue;
+        }
+
+        const aeMovieLayerData * node_layer = node->layer;
+
+        if( node_layer->type == AE_MOVIE_LAYER_TYPE_EVENT )
+        {
+            continue;
+        }
+
+        ae_float_t frameDurationInv = node_layer->composition_data->frameDurationInv;
+
+        ae_float_t frame_time = node->current_time * node->stretchInv * frameDurationInv;
+
+        ae_uint32_t frameId = (ae_uint32_t)frame_time;
+
+        ae_float_t t = 0.f;
+        if( composition_interpolate == AE_TRUE )
+        {
+            t = ae_fractional_f( frame_time );
+        }
+
+        __update_movie_composition_node_matrix( node, update_revision, _composition, _compositionData, _animation, _subcomposition, frameId, composition_interpolate, t );
+    }
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __update_movie_composition_node( const aeMovieComposition * _composition, const aeMovieCompositionData * _compositionData, const aeMovieCompositionAnimation * _animation, const aeMovieSubComposition * _subcomposition, ae_uint32_t _revision, ae_float_t _beginTime, ae_bool_t _end )
+{
+    ae_bool_t composition_interpolate = _composition->interpolate;
+
+    ae_float_t animation_time = _animation->time;
+    ae_bool_t animation_interrupt = _animation->interrupt;
+    ae_bool_t animation_loop = _animation->loop;
+
+    ae_float_t loopBegin = __get_animation_loop_work_begin( _animation );
+    ae_float_t loopEnd = __get_animation_loop_work_end( _animation );
+
+    ae_uint32_t enumerator = 0U;
+
+    aeMovieNode *it_node = _composition->nodes;
+    aeMovieNode *it_node_end = _composition->nodes + _composition->node_count;
+    for( ; it_node != it_node_end; ++it_node, ++enumerator )
+    {
+        aeMovieNode * node = it_node;
+
+        if( node->ignore == AE_TRUE )
+        {
+            continue;
+        }
+
+        if( node->subcomposition != _subcomposition )
+        {
+            continue;
+        }
+
+        const aeMovieLayerData * node_layer = node->layer;
+
+        ae_float_t frameDurationInv = node_layer->composition_data->frameDurationInv;
+
+        ae_bool_t test_time = (_beginTime >= loopBegin
+            && animation_time < loopEnd
+            && animation_interrupt == AE_FALSE
+            && animation_loop == AE_TRUE
+            && node_layer->type != AE_MOVIE_LAYER_TYPE_EVENT);
+
+        ae_float_t in_time = (test_time == AE_TRUE && node->in_time <= loopBegin) ? loopBegin : node->in_time;
+        ae_float_t out_time = (test_time == AE_TRUE && node->out_time >= loopEnd) ? loopEnd : node->out_time;
+
+        ae_float_t beginFrameF = _beginTime;
+        ae_float_t endFrameF = animation_time;
+        ae_float_t indexInF = in_time;
+        ae_float_t indexOutF = out_time;
+
+        ae_uint32_t beginFrame = (ae_uint32_t)(beginFrameF * frameDurationInv + AE_MOVIE_FRAME_EPSILON);
+        ae_uint32_t endFrame = (ae_uint32_t)(endFrameF * frameDurationInv + AE_MOVIE_FRAME_EPSILON);
+        ae_uint32_t indexIn = (ae_uint32_t)(indexInF * frameDurationInv + AE_MOVIE_FRAME_EPSILON);
+        ae_uint32_t indexOut = (ae_uint32_t)(indexOutF * frameDurationInv + AE_MOVIE_FRAME_EPSILON);
+
+        ae_float_t current_time = (endFrameF >= indexOutF) ? out_time - node->in_time + node->start_time : animation_time - node->in_time + node->start_time;
+        ae_float_t stretch_time = current_time * node->stretchInv;
+        ae_float_t frame_time = stretch_time * frameDurationInv;
+
+        ae_uint32_t frameId2 = (ae_uint32_t)frame_time;
+        ae_uint32_t frameId = (ae_uint32_t)(frame_time + AE_MOVIE_FRAME_EPSILON);
+
+        ae_float_t frame_time_for_fractional = frame_time;
+        if( frameId != frameId2 )
+        {
+            frame_time_for_fractional = 0.f;
+        }
+
+        if( node_layer->type == AE_MOVIE_LAYER_TYPE_EVENT )
+        {
+            node->current_time = stretch_time;
+            node->current_frame = frameId;
+            node->current_frame_t = 0.f;
+
+            if( beginFrameF < indexInF && endFrameF > indexInF )
+            {
+                __update_movie_composition_node_matrix( node, _revision, _composition, _compositionData, _animation, _subcomposition, frameId, AE_FALSE, 0.f );
+
+                aeMovieCompositionEventCallbackData callbackData;
+                callbackData.index = enumerator;
+                callbackData.element_userdata = node->element_userdata;
+                callbackData.name = node_layer->name;
+                callbackData.immutable_matrix = node->immutable_matrix;
+                callbackData.matrix = node->matrix;
+                callbackData.immutable_color = node->immutable_color;
+                callbackData.color = node->color;
+                callbackData.opacity = node->opacity;
+                callbackData.begin = AE_TRUE;
+
+                (*_composition->providers.composition_event)(&callbackData, _composition->provider_userdata);
+            }
+
+            if( beginFrameF < indexOutF && endFrameF > indexOutF )
+            {
+                __update_movie_composition_node_matrix( node, _revision, _composition, _compositionData, _animation, _subcomposition, frameId, AE_FALSE, 0.f );
+
+                aeMovieCompositionEventCallbackData callbackData;
+                callbackData.index = enumerator;
+                callbackData.element_userdata = node->element_userdata;
+                callbackData.name = node_layer->name;
+                callbackData.immutable_matrix = node->immutable_matrix;
+                callbackData.matrix = node->matrix;
+                callbackData.immutable_color = node->immutable_color;
+                callbackData.color = node->color;
+                callbackData.opacity = node->opacity;
+                callbackData.begin = AE_FALSE;
+
+                (*_composition->providers.composition_event)(&callbackData, _composition->provider_userdata);
+            }
+
+            node->update_revision = _revision;
+
+            continue;
+        }
+
+        if( indexInF > endFrameF || indexOutF < beginFrameF )
+        {
+            if( node->incessantly == AE_TRUE )
+            {
+                node->current_time = 0.f;
+                node->current_frame = 0U;
+                node->current_frame_t = 0.f;
+
+                __update_movie_composition_node_matrix( node, _revision, _composition, _compositionData, _animation, _subcomposition, 0, AE_FALSE, 0.f );
+
+                __update_movie_composition_node_state( _composition, _animation, node, enumerator, AE_TRUE, AE_TRUE, 0.f, composition_interpolate );
+
+                node->update_revision = _revision;
+                node->active = AE_TRUE;
+            }
+            else
+            {
+                node->active = AE_FALSE;
+            }
+
+            continue;
+        }
+        else if( indexInF > beginFrameF && indexOutF < endFrameF )
+        {
+            if( node->incessantly == AE_TRUE )
+            {
+                node->current_time = stretch_time;
+                node->current_frame = frameId;
+                node->current_frame_t = 0.f;
+
+                __update_movie_composition_node_matrix( node, _revision, _composition, _compositionData, _animation, _subcomposition, frameId, AE_FALSE, 0.f );
+
+                __update_movie_composition_node_state( _composition, _animation, node, enumerator, AE_TRUE, AE_TRUE, stretch_time, composition_interpolate );
+
+                node->update_revision = _revision;
+                node->active = AE_TRUE;
+            }
+            else
+            {
+                node->active = AE_FALSE;
+            }
+
+            continue;
+        }
+
+        node->current_time = stretch_time;
+        node->current_frame = frameId;
+
+        ae_bool_t node_loop = ((animation_loop == AE_TRUE && animation_interrupt == AE_FALSE && loopBegin >= node->in_time && node->out_time >= loopEnd) || node_layer->incessantly == AE_TRUE);
+
+        if( beginFrame < indexIn && endFrame >= indexIn && endFrame < indexOut )
+        {
+            node->active = AE_TRUE;
+
+            ae_bool_t node_interpolate = composition_interpolate ? ((endFrame + 1) < indexOut) : AE_FALSE;
+
+            if( node_interpolate == AE_TRUE )
+            {
+                node->current_frame_t = ae_fractional_f( frame_time_for_fractional );
+            }
+
+            __update_node( _composition, _compositionData, _animation, _subcomposition, node, enumerator, _revision, animation_time, node->current_frame, node->current_frame_t, node_loop, node_interpolate, AE_TRUE );
+        }
+        else if( endFrame >= indexOut && beginFrame >= indexIn && beginFrame < indexOut )
+        {
+            ae_bool_t node_active = (node_loop == AE_TRUE || node->incessantly == AE_TRUE) ? AE_TRUE : AE_FALSE;
+
+            node->active = node_active;
+
+            ae_uint32_t frameEnd = indexOut - indexIn;
+
+            node->current_frame = frameEnd;
+            node->current_frame_t = 0.f;
+
+            ae_bool_t begin = (node->incessantly == AE_TRUE) ? AE_TRUE : AE_FALSE;
+
+            __update_node( _composition, _compositionData, _animation, _subcomposition, node, enumerator, _revision, animation_time, node->current_frame, node->current_frame_t, node_loop, AE_FALSE, begin );
+        }
+        else if( beginFrame >= indexIn && endFrame >= indexIn && endFrame < indexOut )
+        {
+            node->active = AE_TRUE;
+
+            ae_bool_t node_interpolate = (composition_interpolate == AE_TRUE) ? (endFrame + 1) < indexOut : AE_FALSE;
+
+            if( node_interpolate == AE_TRUE )
+            {
+                node->current_frame_t = ae_fractional_f( frame_time_for_fractional );
+            }
+
+            ae_bool_t begin = (_end == AE_TRUE) ? AE_FALSE : AE_TRUE;
+
+            __update_node( _composition, _compositionData, _animation, _subcomposition, node, enumerator, _revision, animation_time, node->current_frame, node->current_frame_t, node_loop, node_interpolate, begin );
+        }
+    }
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __update_movie_camera( const aeMovieComposition * _composition, const aeMovieCompositionAnimation * _animation )
+{
+    if( _composition->camera_userdata == AE_NULLPTR )
+    {
+        return;
+    }
+
+    const aeMovieCompositionData * composition_data = _composition->composition_data;
+    const aeMovieCompositionCamera * camera = composition_data->camera;
+
+    ae_bool_t composition_interpolate = _composition->interpolate;
+
+    aeMovieCameraUpdateCallbackData callbackData;
+    callbackData.camera_userdata = _composition->camera_userdata;
+    callbackData.name = camera->name;
+
+    ae_float_t frameDurationInv = composition_data->frameDurationInv;
+
+    ae_float_t frame_time = _animation->time * frameDurationInv;
+
+    ae_uint32_t frame_id = (ae_uint32_t)frame_time;
+
+    if( composition_interpolate == AE_FALSE )
+    {
+        ae_movie_make_camera_transformation( callbackData.target, callbackData.position, callbackData.quaternion, composition_data->camera, frame_id, AE_FALSE, 0.f );
+    }
+    else
+    {
+        ae_float_t t = ae_fractional_f( frame_time );
+
+        ae_movie_make_camera_transformation( callbackData.target, callbackData.position, callbackData.quaternion, composition_data->camera, frame_id, AE_TRUE, t );
+    }
+
+    (*_composition->providers.camera_update)(&callbackData, _composition->provider_userdata);
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __skip_movie_composition_node( const aeMovieComposition * _composition, const aeMovieCompositionData * _compositionData, aeMovieCompositionAnimation * _animation, const aeMovieSubComposition * _subcomposition, ae_uint32_t _revision, ae_float_t _beginTime, ae_float_t _endTime )
+{
+    ae_uint32_t enumerator = 0U;
+
+    aeMovieNode	*it_node = _composition->nodes;
+    aeMovieNode *it_node_end = _composition->nodes + _composition->node_count;
+    for( ; it_node != it_node_end; ++it_node, ++enumerator )
+    {
+        aeMovieNode * node = it_node;
+
+        if( node->ignore == AE_TRUE )
+        {
+            continue;
+        }
+
+        if( node->subcomposition != _subcomposition )
+        {
+            continue;
+        }
+
+        const aeMovieLayerData * layer = node->layer;
+
+        ae_float_t frameDurationInv = layer->composition_data->frameDurationInv;
+
+        ae_float_t in_time = node->in_time;
+        ae_float_t out_time = node->out_time;
+
+        ae_float_t beginFrameF = _beginTime;
+        ae_float_t endFrameF = _endTime;
+        ae_float_t indexInF = in_time;
+        ae_float_t indexOutF = out_time;
+
+        ae_uint32_t beginFrame = (ae_uint32_t)(beginFrameF * frameDurationInv + AE_MOVIE_FRAME_EPSILON);
+        ae_uint32_t endFrame = (ae_uint32_t)(endFrameF * frameDurationInv + AE_MOVIE_FRAME_EPSILON);
+        ae_uint32_t indexIn = (ae_uint32_t)(indexInF * frameDurationInv + AE_MOVIE_FRAME_EPSILON);
+        ae_uint32_t indexOut = (ae_uint32_t)(indexOutF * frameDurationInv + AE_MOVIE_FRAME_EPSILON);
+
+        if( indexInF > endFrameF || indexOutF < beginFrameF )
+        {
+            node->active = AE_FALSE;
+
+            continue;
+        }
+
+        if( indexInF > beginFrameF && indexOutF < endFrameF )
+        {
+            node->active = AE_FALSE;
+
+            continue;
+        }
+
+        ae_float_t current_time = (endFrame >= indexOut) ? out_time - node->in_time + node->start_time : _animation->time - node->in_time + node->start_time;
+        ae_float_t frame_time = current_time * node->stretchInv * frameDurationInv;
+
+        ae_uint32_t frameId = (ae_uint32_t)frame_time;
+
+        node->current_time = current_time;
+        node->current_frame = frameId;
+        node->current_frame_t = 0.f;
+
+        if( layer->type == AE_MOVIE_LAYER_TYPE_EVENT )
+        {
+        }
+        else
+        {
+            if( beginFrame < indexIn && endFrame >= indexIn && endFrame < indexOut )
+            {
+            }
+            else if( endFrame >= indexOut && beginFrame >= indexIn && beginFrame < indexOut )
+            {
+                node->active = AE_FALSE;
+
+                ae_bool_t node_interpolate = (endFrame + 1) < indexOut;
+
+                if( node_interpolate == AE_TRUE )
+                {
+                    node->current_frame_t = ae_fractional_f( frame_time );
+                }
+
+                __update_node( _composition, _compositionData, _animation, _subcomposition, node, enumerator, _revision, _endTime, node->current_frame, node->current_frame_t, AE_FALSE, node_interpolate, AE_FALSE );
+            }
+            else if( beginFrame >= indexIn && endFrame >= indexIn && endFrame < indexOut )
+            {
+            }
+        }
+
+        node->animate = AE_MOVIE_NODE_ANIMATE_STATIC;
+    }
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_bool_t __update_movie_subcomposition( const aeMovieComposition * _composition, const aeMovieCompositionData * _compositionData, ae_float_t _timing, aeMovieCompositionAnimation * _animation, const aeMovieSubComposition * _subcomposition )
+{
+    ae_uint32_t update_revision = __get_composition_update_revision( _composition );
+
+    ae_float_t prev_time = _animation->time;
+
+    ae_float_t begin_time = prev_time;
+
+    if( _animation->play == AE_TRUE )
+    {
+        ae_float_t current_time = _animation->time;
+        ae_float_t duration = _animation->work_area_end - _animation->work_area_begin;
+
+        ae_float_t frameDuration = _composition->composition_data->frameDuration;
+
+        if( _animation->loop == AE_FALSE || _animation->interrupt == AE_TRUE )
+        {
+            ae_float_t last_time = duration - frameDuration;
+
+            if( current_time + _timing >= last_time )
+            {
+                _animation->time = last_time;
+
+                __update_movie_composition_node( _composition, _compositionData, _animation, _subcomposition, update_revision, begin_time, AE_TRUE );
+
+                __inc_composition_update_revision( _composition );
+
+                if( _animation->interrupt == AE_TRUE )
+                {
+                    aeMovieCompositionExtraInterruptCallbackData callbackData;
+                    callbackData.dummy = 0;
+
+                    ae_bool_t extra_interrupt = (*_composition->providers.composition_extra_interrupt)(&callbackData, _composition->provider_userdata);
+
+                    if( extra_interrupt == AE_FALSE )
+                    {
+                        return AE_FALSE;
+                    }
+                }
+
+                _animation->play = AE_FALSE;
+                _animation->pause = AE_FALSE;
+                _animation->interrupt = AE_FALSE;
+
+                return AE_TRUE;
+            }
+            else
+            {
+                _animation->time += _timing;
+            }
+        }
+        else
+        {
+            ae_float_t loopBegin = ae_max_f_f( _animation->loop_segment_begin, _animation->work_area_begin );
+            ae_float_t loopEnd = ae_min_f_f( _animation->loop_segment_end, _animation->work_area_end );
+
+            ae_float_t last_time = loopEnd - frameDuration;
+
+            if( current_time + _timing >= last_time )
+            {
+                ae_float_t new_composition_time = current_time + _timing - last_time + loopBegin;
+
+                ae_uint32_t loop_count = 1;
+                while( new_composition_time >= last_time )
+                {
+                    new_composition_time -= last_time;
+                    new_composition_time += loopBegin;
+
+                    ++loop_count;
+                }
+
+                _animation->time = last_time;
+
+                __update_movie_composition_node( _composition, _compositionData, _animation, _subcomposition, update_revision, begin_time, AE_TRUE );
+
+                update_revision = __inc_composition_update_revision( _composition );
+
+                ae_float_t new_begin_time = loopBegin;
+
+                _animation->time = new_composition_time;
+
+                __update_movie_composition_node( _composition, _compositionData, _animation, _subcomposition, update_revision, new_begin_time, AE_FALSE );
+
+                __inc_composition_update_revision( _composition );
+
+                uint32_t loop_iterator = 0U;
+                for( ; loop_iterator != loop_count; ++loop_iterator )
+                {
+                    if( _subcomposition == AE_NULLPTR )
+                    {
+                        aeMovieCompositionStateCallbackData callbackData;
+                        callbackData.state = AE_MOVIE_COMPOSITION_LOOP_END;
+
+                        (*_composition->providers.composition_state)(&callbackData, _composition->provider_userdata);
+                    }
+                    else
+                    {
+                        aeMovieSubCompositionStateCallbackData callbackData;
+                        callbackData.state = AE_MOVIE_COMPOSITION_LOOP_END;
+                        callbackData.subcomposition_userdata = _subcomposition->subcomposition_userdata;
+
+                        (*_composition->providers.subcomposition_state)(&callbackData, _composition->provider_userdata);                
+                    }
+                }
+
+                return AE_FALSE;
+            }
+            else
+            {
+                _animation->time += _timing;
+            }
+        }
+    }
+
+    __update_movie_composition_node( _composition, _compositionData, _animation, _subcomposition, update_revision, begin_time, AE_FALSE );
+
+    return AE_FALSE;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_bool_t ae_update_movie_composition( const aeMovieComposition * _composition, ae_time_t _timing )
+{
+    ae_time_t timescale_timing = AE_TIME_INSCALE( _timing );
+
+    __inc_composition_update_revision( _composition );
+
+    aeMovieCompositionAnimation * animation = _composition->animation;
+    const aeMovieCompositionData * composition_data = _composition->composition_data;
+
+    ae_bool_t animation_play = animation->play;
+
+    ae_bool_t composition_end = AE_FALSE;
+    if( animation_play == AE_TRUE && animation->pause == AE_FALSE )
+    {
+        composition_end = __update_movie_subcomposition( _composition, composition_data, timescale_timing, animation, AE_NULLPTR );
+        __update_movie_scene_effect( _composition, animation );
+        __update_movie_camera( _composition, animation );
+    }
+
+    const aeMovieSubComposition *it_subcomposition = _composition->subcompositions;
+    const aeMovieSubComposition *it_subcomposition_end = _composition->subcompositions + _composition->subcomposition_count;
+    for( ; it_subcomposition != it_subcomposition_end; ++it_subcomposition )
+    {
+        const aeMovieSubComposition * subcomposition = it_subcomposition;
+
+        aeMovieCompositionAnimation * subcomposition_animation = subcomposition->animation;
+
+        ae_float_t subcomposition_timing = timescale_timing;
+
+        if( subcomposition_animation->play == AE_FALSE || subcomposition_animation->pause == AE_TRUE )
+        {
+            if( animation_play == AE_FALSE )
+            {
+                continue;
+            }
+
+            subcomposition_timing = 0.f;
+        }
+
+        ae_bool_t subcomposition_end = __update_movie_subcomposition( _composition, subcomposition->composition_data, subcomposition_timing, subcomposition_animation, subcomposition );
+
+        if( subcomposition_end == AE_TRUE )
+        {
+            aeMovieSubCompositionStateCallbackData callbackData;
+            callbackData.state = AE_MOVIE_COMPOSITION_END;
+            callbackData.subcomposition_userdata = subcomposition->subcomposition_userdata;
+
+            (*_composition->providers.subcomposition_state)(&callbackData, _composition->provider_userdata);
+        }
+    }
+
+    if( composition_end == AE_TRUE )
+    {
+        aeMovieCompositionStateCallbackData callbackData;
+        callbackData.state = AE_MOVIE_COMPOSITION_END;
+
+        (*_composition->providers.composition_state)(&callbackData, _composition->provider_userdata);
+    }
+
+    return composition_end;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __set_movie_composition_time( const aeMovieComposition * _composition, const aeMovieCompositionData * _compositionData, aeMovieCompositionAnimation * _animation, ae_float_t _time, const aeMovieSubComposition * _subcomposition )
+{
+    ae_float_t duration = _compositionData->duration;
+
+    if( _time < 0.f )
+    {
+        _time = 0.f;
+    }
+
+    ae_float_t lastFrame = duration - _compositionData->frameDuration;
+
+    ae_bool_t animation_end = AE_FALSE;
+
+    if( _time + f_neps >= lastFrame )
+    {
+        _time = lastFrame + f_neps;
+
+        animation_end = AE_TRUE;
+    }
+
+    ae_float_t current_animation_time = _animation->time;
+
+    if( ae_equal_f_f( current_animation_time, _time ) == AE_TRUE )
+    {
+        return;
+    }
+
+    ae_uint32_t update_revision = __inc_composition_update_revision( _composition );
+
+    if( current_animation_time > _time )
+    {
+        __skip_movie_composition_node( _composition, _compositionData, _animation, _subcomposition, update_revision, current_animation_time, _composition->composition_data->duration );
+
+        update_revision = __inc_composition_update_revision( _composition );
+
+        _animation->time = _time;
+
+        __update_movie_composition_node( _composition, _compositionData, _animation, _subcomposition, update_revision, 0.f, animation_end );
+    }
+    else
+    {
+        _animation->time = _time;
+
+        __update_movie_composition_node( _composition, _compositionData, _animation, _subcomposition, update_revision, current_animation_time, animation_end );
+    }
+}
+//////////////////////////////////////////////////////////////////////////
+ae_bool_t ae_set_movie_composition_work_area( const aeMovieComposition * _composition, ae_time_t _begin, ae_time_t _end )
+{
+    ae_time_t timescale_begin = AE_TIME_INSCALE( _begin );
+    ae_time_t timescale_end = AE_TIME_INSCALE( _end );
+
+    const aeMovieCompositionData * composition_data = _composition->composition_data;
+    ae_time_t duration = composition_data->duration;
+
+    if( timescale_begin < 0.f || timescale_end < 0.f || timescale_begin > duration || timescale_end > duration || timescale_begin > timescale_end )
+    {
+        return AE_FALSE;
+    }
+
+    aeMovieCompositionAnimation * animation = _composition->animation;
+
+    animation->work_area_begin = timescale_begin;
+    animation->work_area_end = timescale_end;
+
+    if( animation->time < timescale_begin || animation->time >= timescale_end )
+    {
+        __set_movie_composition_time( _composition, composition_data, animation, timescale_begin, AE_NULLPTR );
+    }
+
+    return AE_TRUE;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_void_t ae_remove_movie_composition_work_area( const  aeMovieComposition * _composition )
+{
+    const aeMovieCompositionData * composition_data = _composition->composition_data;
+    aeMovieCompositionAnimation * animation = _composition->animation;
+
+    animation->work_area_begin = 0.f;
+    animation->work_area_end = composition_data->duration;
+
+    __set_movie_composition_time( _composition, composition_data, animation, 0.f, AE_NULLPTR );
+}
+//////////////////////////////////////////////////////////////////////////
+ae_void_t ae_play_movie_composition( const aeMovieComposition * _composition, ae_time_t _time )
+{
+    ae_time_t timescale_time = AE_TIME_INSCALE( _time );
+
+    aeMovieCompositionAnimation * animation = _composition->animation;
+
+    if( animation->play == AE_TRUE )
+    {
+        animation->interrupt = AE_FALSE;
+
+        return;
+    }
+
+    if( timescale_time >= 0.f )
+    {
+        ae_time_t work_time = ae_minimax_f_f( timescale_time, animation->work_area_begin, animation->work_area_end );
+
+        const aeMovieCompositionData * composition_data = _composition->composition_data;
+
+        __set_movie_composition_time( _composition, composition_data, animation, work_time, AE_NULLPTR );
+    }
+
+    animation->play = AE_TRUE;
+    animation->pause = AE_FALSE;
+    animation->interrupt = AE_FALSE;
+
+    aeMovieCompositionStateCallbackData callbackData;
+    callbackData.state = AE_MOVIE_COMPOSITION_PLAY;
+
+    (*_composition->providers.composition_state)(&callbackData, _composition->provider_userdata);
+}
+//////////////////////////////////////////////////////////////////////////
+ae_void_t ae_stop_movie_composition( const aeMovieComposition * _composition )
+{
+    aeMovieCompositionAnimation * animation = _composition->animation;
+
+    if( animation->play == AE_FALSE )
+    {
+        animation->interrupt = AE_FALSE;
+
+        return;
+    }
+
+    const aeMovieCompositionData * composition_data = _composition->composition_data;
+
+    __set_movie_composition_time( _composition, composition_data, animation, animation->work_area_begin, AE_NULLPTR );
+
+    animation->play = AE_FALSE;
+    animation->pause = AE_FALSE;
+    animation->interrupt = AE_FALSE;
+
+    __notify_stop_nodies2( _composition );
+
+    aeMovieCompositionStateCallbackData callbackData;
+    callbackData.state = AE_MOVIE_COMPOSITION_STOP;
+
+    (*_composition->providers.composition_state)(&callbackData, _composition->provider_userdata);
+}
+//////////////////////////////////////////////////////////////////////////
+ae_void_t ae_interrupt_movie_composition( const aeMovieComposition * _composition, ae_bool_t _skip )
+{
+    aeMovieCompositionAnimation * animation = _composition->animation;
+
+    if( animation->play == AE_FALSE )
+    {
+        return;
+    }
+
+    if( animation->pause == AE_TRUE )
+    {
+        return;
+    }
+
+    if( animation->interrupt == AE_TRUE )
+    {
+        return;
+    }
+
+    animation->interrupt = AE_TRUE;
+
+    if( _skip == AE_TRUE )
+    {
+        ae_float_t loop_work_end = __get_animation_loop_work_end( animation );
+
+        if( animation->time < loop_work_end )
+        {
+            const aeMovieCompositionData * composition_data = _composition->composition_data;
+
+            __set_movie_composition_time( _composition, composition_data, animation, loop_work_end, AE_NULLPTR );
+        }
+    }
+
+    aeMovieCompositionStateCallbackData callbackData;
+    callbackData.state = AE_MOVIE_COMPOSITION_INTERRUPT;
+
+    (*_composition->providers.composition_state)(&callbackData, _composition->provider_userdata);
+}
+//////////////////////////////////////////////////////////////////////////
+ae_void_t ae_set_movie_composition_time( const aeMovieComposition * _composition, ae_time_t _time )
+{
+    ae_time_t timescale_time = AE_TIME_INSCALE( _time );
+
+    const aeMovieCompositionData * composition_data = _composition->composition_data;
+    aeMovieCompositionAnimation * animation = _composition->animation;
+
+    __set_movie_composition_time( _composition, composition_data, animation, timescale_time, AE_NULLPTR );
+
+    const aeMovieSubComposition *it_subcomposition = _composition->subcompositions;
+    const aeMovieSubComposition *it_subcomposition_end = _composition->subcompositions + _composition->subcomposition_count;
+    for( ; it_subcomposition != it_subcomposition_end; ++it_subcomposition )
+    {
+        const aeMovieSubComposition * subcomposition = it_subcomposition;
+
+        aeMovieCompositionAnimation * subcomposition_animation = subcomposition->animation;
+        const aeMovieCompositionData * subcomposition_composition_data = subcomposition->composition_data;
+
+        __refresh_movie_composition_matrix( _composition, subcomposition_composition_data, subcomposition_animation, subcomposition );
+    }
+}
+//////////////////////////////////////////////////////////////////////////
+const ae_char_t * ae_get_movie_composition_name( const aeMovieComposition * _composition )
+{
+    const aeMovieCompositionData * composition_data = _composition->composition_data;
+
+    const ae_char_t * name = ae_get_movie_composition_data_name( composition_data );
+
+    return name;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_time_t ae_get_movie_composition_time( const aeMovieComposition * _composition )
+{
+    const aeMovieCompositionAnimation * animation = _composition->animation;
+
+    ae_time_t time = animation->time;
+
+    return AE_TIME_OUTSCALE( time );
+}
+//////////////////////////////////////////////////////////////////////////
+ae_time_t ae_get_movie_composition_duration( const aeMovieComposition * _composition )
+{
+    const aeMovieCompositionData * composition_data = _composition->composition_data;
+
+    ae_time_t duration = composition_data->duration;
+
+    return AE_TIME_OUTSCALE( duration );
+}
+//////////////////////////////////////////////////////////////////////////
+ae_void_t ae_get_movie_composition_in_out_loop( const aeMovieComposition * _composition, ae_time_t * _in, ae_time_t * _out )
+{
+    aeMovieCompositionAnimation * animation = _composition->animation;
+    ae_float_t work_begin = ae_max_f_f( animation->loop_segment_begin, animation->work_area_begin );
+    ae_float_t work_end = ae_min_f_f( animation->loop_segment_end, animation->work_area_end );
+
+    *_in = AE_TIME_OUTSCALE( work_begin );
+    *_out = AE_TIME_OUTSCALE( work_end );
+}
+//////////////////////////////////////////////////////////////////////////
+ae_bool_t ae_set_movie_composition_slot_userdata( const aeMovieComposition * _composition, const ae_char_t * _name, ae_voidptr_t _userdata )
+{
+    const aeMovieInstance * instance = _composition->movie_data->instance;
+
+    aeMovieNode *it_node = _composition->nodes;
+    aeMovieNode *it_node_end = _composition->nodes + _composition->node_count;
+    for( ; it_node != it_node_end; ++it_node )
+    {
+        aeMovieNode * node = it_node;
+
+        const aeMovieLayerData * layer = node->layer;
+
+        if( layer->type != AE_MOVIE_LAYER_TYPE_SLOT )
+        {
+            continue;
+        }
+
+        if( AE_STRNCMP( instance, layer->name, _name, AE_MOVIE_MAX_LAYER_NAME ) != 0 )
+        {
+            continue;
+        }
+
+        node->element_userdata = _userdata;
+
+        return AE_TRUE;
+    }
+
+    return AE_FALSE;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_userdata_t ae_get_movie_composition_slot_userdata( const aeMovieComposition * _composition, const ae_char_t * _name )
+{
+    const aeMovieInstance * instance = _composition->movie_data->instance;
+
+    const aeMovieNode *it_node = _composition->nodes;
+    const aeMovieNode *it_node_end = _composition->nodes + _composition->node_count;
+    for( ; it_node != it_node_end; ++it_node )
+    {
+        const aeMovieNode * node = it_node;
+
+        const aeMovieLayerData * layer = node->layer;
+
+        if( layer->type != AE_MOVIE_LAYER_TYPE_SLOT )
+        {
+            continue;
+        }
+
+        if( AE_STRNCMP( instance, layer->name, _name, AE_MOVIE_MAX_LAYER_NAME ) != 0 )
+        {
+            continue;
+        }
+
+        return node->element_userdata;
+    }
+
+    return AE_USERDATA_NULL;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_bool_t ae_has_movie_composition_slot( const aeMovieComposition * _composition, const ae_char_t * _name )
+{
+    const aeMovieInstance * instance = _composition->movie_data->instance;
+
+    const aeMovieNode *it_node = _composition->nodes;
+    const aeMovieNode *it_node_end = _composition->nodes + _composition->node_count;
+    for( ; it_node != it_node_end; ++it_node )
+    {
+        const aeMovieNode * node = it_node;
+
+        const aeMovieLayerData * layer = node->layer;
+
+        if( layer->type != AE_MOVIE_LAYER_TYPE_SLOT )
+        {
+            continue;
+        }
+
+        if( AE_STRNCMP( instance, layer->name, _name, AE_MOVIE_MAX_LAYER_NAME ) != 0 )
+        {
+            continue;
+        }
+
+        return AE_TRUE;
+    }
+
+    return AE_FALSE;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_userdata_t ae_remove_movie_composition_slot( const aeMovieComposition * _composition, const ae_char_t * _name )
+{
+    const aeMovieInstance * instance = _composition->movie_data->instance;
+
+    aeMovieNode *it_node = _composition->nodes;
+    aeMovieNode *it_node_end = _composition->nodes + _composition->node_count;
+    for( ; it_node != it_node_end; ++it_node )
+    {
+        aeMovieNode * node = it_node;
+
+        const aeMovieLayerData * layer = node->layer;
+
+        if( layer->type != AE_MOVIE_LAYER_TYPE_SLOT )
+        {
+            continue;
+        }
+
+        if( AE_STRNCMP( instance, layer->name, _name, AE_MOVIE_MAX_LAYER_NAME ) != 0 )
+        {
+            continue;
+        }
+
+        ae_userdata_t prev_element_userdata = node->element_userdata;
+
+        node->element_userdata = AE_NULLPTR;
+
+        return prev_element_userdata;
+    }
+
+    return AE_USERDATA_NULL;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_userdata_t ae_get_movie_composition_camera_userdata( const aeMovieComposition * _composition )
+{
+    return _composition->camera_userdata;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_bool_t ae_get_movie_composition_socket( const aeMovieComposition * _composition, const ae_char_t * _slotName, const ae_polygon_t ** _polygon )
+{
+    const aeMovieInstance * instance = _composition->movie_data->instance;
+
+    const aeMovieNode *it_node = _composition->nodes;
+    const aeMovieNode *it_node_end = _composition->nodes + _composition->node_count;
+    for( ; it_node != it_node_end; ++it_node )
+    {
+        const aeMovieNode * node = it_node;
+
+        const aeMovieLayerData * layer = node->layer;
+
+        if( layer->type != AE_MOVIE_LAYER_TYPE_SOCKET )
+        {
+            continue;
+        }
+
+        if( AE_STRNCMP( instance, layer->name, _slotName, AE_MOVIE_MAX_LAYER_NAME ) != 0 )
+        {
+            continue;
+        }
+
+        const aeMovieLayerExtensionPolygon * polygon = layer->extensions->polygon;
+
+        if( polygon->immutable == AE_TRUE )
+        {
+            *_polygon = &polygon->immutable_polygon;
+        }
+        else
+        {
+            ae_float_t t;
+            ae_uint32_t frame = __compute_movie_node_frame( node, &t );
+
+            *_polygon = polygon->polygons + frame;
+        }
+
+        return AE_TRUE;
+    }
+
+    return AE_FALSE;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_bool_t ae_compute_movie_mesh( const aeMovieComposition * _composition, ae_uint32_t * _iterator, aeMovieRenderMesh * _render )
+{
+    ae_bool_t composition_interpolate = _composition->interpolate;
+
+    ae_uint32_t render_node_index = *_iterator;
+    ae_uint32_t render_node_max_count = _composition->node_count;
+
+    ae_uint32_t iterator = render_node_index;
+    for( ; iterator != render_node_max_count; ++iterator )
+    {
+        const aeMovieNode * node = _composition->nodes + iterator;
+
+        if( node->active == AE_FALSE )
+        {
+            continue;
+        }
+
+        if( node->enable == AE_FALSE )
+        {
+            continue;
+        }
+
+        if( node->transparent == AE_TRUE )
+        {
+            continue;
+        }
+
+        if( node->track_matte_node != AE_NULLPTR && node->track_matte_node->active == AE_FALSE )
+        {
+            continue;
+        }
+
+        if( node->subcomposition != AE_NULLPTR && node->subcomposition->animation->enable == AE_FALSE )
+        {
+            continue;
+        }
+
+        const aeMovieLayerData * layer = node->layer;
+
+        if( layer->renderable == AE_FALSE )
+        {
+            continue;
+        }
+
+        *_iterator = iterator + 1U;
+
+        __compute_movie_render_mesh( _composition, node, _render, composition_interpolate, AE_FALSE );
+
+        return AE_TRUE;
+    }
+
+    return AE_FALSE;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_uint32_t ae_get_movie_render_mesh_count( const aeMovieComposition * _composition )
+{
+    ae_uint32_t count = 0;
+
+    ae_uint32_t render_node_max_count = _composition->node_count;
+
+    ae_uint32_t iterator = 0U;
+    for( ; iterator != render_node_max_count; ++iterator )
+    {
+        const aeMovieNode * node = _composition->nodes + iterator;
+
+        if( node->active == AE_FALSE )
+        {
+            continue;
+        }
+
+        const aeMovieLayerData * layer = node->layer;
+
+        if( layer->renderable == AE_FALSE )
+        {
+            continue;
+        }
+
+        if( node->track_matte_node != AE_NULLPTR && node->track_matte_node->active == AE_FALSE )
+        {
+            continue;
+        }
+
+        ++count;
+    }
+
+    return count;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_bool_t ae_has_movie_composition_node( const aeMovieComposition * _composition, const ae_char_t * _layerName, aeMovieLayerTypeEnum _type )
+{
+    const aeMovieInstance * instance = _composition->movie_data->instance;
+
+    const aeMovieNode *it_node = _composition->nodes;
+    const aeMovieNode *it_node_end = _composition->nodes + _composition->node_count;
+    for( ; it_node != it_node_end; ++it_node )
+    {
+        const aeMovieNode * node = it_node;
+
+        const aeMovieLayerData * layer = node->layer;
+
+        if( layer->type != _type )
+        {
+            continue;
+        }
+
+        if( AE_STRNCMP( instance, layer->name, _layerName, AE_MOVIE_MAX_LAYER_NAME ) != 0 )
+        {
+            continue;
+        }
+
+        return AE_TRUE;
+    }
+
+    return AE_FALSE;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_bool_t ae_get_movie_composition_node_in_out_time( const aeMovieComposition * _composition, const ae_char_t * _layerName, aeMovieLayerTypeEnum _type, ae_time_t * _in, ae_time_t * _out )
+{
+    const aeMovieInstance * instance = _composition->movie_data->instance;
+
+    const aeMovieNode *it_node = _composition->nodes;
+    const aeMovieNode *it_node_end = _composition->nodes + _composition->node_count;
+    for( ; it_node != it_node_end; ++it_node )
+    {
+        const aeMovieNode * node = it_node;
+
+        const aeMovieLayerData * layer = node->layer;
+
+        if( layer->type != _type )
+        {
+            continue;
+        }
+
+        if( AE_STRNCMP( instance, layer->name, _layerName, AE_MOVIE_MAX_LAYER_NAME ) != 0 )
+        {
+            continue;
+        }
+
+        *_in = AE_TIME_OUTSCALE( node->in_time );
+        *_out = AE_TIME_OUTSCALE( node->out_time );
+
+        return AE_TRUE;
+    }
+
+    return AE_FALSE;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_void_t ae_set_movie_composition_nodes_enable( const aeMovieComposition * _composition, const ae_char_t * _layerName, aeMovieLayerTypeEnum _type, ae_bool_t _enable )
+{
+    const aeMovieInstance * instance = _composition->movie_data->instance;
+
+    aeMovieNode *it_node = _composition->nodes;
+    aeMovieNode *it_node_end = _composition->nodes + _composition->node_count;
+    for( ; it_node != it_node_end; ++it_node )
+    {
+        aeMovieNode * node = it_node;
+
+        const aeMovieLayerData * layer = node->layer;
+
+        if( layer->type != _type )
+        {
+            continue;
+        }
+
+        if( AE_STRNCMP( instance, layer->name, _layerName, AE_MOVIE_MAX_LAYER_NAME ) != 0 )
+        {
+            continue;
+        }
+
+        node->enable = _enable;
+    }
+}
+//////////////////////////////////////////////////////////////////////////
+ae_bool_t ae_set_movie_composition_node_enable( const aeMovieComposition * _composition, const ae_char_t * _layerName, aeMovieLayerTypeEnum _type, ae_bool_t _enable )
+{
+    const aeMovieInstance * instance = _composition->movie_data->instance;
+
+    aeMovieNode *it_node = _composition->nodes;
+    aeMovieNode *it_node_end = _composition->nodes + _composition->node_count;
+    for( ; it_node != it_node_end; ++it_node )
+    {
+        aeMovieNode * node = it_node;
+
+        const aeMovieLayerData * layer = node->layer;
+
+        if( layer->type != _type )
+        {
+            continue;
+        }
+
+        if( AE_STRNCMP( instance, layer->name, _layerName, AE_MOVIE_MAX_LAYER_NAME ) != 0 )
+        {
+            continue;
+        }
+
+        node->enable = _enable;
+
+        return AE_TRUE;
+    }
+
+    return AE_FALSE;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_bool_t ae_get_movie_composition_node_enable( const aeMovieComposition * _composition, const ae_char_t * _layerName, aeMovieLayerTypeEnum _type, ae_bool_t * _enable )
+{
+    const aeMovieInstance * instance = _composition->movie_data->instance;
+
+    const aeMovieNode *it_node = _composition->nodes;
+    const aeMovieNode *it_node_end = _composition->nodes + _composition->node_count;
+    for( ; it_node != it_node_end; ++it_node )
+    {
+        const aeMovieNode * node = it_node;
+
+        const aeMovieLayerData * layer = node->layer;
+
+        if( layer->type != _type )
+        {
+            continue;
+        }
+
+        if( AE_STRNCMP( instance, layer->name, _layerName, AE_MOVIE_MAX_LAYER_NAME ) != 0 )
+        {
+            continue;
+        }
+
+        *_enable = node->enable;
+
+        return AE_TRUE;
+    }
+
+    return AE_FALSE;
+}
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+ae_bool_t ae_has_movie_composition_node_any( const aeMovieComposition * _composition, const ae_char_t * _layerName )
+{
+    const aeMovieInstance * instance = _composition->movie_data->instance;
+
+    const aeMovieNode *it_node = _composition->nodes;
+    const aeMovieNode *it_node_end = _composition->nodes + _composition->node_count;
+    for( ; it_node != it_node_end; ++it_node )
+    {
+        const aeMovieNode * node = it_node;
+
+        const aeMovieLayerData * layer = node->layer;
+
+        if( AE_STRNCMP( instance, layer->name, _layerName, AE_MOVIE_MAX_LAYER_NAME ) != 0 )
+        {
+            continue;
+        }
+
+        return AE_TRUE;
+    }
+
+    return AE_FALSE;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_bool_t ae_get_movie_composition_node_in_out_time_any( const aeMovieComposition * _composition, const ae_char_t * _layerName, ae_time_t * _in, ae_time_t * _out )
+{
+    const aeMovieInstance * instance = _composition->movie_data->instance;
+
+    const aeMovieNode *it_node = _composition->nodes;
+    const aeMovieNode *it_node_end = _composition->nodes + _composition->node_count;
+    for( ; it_node != it_node_end; ++it_node )
+    {
+        const aeMovieNode * node = it_node;
+
+        const aeMovieLayerData * layer = node->layer;
+
+        if( AE_STRNCMP( instance, layer->name, _layerName, AE_MOVIE_MAX_LAYER_NAME ) != 0 )
+        {
+            continue;
+        }
+
+        *_in = AE_TIME_OUTSCALE( node->in_time );
+        *_out = AE_TIME_OUTSCALE( node->out_time );
+
+        return AE_TRUE;
+    }
+
+    return AE_FALSE;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_void_t ae_set_movie_composition_nodes_enable_any( const aeMovieComposition * _composition, const ae_char_t * _layerName, ae_bool_t _enable )
+{
+    const aeMovieInstance * instance = _composition->movie_data->instance;
+
+    aeMovieNode *it_node = _composition->nodes;
+    aeMovieNode *it_node_end = _composition->nodes + _composition->node_count;
+    for( ; it_node != it_node_end; ++it_node )
+    {
+        aeMovieNode * node = it_node;
+
+        const aeMovieLayerData * layer = node->layer;
+
+        if( AE_STRNCMP( instance, layer->name, _layerName, AE_MOVIE_MAX_LAYER_NAME ) != 0 )
+        {
+            continue;
+        }
+
+        node->enable = _enable;
+    }
+}
+//////////////////////////////////////////////////////////////////////////
+ae_bool_t ae_set_movie_composition_node_enable_any( const aeMovieComposition * _composition, const ae_char_t * _layerName, ae_bool_t _enable )
+{
+    const aeMovieInstance * instance = _composition->movie_data->instance;
+
+    aeMovieNode *it_node = _composition->nodes;
+    aeMovieNode *it_node_end = _composition->nodes + _composition->node_count;
+    for( ; it_node != it_node_end; ++it_node )
+    {
+        aeMovieNode * node = it_node;
+
+        const aeMovieLayerData * layer = node->layer;
+
+        if( AE_STRNCMP( instance, layer->name, _layerName, AE_MOVIE_MAX_LAYER_NAME ) != 0 )
+        {
+            continue;
+        }
+
+        node->enable = _enable;
+
+        return AE_TRUE;
+    }
+
+    return AE_FALSE;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_bool_t ae_get_movie_composition_node_enable_any( const aeMovieComposition * _composition, const ae_char_t * _layerName, ae_bool_t * _enable )
+{
+    const aeMovieInstance * instance = _composition->movie_data->instance;
+
+    const aeMovieNode *it_node = _composition->nodes;
+    const aeMovieNode *it_node_end = _composition->nodes + _composition->node_count;
+    for( ; it_node != it_node_end; ++it_node )
+    {
+        const aeMovieNode * node = it_node;
+
+        const aeMovieLayerData * layer = node->layer;
+
+        if( AE_STRNCMP( instance, layer->name, _layerName, AE_MOVIE_MAX_LAYER_NAME ) != 0 )
+        {
+            continue;
+        }
+
+        *_enable = node->enable;
+
+        return AE_TRUE;
+    }
+
+    return AE_FALSE;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_bool_t ae_has_movie_sub_composition( const aeMovieComposition * _composition, const ae_char_t * _name )
+{
+    const aeMovieInstance * instance = _composition->movie_data->instance;
+
+    const aeMovieSubComposition *it_subcomposition = _composition->subcompositions;
+    const aeMovieSubComposition *it_subcomposition_end = _composition->subcompositions + _composition->subcomposition_count;
+    for( ; it_subcomposition != it_subcomposition_end; ++it_subcomposition )
+    {
+        const aeMovieSubComposition * subcomposition = it_subcomposition;
+
+        const aeMovieLayerData * layer = subcomposition->layer;
+
+        if( AE_STRNCMP( instance, layer->name, _name, AE_MOVIE_MAX_LAYER_NAME ) != 0 )
+        {
+            continue;
+        }
+
+        return AE_TRUE;
+    }
+
+    return AE_FALSE;
+}
+//////////////////////////////////////////////////////////////////////////
+const aeMovieSubComposition * ae_get_movie_sub_composition( const aeMovieComposition * _composition, const ae_char_t * _name )
+{
+    const aeMovieInstance * instance = _composition->movie_data->instance;
+
+    const aeMovieSubComposition *it_subcomposition = _composition->subcompositions;
+    const aeMovieSubComposition *it_subcomposition_end = _composition->subcompositions + _composition->subcomposition_count;
+    for( ; it_subcomposition != it_subcomposition_end; ++it_subcomposition )
+    {
+        const aeMovieSubComposition * subcomposition = it_subcomposition;
+
+        const aeMovieLayerData * layer = subcomposition->layer;
+
+        if( AE_STRNCMP( instance, layer->name, _name, AE_MOVIE_MAX_LAYER_NAME ) != 0 )
+        {
+            continue;
+        }
+
+        return subcomposition;
+    }
+
+    return AE_NULLPTR;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_bool_t ae_visit_movie_sub_composition( const aeMovieComposition * _composition, ae_movie_sub_composition_visitor_t _visitor, ae_userdata_t _ud )
+{
+    ae_uint32_t subcomposition_iterator = 0U;
+
+    const aeMovieSubComposition *it_subcomposition = _composition->subcompositions;
+    const aeMovieSubComposition *it_subcomposition_end = _composition->subcompositions + _composition->subcomposition_count;
+    for( ; it_subcomposition != it_subcomposition_end; ++it_subcomposition )
+    {
+        const aeMovieSubComposition * subcomposition = it_subcomposition;
+
+        const aeMovieLayerData * layer = subcomposition->layer;
+
+        if( (*_visitor)(_composition, subcomposition_iterator, layer->name, subcomposition, _ud) == AE_FALSE )
+        {
+            return AE_FALSE;
+        }
+
+        ++subcomposition_iterator;
+    }
+
+    return AE_TRUE;
+}
+//////////////////////////////////////////////////////////////////////////
+const ae_char_t * ae_get_movie_sub_composition_name( const aeMovieSubComposition * _subcomposition )
+{
+    const ae_char_t * name = _subcomposition->layer->name;
+
+    return name;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_void_t ae_get_movie_sub_composition_in_out_loop( const aeMovieSubComposition * _subcomposition, ae_time_t * _in, ae_time_t * _out )
+{
+    aeMovieCompositionAnimation * animation = _subcomposition->animation;
+
+    ae_float_t work_begin = ae_max_f_f( animation->loop_segment_begin, animation->work_area_begin );
+    ae_float_t work_end = ae_min_f_f( animation->loop_segment_end, animation->work_area_end );
+
+    *_in = AE_TIME_OUTSCALE( work_begin );
+    *_out = AE_TIME_OUTSCALE( work_end );
+}
+//////////////////////////////////////////////////////////////////////////
+ae_bool_t ae_play_movie_sub_composition( const aeMovieComposition * _composition, const aeMovieSubComposition * _subcomposition, ae_time_t _time )
+{
+    ae_time_t timescale_time = AE_TIME_INSCALE( _time );
+
+    const aeMovieCompositionData * composition_data = _subcomposition->composition_data;
+    aeMovieCompositionAnimation * animation = _subcomposition->animation;
+
+    if( animation->play == AE_TRUE )
+    {
+        animation->interrupt = AE_FALSE;
+
+        return AE_TRUE;
+    }
+
+    if( timescale_time >= 0.f )
+    {
+        ae_float_t work_time = ae_minimax_f_f( timescale_time, animation->work_area_begin, animation->work_area_end );
+
+        __set_movie_composition_time( _composition, composition_data, animation, work_time, _subcomposition );
+    }
+
+    animation->play = AE_TRUE;
+    animation->pause = AE_FALSE;
+    animation->interrupt = AE_FALSE;
+
+    return AE_TRUE;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_bool_t ae_stop_movie_sub_composition( const aeMovieComposition * _composition, const aeMovieSubComposition * _subcomposition )
+{
+    aeMovieCompositionAnimation * animation = _subcomposition->animation;
+
+    if( animation->play == AE_FALSE )
+    {
+        return AE_TRUE;
+    }
+
+    __notify_stop_nodies( _composition, _subcomposition->composition_data, animation, _subcomposition );
+
+    const aeMovieCompositionData * composition_data = _subcomposition->composition_data;
+
+    __set_movie_composition_time( _composition, composition_data, animation, animation->work_area_begin, _subcomposition );
+
+    animation->play = AE_FALSE;
+    animation->pause = AE_FALSE;
+    animation->interrupt = AE_FALSE;
+
+    aeMovieSubCompositionStateCallbackData callbackData;
+
+    callbackData.state = AE_MOVIE_COMPOSITION_STOP;
+    callbackData.subcomposition_userdata = _subcomposition->subcomposition_userdata;
+
+    (*_composition->providers.subcomposition_state)(&callbackData, _composition->provider_userdata);
+
+    return AE_TRUE;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_bool_t ae_pause_movie_sub_composition( const aeMovieComposition * _composition, const aeMovieSubComposition * _subcomposition )
+{
+    aeMovieCompositionAnimation * animation = _subcomposition->animation;
+
+    if( animation->play == AE_FALSE )
+    {
+        return AE_TRUE;
+    }
+
+    if( animation->pause == AE_TRUE )
+    {
+        return AE_TRUE;
+    }
+
+    __notify_pause_nodies( _composition, _subcomposition->composition_data, animation, _subcomposition );
+
+    animation->pause = AE_TRUE;
+
+    aeMovieSubCompositionStateCallbackData callbackData;
+
+    callbackData.state = AE_MOVIE_COMPOSITION_PAUSE;
+    callbackData.subcomposition_userdata = _subcomposition->subcomposition_userdata;
+
+    (*_composition->providers.subcomposition_state)(&callbackData, _composition->provider_userdata);
+
+    return AE_TRUE;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_bool_t ae_resume_movie_sub_composition( const aeMovieComposition * _composition, const aeMovieSubComposition * _subcomposition )
+{
+    aeMovieCompositionAnimation * animation = _subcomposition->animation;
+
+    if( animation->play == AE_FALSE )
+    {
+        return AE_TRUE;
+    }
+
+    if( animation->pause == AE_FALSE )
+    {
+        return AE_TRUE;
+    }
+
+    __notify_resume_nodies( _composition, _subcomposition->composition_data, animation, _subcomposition );
+
+    animation->pause = AE_FALSE;
+
+    aeMovieSubCompositionStateCallbackData callbackData;
+
+    callbackData.state = AE_MOVIE_COMPOSITION_RESUME;
+    callbackData.subcomposition_userdata = _subcomposition->subcomposition_userdata;
+
+    (*_composition->providers.subcomposition_state)(&callbackData, _composition->provider_userdata);
+
+    return AE_TRUE;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_void_t ae_interrupt_movie_sub_composition( const aeMovieComposition * _composition, const aeMovieSubComposition * _subcomposition, ae_bool_t _skip )
+{
+    const aeMovieCompositionData * composition_data = _subcomposition->composition_data;
+    aeMovieCompositionAnimation * animation = _subcomposition->animation;
+
+    if( animation->play == AE_FALSE )
+    {
+        return;
+    }
+
+    if( animation->pause == AE_TRUE )
+    {
+        return;
+    }
+
+    if( animation->interrupt == AE_TRUE )
+    {
+        return;
+    }
+
+    animation->interrupt = AE_TRUE;
+
+    if( _skip == AE_TRUE )
+    {
+        ae_float_t loop_work_end = __get_animation_loop_work_end( animation );
+
+        if( animation->time < loop_work_end )
+        {
+            __set_movie_composition_time( _composition, composition_data, animation, loop_work_end, _subcomposition );
+        }
+    }
+
+    aeMovieSubCompositionStateCallbackData callbackData;
+
+    callbackData.state = AE_MOVIE_COMPOSITION_INTERRUPT;
+    callbackData.subcomposition_userdata = _subcomposition->subcomposition_userdata;
+
+    (*_composition->providers.subcomposition_state)(&callbackData, _composition->provider_userdata);
+}
+//////////////////////////////////////////////////////////////////////////
+ae_bool_t ae_is_play_movie_sub_composition( const aeMovieSubComposition * _subcomposition )
+{
+    const aeMovieCompositionAnimation * animation = _subcomposition->animation;
+
+    ae_bool_t play = animation->play;
+
+    return play;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_bool_t ae_is_pause_movie_sub_composition( const aeMovieSubComposition * _subcomposition )
+{
+    const aeMovieCompositionAnimation * animation = _subcomposition->animation;
+
+    ae_bool_t pause = animation->pause;
+
+    return pause;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_bool_t ae_is_interrupt_movie_sub_composition( const aeMovieSubComposition * _subcomposition )
+{
+    const aeMovieCompositionAnimation * animation = _subcomposition->animation;
+
+    ae_bool_t interrupt = animation->interrupt;
+
+    return interrupt;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_void_t ae_set_movie_sub_composition_time( const aeMovieComposition * _composition, const aeMovieSubComposition * _subcomposition, ae_time_t _time )
+{
+    ae_time_t timescale_time = AE_TIME_INSCALE( _time );
+
+    const aeMovieCompositionData * composition_data = _subcomposition->composition_data;
+    aeMovieCompositionAnimation * animation = _subcomposition->animation;
+
+    __set_movie_composition_time( _composition, composition_data, animation, timescale_time, _subcomposition );
+}
+//////////////////////////////////////////////////////////////////////////
+ae_time_t ae_get_movie_sub_composition_time( const aeMovieSubComposition * _subcomposition )
+{
+    const aeMovieCompositionAnimation * animation = _subcomposition->animation;
+
+    ae_time_t time = animation->time;
+
+    return AE_TIME_OUTSCALE( time );
+}
+//////////////////////////////////////////////////////////////////////////
+ae_void_t ae_set_movie_sub_composition_loop( const aeMovieSubComposition * _subcomposition, ae_bool_t _loop )
+{
+    aeMovieCompositionAnimation * animation = _subcomposition->animation;
+
+    animation->loop = _loop;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_bool_t ae_get_movie_sub_composition_loop( const aeMovieSubComposition * _subcomposition )
+{
+    const aeMovieCompositionAnimation * animation = _subcomposition->animation;
+
+    ae_bool_t loop = animation->loop;
+
+    return loop;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_void_t ae_set_movie_sub_composition_enable( const aeMovieSubComposition * _subcomposition, ae_bool_t _enable )
+{
+    aeMovieCompositionAnimation * animation = _subcomposition->animation;
+
+    animation->enable = _enable;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_bool_t ae_get_movie_sub_composition_enable( const aeMovieSubComposition * _subcomposition )
+{
+    const aeMovieCompositionAnimation * animation = _subcomposition->animation;
+
+    ae_bool_t enable = animation->enable;
+
+    return enable;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_bool_t ae_set_movie_sub_composition_work_area( const aeMovieComposition * _composition, const aeMovieSubComposition * _subcomposition, ae_time_t _begin, ae_time_t _end )
+{
+    ae_time_t timescale_begin = AE_TIME_INSCALE( _begin );
+    ae_time_t timescale_end = AE_TIME_INSCALE( _end );
+
+    ae_float_t duration = _composition->composition_data->duration;
+
+    if( timescale_begin < 0.f || timescale_end < 0.f || timescale_begin > duration || timescale_end > duration || timescale_begin > timescale_end )
+    {
+        return AE_FALSE;
+    }
+
+    const aeMovieCompositionData * composition_data = _subcomposition->composition_data;
+    aeMovieCompositionAnimation * animation = _subcomposition->animation;
+
+    animation->work_area_begin = timescale_begin;
+    animation->work_area_end = timescale_end;
+
+    if( animation->time < timescale_begin || animation->time >= timescale_end )
+    {
+        __set_movie_composition_time( _composition, composition_data, animation, timescale_begin, _subcomposition );
+    }
+
+    return AE_TRUE;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_void_t ae_remove_movie_sub_composition_work_area( const aeMovieComposition * _composition, const aeMovieSubComposition * _subcomposition )
+{
+    const aeMovieCompositionData * composition_data = _subcomposition->composition_data;
+    aeMovieCompositionAnimation * animation = _subcomposition->animation;
+
+    animation->work_area_begin = 0.f;
+    animation->work_area_end = _composition->composition_data->duration;
+
+    __set_movie_composition_time( _composition, composition_data, animation, 0.f, _subcomposition );
+}
+//////////////////////////////////////////////////////////////////////////
+const aeMovieCompositionData * ae_get_movie_sub_composition_composition_data( const aeMovieSubComposition * _subcomposition )
+{
+    const aeMovieCompositionData * composition_data = _subcomposition->subcomposition_data;
+
+    return composition_data;
+}
+//////////////////////////////////////////////////////////////////////////

+ 2846 - 0
ae-movie/src/movie_data.c

@@ -0,0 +1,2846 @@
+/******************************************************************************
+* libMOVIE Software License v1.0
+*
+* Copyright (c) 2016-2018, Yuriy Levchenko <[email protected]>
+* All rights reserved.
+*
+* You are granted a perpetual, non-exclusive, non-sublicensable, and
+* non-transferable license to use, install, execute, and perform the libMOVIE
+* software and derivative works solely for personal or internal
+* use. Without the written permission of Yuriy Levchenko, you may not (a) modify, translate,
+* adapt, or develop new applications using the libMOVIE or otherwise
+* create derivative works or improvements of the libMOVIE or (b) remove,
+* delete, alter, or obscure any trademarks or any copyright, trademark, patent,
+* or other intellectual property or proprietary rights notices on or in the
+* Software, including any copy thereof. Redistributions in binary or source
+* form must include this license and terms.
+*
+* THIS SOFTWARE IS PROVIDED BY YURIY LEVCHENKO "AS IS" AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+* EVENT SHALL YURIY LEVCHENKO BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION,
+* OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF
+* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+#include "movie/movie_data.h"
+#include "movie/movie_resource.h"
+#include "movie/movie_version.h"
+
+#include "movie_transformation.h"
+#include "movie_bezier.h"
+#include "movie_memory.h"
+#include "movie_stream.h"
+
+//////////////////////////////////////////////////////////////////////////
+aeMovieData * ae_create_movie_data( const aeMovieInstance * _instance, const aeMovieDataProviders * _providers, ae_userdata_t _userdata )
+{
+    aeMovieData * movie = AE_NEW( _instance, aeMovieData );
+
+    if( movie == AE_NULLPTR )
+    {
+        return AE_NULLPTR;
+    }
+
+    movie->instance = _instance;
+
+    movie->name = AE_NULLPTR;
+
+    movie->providers = *_providers;
+    movie->provider_userdata = _userdata;
+
+    movie->atlas_count = 0;
+    movie->atlases = AE_NULLPTR;
+
+    movie->resource_count = 0;
+    movie->resources = AE_NULLPTR;
+
+    movie->composition_count = 0;
+    movie->compositions = AE_NULLPTR;
+
+    return movie;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __delete_mesh_t( const aeMovieInstance * _instance, const ae_mesh_t * _mesh )
+{
+    AE_DELETEN( _instance, _mesh->positions );
+    AE_DELETEN( _instance, _mesh->uvs );
+    AE_DELETEN( _instance, _mesh->indices );
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __delete_layer_mesh_t( const aeMovieInstance * _instance, const aeMovieLayerExtensionMesh * _layerMesh, ae_uint32_t _count )
+{
+    if( _layerMesh->immutable == AE_TRUE )
+    {
+        __delete_mesh_t( _instance, &_layerMesh->immutable_mesh );
+    }
+    else
+    {
+        const ae_mesh_t * it_mesh = _layerMesh->meshes;
+        const ae_mesh_t * it_mesh_end = _layerMesh->meshes + _count;
+        for( ; it_mesh != it_mesh_end; ++it_mesh )
+        {
+            const ae_mesh_t * mesh = it_mesh;
+
+            __delete_mesh_t( _instance, mesh );
+        }
+
+        AE_DELETEN( _instance, _layerMesh->meshes );
+    }
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __delete_property_value( const aeMovieInstance * _instance, const struct aeMoviePropertyValue * _property )
+{
+    AE_DELETEN( _instance, _property->values );
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __delete_property_color_channel( const aeMovieInstance * _instance, const struct aeMoviePropertyColorChannel * _property )
+{
+    AE_DELETEN( _instance, _property->values );
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __delete_property_color( const aeMovieInstance * _instance, const struct aeMoviePropertyColor * _property )
+{
+    __delete_property_color_channel( _instance, _property->color_channel_r );
+    AE_DELETEN( _instance, _property->color_channel_r );
+
+    __delete_property_color_channel( _instance, _property->color_channel_g );
+    AE_DELETEN( _instance, _property->color_channel_g );
+
+    __delete_property_color_channel( _instance, _property->color_channel_b );
+    AE_DELETEN( _instance, _property->color_channel_b );
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __callback_cache_uv_deleter( const aeMovieData * _movieData, ae_userdata_t _userdata )
+{
+    aeMovieDataCacheUVDeleterCallbackData callbackData;
+    callbackData.uv_cache_userdata = _userdata;
+
+    (*_movieData->providers.cache_uv_deleter)(&callbackData, _movieData->provider_userdata);
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __delete_movie_resource( const aeMovieData * _movieData, const aeMovieResource * _resource )
+{
+    const aeMovieInstance * instance = _movieData->instance;
+
+    aeMovieResourceTypeEnum type = _resource->type;
+
+    switch( type )
+    {
+    case AE_MOVIE_RESOURCE_NONE:
+        {
+        }break;
+    case AE_MOVIE_RESOURCE_SOLID:
+        {
+            const aeMovieResourceSolid * resource = (const aeMovieResourceSolid *)_resource;
+
+            AE_UNUSED( resource );
+
+        }break;
+    case AE_MOVIE_RESOURCE_VIDEO:
+        {
+            const aeMovieResourceVideo * resource = (const aeMovieResourceVideo *)_resource;
+
+            AE_DELETE_STRING( instance, resource->path );
+
+            if( resource->cache != AE_NULLPTR )
+            {
+                __callback_cache_uv_deleter( _movieData, resource->cache->uv_cache_userdata );
+
+                ae_uint32_t quality = 0;
+                for( ; quality != AE_MOVIE_BEZIER_MAX_QUALITY; ++quality )
+                {
+                    ae_userdata_t uv_cache_data = resource->cache->bezier_warp_uv_cache_userdata[quality];
+
+                    __callback_cache_uv_deleter( _movieData, uv_cache_data );
+                }
+
+                AE_DELETE( instance, resource->cache );
+            }
+
+        }break;
+    case AE_MOVIE_RESOURCE_SOUND:
+        {
+            const aeMovieResourceSound * resource_sound = (const aeMovieResourceSound *)_resource;
+
+            AE_DELETE_STRING( instance, resource_sound->path );
+
+        }break;
+    case AE_MOVIE_RESOURCE_IMAGE:
+        {
+            const aeMovieResourceImage * resource_image = (const aeMovieResourceImage *)_resource;
+
+            AE_DELETE_STRING( instance, resource_image->path );
+
+            if( resource_image->uvs != instance->sprite_uv )
+            {
+                AE_DELETEN( instance, resource_image->uvs );
+            }
+
+            ae_uint32_t index_bezier_warp_uv = 0;
+            for( ; index_bezier_warp_uv != AE_MOVIE_BEZIER_MAX_QUALITY; ++index_bezier_warp_uv )
+            {
+                const ae_vector2_t * uvs = resource_image->bezier_warp_uvs[index_bezier_warp_uv];
+
+                if( uvs != instance->bezier_warp_uvs[index_bezier_warp_uv] )
+                {
+                    AE_DELETEN( instance, uvs );
+                }
+            }
+
+            if( resource_image->mesh != AE_NULLPTR )
+            {
+                __delete_mesh_t( instance, resource_image->mesh );
+
+                AE_DELETE( instance, resource_image->mesh );
+            }
+
+            if( resource_image->cache != AE_NULLPTR )
+            {
+                __callback_cache_uv_deleter( _movieData, resource_image->cache->uv_cache_userdata );
+                __callback_cache_uv_deleter( _movieData, resource_image->cache->mesh_uv_cache_userdata );
+
+                ae_uint32_t quality = 0;
+                for( ; quality != AE_MOVIE_BEZIER_MAX_QUALITY; ++quality )
+                {
+                    ae_userdata_t uv_cache_data = resource_image->cache->bezier_warp_uv_cache_userdata[quality];
+
+                    __callback_cache_uv_deleter( _movieData, uv_cache_data );
+                }
+
+                AE_DELETE( instance, resource_image->cache );
+            }
+
+        }break;
+    case AE_MOVIE_RESOURCE_SEQUENCE:
+        {
+            const aeMovieResourceSequence * resource_sequence = (const aeMovieResourceSequence *)_resource;
+
+            AE_DELETEN( instance, resource_sequence->images );
+
+        }break;
+    case AE_MOVIE_RESOURCE_PARTICLE:
+        {
+            const aeMovieResourceParticle * resource_particle = (const aeMovieResourceParticle *)_resource;
+
+            AE_DELETE_STRING( instance, resource_particle->path );
+
+        }break;
+    case AE_MOVIE_RESOURCE_SLOT:
+        {
+            const aeMovieResourceSlot * resource_slot = (const aeMovieResourceSlot *)_resource;
+
+            AE_UNUSED( resource_slot );
+
+        }break;
+    }
+
+    (*_movieData->providers.resource_deleter)(type, _resource->userdata, _movieData->provider_userdata);
+
+    AE_DELETE_STRING( instance, _resource->name );
+}
+//////////////////////////////////////////////////////////////////////////
+ae_void_t ae_delete_movie_data( const aeMovieData * _movieData )
+{
+    const aeMovieInstance * instance = _movieData->instance;
+
+    if( _movieData->atlases != AE_NULLPTR )
+    {
+        const aeMovieResource * const * it_atlas = _movieData->atlases;
+        const aeMovieResource * const * it_atlas_end = _movieData->atlases + _movieData->atlas_count;
+        for( ; it_atlas != it_atlas_end; ++it_atlas )
+        {
+            const aeMovieResource * atlas = *it_atlas;
+
+            __delete_movie_resource( _movieData, atlas );
+
+            AE_DELETE( instance, atlas );
+        }
+
+        AE_DELETEN( instance, _movieData->atlases );
+    }
+
+    if( _movieData->resources != AE_NULLPTR )
+    {
+        const aeMovieResource * const * it_resource = _movieData->resources;
+        const aeMovieResource * const * it_resource_end = _movieData->resources + _movieData->resource_count;
+        for( ; it_resource != it_resource_end; ++it_resource )
+        {
+            const aeMovieResource * resource = *it_resource;
+
+            __delete_movie_resource( _movieData, resource );
+
+            AE_DELETE( instance, resource );
+        }
+    }
+
+    if( _movieData->compositions != AE_NULLPTR )
+    {
+        const aeMovieCompositionData * it_composition = _movieData->compositions;
+        const aeMovieCompositionData * it_composition_end = _movieData->compositions + _movieData->composition_count;
+        for( ; it_composition != it_composition_end; ++it_composition )
+        {
+            const aeMovieCompositionData * composition = it_composition;
+
+            if( composition->camera != AE_NULLPTR )
+            {
+                const aeMovieCompositionCamera * camera = composition->camera;
+
+                AE_DELETE_STRING( instance, camera->name );
+
+                AE_DELETE( instance, composition->camera );
+            }
+
+            const aeMovieLayerData * it_layer = composition->layers;
+            const aeMovieLayerData * it_layer_end = composition->layers + composition->layer_count;
+            for( ; it_layer != it_layer_end; ++it_layer )
+            {
+                const aeMovieLayerData * layer = it_layer;
+
+                if( layer->cache != AE_NULLPTR )
+                {
+                    __callback_cache_uv_deleter( _movieData, layer->cache->immutable_mesh_uv_cache_userdata );
+
+                    ae_uint32_t frame_count = layer->frame_count;
+
+                    if( layer->cache->mesh_uv_cache_userdata != AE_NULLPTR )
+                    {
+                        ae_uint32_t index = 0;
+                        for( ; index != frame_count; ++index )
+                        {
+                            ae_userdata_t uv_cache_data = layer->cache->mesh_uv_cache_userdata[index];
+
+                            __callback_cache_uv_deleter( _movieData, uv_cache_data );
+                        }
+
+                        AE_DELETEN( instance, layer->cache->mesh_uv_cache_userdata );
+                    }
+
+                    AE_DELETE( instance, layer->cache );
+                }
+
+                const aeMovieLayerExtensions * extensions = layer->extensions;
+
+                if( extensions->timeremap != AE_NULLPTR )
+                {
+                    const aeMovieLayerExtensionTimeremap * timeremap = extensions->timeremap;
+
+                    AE_DELETEN( instance, timeremap->times );
+
+                    AE_DELETE( instance, extensions->timeremap );
+                }
+
+                if( extensions->mesh != AE_NULLPTR )
+                {
+                    const aeMovieLayerExtensionMesh * mesh = extensions->mesh;
+
+                    __delete_layer_mesh_t( instance, mesh, layer->frame_count );
+
+                    AE_DELETE( instance, extensions->mesh );
+                }
+
+                if( extensions->bezier_warp != AE_NULLPTR )
+                {
+                    const aeMovieLayerExtensionBezierWarp * bezier_warp = extensions->bezier_warp;
+
+                    AE_DELETEN( instance, bezier_warp->bezier_warps );
+
+                    AE_DELETE( instance, extensions->bezier_warp );
+                }
+
+                if( extensions->polygon != AE_NULLPTR )
+                {
+                    const aeMovieLayerExtensionPolygon * polygon = extensions->polygon;
+
+                    AE_DELETEN( instance, polygon->polygons );
+
+                    AE_DELETE( instance, extensions->polygon );
+                }
+
+                if( extensions->shader != AE_NULLPTR )
+                {
+                    const aeMovieLayerExtensionShader * shader = extensions->shader;
+
+                    AE_DELETE_STRING( instance, shader->name );
+                    AE_DELETE_STRING( instance, shader->description );
+
+                    const struct aeMovieLayerShaderParameter ** it_parameter = shader->parameters;
+                    const struct aeMovieLayerShaderParameter ** it_parameter_end = shader->parameters + shader->parameter_count;
+
+                    for( ;
+                        it_parameter != it_parameter_end;
+                        ++it_parameter )
+                    {
+                        const struct aeMovieLayerShaderParameter * parameter = *it_parameter;
+
+                        AE_DELETE_STRING( instance, parameter->name );
+                        AE_DELETE_STRING( instance, parameter->uniform );
+
+                        aeMovieShaderParameterTypeEnum parameter_type = parameter->type;
+
+                        switch( parameter_type )
+                        {
+                        case AE_MOVIE_EXTENSION_SHADER_PARAMETER_SLIDER:
+                            {
+                                const struct aeMovieLayerShaderParameterSlider * parameter_slider = (const struct aeMovieLayerShaderParameterSlider *)parameter;
+
+                                __delete_property_value( instance, parameter_slider->property_value );
+
+                                AE_DELETE( instance, parameter_slider->property_value );
+                            }break;
+                        case AE_MOVIE_EXTENSION_SHADER_PARAMETER_ANGLE:
+                            {
+                                const struct aeMovieLayerShaderParameterAngle * parameter_angle = (const struct aeMovieLayerShaderParameterAngle *)parameter;
+
+                                __delete_property_value( instance, parameter_angle->property_value );
+
+                                AE_DELETE( instance, parameter_angle->property_value );
+                            }break;
+                        case AE_MOVIE_EXTENSION_SHADER_PARAMETER_COLOR:
+                            {
+                                const struct aeMovieLayerShaderParameterColor * parameter_color = (const struct aeMovieLayerShaderParameterColor *)parameter;
+
+                                __delete_property_color( instance, parameter_color->property_color );
+
+                                AE_DELETE( instance, parameter_color->property_color );
+                            }break;
+                        case AE_MOVIE_EXTENSION_SHADER_PARAMETER_TIME:
+                            {
+                            }break;
+                        }
+
+                        AE_DELETE( instance, parameter );
+                    }
+
+                    AE_DELETEN( instance, shader->parameters );
+
+                    AE_DELETE( instance, extensions->shader );
+                }
+
+                if( extensions->viewport != AE_NULLPTR )
+                {
+                    const aeMovieLayerExtensionViewport * viewport = extensions->viewport;
+
+                    AE_UNUSED( viewport );
+
+                    AE_DELETE( instance, extensions->viewport );
+                }
+
+                if( extensions->volume != AE_NULLPTR )
+                {
+                    const aeMovieLayerExtensionVolume * volume = extensions->volume;
+
+                    AE_DELETE( instance, volume->property_volume );
+
+                    AE_DELETE( instance, extensions->volume );
+                }
+
+                if( extensions != &instance->layer_extensions_default )
+                {
+                    AE_DELETE( instance, layer->extensions );
+                }
+
+                ae_movie_delete_layer_transformation( instance, layer->transformation, layer->threeD );
+
+                AE_DELETE( instance, layer->transformation );
+
+                AE_DELETE_STRING( instance, layer->name );
+            }
+
+            AE_DELETEN( instance, composition->layers );
+
+            AE_DELETE_STRING( instance, composition->name );
+        }
+    }
+
+    AE_DELETEN( instance, _movieData->resources );
+    AE_DELETEN( instance, _movieData->compositions );
+
+    if( _movieData->name != AE_NULLPTR )
+    {
+        AE_DELETE_STRING( instance, _movieData->name );
+    }
+
+    AE_DELETE( instance, _movieData );
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_result_t __load_movie_data_composition_camera( aeMovieStream * _stream, aeMovieCompositionData * _compositionData )
+{
+    aeMovieCompositionCamera * camera = AE_NEW( _stream->instance, aeMovieCompositionCamera );
+
+    AE_RESULT_PANIC_MEMORY( camera );
+
+    ae_bool_t export_camera = AE_READB( _stream );
+
+    if( export_camera == AE_FALSE )
+    {
+        ae_char_t * camera_name = AE_NEWN( _stream->instance, ae_char_t, 5 );
+
+        AE_RESULT_PANIC_MEMORY( camera_name );
+
+        camera_name[0] = 'N';
+        camera_name[1] = 'o';
+        camera_name[2] = 'n';
+        camera_name[3] = 'e';
+        camera_name[4] = '\0';
+
+        camera->name = camera_name;
+
+        AE_READF( _stream, camera->zoom );
+        AE_READF( _stream, camera->fov );
+
+        ae_float_t width = _compositionData->width;
+        ae_float_t height = _compositionData->height;
+
+        camera->immutable_property_mask = AE_MOVIE_PROPERTY_TRANSFORM_SUPER_ALL_CAMERA;
+        camera->identity_property_mask = AE_MOVIE_PROPERTY_ANCHOR_POINT_Z | AE_MOVIE_PROPERTY_TRANSFORM_SUPER_ALL_QUATERNION;
+
+        camera->immutable.position_x = width * 0.5f;
+        camera->immutable.position_y = height * 0.5f;
+        camera->immutable.position_z = -camera->zoom;
+
+        camera->immutable.target_x = width * 0.5f;
+        camera->immutable.target_y = height * 0.5f;
+        camera->immutable.target_z = 0.f;
+
+        camera->immutable.quaternion_x = 0.f;
+        camera->immutable.quaternion_y = 0.f;
+        camera->immutable.quaternion_z = 0.f;
+        camera->immutable.quaternion_w = 1.f;
+
+        camera->timeline = AE_NULLPTR;
+    }
+    else
+    {
+        AE_READ_STRING( _stream, camera->name );
+
+        AE_READF( _stream, camera->zoom );
+        AE_READF( _stream, camera->fov );
+
+        AE_RESULT( ae_movie_load_camera_transformation, (_stream, camera) );
+    }
+
+    _compositionData->camera = camera;
+
+    return AE_RESULT_SUCCESSFUL;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_bool_t __find_movie_data_composition_layer_position_by_index( const aeMovieCompositionData * _compositionData, const aeMovieLayerData * _layers, ae_uint32_t _index, ae_uint32_t * _position )
+{
+    ae_uint32_t iterator = 0U;
+
+    const aeMovieLayerData * it_layer = _layers;
+    const aeMovieLayerData * it_layer_end = _layers + _compositionData->layer_count;
+    for( ; it_layer != it_layer_end; ++it_layer )
+    {
+        const aeMovieLayerData * layer = it_layer;
+
+        if( layer->index == _index )
+        {
+            *_position = iterator;
+
+            return AE_TRUE;
+        }
+
+        ++iterator;
+    }
+
+    return AE_FALSE;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_result_t __load_movie_property_value( aeMovieStream * _stream, const aeMovieLayerData * _layer, struct aeMoviePropertyValue * _property )
+{
+    _property->immutable = AE_READB( _stream );
+
+    if( _property->immutable == AE_TRUE )
+    {
+        AE_READF( _stream, _property->immutable_value );
+
+        _property->values = AE_NULLPTR;
+    }
+    else
+    {
+        _property->immutable_value = 0.f;
+
+        ae_float_t * values = AE_NEWN( _stream->instance, ae_float_t, _layer->frame_count );
+
+        AE_RESULT_PANIC_MEMORY( values );
+
+        AE_READN( _stream, values, _layer->frame_count );
+
+        _property->values = values;
+    }
+
+    return AE_RESULT_SUCCESSFUL;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_result_t __load_movie_property_color_channel( aeMovieStream * _stream, const aeMovieLayerData * _layer, struct aeMoviePropertyColorChannel * _property )
+{
+    _property->immutable = AE_READB( _stream );
+
+    if( _property->immutable == AE_TRUE )
+    {
+        AE_READ_COLOR_CHANNEL( _stream, _property->immutable_value );
+
+        _property->values = AE_NULLPTR;
+    }
+    else
+    {
+        _property->immutable_value = 1.f;
+
+        ae_color_channel_t * values = AE_NEWN( _stream->instance, ae_color_channel_t, _layer->frame_count );
+
+        AE_RESULT_PANIC_MEMORY( values );
+
+        AE_READN( _stream, values, _layer->frame_count );
+
+        _property->values = values;
+    }
+
+    return AE_RESULT_SUCCESSFUL;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_result_t __load_movie_property_color( aeMovieStream * _stream, const aeMovieLayerData * _layer, struct aeMoviePropertyColor * _property )
+{
+    const aeMovieInstance * instance = _stream->instance;
+
+    struct aeMoviePropertyColorChannel * color_channel_r = AE_NEW( instance, struct aeMoviePropertyColorChannel );
+    AE_RESULT( __load_movie_property_color_channel, (_stream, _layer, color_channel_r) );
+    _property->color_channel_r = color_channel_r;
+
+    struct aeMoviePropertyColorChannel * color_channel_g = AE_NEW( instance, struct aeMoviePropertyColorChannel );
+    AE_RESULT( __load_movie_property_color_channel, (_stream, _layer, color_channel_g) );
+    _property->color_channel_g = color_channel_g;
+
+    struct aeMoviePropertyColorChannel * color_channel_b = AE_NEW( instance, struct aeMoviePropertyColorChannel );
+    AE_RESULT( __load_movie_property_color_channel, (_stream, _layer, color_channel_b) );
+    _property->color_channel_b = color_channel_b;
+
+    return AE_RESULT_SUCCESSFUL;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL aeMovieLayerExtensions * __request_extensions( const aeMovieInstance * _instance, aeMovieLayerExtensions * _extensions )
+{
+    if( _extensions != AE_NULLPTR )
+    {
+        return _extensions;
+    }
+
+    aeMovieLayerExtensions * extensions = AE_NEW( _instance, aeMovieLayerExtensions );
+
+    if( extensions == AE_NULLPTR )
+    {
+        return AE_NULLPTR;
+    }
+
+    __clear_layer_extensions( extensions );
+
+    return extensions;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_result_t __load_movie_data_layer( const aeMovieData * _movieData, const aeMovieCompositionData * _compositions, aeMovieStream * _stream, aeMovieLayerData * _layer )
+{
+    const aeMovieInstance * instance = _movieData->instance;
+
+    AE_READ_STRING( _stream, _layer->name );
+
+    _layer->index = AE_READZ( _stream );
+
+    _layer->is_track_matte = AE_READB( _stream );
+    _layer->has_track_matte = AE_READB( _stream );
+
+    if( _layer->has_track_matte == AE_TRUE )
+    {
+        _layer->track_matte_mode = AE_READ8( _stream );
+    }
+    else
+    {
+        _layer->track_matte_mode = AE_MOVIE_TRACK_MATTE_NONE;
+    }
+
+    ae_uint8_t type;
+    AE_READ( _stream, type );
+    _layer->type = type;
+
+    _layer->frame_count = AE_READZ( _stream );
+
+    aeMovieLayerExtensions * layer_extensions = AE_NULLPTR;
+
+    for( ;; )
+    {
+        ae_uint8_t extension;
+        AE_READ( _stream, extension );
+
+        switch( extension )
+        {
+        case 0:
+            {
+            }break;
+        case AE_LAYER_EXTENSION_TIMEREMAP:
+            {
+                aeMovieLayerExtensionTimeremap * layer_timeremap = AE_NEW( instance, aeMovieLayerExtensionTimeremap );
+
+                AE_RESULT_PANIC_MEMORY( layer_timeremap );
+
+                ae_float_t * times = AE_NEWN( instance, ae_float_t, _layer->frame_count );
+
+                AE_RESULT_PANIC_MEMORY( times );
+
+                AE_READN( _stream, times, _layer->frame_count );
+
+                layer_timeremap->times = times;
+
+                for( ;; )
+                {
+                    ae_uint8_t params;
+                    AE_READ( _stream, params );
+
+                    switch( params )
+                    {
+                    case 0:
+                        {
+                        }break;
+                    default:
+                        {
+                            AE_RETURN_ERROR_RESULT( AE_RESULT_INVALID_STREAM );
+                        }break;
+                    }
+
+                    if( params == 0 )
+                    {
+                        break;
+                    }
+                }
+
+                layer_extensions = __request_extensions( instance, layer_extensions );
+
+                AE_RESULT_PANIC_MEMORY( layer_extensions );
+
+                layer_extensions->timeremap = layer_timeremap;
+            }break;
+        case AE_LAYER_EXTENSION_MESH:
+            {
+                aeMovieLayerExtensionMesh * layer_mesh = AE_NEW( instance, aeMovieLayerExtensionMesh );
+
+                AE_RESULT_PANIC_MEMORY( layer_mesh );
+
+                layer_mesh->immutable = AE_READB( _stream );
+
+                if( layer_mesh->immutable == AE_TRUE )
+                {
+                    AE_READ_MESH( _stream, &layer_mesh->immutable_mesh );
+
+                    layer_mesh->meshes = AE_NULLPTR;
+                }
+                else
+                {
+                    ae_mesh_t * meshes = AE_NEWN( instance, ae_mesh_t, _layer->frame_count );
+
+                    AE_RESULT_PANIC_MEMORY( meshes );
+
+                    ae_mesh_t * it_mesh = meshes;
+                    ae_mesh_t * it_mesh_end = meshes + _layer->frame_count;
+                    for( ; it_mesh != it_mesh_end; ++it_mesh )
+                    {
+                        AE_READ_MESH( _stream, it_mesh );
+                    }
+
+                    layer_mesh->meshes = meshes;
+                }
+
+                for( ;; )
+                {
+                    ae_uint8_t params;
+                    AE_READ( _stream, params );
+
+                    switch( params )
+                    {
+                    case 0:
+                        {
+                        }break;
+                    default:
+                        {
+                            AE_RETURN_ERROR_RESULT( AE_RESULT_INVALID_STREAM );
+                        }break;
+                    }
+
+                    if( params == 0 )
+                    {
+                        break;
+                    }
+                }
+
+                layer_extensions = __request_extensions( instance, layer_extensions );
+
+                AE_RESULT_PANIC_MEMORY( layer_extensions );
+
+                layer_extensions->mesh = layer_mesh;
+            }break;
+        case AE_LAYER_EXTENSION_BEZIERWARP:
+            {
+                aeMovieLayerExtensionBezierWarp * layer_bezier_warp = AE_NEW( instance, aeMovieLayerExtensionBezierWarp );
+
+                AE_RESULT_PANIC_MEMORY( layer_bezier_warp );
+
+                layer_bezier_warp->immutable = AE_READB( _stream );
+
+                if( layer_bezier_warp->immutable == AE_TRUE )
+                {
+                    AE_READN( _stream, layer_bezier_warp->immutable_bezier_warp.corners, 4 );
+                    AE_READN( _stream, layer_bezier_warp->immutable_bezier_warp.beziers, 8 );
+
+                    layer_bezier_warp->bezier_warps = AE_NULLPTR;
+                }
+                else
+                {
+                    aeMovieBezierWarp * bezier_warps = AE_NEWN( instance, aeMovieBezierWarp, _layer->frame_count );
+
+                    AE_RESULT_PANIC_MEMORY( bezier_warps );
+
+                    aeMovieBezierWarp * it_bezier_warp = bezier_warps;
+                    aeMovieBezierWarp * it_bezier_warp_end = bezier_warps + _layer->frame_count;
+                    for( ; it_bezier_warp != it_bezier_warp_end; ++it_bezier_warp )
+                    {
+                        AE_READN( _stream, it_bezier_warp->corners, 4 );
+                        AE_READN( _stream, it_bezier_warp->beziers, 8 );
+                    }
+
+                    layer_bezier_warp->bezier_warps = bezier_warps;
+                }
+
+                ae_uint8_t quality;
+                AE_READ( _stream, quality );
+
+                layer_bezier_warp->quality = quality;
+
+                for( ;; )
+                {
+                    ae_uint8_t params;
+                    AE_READ( _stream, params );
+
+                    switch( params )
+                    {
+                    case 0:
+                        {
+                        }break;
+                    default:
+                        {
+                            AE_RETURN_ERROR_RESULT( AE_RESULT_INVALID_STREAM );
+                        }break;
+                    }
+
+                    if( params == 0 )
+                    {
+                        break;
+                    }
+                }
+
+                layer_extensions = __request_extensions( instance, layer_extensions );
+
+                AE_RESULT_PANIC_MEMORY( layer_extensions );
+
+                layer_extensions->bezier_warp = layer_bezier_warp;
+            }break;
+        case AE_LAYER_EXTENSION_POLYGON:
+            {
+                aeMovieLayerExtensionPolygon * layer_polygon = AE_NEW( instance, aeMovieLayerExtensionPolygon );
+
+                AE_RESULT_PANIC_MEMORY( layer_polygon );
+
+                layer_polygon->immutable = AE_READB( _stream );
+
+                if( layer_polygon->immutable == AE_TRUE )
+                {
+                    AE_READ_POLYGON( _stream, &layer_polygon->immutable_polygon );
+
+                    layer_polygon->polygons = AE_NULLPTR;
+                }
+                else
+                {
+                    ae_uint32_t polygon_count = AE_READZ( _stream );
+
+                    ae_polygon_t * polygons = AE_NEWN( instance, ae_polygon_t, polygon_count );
+
+                    AE_RESULT_PANIC_MEMORY( polygons );
+
+                    ae_polygon_t * it_polygon = polygons;
+                    ae_polygon_t * it_polygon_end = polygons + polygon_count;
+                    for( ; it_polygon != it_polygon_end; ++it_polygon )
+                    {
+                        AE_READ_POLYGON( _stream, it_polygon );
+                    }
+
+                    layer_polygon->polygons = polygons;
+                }
+
+                for( ;; )
+                {
+                    ae_uint8_t params;
+                    AE_READ( _stream, params );
+
+                    switch( params )
+                    {
+                    case 0:
+                        {
+                        }break;
+                    default:
+                        {
+                            AE_RETURN_ERROR_RESULT( AE_RESULT_INVALID_STREAM );
+                        }break;
+                    }
+
+                    if( params == 0 )
+                    {
+                        break;
+                    }
+                }
+
+                layer_extensions = __request_extensions( instance, layer_extensions );
+
+                AE_RESULT_PANIC_MEMORY( layer_extensions );
+
+                layer_extensions->polygon = layer_polygon;
+            }break;
+        case AE_LAYER_EXTENSION_SHADER:
+            {
+                aeMovieLayerExtensionShader * layer_shader = AE_NEW( instance, aeMovieLayerExtensionShader );
+
+                AE_RESULT_PANIC_MEMORY( layer_shader );
+
+                AE_READ_STRING( _stream, layer_shader->name );
+                AE_READ_STRING( _stream, layer_shader->description );
+                AE_READ( _stream, layer_shader->version );
+                AE_READ( _stream, layer_shader->flags );
+
+                layer_shader->parameter_count = AE_READZ( _stream );
+
+                const struct aeMovieLayerShaderParameter ** parameters = AE_NEWN( _stream->instance, const struct aeMovieLayerShaderParameter *, layer_shader->parameter_count );
+
+                AE_RESULT_PANIC_MEMORY( parameters );
+
+                const struct aeMovieLayerShaderParameter ** it_parameter = parameters;
+                const struct aeMovieLayerShaderParameter ** it_parameter_end = parameters + layer_shader->parameter_count;
+
+                for( ;
+                    it_parameter != it_parameter_end;
+                    ++it_parameter )
+                {
+                    ae_uint8_t paramater_type;
+                    AE_READ( _stream, paramater_type );
+
+                    switch( paramater_type )
+                    {
+                    case AE_MOVIE_EXTENSION_SHADER_PARAMETER_SLIDER:
+                        {
+                            struct aeMovieLayerShaderParameterSlider * parameter_slider = AE_NEW( _stream->instance, struct aeMovieLayerShaderParameterSlider );
+
+                            AE_RESULT_PANIC_MEMORY( parameter_slider );
+
+                            parameter_slider->type = paramater_type;
+                            AE_READ_STRING( _stream, parameter_slider->name );
+                            AE_READ_STRING( _stream, parameter_slider->uniform );
+
+                            struct aeMoviePropertyValue * property_value = AE_NEW( _stream->instance, struct aeMoviePropertyValue );
+
+                            AE_RESULT_PANIC_MEMORY( property_value );
+
+                            AE_RESULT( __load_movie_property_value, (_stream, _layer, property_value) );
+
+                            parameter_slider->property_value = property_value;
+
+                            *it_parameter = (struct aeMovieLayerShaderParameter *)parameter_slider;
+                        }break;
+                    case AE_MOVIE_EXTENSION_SHADER_PARAMETER_ANGLE:
+                        {
+                            struct aeMovieLayerShaderParameterAngle * parameter_angle = AE_NEW( _stream->instance, struct aeMovieLayerShaderParameterAngle );
+
+                            AE_RESULT_PANIC_MEMORY( parameter_angle );
+
+                            parameter_angle->type = paramater_type;
+                            AE_READ_STRING( _stream, parameter_angle->name );
+                            AE_READ_STRING( _stream, parameter_angle->uniform );
+
+                            struct aeMoviePropertyValue * property_value = AE_NEW( _stream->instance, struct aeMoviePropertyValue );
+
+                            AE_RESULT_PANIC_MEMORY( property_value );
+
+                            AE_RESULT( __load_movie_property_value, (_stream, _layer, property_value) );
+
+                            parameter_angle->property_value = property_value;
+
+                            *it_parameter = (struct aeMovieLayerShaderParameter *)parameter_angle;
+                        }break;
+                    case AE_MOVIE_EXTENSION_SHADER_PARAMETER_COLOR:
+                        {
+                            struct aeMovieLayerShaderParameterColor * parameter_color = AE_NEW( _stream->instance, struct aeMovieLayerShaderParameterColor );
+
+                            AE_RESULT_PANIC_MEMORY( parameter_color );
+
+                            parameter_color->type = paramater_type;
+                            AE_READ_STRING( _stream, parameter_color->name );
+                            AE_READ_STRING( _stream, parameter_color->uniform );
+
+                            struct aeMoviePropertyColor * property_color = AE_NEW( _stream->instance, struct aeMoviePropertyColor );
+
+                            AE_RESULT_PANIC_MEMORY( property_color );
+
+                            AE_RESULT( __load_movie_property_color, (_stream, _layer, property_color) );
+
+                            parameter_color->property_color = property_color;
+
+                            *it_parameter = (struct aeMovieLayerShaderParameter *)parameter_color;
+                        }break;
+                    case AE_MOVIE_EXTENSION_SHADER_PARAMETER_TIME:
+                        {
+                            struct aeMovieLayerShaderParameterTime * parameter_time = AE_NEW( _stream->instance, struct aeMovieLayerShaderParameterTime );
+
+                            AE_RESULT_PANIC_MEMORY( parameter_time );
+
+                            parameter_time->type = paramater_type;
+                            AE_READ_STRING( _stream, parameter_time->name );
+                            AE_READ_STRING( _stream, parameter_time->uniform );
+
+                            AE_READ( _stream, parameter_time->scale );
+
+                            *it_parameter = (struct aeMovieLayerShaderParameter *)parameter_time;
+                        }break;
+                    }
+                }
+
+                layer_shader->parameters = parameters;
+
+                for( ;; )
+                {
+                    ae_uint8_t params;
+                    AE_READ( _stream, params );
+
+                    switch( params )
+                    {
+                    case 0:
+                        {
+                        }break;
+                    default:
+                        {
+                            AE_RETURN_ERROR_RESULT( AE_RESULT_INVALID_STREAM );
+                        }break;
+                    }
+
+                    if( params == 0 )
+                    {
+                        break;
+                    }
+                }
+
+                layer_extensions = __request_extensions( instance, layer_extensions );
+
+                AE_RESULT_PANIC_MEMORY( layer_extensions );
+
+                layer_extensions->shader = layer_shader;
+            }break;
+        case AE_LAYER_EXTENSION_VIEWPORT:
+            {
+                aeMovieLayerExtensionViewport * layer_viewport = AE_NEW( instance, aeMovieLayerExtensionViewport );
+
+                AE_RESULT_PANIC_MEMORY( layer_viewport );
+
+                ae_magic_read_viewport( _stream, &layer_viewport->viewport );
+
+                for( ;; )
+                {
+                    ae_uint8_t params;
+                    AE_READ( _stream, params );
+
+                    switch( params )
+                    {
+                    case 0:
+                        {
+                        }break;
+                    default:
+                        {
+                            AE_RETURN_ERROR_RESULT( AE_RESULT_INVALID_STREAM );
+                        }break;
+                    }
+
+                    if( params == 0 )
+                    {
+                        break;
+                    }
+                }
+
+                layer_extensions = __request_extensions( instance, layer_extensions );
+
+                AE_RESULT_PANIC_MEMORY( layer_extensions );
+
+                layer_extensions->viewport = layer_viewport;
+            }break;
+        case AE_LAYER_EXTENSION_VOLUME:
+            {
+                aeMovieLayerExtensionVolume * layer_volume = AE_NEW( instance, aeMovieLayerExtensionVolume );
+
+                AE_RESULT_PANIC_MEMORY( layer_volume );
+
+                struct aeMoviePropertyValue * property_volume = AE_NEW( _stream->instance, struct aeMoviePropertyValue );
+
+                AE_RESULT_PANIC_MEMORY( property_volume );
+
+                AE_RESULT( __load_movie_property_value, (_stream, _layer, property_volume) );
+
+                layer_volume->property_volume = property_volume;
+
+                for( ;; )
+                {
+                    ae_uint8_t params;
+                    AE_READ( _stream, params );
+
+                    switch( params )
+                    {
+                    case 0:
+                        {
+                        }break;
+                    default:
+                        {
+                            AE_RETURN_ERROR_RESULT( AE_RESULT_INVALID_STREAM );
+                        }break;
+                    }
+
+                    if( params == 0 )
+                    {
+                        break;
+                    }
+                }
+
+                layer_extensions = __request_extensions( instance, layer_extensions );
+
+                AE_RESULT_PANIC_MEMORY( layer_extensions );
+
+                layer_extensions->volume = layer_volume;
+            }break;
+        default:
+            {
+                AE_RETURN_ERROR_RESULT( AE_RESULT_INVALID_STREAM );
+            }break;
+        }
+
+        if( extension == 0 )
+        {
+            break;
+        }
+    }
+
+    if( layer_extensions == AE_NULLPTR )
+    {
+        _layer->extensions = &instance->layer_extensions_default;
+    }
+    else
+    {
+        _layer->extensions = layer_extensions;
+    }
+
+    ae_bool_t is_resource_or_composition = AE_READB( _stream );
+
+    if( is_resource_or_composition == AE_TRUE )
+    {
+        ae_uint32_t resource_index = AE_READZ( _stream );
+
+        if( resource_index == 0 )
+        {
+            _layer->resource = AE_NULLPTR;
+        }
+        else
+        {
+            _layer->resource = _movieData->resources[resource_index - 1];
+        }
+
+        _layer->subcomposition_data = AE_NULLPTR;
+    }
+    else
+    {
+        ae_uint32_t composition_index = AE_READZ( _stream );
+        _layer->subcomposition_data = _compositions + composition_index;
+
+        _layer->resource = AE_NULLPTR;
+    }
+
+    ae_uint32_t parent_index = AE_READZ( _stream );
+
+    _layer->parent_index = parent_index;
+
+
+    AE_READF( _stream, _layer->in_time );
+    AE_READF( _stream, _layer->out_time );
+    AE_READF( _stream, _layer->start_time );
+    AE_READF( _stream, _layer->finish_time );
+
+    _layer->reverse_time = AE_READB( _stream );
+    _layer->trimmed_time = AE_READB( _stream );
+
+    ae_uint8_t blend_mode;
+    AE_READ( _stream, blend_mode );
+    _layer->blend_mode = blend_mode;
+
+    _layer->threeD = AE_READB( _stream );
+
+    _layer->incessantly = AE_FALSE;
+
+    _layer->options_count = 0U;
+    
+    for( ;;)
+    {
+        ae_uint32_t option_value;
+        AE_READ( _stream, option_value );
+
+        if( option_value == AE_OPTION( 'l', 'o', 'o', 'p' ) )
+        {
+            _layer->incessantly = AE_TRUE;
+        }
+
+        if( option_value != 0U )
+        {
+            if( _layer->options_count == AE_MOVIE_LAYER_MAX_OPTIONS )
+            {
+                return AE_RESULT_INVALID_DATA;
+            }
+
+            _layer->options[_layer->options_count] = option_value;
+            _layer->options_count++;            
+        }
+        else
+        {
+            break;
+        }
+    }    
+
+    _layer->play_count = AE_READZ( _stream );
+
+    AE_READF( _stream, _layer->stretch );
+
+    aeMovieLayerTransformation * transformation = AE_NULLPTR;
+
+    if( _layer->threeD == AE_FALSE )
+    {
+        transformation = (aeMovieLayerTransformation *)AE_NEW( instance, aeMovieLayerTransformation2D );
+
+        AE_RESULT_PANIC_MEMORY( transformation );
+    }
+    else
+    {
+        transformation = (aeMovieLayerTransformation *)AE_NEW( instance, aeMovieLayerTransformation3D );
+
+        AE_RESULT_PANIC_MEMORY( transformation );
+    }
+
+    AE_RESULT( ae_movie_load_layer_transformation, (_stream, transformation, _layer->threeD) );
+
+    _layer->transformation = transformation;
+
+    if( _layer->is_track_matte == AE_TRUE )
+    {
+        _layer->renderable = AE_FALSE;
+    }
+    else
+    {
+        aeMovieLayerTypeEnum layer_type = _layer->type;
+
+        switch( layer_type )
+        {
+        case AE_MOVIE_LAYER_TYPE_MOVIE:
+            {
+                _layer->renderable = AE_FALSE;
+            }break;
+        case AE_MOVIE_LAYER_TYPE_SPRITE:
+            {
+                _layer->renderable = AE_TRUE;
+            }break;
+        case AE_MOVIE_LAYER_TYPE_TEXT:
+            {
+                _layer->renderable = AE_TRUE;
+            }break;
+        case AE_MOVIE_LAYER_TYPE_EVENT:
+            {
+                _layer->renderable = AE_FALSE;
+            }break;
+        case AE_MOVIE_LAYER_TYPE_SOCKET:
+            {
+                _layer->renderable = AE_TRUE;
+            }break;
+        case AE_MOVIE_LAYER_TYPE_SHAPE:
+            {
+                _layer->renderable = AE_TRUE;
+            }break;
+        case AE_MOVIE_LAYER_TYPE_SLOT:
+            {
+                _layer->renderable = AE_TRUE;
+            }break;
+        case AE_MOVIE_LAYER_TYPE_NULL:
+            {
+                _layer->renderable = AE_FALSE;
+            }break;
+        case AE_MOVIE_LAYER_TYPE_SCENE_EFFECT:
+            {
+                _layer->renderable = AE_FALSE;
+            }break;
+        case AE_MOVIE_LAYER_TYPE_SOLID:
+            {
+                _layer->renderable = AE_TRUE;
+            }break;
+        case AE_MOVIE_LAYER_TYPE_SEQUENCE:
+            {
+                _layer->renderable = AE_TRUE;
+            }break;
+        case AE_MOVIE_LAYER_TYPE_VIDEO:
+            {
+                _layer->renderable = AE_TRUE;
+            }break;
+        case AE_MOVIE_LAYER_TYPE_SOUND:
+            {
+                _layer->renderable = AE_FALSE;
+            }break;
+        case AE_MOVIE_LAYER_TYPE_PARTICLE:
+            {
+                _layer->renderable = AE_TRUE;
+            }break;
+        case AE_MOVIE_LAYER_TYPE_IMAGE:
+            {
+                _layer->renderable = AE_TRUE;
+            }break;
+        case AE_MOVIE_LAYER_TYPE_SUB_MOVIE:
+            {
+                _layer->renderable = AE_FALSE;
+            }break;
+        default:
+            {
+                AE_RETURN_ERROR_RESULT( AE_RESULT_INVALID_DATA );
+            }break;
+        }
+    }
+
+    _layer->cache = AE_NULLPTR;
+
+    return AE_RESULT_SUCCESSFUL;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_result_t __load_movie_data_composition_layers( const aeMovieData * _movieData, const aeMovieCompositionData * _compositions, aeMovieLayerData * _layers, aeMovieStream * _stream, aeMovieCompositionData * _compositionData )
+{
+    aeMovieLayerData * it_layer = _layers;
+    aeMovieLayerData * it_layer_end = _layers + _compositionData->layer_count;
+    for( ; it_layer != it_layer_end; ++it_layer )
+    {
+        aeMovieLayerData * layer = it_layer;
+
+        layer->composition_data = _compositionData;
+
+        AE_RESULT( __load_movie_data_layer, (_movieData, _compositions, _stream, layer) );
+    }
+
+    return AE_RESULT_SUCCESSFUL;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_result_t __setup_movie_data_layer_track_matte( const aeMovieCompositionData * _compositionData, const aeMovieLayerData * _layers, aeMovieLayerData * _layer )
+{
+    if( _layer->has_track_matte == AE_TRUE )
+    {
+        ae_uint32_t layer_position;
+        if( __find_movie_data_composition_layer_position_by_index( _compositionData, _layers, _layer->index, &layer_position ) == AE_FALSE )
+        {
+            AE_RETURN_ERROR_RESULT( AE_RESULT_INVALID_DATA );
+        }
+
+        if( layer_position + 1 >= _compositionData->layer_count )
+        {
+            AE_RETURN_ERROR_RESULT( AE_RESULT_INVALID_DATA );
+        }
+
+        _layer->track_matte_layer = _compositionData->layers + layer_position + 1U;
+    }
+    else
+    {
+        _layer->track_matte_layer = AE_NULLPTR;
+    }
+
+    return AE_RESULT_SUCCESSFUL;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_result_t __setup_movie_data_composition_layers( const aeMovieCompositionData * _compositionData, aeMovieLayerData * _layers )
+{
+    aeMovieLayerData * it_layer = _layers;
+    aeMovieLayerData * it_layer_end = _layers + _compositionData->layer_count;
+    for( ; it_layer != it_layer_end; ++it_layer )
+    {
+        aeMovieLayerData * layer = it_layer;
+
+        AE_RESULT( __setup_movie_data_layer_track_matte, (_compositionData, _layers, layer) );
+    }
+
+    return AE_RESULT_SUCCESSFUL;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_result_t __callback_cache_uv_provider( const aeMovieData * _movieData, ae_userdataptr_t _cu, const aeMovieResource * _resource, ae_uint32_t _count, const ae_vector2_t * _uvs )
+{
+    aeMovieDataCacheUVProviderCallbackData callbackData;
+    callbackData.resource = _resource;
+    callbackData.vertex_count = _count;
+    callbackData.uvs = _uvs;
+
+    if( (*_movieData->providers.cache_uv_provider)(&callbackData, _cu, _movieData->provider_userdata) == AE_FALSE )
+    {
+        AE_RETURN_ERROR_RESULT( AE_RESULT_INTERNAL_ERROR );
+    }
+
+    return AE_RESULT_SUCCESSFUL;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_result_t __setup_movie_data_layer_cache( const aeMovieData * _movieData, aeMovieLayerData * _layer )
+{
+    const aeMovieInstance * instance = _movieData->instance;
+
+    aeMovieResourceTypeEnum resource_type = _layer->resource->type;
+
+    switch( resource_type )
+    {
+    case AE_MOVIE_RESOURCE_IMAGE:
+        {
+            if( _layer->extensions->mesh != AE_NULLPTR )
+            {
+                struct aeMovieLayerCache * cache = AE_NEW( instance, struct aeMovieLayerCache );
+
+                cache->immutable_mesh_uv_cache_userdata = AE_NULLPTR;
+                cache->mesh_uv_cache_userdata = AE_NULLPTR;
+
+                if( _layer->extensions->mesh->immutable == AE_TRUE )
+                {
+                    const ae_mesh_t * immutable_mesh = &_layer->extensions->mesh->immutable_mesh;
+
+                    ae_userdata_t uv_cache_userdata = AE_USERDATA_NULL;
+                    AE_RESULT( __callback_cache_uv_provider, (_movieData, &uv_cache_userdata, _layer->resource, immutable_mesh->vertex_count, immutable_mesh->uvs) );
+
+                    cache->immutable_mesh_uv_cache_userdata = uv_cache_userdata;
+                }
+                else
+                {
+                    ae_uint32_t layer_frame_count = _layer->frame_count;
+
+                    ae_userdata_t * mesh_uv_cache_userdata = AE_NEWN( instance, ae_userdata_t, layer_frame_count );
+
+                    ae_uint32_t index = 0;
+                    for( ; index != layer_frame_count; ++index )
+                    {
+                        const ae_mesh_t * mesh = _layer->extensions->mesh->meshes + index;
+
+                        if( mesh->vertex_count == 0 )
+                        {
+                            mesh_uv_cache_userdata[index] = AE_NULLPTR;
+
+                            continue;
+                        }
+
+                        ae_userdata_t uv_cache_userdata = AE_USERDATA_NULL;
+                        AE_RESULT( __callback_cache_uv_provider, (_movieData, &uv_cache_userdata, _layer->resource, mesh->vertex_count, mesh->uvs) );
+
+                        mesh_uv_cache_userdata[index] = uv_cache_userdata;
+                    }
+
+                    cache->mesh_uv_cache_userdata = mesh_uv_cache_userdata;
+                }
+
+                _layer->cache = cache;
+            }
+        }break;
+    default:
+        {
+        }break;
+    }
+
+    return AE_RESULT_SUCCESSFUL;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_result_t __setup_movie_data_composition_cache( const aeMovieData * _movieData, const aeMovieCompositionData * _compositionData, aeMovieLayerData * _layers )
+{
+    aeMovieLayerData * it_layer = _layers;
+    aeMovieLayerData * it_layer_end = _layers + _compositionData->layer_count;
+    for( ; it_layer != it_layer_end; ++it_layer )
+    {
+        aeMovieLayerData * layer = it_layer;
+
+        if( layer->resource == AE_NULLPTR )
+        {
+            continue;
+        }
+
+        AE_RESULT( __setup_movie_data_layer_cache, (_movieData, layer) );
+    }
+
+    return AE_RESULT_SUCCESSFUL;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_result_t __load_movie_data_composition( const aeMovieData * _movieData, const aeMovieCompositionData * _compositions, aeMovieStream * _stream, aeMovieCompositionData * _compositionData, ae_bool_t _cache_uv_available )
+{
+    const aeMovieInstance * instance = _movieData->instance;
+
+    AE_READ_STRING( _stream, _compositionData->name );
+
+    _compositionData->master = AE_READB( _stream );
+
+    AE_READF( _stream, _compositionData->width );
+    AE_READF( _stream, _compositionData->height );
+
+    AE_READF( _stream, _compositionData->duration );
+    AE_READF( _stream, _compositionData->frameDuration );
+    AE_READF( _stream, _compositionData->frameDurationInv );
+
+    _compositionData->camera = AE_NULLPTR;
+
+    _compositionData->frameCount = (ae_uint32_t)(_compositionData->duration * _compositionData->frameDurationInv + 0.5f);
+
+    _compositionData->flags = 0;
+
+    _compositionData->loop_segment[0] = 0.f;
+    _compositionData->loop_segment[1] = _compositionData->duration;
+
+    _compositionData->anchor_point[0] = 0.f;
+    _compositionData->anchor_point[1] = 0.f;
+    _compositionData->anchor_point[2] = 0.f;
+
+    _compositionData->offset_point[0] = 0.f;
+    _compositionData->offset_point[1] = 0.f;
+    _compositionData->offset_point[2] = 0.f;
+
+    _compositionData->bounds.begin_x = 0.f;
+    _compositionData->bounds.begin_y = 0.f;
+    _compositionData->bounds.end_x = 0.f;
+    _compositionData->bounds.end_y = 0.f;
+
+    _compositionData->camera = AE_NULLPTR;
+
+    for( ;; )
+    {
+        ae_uint8_t flag;
+        AE_READ( _stream, flag );
+
+        switch( flag )
+        {
+        case 0:
+            {
+            }break;
+        case 1:
+            {
+                AE_READF2( _stream, _compositionData->loop_segment );
+
+                _compositionData->flags |= AE_MOVIE_COMPOSITION_LOOP_SEGMENT;
+            }break;
+        case 2:
+            {
+                AE_READF3( _stream, _compositionData->anchor_point );
+
+                _compositionData->flags |= AE_MOVIE_COMPOSITION_ANCHOR_POINT;
+            }break;
+        case 3:
+            {
+                AE_READF3( _stream, _compositionData->offset_point );
+
+                _compositionData->flags |= AE_MOVIE_COMPOSITION_OFFSET_POINT;
+            }break;
+        case 4:
+            {
+                AE_READF4( _stream, _compositionData->bounds );
+
+                _compositionData->flags |= AE_MOVIE_COMPOSITION_BOUNDS;
+            }break;
+        case 5:
+            {
+                AE_RESULT( __load_movie_data_composition_camera, (_stream, _compositionData) );
+
+                _compositionData->flags |= AE_MOVIE_COMPOSITION_CAMERA;
+            }break;
+        default:
+            {
+                AE_RETURN_ERROR_RESULT( AE_RESULT_INVALID_STREAM );
+            }break;
+        };
+
+        if( flag == 0 )
+        {
+            break;
+        }
+    }
+
+    ae_uint32_t layer_count = AE_READZ( _stream );
+
+    _compositionData->layer_count = layer_count;
+    aeMovieLayerData * layers = AE_NEWN( instance, aeMovieLayerData, layer_count );
+
+    AE_RESULT_PANIC_MEMORY( layers );
+
+    AE_RESULT( __load_movie_data_composition_layers, (_movieData, _compositions, layers, _stream, _compositionData) );
+
+    AE_RESULT( __setup_movie_data_composition_layers, (_compositionData, layers) );
+
+    if( _cache_uv_available == AE_TRUE )
+    {
+        AE_RESULT( __setup_movie_data_composition_cache, (_movieData, _compositionData, layers) );
+    }
+
+    _compositionData->layers = layers;
+
+    return AE_RESULT_SUCCESSFUL;
+}
+//////////////////////////////////////////////////////////////////////////
+aeMovieStream * ae_create_movie_stream( const aeMovieInstance * _instance, ae_movie_stream_memory_read_t _read, ae_movie_stream_memory_copy_t _copy, ae_userdata_t _userdata )
+{
+#ifdef AE_MOVIE_DEBUG
+    if( _instance == AE_NULLPTR )
+    {
+        return AE_NULLPTR;
+    }
+
+    if( _read == AE_NULLPTR )
+    {
+        return AE_NULLPTR;
+    }
+
+    if( _copy == AE_NULLPTR )
+    {
+        return AE_NULLPTR;
+    }
+#endif
+
+    aeMovieStream * stream = AE_NEW( _instance, aeMovieStream );
+
+    AE_MOVIE_PANIC_MEMORY( stream, AE_NULLPTR );
+
+    stream->instance = _instance;
+    stream->memory_read = _read;
+    stream->memory_copy = _copy;
+    stream->read_userdata = _userdata;
+    stream->copy_userdata = _userdata;
+
+    stream->buffer = AE_NULLPTR;
+    stream->carriage = 0U;
+
+    return stream;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_size_t __movie_read_buffer( ae_userdata_t _userdata, ae_voidptr_t _buff, ae_size_t _carriage, ae_size_t _size )
+{
+    aeMovieStream * stream = (aeMovieStream *)_userdata;
+
+    stream->memory_copy( stream->copy_userdata, (ae_constbyteptr_t)stream->buffer + _carriage, _buff, _size );
+
+    return _size;
+}
+//////////////////////////////////////////////////////////////////////////
+aeMovieStream * ae_create_movie_stream_memory( const aeMovieInstance * _instance, ae_constvoidptr_t _buffer, ae_movie_stream_memory_copy_t _copy, ae_userdata_t _userdata )
+{
+#ifdef AE_MOVIE_DEBUG
+    if( _instance == AE_NULLPTR )
+    {
+        return AE_NULLPTR;
+    }
+
+    if( _copy == AE_NULLPTR )
+    {
+        return AE_NULLPTR;
+    }
+#endif
+
+    aeMovieStream * stream = AE_NEW( _instance, aeMovieStream );
+
+    AE_MOVIE_PANIC_MEMORY( stream, AE_NULLPTR );
+
+    stream->instance = _instance;
+    stream->memory_read = &__movie_read_buffer;
+    stream->memory_copy = _copy;
+    stream->read_userdata = stream;
+    stream->copy_userdata = _userdata;
+
+    stream->buffer = _buffer;
+    stream->carriage = 0U;
+
+    return stream;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_void_t ae_delete_movie_stream( const aeMovieStream * _stream )
+{
+    AE_DELETE( _stream->instance, _stream );
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_result_t __check_movie_data( aeMovieStream * _stream, ae_uint32_t * _major, ae_uint32_t * _minor )
+{
+    ae_uint8_t magic[4] = { 0 };
+    AE_READN( _stream, magic, 4 );
+
+    if( magic[0] != 'A' ||
+        magic[1] != 'E' ||
+        magic[2] != 'M' ||
+        magic[3] != '1' )
+    {
+        AE_RETURN_ERROR_RESULT( AE_RESULT_INVALID_MAGIC );
+    }
+
+    ae_uint32_t major_version;
+    AE_READ( _stream, major_version );
+
+    *_major = major_version;
+
+    if( major_version != AE_MOVIE_SDK_MAJOR_VERSION )
+    {
+        AE_RETURN_ERROR_RESULT( AE_RESULT_INVALID_VERSION );
+    }
+
+    ae_uint32_t minor_version;
+    AE_READ( _stream, minor_version );
+
+    *_minor = minor_version;
+
+    if( minor_version != AE_MOVIE_SDK_MINOR_VERSION )
+    {
+        AE_RETURN_ERROR_RESULT( AE_RESULT_INVALID_VERSION );
+    }
+
+    ae_uint32_t hash_crc;
+    AE_READ( _stream, hash_crc );
+
+    ae_uint32_t ae_movie_hashmask_crc =
+        _stream->instance->hashmask[0] ^
+        _stream->instance->hashmask[1] ^
+        _stream->instance->hashmask[2] ^
+        _stream->instance->hashmask[3] ^
+        _stream->instance->hashmask[4];
+
+    if( hash_crc != ae_movie_hashmask_crc )
+    {
+        AE_RETURN_ERROR_RESULT( AE_RESULT_INVALID_HASH );
+    }
+
+    return AE_RESULT_SUCCESSFUL;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_result_t ae_check_movie_data( aeMovieStream * _stream, ae_uint32_t * _major, ae_uint32_t * _minor )
+{
+    ae_result_t result = __check_movie_data( _stream, _major, _minor );
+
+    return result;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_uint32_t ae_get_movie_sdk_major_version( void )
+{
+    return AE_MOVIE_SDK_MAJOR_VERSION;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_uint32_t ae_get_movie_sdk_minor_version( void )
+{
+    return AE_MOVIE_SDK_MINOR_VERSION;
+}
+//////////////////////////////////////////////////////////////////////////
+const ae_char_t * ae_get_result_string_info( ae_result_t _result )
+{
+    switch( _result )
+    {
+    case AE_RESULT_SUCCESSFUL:
+        {
+            return "successful";
+        }break;
+    case AE_RESULT_INVALID_MAGIC:
+        {
+            return "invalid magic number";
+        }break;
+    case AE_RESULT_INVALID_VERSION:
+        {
+            return "invalid version";
+        }break;
+    case AE_RESULT_INVALID_HASH:
+        {
+            return "invalid hash";
+        }break;
+    case AE_RESULT_INVALID_STREAM:
+        {
+            return "invalid stream";
+        }break;
+    case AE_RESULT_INVALID_DATA:
+        {
+            return "invalid data";
+        }break;
+    case AE_RESULT_INVALID_MEMORY:
+        {
+            return "invalid memory";
+        }break;
+    case AE_RESULT_INTERNAL_ERROR:
+        {
+            return "internal error";
+        }break;
+    }
+
+    return "invalid result";
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_bool_t __dummy_movie_data_callback_resource_provider(const aeMovieResource * _resource, ae_userdataptr_t _rd, ae_userdata_t _ud)
+{
+	AE_UNUSED(_resource);
+	AE_UNUSED(_ud);
+
+	*_rd = AE_NULLPTR;
+
+	return AE_TRUE;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __dummy_movie_data_callback_resource_deleter(aeMovieResourceTypeEnum _type, ae_voidptr_t _data, ae_userdata_t _ud)
+{
+	AE_UNUSED(_type);
+	AE_UNUSED(_data);
+	AE_UNUSED(_ud);
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_bool_t __dummy_movie_data_callback_cache_uv_available(const aeMovieDataCacheUVAvailableCallbackData * _callbackData, ae_userdata_t _ud)
+{
+	AE_UNUSED(_callbackData);
+	AE_UNUSED(_ud);
+
+	return AE_FALSE;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_bool_t __dummy_movie_data_callback_cache_uv_provider(const aeMovieDataCacheUVProviderCallbackData * _callbackData, ae_userdataptr_t _rd, ae_userdata_t _ud)
+{
+	AE_UNUSED(_callbackData);
+	AE_UNUSED(_ud);
+
+	*_rd = AE_NULLPTR;
+
+	return AE_TRUE;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __dummy_movie_data_callback_cache_uv_deleter(const aeMovieDataCacheUVDeleterCallbackData * _callbackData, ae_userdata_t _ud)
+{
+	AE_UNUSED(_callbackData);
+	AE_UNUSED(_ud);
+}
+//////////////////////////////////////////////////////////////////////////
+ae_void_t ae_clear_movie_data_providers( aeMovieDataProviders * _providers )
+{
+    _providers->resource_provider = &__dummy_movie_data_callback_resource_provider;
+    _providers->resource_deleter = &__dummy_movie_data_callback_resource_deleter;
+	_providers->cache_uv_available = &__dummy_movie_data_callback_cache_uv_available;
+    _providers->cache_uv_provider = &__dummy_movie_data_callback_cache_uv_provider;
+    _providers->cache_uv_deleter = &__dummy_movie_data_callback_cache_uv_deleter;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_result_t __load_movie_resource_solid( const aeMovieInstance * _instance, aeMovieStream * _stream, const aeMovieResource ** _atlases, const aeMovieResource ** _resources, aeMovieResource ** _out )
+{
+    AE_UNUSED( _atlases );
+    AE_UNUSED( _resources );
+
+    aeMovieResourceSolid * resource = AE_NEW( _instance, aeMovieResourceSolid );
+
+    AE_RESULT_PANIC_MEMORY( resource );
+
+    AE_READF( _stream, resource->width );
+    AE_READF( _stream, resource->height );
+    AE_READ_COLOR( _stream, &resource->color );
+
+    for( ;;)
+    {
+        ae_uint8_t param_type;
+        AE_READ( _stream, param_type );
+
+        switch( param_type )
+        {
+        case 0:
+            {
+            }break;
+        default:
+            {
+                AE_RETURN_ERROR_RESULT( AE_RESULT_INVALID_STREAM );
+            }
+        }
+
+        if( param_type == 0 )
+        {
+            break;
+        }
+    }
+
+    *_out = (aeMovieResource *)resource;
+
+    return AE_RESULT_SUCCESSFUL;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_result_t __load_movie_resource_video( const aeMovieInstance * _instance, aeMovieStream * _stream, const aeMovieResource ** _atlases, const aeMovieResource ** _resources, aeMovieResource ** _out )
+{
+    AE_UNUSED( _atlases );
+    AE_UNUSED( _resources );
+
+    aeMovieResourceVideo * resource = AE_NEW( _instance, aeMovieResourceVideo );
+
+    AE_RESULT_PANIC_MEMORY( resource );
+
+    AE_READ_STRING( _stream, resource->path );
+    resource->codec = AE_READ8( _stream );
+
+    //TODO 17.6
+    //AE_READ( _stream, resource->options );
+    resource->options = 0;
+
+    AE_READF( _stream, resource->base_width );
+    AE_READF( _stream, resource->base_height );
+
+    resource->has_alpha_channel = AE_READB( _stream );
+
+    AE_READF( _stream, resource->frameRate );
+    AE_READF( _stream, resource->duration );
+
+    resource->trim_width = resource->base_width;
+    resource->trim_height = resource->base_height;
+    resource->offset_x = 0.f;
+    resource->offset_y = 0.f;
+
+    resource->cache = AE_NULLPTR;
+
+    for( ;;)
+    {
+        ae_uint8_t param_type;
+        AE_READ( _stream, param_type );
+
+        switch( param_type )
+        {
+        case 0:
+            {
+            }break;
+        case 1:
+            {
+                AE_READF( _stream, resource->trim_width );
+                AE_READF( _stream, resource->trim_height );
+                AE_READF( _stream, resource->offset_x );
+                AE_READF( _stream, resource->offset_y );
+            }break;
+        default:
+            {
+                AE_RETURN_ERROR_RESULT( AE_RESULT_INVALID_STREAM );
+            }
+        }
+
+        if( param_type == 0 )
+        {
+            break;
+        }
+    }
+
+    *_out = (aeMovieResource *)resource;
+
+    return AE_RESULT_SUCCESSFUL;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_result_t __load_movie_resource_sound( const aeMovieInstance * _instance, aeMovieStream * _stream, const aeMovieResource ** _atlases, const aeMovieResource ** _resources, aeMovieResource ** _out )
+{
+    AE_UNUSED( _atlases );
+    AE_UNUSED( _resources );
+
+    aeMovieResourceSound * resource = AE_NEW( _instance, aeMovieResourceSound );
+
+    AE_RESULT_PANIC_MEMORY( resource );
+
+    AE_READ_STRING( _stream, resource->path );
+    resource->codec = AE_READ8( _stream );
+
+    AE_READF( _stream, resource->duration );
+
+    for( ;;)
+    {
+        ae_uint8_t param_type;
+        AE_READ( _stream, param_type );
+
+        switch( param_type )
+        {
+        case 0:
+            {
+            }break;
+        default:
+            {
+                AE_RETURN_ERROR_RESULT( AE_RESULT_INVALID_STREAM );
+            }
+        }
+
+        if( param_type == 0 )
+        {
+            break;
+        }
+    }
+
+    *_out = (aeMovieResource *)resource;
+
+    return AE_RESULT_SUCCESSFUL;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_result_t __load_movie_resource_image( const aeMovieInstance * _instance, aeMovieStream * _stream, const aeMovieResource ** _atlases, const aeMovieResource ** _resources, aeMovieResource ** _out )
+{
+    AE_UNUSED( _resources );
+
+    aeMovieResourceImage * resource = AE_NEW( _instance, aeMovieResourceImage );
+
+    AE_RESULT_PANIC_MEMORY( resource );
+
+    AE_READ_STRING( _stream, resource->path );
+    resource->codec = AE_READ8( _stream );
+
+    AE_READ( _stream, resource->options );
+    resource->atlas_image = AE_NULLPTR;
+    resource->atlas_rotate = AE_FALSE;
+
+    AE_READF( _stream, resource->base_width );
+    AE_READF( _stream, resource->base_height );
+
+    resource->trim_width = resource->base_width;
+    resource->trim_height = resource->base_height;
+    resource->offset_x = 0.f;
+    resource->offset_y = 0.f;
+    resource->uvs = _instance->sprite_uv;
+
+    ae_uint32_t quality_default_bezier_warp = 0;
+    for( ; quality_default_bezier_warp != AE_MOVIE_BEZIER_MAX_QUALITY; ++quality_default_bezier_warp )
+    {
+        const ae_vector2_t * uvs = _instance->bezier_warp_uvs[quality_default_bezier_warp];
+
+        resource->bezier_warp_uvs[quality_default_bezier_warp] = uvs;
+    }
+
+    resource->mesh = AE_NULLPTR;
+    resource->cache = AE_NULLPTR;
+
+    for( ;;)
+    {
+        ae_uint8_t param_type;
+        AE_READ( _stream, param_type );
+
+        switch( param_type )
+        {
+        case 0:
+            {
+            }break;
+        case 1:
+            {
+                AE_READF( _stream, resource->trim_width );
+                AE_READF( _stream, resource->trim_height );
+                AE_READF( _stream, resource->offset_x );
+                AE_READF( _stream, resource->offset_y );
+            }break;
+        case 2:
+            {
+                ae_vector2_t * uv = AE_NEWN( _instance, ae_vector2_t, 4 );
+
+                AE_RESULT_PANIC_MEMORY( uv );
+
+                AE_READF2( _stream, uv[0] );
+                AE_READF2( _stream, uv[1] );
+                AE_READF2( _stream, uv[2] );
+                AE_READF2( _stream, uv[3] );
+
+                resource->uvs = (const ae_vector2_t *)uv;
+
+                ae_float_t u_base = resource->uvs[0][0];
+                ae_float_t v_base = resource->uvs[0][1];
+
+                ae_float_t u_width = resource->uvs[1][0] - u_base;
+                ae_float_t v_width = resource->uvs[3][1] - v_base;
+
+                ae_uint16_t quality_bezier_warp = 0U;
+                for( ; quality_bezier_warp != AE_MOVIE_BEZIER_MAX_QUALITY; ++quality_bezier_warp )
+                {
+                    ae_uint32_t vertex_count = get_bezier_warp_vertex_count( quality_bezier_warp );
+
+                    ae_vector2_t * bezier_warp_uvs = AE_NEWN( _instance, ae_vector2_t, vertex_count );
+
+                    const ae_vector2_t * uvs = _instance->bezier_warp_uvs[quality_bezier_warp];
+
+                    ae_uint32_t index_vertex = 0U;
+                    for( ; index_vertex != vertex_count; ++index_vertex )
+                    {
+                        bezier_warp_uvs[index_vertex][0] = u_base + uvs[index_vertex][0] * u_width;
+                        bezier_warp_uvs[index_vertex][1] = v_base + uvs[index_vertex][1] * v_width;
+                    }
+
+                    resource->bezier_warp_uvs[quality_bezier_warp] = (const ae_vector2_t *)bezier_warp_uvs;
+                }
+            }break;
+        case 3:
+            {
+                ae_mesh_t * mesh = AE_NEW( _instance, ae_mesh_t );
+
+                AE_RESULT_PANIC_MEMORY( mesh );
+
+                AE_READ_MESH( _stream, mesh );
+
+                resource->mesh = mesh;
+            }break;
+        case 4:
+            {
+                ae_uint32_t atlas_id = AE_READZ( _stream );
+
+                resource->atlas_image = (const aeMovieResourceImage *)_atlases[atlas_id];
+
+                resource->atlas_rotate = AE_READB( _stream );
+            }break;
+        default:
+            {
+                AE_RETURN_ERROR_RESULT( AE_RESULT_INVALID_STREAM );
+            }
+        }
+
+        if( param_type == 0 )
+        {
+            break;
+        }
+    }
+
+    *_out = (aeMovieResource *)resource;
+
+    return AE_RESULT_SUCCESSFUL;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_result_t __load_movie_resource_sequence( const aeMovieInstance * _instance, aeMovieStream * _stream, const aeMovieResource ** _atlases, const aeMovieResource ** _resources, aeMovieResource ** _out )
+{
+    AE_UNUSED( _atlases );
+
+    aeMovieResourceSequence * resource = AE_NEW( _instance, aeMovieResourceSequence );
+
+    AE_RESULT_PANIC_MEMORY( resource );
+
+    AE_READF( _stream, resource->frameDurationInv );
+
+    ae_uint32_t image_count = AE_READZ( _stream );
+
+    resource->image_count = image_count;
+    const aeMovieResourceImage ** images = AE_NEWN( _instance, const aeMovieResourceImage *, image_count );
+
+    AE_RESULT_PANIC_MEMORY( images );
+
+    const aeMovieResourceImage ** it_image = images;
+    const aeMovieResourceImage ** it_image_end = images + image_count;
+    for( ; it_image != it_image_end; ++it_image )
+    {
+        ae_uint32_t resource_id = AE_READZ( _stream );
+
+        *it_image = (const aeMovieResourceImage *)_resources[resource_id];
+    }
+
+    resource->images = images;
+
+    for( ;;)
+    {
+        ae_uint8_t param_type;
+        AE_READ( _stream, param_type );
+
+        switch( param_type )
+        {
+        case 0:
+            {
+            }break;
+        default:
+            {
+                AE_RETURN_ERROR_RESULT( AE_RESULT_INVALID_STREAM );
+            }
+        }
+
+        if( param_type == 0 )
+        {
+            break;
+        }
+    }
+
+    *_out = (aeMovieResource *)resource;
+
+    return AE_RESULT_SUCCESSFUL;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_result_t __load_movie_resource_particle( const aeMovieInstance * _instance, aeMovieStream * _stream, const aeMovieResource ** _atlases, const aeMovieResource ** _resources, aeMovieResource ** _out )
+{
+    AE_UNUSED( _atlases );
+
+    aeMovieResourceParticle * resource = AE_NEW( _instance, aeMovieResourceParticle );
+
+    AE_RESULT_PANIC_MEMORY( resource );
+
+    AE_READ_STRING( _stream, resource->path );
+    resource->codec = AE_READ8( _stream );
+
+    ae_uint32_t image_count = AE_READZ( _stream );
+
+    resource->image_count = image_count;
+    const aeMovieResourceImage ** images = AE_NEWN( _instance, const aeMovieResourceImage *, image_count );
+
+    AE_RESULT_PANIC_MEMORY( images );
+
+    const aeMovieResourceImage ** it_image = images;
+    const aeMovieResourceImage ** it_image_end = images + image_count;
+    for( ; it_image != it_image_end; ++it_image )
+    {
+        ae_uint32_t resource_id = AE_READZ( _stream );
+
+        *it_image = (const aeMovieResourceImage *)_resources[resource_id];
+    }
+
+    resource->images = images;
+
+    for( ;;)
+    {
+        ae_uint8_t param_type;
+        AE_READ( _stream, param_type );
+
+        switch( param_type )
+        {
+        case 0:
+            {
+            }break;
+        default:
+            {
+                AE_RETURN_ERROR_RESULT( AE_RESULT_INVALID_STREAM );
+            }
+        }
+
+        if( param_type == 0 )
+        {
+            break;
+        }
+    }
+
+    *_out = (aeMovieResource *)resource;
+
+    return AE_RESULT_SUCCESSFUL;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_result_t __load_movie_resource_slot( const aeMovieInstance * _instance, aeMovieStream * _stream, const aeMovieResource ** _atlases, const aeMovieResource ** _resources, aeMovieResource ** _out )
+{
+    AE_UNUSED( _atlases );
+    AE_UNUSED( _resources );
+
+    aeMovieResourceSlot * resource = AE_NEW( _instance, aeMovieResourceSlot );
+
+    AE_RESULT_PANIC_MEMORY( resource );
+
+    AE_READF( _stream, resource->width );
+    AE_READF( _stream, resource->height );
+
+    for( ;;)
+    {
+        ae_uint8_t param_type;
+        AE_READ( _stream, param_type );
+
+        switch( param_type )
+        {
+        case 0:
+            {
+            }break;
+        default:
+            {
+                AE_RETURN_ERROR_RESULT( AE_RESULT_INVALID_STREAM );
+            }
+        }
+
+        if( param_type == 0 )
+        {
+            break;
+        }
+    }
+
+    *_out = (aeMovieResource *)resource;
+
+    return AE_RESULT_SUCCESSFUL;
+}
+//////////////////////////////////////////////////////////////////////////
+typedef ae_result_t( *ae_load_movie_resource_t )(const aeMovieInstance * _instance, aeMovieStream * _stream, const aeMovieResource ** _atlases, const aeMovieResource ** _resources, aeMovieResource ** _out);
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_result_t __load_movie_resource( aeMovieData * _movieData, aeMovieStream * _stream, const aeMovieResource ** _atlases, const aeMovieResource ** _resources, aeMovieResource ** _resource )
+{
+    const aeMovieInstance * instance = _movieData->instance;
+
+    ae_uint8_t type;
+    AE_READ( _stream, type );
+
+    ae_string_t name;
+    AE_READ_STRING( _stream, name );
+
+#ifdef AE_MOVIE_DEBUG_STREAM
+    instance->logger( instance->instance_userdata, AE_ERROR_STREAM, "read type %d", type );
+#endif
+
+    static const ae_load_movie_resource_t resource_loaders[] = { 
+        0, //0
+        0, //1
+        0, //2
+        0, //3
+        &__load_movie_resource_solid, //AE_MOVIE_RESOURCE_SOLID
+        &__load_movie_resource_video, //AE_MOVIE_RESOURCE_VIDEO
+        &__load_movie_resource_sound, //AE_MOVIE_RESOURCE_SOUND
+        &__load_movie_resource_image, //AE_MOVIE_RESOURCE_IMAGE
+        &__load_movie_resource_sequence, //AE_MOVIE_RESOURCE_SEQUENCE
+        &__load_movie_resource_particle, //AE_MOVIE_RESOURCE_PARTICLE
+        &__load_movie_resource_slot, //AE_MOVIE_RESOURCE_SLOT 
+    };
+
+#ifdef AE_MOVIE_DEBUG
+    if( type >= sizeof( resource_loaders ) / sizeof( resource_loaders[0] ) )
+    {
+        AE_RETURN_ERROR_RESULT( AE_RESULT_INVALID_STREAM );
+    }
+#endif
+
+    aeMovieResource * new_resource = AE_NULLPTR;
+    ae_load_movie_resource_t resource_loader = resource_loaders[type];
+
+#ifdef AE_MOVIE_DEBUG
+    if( resource_loader == AE_NULLPTR )
+    {
+        AE_RETURN_ERROR_RESULT( AE_RESULT_INVALID_STREAM );
+    }
+#endif
+
+    AE_RESULT( (*resource_loader), (instance, _stream, _atlases, _resources, &new_resource) );
+
+    new_resource->type = type;
+    new_resource->name = name;
+
+    ae_userdata_t resource_userdata = AE_USERDATA_NULL;
+    if( (*_movieData->providers.resource_provider)(new_resource, &resource_userdata, _movieData->provider_userdata) == AE_FALSE )
+    {
+        return AE_RESULT_INTERNAL_ERROR;
+    }
+
+    new_resource->userdata = resource_userdata;
+
+    *_resource = new_resource;
+
+    return AE_RESULT_SUCCESSFUL;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_result_t __cache_movie_resource_data( aeMovieData * _movieData, aeMovieResource * _resource )
+{
+    const aeMovieInstance * instance = _movieData->instance;
+
+    aeMovieResourceTypeEnum resource_type = _resource->type;
+
+    switch( resource_type )
+    {
+    case AE_MOVIE_RESOURCE_IMAGE:
+        {
+            aeMovieResourceImage * resource_image = (aeMovieResourceImage *)_resource;
+
+            struct aeMovieResourceImageCache * cache = AE_NEW( instance, struct aeMovieResourceImageCache );
+
+            ae_userdata_t uv_cache_userdata = AE_USERDATA_NULL;
+            AE_RESULT( __callback_cache_uv_provider, (_movieData, &uv_cache_userdata, _resource, 4, resource_image->uvs) );
+
+            cache->uv_cache_userdata = uv_cache_userdata;
+
+            if( resource_image->mesh != AE_NULLPTR )
+            {
+                ae_userdata_t mesh_uv_cache_userdata = AE_USERDATA_NULL;
+                AE_RESULT( __callback_cache_uv_provider, (_movieData, &mesh_uv_cache_userdata, _resource, resource_image->mesh->vertex_count, resource_image->mesh->uvs) );
+
+                cache->mesh_uv_cache_userdata = mesh_uv_cache_userdata;
+            }
+            else
+            {
+                cache->mesh_uv_cache_userdata = AE_NULLPTR;
+            }
+
+            ae_uint32_t quality = 0;
+            for( ; quality != AE_MOVIE_BEZIER_MAX_QUALITY; ++quality )
+            {
+                ae_uint32_t vertex_count = get_bezier_warp_vertex_count( quality );
+                const ae_vector2_t * uvs = instance->bezier_warp_uvs[quality];
+
+                ae_userdata_t bezier_warp_uv_cache_userdata = AE_USERDATA_NULL;
+                AE_RESULT( __callback_cache_uv_provider, (_movieData, &bezier_warp_uv_cache_userdata, _resource, vertex_count, uvs) );
+
+                cache->bezier_warp_uv_cache_userdata[quality] = bezier_warp_uv_cache_userdata;
+            }
+
+            resource_image->cache = cache;
+        }break;
+    case AE_MOVIE_RESOURCE_VIDEO:
+        {
+            aeMovieResourceVideo * resource_video = (aeMovieResourceVideo *)_resource;
+
+            struct aeMovieResourceVideoCache * cache = AE_NEW( instance, struct aeMovieResourceVideoCache );
+
+            ae_userdata_t uv_cache_userdata = AE_USERDATA_NULL;
+            AE_RESULT( __callback_cache_uv_provider, (_movieData, &uv_cache_userdata, _resource, 4, instance->sprite_uv) );
+
+            cache->uv_cache_userdata = uv_cache_userdata;
+
+            ae_uint32_t quality = 0;
+            for( ; quality != AE_MOVIE_BEZIER_MAX_QUALITY; ++quality )
+            {
+                ae_uint32_t vertex_count = get_bezier_warp_vertex_count( quality );
+                const ae_vector2_t * uvs = instance->bezier_warp_uvs[quality];
+
+                ae_userdata_t bezier_warp_uv_cache_userdata = AE_USERDATA_NULL;
+                AE_RESULT( __callback_cache_uv_provider, (_movieData, &bezier_warp_uv_cache_userdata, _resource, vertex_count, uvs) );
+
+                cache->bezier_warp_uv_cache_userdata[quality] = bezier_warp_uv_cache_userdata;
+            }
+
+            resource_video->cache = cache;
+        }break;
+    default:
+        {
+        }break;
+    }
+
+    return AE_RESULT_SUCCESSFUL;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_result_t ae_load_movie_data( aeMovieData * _movieData, aeMovieStream * _stream, ae_uint32_t * _major, ae_uint32_t * _minor )
+{
+    const aeMovieInstance * instance = _movieData->instance;
+
+#ifdef AE_MOVIE_DEBUG_STREAM
+    instance->logger( instance->instance_userdata, AE_ERROR_STREAM, "begin" );
+#endif
+
+    ae_result_t check_result = __check_movie_data( _stream, _major, _minor );
+
+    if( check_result != AE_RESULT_SUCCESSFUL )
+    {
+        return check_result;
+    }
+
+    AE_READ_STRING( _stream, _movieData->name );
+
+    _movieData->common_store = AE_READB( _stream );
+
+    ae_uint32_t atlas_count = AE_READZ( _stream );
+
+    _movieData->atlas_count = atlas_count;
+
+    const aeMovieResource ** atlases = AE_NULLPTR;
+
+    if( atlas_count != 0 )
+    {
+        atlases = AE_NEWN( instance, const aeMovieResource *, atlas_count );
+
+        AE_RESULT_PANIC_MEMORY( atlases );
+
+        const aeMovieResource ** it_atlas = atlases;
+        const aeMovieResource ** it_atlas_end = atlases + atlas_count;
+        for( ; it_atlas != it_atlas_end; ++it_atlas )
+        {
+            aeMovieResource * new_atlas;
+            AE_RESULT( __load_movie_resource, (_movieData, _stream, AE_NULLPTR, atlases, &new_atlas) );
+
+            *it_atlas = new_atlas;
+        }
+
+        _movieData->atlases = atlases;
+    }
+
+    ae_uint32_t resource_count = AE_READZ( _stream );
+
+    aeMovieDataCacheUVAvailableCallbackData callbackData;
+    callbackData.dummy = 0;
+
+    ae_bool_t cache_uv_available = (*_movieData->providers.cache_uv_available)(&callbackData, _movieData->provider_userdata);
+
+    _movieData->resource_count = resource_count;
+    const aeMovieResource ** resources = AE_NEWN( instance, const aeMovieResource *, resource_count );
+
+    AE_RESULT_PANIC_MEMORY( resources );
+
+    const aeMovieResource ** it_resource = resources;
+    const aeMovieResource ** it_resource_end = resources + resource_count;
+    for( ; it_resource != it_resource_end; ++it_resource )
+    {
+        aeMovieResource * new_resource;
+        AE_RESULT( __load_movie_resource, (_movieData, _stream, atlases, resources, &new_resource) );
+
+        if( cache_uv_available == AE_TRUE )
+        {
+            AE_RESULT( __cache_movie_resource_data, (_movieData, new_resource) );
+        }
+
+        *it_resource = new_resource;
+    }
+
+    _movieData->resources = resources;
+
+    ae_uint32_t composition_count = AE_READZ( _stream );
+
+    _movieData->composition_count = composition_count;
+
+    aeMovieCompositionData * compositions = AE_NEWN( instance, aeMovieCompositionData, composition_count );
+
+    AE_RESULT_PANIC_MEMORY( compositions );
+
+    aeMovieCompositionData * it_composition = compositions;
+    aeMovieCompositionData * it_composition_end = compositions + composition_count;
+    for( ; it_composition != it_composition_end; ++it_composition )
+    {
+        aeMovieCompositionData * composition = it_composition;
+
+        AE_RESULT( __load_movie_data_composition, (_movieData, compositions, _stream, composition, cache_uv_available) );
+    }
+
+    _movieData->compositions = compositions;
+
+    return AE_RESULT_SUCCESSFUL;
+}
+//////////////////////////////////////////////////////////////////////////
+const ae_char_t * ae_get_movie_name( const aeMovieData * _movieData )
+{
+    const ae_char_t * name = _movieData->name;
+
+    return name;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_bool_t ae_is_movie_common_store( const aeMovieData * _movieData )
+{
+    ae_bool_t common_store = _movieData->common_store;
+
+    return common_store;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_bool_t ae_has_movie_composition_data( const aeMovieData * _movieData, const ae_char_t * _name )
+{
+    const aeMovieInstance * instance = _movieData->instance;
+
+    const aeMovieCompositionData * it_composition = _movieData->compositions;
+    const aeMovieCompositionData * it_composition_end = _movieData->compositions + _movieData->composition_count;
+    for( ; it_composition != it_composition_end; ++it_composition )
+    {
+        const aeMovieCompositionData * composition = it_composition;
+
+        if( AE_STRNCMP( instance, composition->name, _name, AE_MOVIE_MAX_COMPOSITION_NAME ) != 0 )
+        {
+            continue;
+        }
+
+        return AE_TRUE;
+    }
+
+    return AE_FALSE;
+}
+//////////////////////////////////////////////////////////////////////////
+const aeMovieCompositionData * ae_get_movie_composition_data( const aeMovieData * _movieData, const ae_char_t * _name )
+{
+    const aeMovieInstance * instance = _movieData->instance;
+
+    const aeMovieCompositionData * it_composition = _movieData->compositions;
+    const aeMovieCompositionData * it_composition_end = _movieData->compositions + _movieData->composition_count;
+    for( ; it_composition != it_composition_end; ++it_composition )
+    {
+        const aeMovieCompositionData * composition = it_composition;
+
+        if( AE_STRNCMP( instance, composition->name, _name, AE_MOVIE_MAX_COMPOSITION_NAME ) != 0 )
+        {
+            continue;
+        }
+
+        return composition;
+    }
+
+    return AE_NULLPTR;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_bool_t ae_visit_movie_layer_data( const aeMovieData * _movieData, ae_movie_layer_data_visitor_t _visitor, ae_userdata_t _ud )
+{
+    const aeMovieCompositionData * it_composition = _movieData->compositions;
+    const aeMovieCompositionData * it_composition_end = _movieData->compositions + _movieData->composition_count;
+    for( ; it_composition != it_composition_end; ++it_composition )
+    {
+        const aeMovieCompositionData * compositionData = it_composition;
+
+        const aeMovieLayerData *it_layer = compositionData->layers;
+        const aeMovieLayerData *it_layer_end = compositionData->layers + compositionData->layer_count;
+        for( ; it_layer != it_layer_end; ++it_layer )
+        {
+            const aeMovieLayerData * layerData = it_layer;
+
+            if( (*_visitor)(compositionData, layerData, _ud) == AE_FALSE )
+            {
+                return AE_FALSE;
+            }
+        }
+    }
+
+    return AE_TRUE;
+}
+//////////////////////////////////////////////////////////////////////////
+const ae_char_t * ae_get_movie_layer_data_name( const aeMovieLayerData * _layer )
+{
+    return _layer->name;
+}
+//////////////////////////////////////////////////////////////////////////
+aeMovieLayerTypeEnum ae_get_movie_layer_data_type( const aeMovieLayerData * _layer )
+{
+    return _layer->type;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_bool_t ae_is_movie_layer_data_track_mate( const aeMovieLayerData * _layer )
+{
+    return _layer->is_track_matte;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_bool_t ae_is_movie_layer_data_threeD( const aeMovieLayerData * _layer )
+{
+    return _layer->threeD;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_bool_t ae_is_movie_layer_data_incessantly( const aeMovieLayerData * _layer )
+{
+    return _layer->incessantly;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_bool_t ae_has_movie_layer_data_option( const aeMovieLayerData * _layer, ae_uint32_t _option )
+{
+    ae_uint32_t index = 0;
+    for( ; index != _layer->options_count; ++index )
+    {
+        ae_uint32_t option_value = _layer->options[index];
+
+        if( option_value != _option )
+        {
+            continue;
+        }
+
+        return AE_TRUE;
+    }
+    
+    return AE_FALSE;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_uint32_t ae_get_movie_layer_data_option_count( const aeMovieLayerData * _layer )
+{
+    return _layer->options_count;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_uint32_t ae_get_movie_layer_data_option( const aeMovieLayerData * _layer, ae_uint32_t _index )
+{
+    return _layer->options[_index];
+}
+//////////////////////////////////////////////////////////////////////////
+const aeMovieResource * ae_get_movie_layer_data_resource( const aeMovieLayerData * _layer )
+{
+    return _layer->resource;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_voidptr_t ae_get_movie_layer_data_resource_userdata( const aeMovieLayerData * _layer )
+{
+    const aeMovieResource * resource = _layer->resource;
+
+    return resource->userdata;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_bool_t ae_test_movie_layer_data_opacity_transparent( const aeMovieLayerData * _layer )
+{
+    if( _layer->transformation->timeline_opacity != AE_NULLPTR )
+    {
+        return AE_FALSE;
+    }
+
+    if( _layer->transformation->immutable_opacity != 0.f )
+    {
+        return AE_FALSE;
+    }
+
+    return AE_TRUE;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_track_matte_mode_t ae_get_movie_layer_data_track_matte_mode( const aeMovieLayerData * _layer )
+{
+    return _layer->track_matte_mode;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_blend_mode_t ae_get_movie_layer_data_blend_mode( const aeMovieLayerData * _layer )
+{
+    return _layer->blend_mode;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_float_t ae_get_movie_layer_data_stretch( const aeMovieLayerData * _layer )
+{
+    return _layer->stretch;
+}
+//////////////////////////////////////////////////////////////////////////
+const ae_viewport_t * ae_get_movie_layer_data_viewport( const aeMovieLayerData * _layer )
+{
+    const aeMovieLayerExtensions * extensions = _layer->extensions;
+
+    if( extensions == AE_NULLPTR )
+    {
+        return AE_NULLPTR;
+    }
+
+    const aeMovieLayerExtensionViewport * viewport = extensions->viewport;
+
+    if( viewport == AE_NULLPTR )
+    {
+        return AE_NULLPTR;
+    }
+
+    return &viewport->viewport;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_bool_t ae_get_movie_layer_data_socket_polygon( const aeMovieLayerData * _layerData, ae_uint32_t _frame, const ae_polygon_t ** _polygon )
+{
+#ifdef AE_MOVIE_DEBUG
+    if( _layerData->type != AE_MOVIE_LAYER_TYPE_SOCKET )
+    {
+        return AE_FALSE;
+    }
+
+    if( _frame >= _layerData->frame_count )
+    {
+        return AE_FALSE;
+    }
+#endif
+
+    const aeMovieLayerExtensionPolygon * polygon = _layerData->extensions->polygon;
+
+    if( polygon->immutable == AE_TRUE )
+    {
+        *_polygon = &polygon->immutable_polygon;
+    }
+    else
+    {
+        *_polygon = polygon->polygons + _frame;
+    }
+
+    return AE_TRUE;
+}
+//////////////////////////////////////////////////////////////////////////
+const ae_char_t * ae_get_movie_composition_data_name( const aeMovieCompositionData * _compositionData )
+{
+    return _compositionData->name;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_float_t ae_get_movie_composition_data_width( const aeMovieCompositionData * _compositionData )
+{
+    return _compositionData->width;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_float_t ae_get_movie_composition_data_height( const aeMovieCompositionData * _compositionData )
+{
+    return _compositionData->height;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_time_t ae_get_movie_composition_data_duration( const aeMovieCompositionData * _compositionData )
+{
+    return AE_TIME_OUTSCALE( _compositionData->duration );
+}
+//////////////////////////////////////////////////////////////////////////
+ae_time_t ae_get_movie_composition_data_frame_duration( const aeMovieCompositionData * _compositionData )
+{
+    return AE_TIME_OUTSCALE( _compositionData->frameDuration );
+}
+//////////////////////////////////////////////////////////////////////////
+ae_uint32_t ae_get_movie_composition_data_frame_count( const aeMovieCompositionData * _compositionData )
+{
+    return _compositionData->frameCount;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_void_t ae_get_movie_composition_data_loop_segment( const aeMovieCompositionData * _compositionData, ae_time_t * _in, ae_time_t * _out )
+{
+    *_in = AE_TIME_OUTSCALE( _compositionData->loop_segment[0] );
+    *_out = AE_TIME_OUTSCALE( _compositionData->loop_segment[1] );
+}
+//////////////////////////////////////////////////////////////////////////
+ae_bool_t ae_is_movie_composition_data_master( const aeMovieCompositionData * _compositionData )
+{
+    return _compositionData->master;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_uint32_t ae_get_movie_composition_data_count( const aeMovieData * _movieData )
+{
+    return _movieData->composition_count;
+}
+//////////////////////////////////////////////////////////////////////////
+const aeMovieCompositionData * ae_get_movie_composition_data_by_index( const aeMovieData * _movieData, ae_uint32_t _index )
+{
+    return _movieData->compositions + _index;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_uint32_t ae_get_movie_composition_data_event_count( const aeMovieCompositionData * _compositionData )
+{
+    ae_uint32_t count = 0;
+
+    const aeMovieLayerData * it_layer = _compositionData->layers;
+    const aeMovieLayerData * it_layer_end = _compositionData->layers + _compositionData->layer_count;
+    for( ; it_layer != it_layer_end; ++it_layer )
+    {
+        aeMovieLayerTypeEnum type = it_layer->type;
+
+        if( type == AE_MOVIE_LAYER_TYPE_EVENT )
+        {
+            ++count;
+        }
+        else if( type == AE_MOVIE_LAYER_TYPE_MOVIE )
+        {
+            count += ae_get_movie_composition_data_event_count( it_layer->subcomposition_data );
+        }
+    }
+
+    return count;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_bool_t __get_composition_data_event_name( const aeMovieCompositionData * _compositionData, ae_uint32_t * _iterator, ae_uint32_t _index, const ae_char_t ** _name )
+{
+    const aeMovieLayerData * it_layer = _compositionData->layers;
+    const aeMovieLayerData * it_layer_end = _compositionData->layers + _compositionData->layer_count;
+    for( ; it_layer != it_layer_end; ++it_layer )
+    {
+        aeMovieLayerTypeEnum type = it_layer->type;
+
+        if( type == AE_MOVIE_LAYER_TYPE_EVENT )
+        {
+            if( (*_iterator)++ == _index )
+            {
+                *_name = it_layer->name;
+
+                return AE_TRUE;
+            }
+        }
+        else if( type == AE_MOVIE_LAYER_TYPE_MOVIE )
+        {
+            if( __get_composition_data_event_name( it_layer->subcomposition_data, _iterator, _index, _name ) == AE_TRUE )
+            {
+                return AE_TRUE;
+            }
+        }
+    }
+
+    return AE_FALSE;
+}
+//////////////////////////////////////////////////////////////////////////
+const ae_char_t * ae_get_movie_composition_data_event_name( const aeMovieCompositionData * _compositionData, ae_uint32_t _index )
+{
+    ae_uint32_t iterator = 0U;
+    const ae_char_t * name;
+    if( __get_composition_data_event_name( _compositionData, &iterator, _index, &name ) == AE_FALSE )
+    {
+        return AE_NULLPTR;
+    }
+
+    return name;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_bool_t ae_has_movie_composition_data_bounds( const aeMovieCompositionData * _compositionData )
+{
+    if( (_compositionData->flags & AE_MOVIE_COMPOSITION_BOUNDS) == 0 )
+    {
+        return AE_FALSE;
+    }
+
+    return AE_TRUE;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_bool_t ae_get_movie_composition_data_bounds( const aeMovieCompositionData * _compositionData, ae_viewport_t * _bounds )
+{
+    if( _compositionData->flags & AE_MOVIE_COMPOSITION_BOUNDS )
+    {
+        *_bounds = _compositionData->bounds;
+
+        return AE_TRUE;
+    }
+
+    return AE_FALSE;
+}
+//////////////////////////////////////////////////////////////////////////

+ 54 - 0
ae-movie/src/movie_debug.h

@@ -0,0 +1,54 @@
+/******************************************************************************
+* libMOVIE Software License v1.0
+*
+* Copyright (c) 2016-2018, Yuriy Levchenko <[email protected]>
+* All rights reserved.
+*
+* You are granted a perpetual, non-exclusive, non-sublicensable, and
+* non-transferable license to use, install, execute, and perform the libMOVIE
+* software and derivative works solely for personal or internal
+* use. Without the written permission of Yuriy Levchenko, you may not (a) modify, translate,
+* adapt, or develop new applications using the libMOVIE or otherwise
+* create derivative works or improvements of the libMOVIE or (b) remove,
+* delete, alter, or obscure any trademarks or any copyright, trademark, patent,
+* or other intellectual property or proprietary rights notices on or in the
+* Software, including any copy thereof. Redistributions in binary or source
+* form must include this license and terms.
+*
+* THIS SOFTWARE IS PROVIDED BY YURIY LEVCHENKO "AS IS" AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+* EVENT SHALL YURIY LEVCHENKO BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION,
+* OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF
+* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+#ifndef MOVIE_DEBUG_H_
+#define MOVIE_DEBUG_H_
+
+#include "movie/movie_type.h"
+
+AE_INTERNAL ae_void_t __movie_break_point( ae_void_t )
+{
+    //Breakpoint
+    ae_uint32_t breakpoint_this;
+    (ae_void_t)breakpoint_this;
+}
+
+#ifdef AE_MOVIE_DEBUG
+#   define AE_RETURN_ERROR_RESULT(Result) __movie_break_point(); return Result
+#else
+#   define AE_RETURN_ERROR_RESULT(Result) return Result
+#endif
+
+#ifdef AE_MOVIE_DEBUG
+#	define AE_MOVIE_PANIC_MEMORY(Memory, Result) {if(Memory == AE_NULLPTR) {__movie_break_point(); return Result;}}
+#else
+#   define AE_MOVIE_PANIC_MEMORY(Memory, Result)
+#endif
+
+#endif

+ 236 - 0
ae-movie/src/movie_instance.c

@@ -0,0 +1,236 @@
+/******************************************************************************
+* libMOVIE Software License v1.0
+*
+* Copyright (c) 2016-2018, Yuriy Levchenko <[email protected]>
+* All rights reserved.
+*
+* You are granted a perpetual, non-exclusive, non-sublicensable, and
+* non-transferable license to use, install, execute, and perform the libMOVIE
+* software and derivative works solely for personal or internal
+* use. Without the written permission of Yuriy Levchenko, you may not (a) modify, translate,
+* adapt, or develop new applications using the libMOVIE or otherwise
+* create derivative works or improvements of the libMOVIE or (b) remove,
+* delete, alter, or obscure any trademarks or any copyright, trademark, patent,
+* or other intellectual property or proprietary rights notices on or in the
+* Software, including any copy thereof. Redistributions in binary or source
+* form must include this license and terms.
+*
+* THIS SOFTWARE IS PROVIDED BY YURIY LEVCHENKO "AS IS" AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+* EVENT SHALL YURIY LEVCHENKO BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION,
+* OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF
+* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+#include "movie/movie_instance.h"
+
+#include "movie_struct.h"
+#include "movie_memory.h"
+
+//////////////////////////////////////////////////////////////////////////
+AE_CALLBACK ae_int32_t __movie_strncmp( ae_voidptr_t _data, const ae_char_t * _src, const ae_char_t * _dst, ae_size_t _count )
+{
+    AE_UNUSED( _data );
+
+    for( ; _count > 0; _src++, _dst++, --_count )
+    {
+        if( *_src != *_dst )
+        {
+            if( *(ae_uint8_t *)_src < *(ae_uint8_t *)_dst )
+            {
+                return -1;
+            }
+            else
+            {
+                return +1;
+            }
+        }
+        else if( *_src == '\0' )
+        {
+            return 0;
+        }
+    }
+
+    return 0;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_CALLBACK ae_void_t __movie_logerror( ae_voidptr_t _data, aeMovieErrorCode _code, const ae_char_t * _message, ... )
+{
+    AE_UNUSED( _data );
+    AE_UNUSED( _code );
+    AE_UNUSED( _message );
+    //SILENT
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __instance_setup_bezier_warp( aeMovieInstance * _instance )
+{
+    ae_uint32_t quality = 0;
+    for( ; quality != AE_MOVIE_BEZIER_MAX_QUALITY; ++quality )
+    {
+        ae_uint32_t line_count = get_bezier_warp_line_count( quality );
+        ae_uint32_t vertex_count = get_bezier_warp_vertex_count( quality );
+
+        ae_vector2_t * bezier_warp_uvs = AE_NEWN( _instance, ae_vector2_t, vertex_count );
+
+        ae_vector2_t * bezier_warp_uvs_iterator = bezier_warp_uvs;
+
+        ae_float_t grid_invf = 1.f / (ae_float_t)(line_count - 1);
+
+        ae_uint32_t v = 0;
+        for( ; v != line_count; ++v )
+        {
+            ae_uint32_t u = 0;
+            for( ; u != line_count; ++u )
+            {
+                ae_vector2_t * uv = bezier_warp_uvs_iterator++;
+                (*uv)[0] = (ae_float_t)u * grid_invf;
+                (*uv)[1] = (ae_float_t)v * grid_invf;
+            }
+        }
+
+        _instance->bezier_warp_uvs[quality] = (const ae_vector2_t *)bezier_warp_uvs;
+
+        ae_uint32_t index_count = (line_count - 1) * (line_count - 1) * 6;
+        ae_uint16_t * bezier_warp_indices = AE_NEWN( _instance, ae_uint16_t, index_count );
+
+        ae_uint16_t * bezier_warp_indices_iterator = bezier_warp_indices;
+
+        ae_uint16_t uv_count = (ae_uint16_t)line_count;
+        ae_uint16_t uv_count_one = uv_count - 1;
+
+        ae_uint16_t v2 = 0;
+        for( ; v2 != uv_count_one; ++v2 )
+        {
+            ae_uint16_t u2 = 0;
+            for( ; u2 != uv_count_one; ++u2 )
+            {
+                *bezier_warp_indices_iterator++ = u2 + (v2 + 0U) * uv_count + 0U;
+                *bezier_warp_indices_iterator++ = u2 + (v2 + 1U) * uv_count + 0U;
+                *bezier_warp_indices_iterator++ = u2 + (v2 + 0U) * uv_count + 1U;
+                *bezier_warp_indices_iterator++ = u2 + (v2 + 0U) * uv_count + 1U;
+                *bezier_warp_indices_iterator++ = u2 + (v2 + 1U) * uv_count + 0U;
+                *bezier_warp_indices_iterator++ = u2 + (v2 + 1U) * uv_count + 1U;
+            }
+        }
+
+        _instance->bezier_warp_indices[quality] = (const ae_uint16_t *)bezier_warp_indices;
+    }
+}
+//////////////////////////////////////////////////////////////////////////
+const aeMovieInstance * ae_create_movie_instance( const ae_char_t * _hashkey, ae_movie_alloc_t _alloc, ae_movie_alloc_n_t _alloc_n, ae_movie_free_t _free, ae_movie_free_n_t _free_n, ae_movie_strncmp_t _strncmp, ae_movie_logger_t _logger, ae_userdata_t _userdata )
+{
+    if( _hashkey == AE_NULLPTR || _alloc == AE_NULLPTR || _alloc_n == AE_NULLPTR || _free == AE_NULLPTR || _free_n == AE_NULLPTR )
+    {
+        return AE_NULLPTR;
+    }
+
+#ifdef AE_MOVIE_MEMORY_DEBUG
+    aeMovieInstance * instance = (*_alloc)(_userdata, sizeof( aeMovieInstance ), __FILE__, __LINE__);
+#else
+    aeMovieInstance * instance = (*_alloc)(_userdata, sizeof( aeMovieInstance ));
+#endif
+
+    instance->hashmask[0] = 0;
+    instance->hashmask[1] = 0;
+    instance->hashmask[2] = 0;
+    instance->hashmask[3] = 0;
+    instance->hashmask[4] = 0;
+
+    ae_uint32_t i = 0;
+    for( ; i != 41; ++i )
+    {
+        if( _hashkey[i] == '\0' && i != 40 )
+        {
+            return AE_NULLPTR;
+        }
+
+        if( _hashkey[i] != '\0' && i == 40 )
+        {
+            return AE_NULLPTR;
+        }
+
+        if( _hashkey[i] == '\0' && i == 40 )
+        {
+            break;
+        }
+
+        ae_uint32_t j = i / 8;
+        ae_uint32_t k = i % 8;
+
+        ae_char_t hash_char = _hashkey[i];
+
+        ae_uint32_t v = (hash_char > '9') ? hash_char - 'a' + 10 : (hash_char - '0');
+
+        instance->hashmask[j] += v << (k * 4);
+    }
+
+    instance->memory_alloc = _alloc;
+    instance->memory_alloc_n = _alloc_n;
+    instance->memory_free = _free;
+    instance->memory_free_n = _free_n;
+    instance->strncmp = _strncmp;
+    instance->logger = _logger;
+    instance->instance_userdata = _userdata;
+
+    if( instance->strncmp == AE_NULLPTR )
+    {
+        instance->strncmp = &__movie_strncmp;
+    }
+
+    if( instance->logger == AE_NULLPTR )
+    {
+        instance->logger = &__movie_logerror;
+    }
+
+    ae_float_t * sprite_uv = &instance->sprite_uv[0][0];
+
+    *sprite_uv++ = 0.f;
+    *sprite_uv++ = 0.f;
+    *sprite_uv++ = 1.f;
+    *sprite_uv++ = 0.f;
+    *sprite_uv++ = 1.f;
+    *sprite_uv++ = 1.f;
+    *sprite_uv++ = 0.f;
+    *sprite_uv++ = 1.f;
+
+    ae_uint16_t * sprite_indices = instance->sprite_indices;
+
+    *sprite_indices++ = 0;
+    *sprite_indices++ = 3;
+    *sprite_indices++ = 1;
+    *sprite_indices++ = 1;
+    *sprite_indices++ = 3;
+    *sprite_indices++ = 2;
+
+    __instance_setup_bezier_warp( instance );
+
+    __clear_layer_extensions( &instance->layer_extensions_default );
+
+    return instance;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_void_t ae_delete_movie_instance( const aeMovieInstance * _instance )
+{
+    if( _instance == AE_NULLPTR )
+    {
+        return;
+    }
+
+    ae_uint32_t i;
+    for( i = 0; i != AE_MOVIE_BEZIER_MAX_QUALITY; ++i )
+    {
+        const ae_vector2_t * bezier_warp_uv = _instance->bezier_warp_uvs[i];
+        (*_instance->memory_free_n)(_instance->instance_userdata, bezier_warp_uv);
+
+        const ae_uint16_t * bezier_warp_indices = _instance->bezier_warp_indices[i];
+        (*_instance->memory_free_n)(_instance->instance_userdata, bezier_warp_indices);
+    }
+
+    (*_instance->memory_free)(_instance->instance_userdata, _instance);
+}
+//////////////////////////////////////////////////////////////////////////

+ 483 - 0
ae-movie/src/movie_math.c

@@ -0,0 +1,483 @@
+/******************************************************************************
+* libMOVIE Software License v1.0
+*
+* Copyright (c) 2016-2018, Yuriy Levchenko <[email protected]>
+* All rights reserved.
+*
+* You are granted a perpetual, non-exclusive, non-sublicensable, and
+* non-transferable license to use, install, execute, and perform the libMOVIE
+* software and derivative works solely for personal or internal
+* use. Without the written permission of Yuriy Levchenko, you may not (a) modify, translate,
+* adapt, or develop new applications using the libMOVIE or otherwise
+* create derivative works or improvements of the libMOVIE or (b) remove,
+* delete, alter, or obscure any trademarks or any copyright, trademark, patent,
+* or other intellectual property or proprietary rights notices on or in the
+* Software, including any copy thereof. Redistributions in binary or source
+* form must include this license and terms.
+*
+* THIS SOFTWARE IS PROVIDED BY YURIY LEVCHENKO "AS IS" AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+* EVENT SHALL YURIY LEVCHENKO BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION,
+* OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF
+* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+#include "movie_math.h"
+
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __mul_v3_m34_r( ae_vector3_t _out, const ae_vector3_t _a, const ae_matrix34_t _b )
+{
+    _out[0] = _a[0] * _b[0 * 3 + 0] + _a[1] * _b[1 * 3 + 0] + _a[2] * _b[2 * 3 + 0];
+    _out[1] = _a[0] * _b[0 * 3 + 1] + _a[1] * _b[1 * 3 + 1] + _a[2] * _b[2 * 3 + 1];
+    _out[2] = _a[0] * _b[0 * 3 + 2] + _a[1] * _b[1 * 3 + 2] + _a[2] * _b[2 * 3 + 2];
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __mul_v3_m34_rr( ae_vector3_t _out, const ae_vector3_t _a, const ae_matrix34_t _b )
+{
+    _out[0] = _a[0] * _b[0 * 3 + 0] + _a[1] * _b[1 * 3 + 0] + _a[2] * _b[2 * 3 + 0] + _b[3 * 3 + 0];
+    _out[1] = _a[0] * _b[0 * 3 + 1] + _a[1] * _b[1 * 3 + 1] + _a[2] * _b[2 * 3 + 1] + _b[3 * 3 + 1];
+    _out[2] = _a[0] * _b[0 * 3 + 2] + _a[1] * _b[1 * 3 + 2] + _a[2] * _b[2 * 3 + 2] + _b[3 * 3 + 2];
+}
+//////////////////////////////////////////////////////////////////////////
+ae_void_t ae_mul_v3_xy_m34( ae_vector3_t _out, ae_float_t _x, ae_float_t _y, const ae_matrix34_t _b )
+{
+    _out[0] = _x * _b[0 * 3 + 0] + _y * _b[1 * 3 + 0] + _b[3 * 3 + 0];
+    _out[1] = _x * _b[0 * 3 + 1] + _y * _b[1 * 3 + 1] + _b[3 * 3 + 1];
+    _out[2] = _x * _b[0 * 3 + 2] + _y * _b[1 * 3 + 2] + _b[3 * 3 + 2];
+}
+//////////////////////////////////////////////////////////////////////////
+ae_void_t ae_mul_v3_v2_m34( ae_vector3_t _out, const ae_vector2_t _a, const ae_matrix34_t _b )
+{
+    _out[0] = _a[0] * _b[0 * 3 + 0] + _a[1] * _b[1 * 3 + 0] + _b[3 * 3 + 0];
+    _out[1] = _a[0] * _b[0 * 3 + 1] + _a[1] * _b[1 * 3 + 1] + _b[3 * 3 + 1];
+    _out[2] = _a[0] * _b[0 * 3 + 2] + _a[1] * _b[1 * 3 + 2] + _b[3 * 3 + 2];
+}
+//////////////////////////////////////////////////////////////////////////
+ae_void_t ae_mul_m34_m34_r( ae_matrix34_t _out, const ae_matrix34_t _a, const ae_matrix34_t _b )
+{
+    __mul_v3_m34_r( _out + 0, _a + 0, _b );
+    __mul_v3_m34_r( _out + 3, _a + 3, _b );
+    __mul_v3_m34_r( _out + 6, _a + 6, _b );
+    __mul_v3_m34_rr( _out + 9, _a + 9, _b );
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __mul_v3_m34( ae_vector3_t _out, const ae_vector3_t _a, const ae_matrix34_t _b )
+{
+    _out[0] = _a[0] * _b[0 * 3 + 0] + _a[1] * _b[1 * 3 + 0] + _a[2] * _b[2 * 3 + 0] + _b[3 * 3 + 0];
+    _out[1] = _a[0] * _b[0 * 3 + 1] + _a[1] * _b[1 * 3 + 1] + _a[2] * _b[2 * 3 + 1] + _b[3 * 3 + 1];
+    _out[2] = _a[0] * _b[0 * 3 + 2] + _a[1] * _b[1 * 3 + 2] + _a[2] * _b[2 * 3 + 2] + _b[3 * 3 + 2];
+}
+//////////////////////////////////////////////////////////////////////////
+ae_void_t ae_mul_m34_m34( ae_matrix34_t _out, const ae_matrix34_t _a, const ae_matrix34_t _b )
+{
+    __mul_v3_m34( _out + 0, _a + 0, _b );
+    __mul_v3_m34( _out + 3, _a + 3, _b );
+    __mul_v3_m34( _out + 6, _a + 6, _b );
+    __mul_v3_m34( _out + 9, _a + 9, _b );
+}
+//////////////////////////////////////////////////////////////////////////
+ae_void_t ae_ident_m34( ae_matrix34_t _out )
+{
+    _out[0 * 3 + 0] = 1.f;
+    _out[0 * 3 + 1] = 0.f;
+    _out[0 * 3 + 2] = 0.f;
+
+    _out[1 * 3 + 0] = 0.f;
+    _out[1 * 3 + 1] = 1.f;
+    _out[1 * 3 + 2] = 0.f;
+
+    _out[2 * 3 + 0] = 0.f;
+    _out[2 * 3 + 1] = 0.f;
+    _out[2 * 3 + 2] = 1.f;
+
+    _out[3 * 3 + 0] = 0.f;
+    _out[3 * 3 + 1] = 0.f;
+    _out[3 * 3 + 2] = 0.f;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_void_t ae_copy_m34( ae_matrix34_t _out, const ae_matrix34_t _in )
+{
+    *_out++ = *_in++;
+    *_out++ = *_in++;
+    *_out++ = *_in++;
+
+    *_out++ = *_in++;
+    *_out++ = *_in++;
+    *_out++ = *_in++;
+
+    *_out++ = *_in++;
+    *_out++ = *_in++;
+    *_out++ = *_in++;
+
+    *_out++ = *_in++;
+    *_out++ = *_in++;
+    *_out++ = *_in++;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __make_quaternion_m34( ae_matrix34_t _m, const ae_quaternion_t _quaternion )
+{
+    ae_float_t x = _quaternion[0];
+    ae_float_t y = _quaternion[1];
+    ae_float_t z = _quaternion[2];
+    ae_float_t w = _quaternion[3];
+
+    ae_float_t x2 = x + x;
+    ae_float_t y2 = y + y;
+    ae_float_t z2 = z + z;
+    ae_float_t xx = x * x2;
+    ae_float_t xy = x * y2;
+    ae_float_t xz = x * z2;
+    ae_float_t yy = y * y2;
+    ae_float_t yz = y * z2;
+    ae_float_t zz = z * z2;
+    ae_float_t wx = w * x2;
+    ae_float_t wy = w * y2;
+    ae_float_t wz = w * z2;
+
+    _m[0 * 3 + 0] = 1.f - (yy + zz);
+    _m[0 * 3 + 1] = xy - wz;
+    _m[0 * 3 + 2] = xz + wy;
+
+    _m[1 * 3 + 0] = xy + wz;
+    _m[1 * 3 + 1] = 1.f - (xx + zz);
+    _m[1 * 3 + 2] = yz - wx;
+
+    _m[2 * 3 + 0] = xz - wy;
+    _m[2 * 3 + 1] = yz + wx;
+    _m[2 * 3 + 2] = 1.f - (xx + yy);
+
+    _m[3 * 3 + 0] = 0.f;
+    _m[3 * 3 + 1] = 0.f;
+    _m[3 * 3 + 2] = 0.f;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __make_quaternionzw_m34( ae_matrix34_t _m, const ae_quaternionzw_t _quaternion )
+{
+    ae_float_t z = _quaternion[0];
+    ae_float_t w = _quaternion[1];
+
+    ae_float_t z2 = z + z;
+    ae_float_t zz = z * z2;
+    ae_float_t wz = w * z2;
+
+    _m[0 * 3 + 0] = 1.f - zz;
+    _m[0 * 3 + 1] = -wz;
+    _m[0 * 3 + 2] = 0.f;
+
+    _m[1 * 3 + 0] = +wz;
+    _m[1 * 3 + 1] = 1.f - zz;
+    _m[1 * 3 + 2] = 0.f;
+
+    _m[2 * 3 + 0] = 0.f;
+    _m[2 * 3 + 1] = 0.f;
+    _m[2 * 3 + 2] = 1.f;
+
+    _m[3 * 3 + 0] = 0.f;
+    _m[3 * 3 + 1] = 0.f;
+    _m[3 * 3 + 2] = 0.f;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __make_transformation2d_anchor_scale_m34( ae_matrix34_t _m, const ae_vector2_t _anchor, const ae_vector2_t _scale )
+{
+    _m[0 * 3 + 0] = _scale[0];
+    _m[0 * 3 + 1] = 0.f;
+    _m[0 * 3 + 2] = 0.f;
+
+    _m[1 * 3 + 0] = 0.f;
+    _m[1 * 3 + 1] = _scale[1];
+    _m[1 * 3 + 2] = 0.f;
+
+    _m[2 * 3 + 0] = 0.f;
+    _m[2 * 3 + 1] = 0.f;
+    _m[2 * 3 + 2] = 1.f;
+
+    _m[3 * 3 + 0] = -_anchor[0] * _scale[0];
+    _m[3 * 3 + 1] = -_anchor[1] * _scale[1];
+    _m[3 * 3 + 2] = 0.f;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __make_transformation3d_anchor_scale_m34( ae_matrix34_t _m, const ae_vector3_t _anchor, const ae_vector3_t _scale )
+{
+    _m[0 * 3 + 0] = _scale[0];
+    _m[0 * 3 + 1] = 0.f;
+    _m[0 * 3 + 2] = 0.f;
+
+    _m[1 * 3 + 0] = 0.f;
+    _m[1 * 3 + 1] = _scale[1];
+    _m[1 * 3 + 2] = 0.f;
+
+    _m[2 * 3 + 0] = 0.f;
+    _m[2 * 3 + 1] = 0.f;
+    _m[2 * 3 + 2] = _scale[2];
+
+    _m[3 * 3 + 0] = -_anchor[0] * _scale[0];
+    _m[3 * 3 + 1] = -_anchor[1] * _scale[1];
+    _m[3 * 3 + 2] = -_anchor[2] * _scale[2];
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __make_transformation_skew_m34( ae_matrix34_t _m, const ae_float_t _skew )
+{
+    _m[0 * 3 + 0] = 1.f;
+    _m[0 * 3 + 1] = _skew;
+    _m[0 * 3 + 2] = 0.f;
+
+    _m[1 * 3 + 0] = 0.f;
+    _m[1 * 3 + 1] = 1.f;
+    _m[1 * 3 + 2] = 0.f;
+
+    _m[2 * 3 + 0] = 0.f;
+    _m[2 * 3 + 1] = 0.f;
+    _m[2 * 3 + 2] = 1.f;
+
+    _m[3 * 3 + 0] = 0.f;
+    _m[3 * 3 + 1] = 0.f;
+    _m[3 * 3 + 2] = 0.f;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __apply_transformation_skew_m34( ae_matrix34_t _out, const ae_matrix34_t _in, const ae_skew_t _skew )
+{
+    ae_quaternionzw_t qzw_skew_rotate_inv;
+    qzw_skew_rotate_inv[0] = -_skew[1];
+    qzw_skew_rotate_inv[1] = _skew[2];
+
+    ae_matrix34_t m4_skew_rotate_inv;
+    __make_quaternionzw_m34( m4_skew_rotate_inv, qzw_skew_rotate_inv );
+
+    ae_matrix34_t m4_skew;
+    __make_transformation_skew_m34( m4_skew, _skew[0] );
+
+    ae_quaternionzw_t qzw_skew_rotate;
+    qzw_skew_rotate[0] = _skew[1];
+    qzw_skew_rotate[1] = _skew[2];
+
+    ae_matrix34_t m4_skew_rotate;
+    __make_quaternionzw_m34( m4_skew_rotate, qzw_skew_rotate );
+
+    ae_matrix34_t m4_skew_1;
+    ae_mul_m34_m34_r( m4_skew_1, _in, m4_skew_rotate_inv );
+
+    ae_matrix34_t m4_skew_2;
+    ae_mul_m34_m34_r( m4_skew_2, m4_skew_1, m4_skew );
+
+    ae_mul_m34_m34_r( _out, m4_skew_2, m4_skew_rotate );
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __apply_transformation3d_rotate_m34( ae_matrix34_t _out, const ae_matrix34_t _in, const ae_quaternion_t _quaternion )
+{
+    ae_matrix34_t m4_rotate;
+    __make_quaternion_m34( m4_rotate, _quaternion );
+
+    ae_mul_m34_m34_r( _out, _in, m4_rotate );
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __apply_transformation2d_rotate_m34( ae_matrix34_t _out, const ae_matrix34_t _in, const ae_quaternionzw_t _quaternion )
+{
+    ae_matrix34_t m4_rotate;
+    __make_quaternionzw_m34( m4_rotate, _quaternion );
+
+    ae_mul_m34_m34_r( _out, _in, m4_rotate );
+}
+//////////////////////////////////////////////////////////////////////////
+ae_void_t ae_movie_make_transformation3d_m34( ae_matrix34_t _out, const ae_vector3_t _position, const ae_vector3_t _anchor, const ae_vector3_t _scale, const ae_quaternion_t _quaternion, const ae_skew_t _skew )
+{
+    ae_matrix34_t m4_anchor_scale;
+    __make_transformation3d_anchor_scale_m34( m4_anchor_scale, _anchor, _scale );
+
+    ae_matrix34_t m4_anchor_scale_rotate;
+    __apply_transformation3d_rotate_m34( m4_anchor_scale_rotate, m4_anchor_scale, _quaternion );
+
+    __apply_transformation_skew_m34( _out, m4_anchor_scale_rotate, _skew );
+
+    _out[3 * 3 + 0] += _position[0];
+    _out[3 * 3 + 1] += _position[1];
+    _out[3 * 3 + 2] += _position[2];
+}
+//////////////////////////////////////////////////////////////////////////
+ae_void_t ae_movie_make_transformation3d_m34wq( ae_matrix34_t _out, const ae_vector3_t _position, const ae_vector3_t _anchor, const ae_vector3_t _scale, const ae_skew_t _skew )
+{
+    ae_matrix34_t m4_anchor_scale;
+    __make_transformation3d_anchor_scale_m34( m4_anchor_scale, _anchor, _scale );
+
+    __apply_transformation_skew_m34( _out, m4_anchor_scale, _skew );
+
+    _out[3 * 3 + 0] += _position[0];
+    _out[3 * 3 + 1] += _position[1];
+    _out[3 * 3 + 2] += _position[2];
+}
+//////////////////////////////////////////////////////////////////////////
+ae_void_t ae_movie_make_transformation3d_m34wsk( ae_matrix34_t _out, const ae_vector3_t _position, const ae_vector3_t _anchor, const ae_vector3_t _scale, const ae_quaternion_t _quaternion )
+{
+    ae_matrix34_t m4_anchor_scale;
+    __make_transformation3d_anchor_scale_m34( m4_anchor_scale, _anchor, _scale );
+
+    __apply_transformation3d_rotate_m34( _out, m4_anchor_scale, _quaternion );
+
+    _out[3 * 3 + 0] += _position[0];
+    _out[3 * 3 + 1] += _position[1];
+    _out[3 * 3 + 2] += _position[2];
+}
+//////////////////////////////////////////////////////////////////////////
+ae_void_t ae_movie_make_transformation3d_m34wskq( ae_matrix34_t _out, const ae_vector3_t _position, const ae_vector3_t _anchor, const ae_vector3_t _scale )
+{
+    __make_transformation3d_anchor_scale_m34( _out, _anchor, _scale );
+
+    _out[3 * 3 + 0] += _position[0];
+    _out[3 * 3 + 1] += _position[1];
+    _out[3 * 3 + 2] += _position[2];
+}
+//////////////////////////////////////////////////////////////////////////
+ae_void_t ae_movie_make_transformation2d_m34wq( ae_matrix34_t _out, const ae_vector2_t _position, const ae_vector2_t _anchor, const ae_vector2_t _scale, const ae_skew_t _skew )
+{
+    ae_matrix34_t m4_anchor_scale;
+    __make_transformation2d_anchor_scale_m34( m4_anchor_scale, _anchor, _scale );
+
+    __apply_transformation_skew_m34( _out, m4_anchor_scale, _skew );
+
+    _out[3 * 3 + 0] += _position[0];
+    _out[3 * 3 + 1] += _position[1];
+}
+//////////////////////////////////////////////////////////////////////////
+ae_void_t ae_movie_make_transformation2d_m34wsk( ae_matrix34_t _out, const ae_vector2_t _position, const ae_vector2_t _anchor, const ae_vector2_t _scale, const ae_quaternionzw_t _quaternion )
+{
+    ae_matrix34_t m4_anchor_scale;
+    __make_transformation2d_anchor_scale_m34( m4_anchor_scale, _anchor, _scale );
+
+    __apply_transformation2d_rotate_m34( _out, m4_anchor_scale, _quaternion );
+
+    _out[3 * 3 + 0] += _position[0];
+    _out[3 * 3 + 1] += _position[1];
+}
+//////////////////////////////////////////////////////////////////////////
+ae_void_t ae_movie_make_transformation2d_m34wskq( ae_matrix34_t _out, const ae_vector2_t _position, const ae_vector2_t _anchor, const ae_vector2_t _scale )
+{
+    __make_transformation2d_anchor_scale_m34( _out, _anchor, _scale );
+
+    _out[3 * 3 + 0] += _position[0];
+    _out[3 * 3 + 1] += _position[1];
+}
+//////////////////////////////////////////////////////////////////////////
+ae_void_t ae_movie_make_transformation2d_m34( ae_matrix34_t _out, const ae_vector2_t _position, const ae_vector2_t _anchor, const ae_vector2_t _scale, const ae_quaternionzw_t _quaternion, const ae_skew_t _skew )
+{
+    ae_matrix34_t m4_anchor_scale;
+    __make_transformation2d_anchor_scale_m34( m4_anchor_scale, _anchor, _scale );
+
+    ae_matrix34_t m4_anchor_scale_rotate;
+    __apply_transformation2d_rotate_m34( m4_anchor_scale_rotate, m4_anchor_scale, _quaternion );
+
+    __apply_transformation_skew_m34( _out, m4_anchor_scale_rotate, _skew );
+
+    _out[3 * 3 + 0] += _position[0];
+    _out[3 * 3 + 1] += _position[1];
+}
+//////////////////////////////////////////////////////////////////////////
+#ifdef LIBMOVIE_EXTERNAL_INVERSE_SQRTF
+extern ae_float_t libmovie_external_inverse_sqrtf( ae_float_t );
+
+#define __inverse_sqrtf libmovie_external_inverse_sqrtf
+#else
+//////////////////////////////////////////////////////////////////////////
+union __inverse_sqrtf_alias_cast_t
+{
+    ae_float_t raw;
+    ae_uint32_t data;
+};
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_float_t __inverse_sqrtf( ae_float_t _number )
+{
+    ae_float_t x2 = _number * 0.5f;
+
+    union __inverse_sqrtf_alias_cast_t i_cast;
+    i_cast.raw = _number;
+    ae_uint32_t i = i_cast.data;
+
+    i = 0x5F3759DF - (i >> 1);
+
+    union __inverse_sqrtf_alias_cast_t f_cast;
+    f_cast.data = i;
+
+    ae_float_t y = f_cast.raw;
+
+    y = y * (1.5f - (x2 * y * y));
+    y = y * (1.5f - (x2 * y * y));
+
+    return y;
+}
+#endif
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_float_t __dot_q( const ae_quaternion_t _q1, const ae_quaternion_t _q2 )
+{
+    return _q1[0] * _q2[0] + _q1[1] * _q2[1] + _q1[2] * _q2[2] + _q1[3] * _q2[3];
+}
+//////////////////////////////////////////////////////////////////////////
+ae_void_t ae_linerp_q( ae_quaternion_t _q, const ae_quaternion_t _q1, const ae_quaternion_t _q2, ae_float_t _t )
+{
+    ae_float_t inv_t = 1.f - _t;
+
+    ae_float_t dot = __dot_q( _q1, _q2 );
+
+    ae_float_t x;
+    ae_float_t y;
+    ae_float_t z;
+    ae_float_t w;
+
+    if( dot < 0.f )
+    {
+        x = _q1[0] * inv_t - _q2[0] * _t;
+        y = _q1[1] * inv_t - _q2[1] * _t;
+        z = _q1[2] * inv_t - _q2[2] * _t;
+        w = _q1[3] * inv_t - _q2[3] * _t;
+    }
+    else
+    {
+        x = _q1[0] * inv_t + _q2[0] * _t;
+        y = _q1[1] * inv_t + _q2[1] * _t;
+        z = _q1[2] * inv_t + _q2[2] * _t;
+        w = _q1[3] * inv_t + _q2[3] * _t;
+    }
+
+    ae_float_t q_dot = x * x + y * y + z * z + w * w;
+    ae_float_t inv_length = __inverse_sqrtf( q_dot );
+
+    _q[0] = x * inv_length;
+    _q[1] = y * inv_length;
+    _q[2] = z * inv_length;
+    _q[3] = w * inv_length;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_float_t __dot_qzw( const ae_quaternionzw_t _q1, const ae_quaternionzw_t _q2 )
+{
+    return _q1[0] * _q2[0] + _q1[1] * _q2[1];
+}
+//////////////////////////////////////////////////////////////////////////
+ae_void_t ae_linerp_qzw( ae_quaternionzw_t _q, const ae_quaternionzw_t _q1, const ae_quaternionzw_t _q2, ae_float_t _t )
+{
+    ae_float_t inv_t = 1.f - _t;
+
+    ae_float_t dot = __dot_qzw( _q1, _q2 );
+
+    ae_float_t z;
+    ae_float_t w;
+
+    if( dot < 0.f )
+    {
+        z = _q1[0] * inv_t - _q2[0] * _t;
+        w = _q1[1] * inv_t - _q2[1] * _t;
+    }
+    else
+    {
+        z = _q1[0] * inv_t + _q2[0] * _t;
+        w = _q1[1] * inv_t + _q2[1] * _t;
+    }
+
+    ae_float_t q_dot = z * z + w * w;
+    ae_float_t inv_length = __inverse_sqrtf( q_dot );
+
+    _q[0] = z * inv_length;
+    _q[1] = w * inv_length;
+}
+

+ 119 - 0
ae-movie/src/movie_math.h

@@ -0,0 +1,119 @@
+/******************************************************************************
+* libMOVIE Software License v1.0
+*
+* Copyright (c) 2016-2018, Yuriy Levchenko <[email protected]>
+* All rights reserved.
+*
+* You are granted a perpetual, non-exclusive, non-sublicensable, and
+* non-transferable license to use, install, execute, and perform the libMOVIE
+* software and derivative works solely for personal or internal
+* use. Without the written permission of Yuriy Levchenko, you may not (a) modify, translate,
+* adapt, or develop new applications using the libMOVIE or otherwise
+* create derivative works or improvements of the libMOVIE or (b) remove,
+* delete, alter, or obscure any trademarks or any copyright, trademark, patent,
+* or other intellectual property or proprietary rights notices on or in the
+* Software, including any copy thereof. Redistributions in binary or source
+* form must include this license and terms.
+*
+* THIS SOFTWARE IS PROVIDED BY YURIY LEVCHENKO "AS IS" AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+* EVENT SHALL YURIY LEVCHENKO BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION,
+* OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF
+* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+#ifndef MOVIE_MATRIX_H_
+#define MOVIE_MATRIX_H_
+
+#include "movie/movie_type.h"
+
+//////////////////////////////////////////////////////////////////////////
+static const ae_float_t f_eps = 0.00001f;
+static const ae_float_t f_neps = -0.00001f;
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_bool_t ae_equal_f_z( ae_float_t _a )
+{
+    return ((_a >= 0.f + f_neps) && (_a <= 0.f + f_eps)) ? AE_TRUE : AE_FALSE;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_bool_t ae_equal_f_f( ae_float_t _a, ae_float_t _b )
+{
+    return ((_a >= _b + f_neps) && (_a <= _b + f_eps)) ? AE_TRUE : AE_FALSE;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_float_t ae_min_f_f( ae_float_t _a, ae_float_t _b )
+{
+    return (_a > _b) ? _b : _a;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_float_t ae_max_f_f( ae_float_t _a, ae_float_t _b )
+{
+    return (_a > _b) ? _a : _b;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_float_t ae_minimax_f_f( ae_float_t _v, ae_float_t _min, ae_float_t _max )
+{
+    return (_v > _min) ? ((_v < _max) ? _v : _max) : _min;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t ae_copy_v2( ae_vector2_t _out, const ae_vector2_t _in )
+{
+    _out[0] = _in[0];
+    _out[1] = _in[1];
+}
+//////////////////////////////////////////////////////////////////////////
+ae_void_t ae_mul_v3_xy_m34( ae_vector3_t _out, ae_float_t _x, ae_float_t _y, const ae_matrix34_t _b );
+ae_void_t ae_mul_v3_v2_m34( ae_vector3_t _out, const ae_vector2_t _a, const ae_matrix34_t _b );
+ae_void_t ae_mul_m34_m34_r( ae_matrix34_t _out, const ae_matrix34_t _a, const ae_matrix34_t _b );
+ae_void_t ae_mul_m34_m34( ae_matrix34_t _out, const ae_matrix34_t _a, const ae_matrix34_t _b );
+ae_void_t ae_ident_m34( ae_matrix34_t _out );
+ae_void_t ae_copy_m34( ae_matrix34_t _out, const ae_matrix34_t _in );
+ae_void_t ae_movie_make_transformation3d_m34( ae_matrix34_t _out, const ae_vector3_t _position, const ae_vector3_t _anchor, const ae_vector3_t _scale, const ae_quaternion_t _quaternion, const ae_skew_t _skew );
+ae_void_t ae_movie_make_transformation3d_m34wq( ae_matrix34_t _out, const ae_vector3_t _position, const ae_vector3_t _anchor, const ae_vector3_t _scale, const ae_skew_t _skew );
+ae_void_t ae_movie_make_transformation3d_m34wsk( ae_matrix34_t _out, const ae_vector3_t _position, const ae_vector3_t _anchor, const ae_vector3_t _scale, const ae_quaternion_t _quaternion );
+ae_void_t ae_movie_make_transformation3d_m34wskq( ae_matrix34_t _out, const ae_vector3_t _position, const ae_vector3_t _anchor, const ae_vector3_t _scale );
+ae_void_t ae_movie_make_transformation2d_m34( ae_matrix34_t _out, const ae_vector2_t _position, const ae_vector2_t _anchor, const ae_vector2_t _scale, const ae_quaternionzw_t _quaternion, const ae_skew_t _skew );
+ae_void_t ae_movie_make_transformation2d_m34wq( ae_matrix34_t _out, const ae_vector2_t _position, const ae_vector2_t _anchor, const ae_vector2_t _scale, const ae_skew_t _skew );
+ae_void_t ae_movie_make_transformation2d_m34wsk( ae_matrix34_t _out, const ae_vector2_t _position, const ae_vector2_t _anchor, const ae_vector2_t _scale, const ae_quaternionzw_t _quaternion );
+ae_void_t ae_movie_make_transformation2d_m34wskq( ae_matrix34_t _out, const ae_vector2_t _position, const ae_vector2_t _anchor, const ae_vector2_t _scale );
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_float_t ae_linerp_f1( ae_float_t _in1, ae_float_t _in2, ae_float_t _t )
+{
+    return _in1 * (1.f - _t) + _in2 * _t;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t ae_linerp_f2( ae_vector2_t _out, const ae_vector2_t _in1, const ae_vector2_t _in2, ae_float_t _t )
+{
+    _out[0] = ae_linerp_f1( _in1[0], _in2[0], _t );
+    _out[1] = ae_linerp_f1( _in1[1], _in2[1], _t );
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_float_t ae_fractional_f( ae_float_t value )
+{
+    ae_float_t ff = value + 16777215.f;
+    ff -= 16777215.f;
+
+    if( ff > value )
+    {
+        ff -= 1.f;
+    }
+
+    ae_float_t fractional = value - ff;
+
+    if( fractional >= 1.f )
+    {
+        return 0.f;
+    }
+
+    return fractional;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_void_t ae_linerp_q( ae_quaternion_t _q, const ae_quaternion_t _q1, const ae_quaternion_t _q2, ae_float_t _t );
+ae_void_t ae_linerp_qzw( ae_quaternionzw_t _q, const ae_quaternionzw_t _q1, const ae_quaternionzw_t _q2, ae_float_t _t );
+//////////////////////////////////////////////////////////////////////////
+#endif

+ 105 - 0
ae-movie/src/movie_memory.h

@@ -0,0 +1,105 @@
+/******************************************************************************
+* libMOVIE Software License v1.0
+*
+* Copyright (c) 2016-2018, Yuriy Levchenko <[email protected]>
+* All rights reserved.
+*
+* You are granted a perpetual, non-exclusive, non-sublicensable, and
+* non-transferable license to use, install, execute, and perform the libMOVIE
+* software and derivative works solely for personal or internal
+* use. Without the written permission of Yuriy Levchenko, you may not (a) modify, translate,
+* adapt, or develop new applications using the libMOVIE or otherwise
+* create derivative works or improvements of the libMOVIE or (b) remove,
+* delete, alter, or obscure any trademarks or any copyright, trademark, patent,
+* or other intellectual property or proprietary rights notices on or in the
+* Software, including any copy thereof. Redistributions in binary or source
+* form must include this license and terms.
+*
+* THIS SOFTWARE IS PROVIDED BY YURIY LEVCHENKO "AS IS" AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+* EVENT SHALL YURIY LEVCHENKO BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION,
+* OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF
+* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+#ifndef MOVIE_MEMORY_H_
+#define MOVIE_MEMORY_H_
+
+#include "movie/movie_type.h"
+
+#include "movie_struct.h"
+
+#ifdef AE_MOVIE_MEMORY_DEBUG
+//////////////////////////////////////////////////////////////////////////
+#	define AE_NEW(instance, type) ((type *)__magic_memory_alloc( instance, #type, sizeof(type), __FILE__, __LINE__))
+#	define AE_NEWV(instance, size, doc) (__magic_memory_alloc( instance, doc, size, __FILE__, __LINE__))
+#	define AE_NEWN(instance, type, n) ((type *)__magic_memory_alloc_n(instance, #type, sizeof(type), n, __FILE__, __LINE__))
+#	define AE_DELETE(instance, ptr) (__magic_memory_free(instance, #ptr, ptr))
+#	define AE_DELETEN(instance, ptr) (__magic_memory_free_n(instance, #ptr, ptr))
+#	define AE_DELETE_STRING(instance, ptr) (__magic_memory_free_n(instance, #ptr, ptr))
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_voidptr_t __magic_memory_alloc( const aeMovieInstance * _instance, const ae_char_t * _doc, ae_size_t _size, const ae_char_t * _file, ae_uint32_t _line )
+{
+    AE_UNUSED( _doc );
+
+    ae_userdata_t ptr = _instance->memory_alloc( _instance->instance_userdata, _size, _file, _line );
+
+#   ifdef AE_MOVIE_MEMORY_INFO
+    _instance->logger( _instance->instance_userdata, AE_ERROR_MEMORY, "alloc type '%s' ptr '%p' size '%d'\n", _doc, ptr, (ae_uint32_t)_size );
+#   endif
+
+    return ptr;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_voidptr_t __magic_memory_alloc_n( const aeMovieInstance * _instance, const ae_char_t * _type, ae_size_t _size, ae_size_t _count, const ae_char_t * _file, ae_uint32_t _line )
+{
+    AE_UNUSED( _type );
+
+    ae_userdata_t ptr = _instance->memory_alloc_n( _instance->instance_userdata, _size, _count, _file, _line );
+
+#   ifdef AE_MOVIE_MEMORY_INFO
+    _instance->logger( _instance->instance_userdata, AE_ERROR_MEMORY, "alloc n type '%s' ptr '%p' size '%d' count '%d'\n", _type, ptr, (ae_uint32_t)_size, (ae_uint32_t)_count );
+#   endif
+
+    return ptr;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __magic_memory_free( const aeMovieInstance * _instance, const ae_char_t * _type, ae_constvoidptr_t _ptr )
+{
+    AE_UNUSED( _type );
+#   ifdef AE_MOVIE_MEMORY_INFO
+    _instance->logger( _instance->instance_userdata, AE_ERROR_MEMORY, "free type '%s' ptr '%p'\n", _type, _ptr );
+#   endif
+
+    _instance->memory_free( _instance->instance_userdata, _ptr );
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __magic_memory_free_n( const aeMovieInstance * _instance, const ae_char_t * _type, ae_constvoidptr_t _ptr )
+{
+    AE_UNUSED( _type );
+#   ifdef AE_MOVIE_MEMORY_INFO
+    _instance->logger( _instance->instance_userdata, AE_ERROR_MEMORY, "free n type '%s' ptr '%p'\n", _type, _ptr );
+#   endif
+
+    _instance->memory_free_n( _instance->instance_userdata, _ptr );
+}
+//////////////////////////////////////////////////////////////////////////
+#else
+//////////////////////////////////////////////////////////////////////////
+#	define AE_NEW(instance, type) ((type *)instance->memory_alloc( instance->instance_userdata, sizeof(type) ))
+#	define AE_NEWV(instance, size, doc) (instance->memory_alloc( instance->instance_userdata, size ))
+#	define AE_NEWN(instance, type, n) ((type *)instance->memory_alloc_n( instance->instance_userdata, sizeof(type), n ))
+#	define AE_DELETE(instance, ptr) (instance->memory_free( instance->instance_userdata, ptr))
+#	define AE_DELETEN(instance, ptr) (instance->memory_free_n( instance->instance_userdata, ptr))
+#	define AE_DELETE_STRING(instance, ptr) (instance->memory_free_n( instance->instance_userdata, ptr))
+//////////////////////////////////////////////////////////////////////////
+#endif
+//////////////////////////////////////////////////////////////////////////
+#define AE_STRNCMP(instance, src, dst, count) (instance->strncmp(instance->instance_userdata, src, dst, count))
+
+#endif

+ 208 - 0
ae-movie/src/movie_providers.c

@@ -0,0 +1,208 @@
+/******************************************************************************
+* libMOVIE Software License v1.0
+*
+* Copyright (c) 2016-2018, Yuriy Levchenko <[email protected]>
+* All rights reserved.
+*
+* You are granted a perpetual, non-exclusive, non-sublicensable, and
+* non-transferable license to use, install, execute, and perform the libMOVIE
+* software and derivative works solely for personal or internal
+* use. Without the written permission of Yuriy Levchenko, you may not (a) modify, translate,
+* adapt, or develop new applications using the libMOVIE or otherwise
+* create derivative works or improvements of the libMOVIE or (b) remove,
+* delete, alter, or obscure any trademarks or any copyright, trademark, patent,
+* or other intellectual property or proprietary rights notices on or in the
+* Software, including any copy thereof. Redistributions in binary or source
+* form must include this license and terms.
+*
+* THIS SOFTWARE IS PROVIDED BY YURIY LEVCHENKO "AS IS" AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+* EVENT SHALL YURIY LEVCHENKO BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION,
+* OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF
+* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+#include "movie/movie_providers.h"
+
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_bool_t __dummy_movie_composition_callback_node_provider(const aeMovieNodeProviderCallbackData * _callbackData, ae_userdataptr_t _rd, ae_userdata_t _ud)
+{
+    AE_UNUSED(_callbackData);
+    AE_UNUSED(_ud);
+
+    *_rd = AE_NULLPTR;
+
+    return AE_TRUE;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __dummy_movie_composition_callback_node_deleter(const aeMovieNodeDeleterCallbackData * _callbackData, ae_userdata_t _ud)
+{
+    AE_UNUSED(_callbackData);
+    AE_UNUSED(_ud);
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __dummy_movie_composition_callback_node_update(const aeMovieNodeUpdateCallbackData * _callbackData, ae_userdata_t _ud)
+{
+    AE_UNUSED(_callbackData);
+    AE_UNUSED(_ud);
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_bool_t __dummy_movie_composition_callback_camera_provider(const aeMovieCameraProviderCallbackData * _callbackData, ae_userdataptr_t _rd, ae_userdata_t _ud)
+{
+    AE_UNUSED(_callbackData);
+    AE_UNUSED(_ud);
+
+    *_rd = AE_NULLPTR;
+
+    return AE_TRUE;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __dummy_movie_composition_callback_camera_deleter(const aeMovieCameraDeleterCallbackData * _callbackData, ae_userdata_t _ud)
+{
+    AE_UNUSED(_callbackData);
+    AE_UNUSED(_ud);
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __dummy_movie_composition_callback_camera_update(const aeMovieCameraUpdateCallbackData * _callbackData, ae_userdata_t _ud)
+{
+    AE_UNUSED(_callbackData);
+    AE_UNUSED(_ud);
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_bool_t __dummy_movie_composition_callback_track_matte_provider(const aeMovieTrackMatteProviderCallbackData * _callbackData, ae_userdataptr_t _rd, ae_userdata_t _ud)
+{
+    AE_UNUSED(_callbackData);
+    AE_UNUSED(_ud);
+
+    *_rd = AE_NULLPTR;
+
+    return AE_TRUE;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __dummy_movie_composition_callback_track_matte_deleter(const aeMovieTrackMatteDeleterCallbackData * _callbackData, ae_userdata_t _ud)
+{
+    AE_UNUSED(_callbackData);
+    AE_UNUSED(_ud);
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __dummy_movie_composition_callback_track_matte_update(const aeMovieTrackMatteUpdateCallbackData * _callbackData, ae_userdata_t _ud)
+{
+    AE_UNUSED(_callbackData);
+    AE_UNUSED(_ud);
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_bool_t __dummy_movie_composition_callback_shader_provider(const aeMovieShaderProviderCallbackData * _callbackData, ae_userdataptr_t _rd, ae_userdata_t _ud)
+{
+    AE_UNUSED(_callbackData);
+    AE_UNUSED(_ud);
+
+    *_rd = AE_NULLPTR;
+
+    return AE_TRUE;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __dummy_movie_composition_callback_shader_deleter(const aeMovieShaderDeleterCallbackData * _callbackData, ae_userdata_t _ud)
+{
+    AE_UNUSED(_callbackData);
+    AE_UNUSED(_ud);
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __dummy_movie_composition_callback_shader_property_update(const aeMovieShaderPropertyUpdateCallbackData * _callbackData, ae_userdata_t _ud)
+{
+    AE_UNUSED(_callbackData);
+    AE_UNUSED(_ud);
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __dummy_movie_composition_callback_composition_event(const aeMovieCompositionEventCallbackData * _callbackData, ae_userdata_t _ud)
+{
+    AE_UNUSED(_callbackData);
+    AE_UNUSED(_ud);
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __dummy_movie_composition_callback_composition_state(const aeMovieCompositionStateCallbackData * _callbackData, ae_userdata_t _ud)
+{
+    AE_UNUSED(_callbackData);
+    AE_UNUSED(_ud);
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_bool_t __dummy_movie_composition_callback_composition_extra_interrupt(const aeMovieCompositionExtraInterruptCallbackData * _callbackData, ae_userdata_t _ud)
+{
+    AE_UNUSED(_callbackData);
+    AE_UNUSED(_ud);
+
+    return AE_TRUE;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_bool_t __dummy_movie_composition_callback_scene_effect_provider(const aeMovieCompositionSceneEffectProviderCallbackData * _callbackData, ae_userdataptr_t _rd, ae_userdata_t _ud)
+{
+    AE_UNUSED(_callbackData);
+    AE_UNUSED(_ud);
+
+    *_rd = AE_NULLPTR;
+
+    return AE_TRUE;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __dummy_movie_composition_callback_scene_effect_deleter(const aeMovieCompositionSceneEffectDeleterCallbackData * _callbackData, ae_userdata_t _ud)
+{
+    AE_UNUSED(_callbackData);
+    AE_UNUSED(_ud);
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __dummy_movie_composition_callback_scene_effect_update(const aeMovieCompositionSceneEffectUpdateCallbackData * _callbackData, ae_userdata_t _ud)
+{
+    AE_UNUSED(_callbackData);
+    AE_UNUSED(_ud);
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_bool_t __dummy_movie_composition_callback_subcomposition_provider(const aeMovieSubCompositionProviderCallbackData * _callbackData, ae_userdataptr_t _rd, ae_userdata_t _ud)
+{
+    AE_UNUSED(_callbackData);
+    AE_UNUSED(_ud);
+
+    *_rd = AE_NULLPTR;
+
+    return AE_TRUE;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __dummy_movie_composition_callback_subcomposition_deleter(const aeMovieSubCompositionDeleterCallbackData * _callbackData, ae_userdata_t _ud)
+{
+    AE_UNUSED(_callbackData);
+    AE_UNUSED(_ud);
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __dummy_movie_composition_callback_subcomposition_state(const aeMovieSubCompositionStateCallbackData * _callbackData, ae_userdata_t _ud)
+{
+    AE_UNUSED(_callbackData);
+    AE_UNUSED(_ud);
+}
+//////////////////////////////////////////////////////////////////////////
+ae_void_t ae_clear_movie_composition_providers( aeMovieCompositionProviders * _providers )
+{
+    _providers->node_provider = &__dummy_movie_composition_callback_node_provider;
+    _providers->node_deleter = &__dummy_movie_composition_callback_node_deleter;
+    _providers->node_update = &__dummy_movie_composition_callback_node_update;
+    _providers->camera_provider = &__dummy_movie_composition_callback_camera_provider;
+    _providers->camera_deleter = &__dummy_movie_composition_callback_camera_deleter;
+    _providers->camera_update = &__dummy_movie_composition_callback_camera_update;
+    _providers->track_matte_provider = &__dummy_movie_composition_callback_track_matte_provider;
+    _providers->track_matte_deleter = &__dummy_movie_composition_callback_track_matte_deleter;
+    _providers->track_matte_update = &__dummy_movie_composition_callback_track_matte_update;
+    _providers->shader_provider = &__dummy_movie_composition_callback_shader_provider;
+    _providers->shader_deleter = &__dummy_movie_composition_callback_shader_deleter;
+    _providers->shader_property_update = &__dummy_movie_composition_callback_shader_property_update;
+    _providers->composition_event = &__dummy_movie_composition_callback_composition_event;
+    _providers->composition_state = &__dummy_movie_composition_callback_composition_state;
+    _providers->composition_extra_interrupt = &__dummy_movie_composition_callback_composition_extra_interrupt;
+    _providers->scene_effect_provider = &__dummy_movie_composition_callback_scene_effect_provider;
+    _providers->scene_effect_deleter = &__dummy_movie_composition_callback_scene_effect_deleter;
+    _providers->scene_effect_update = &__dummy_movie_composition_callback_scene_effect_update;
+    _providers->subcomposition_provider = &__dummy_movie_composition_callback_subcomposition_provider;
+    _providers->subcomposition_deleter = &__dummy_movie_composition_callback_subcomposition_deleter;
+    _providers->subcomposition_state = &__dummy_movie_composition_callback_subcomposition_state;
+}

+ 179 - 0
ae-movie/src/movie_skeleton.c

@@ -0,0 +1,179 @@
+/******************************************************************************
+* libMOVIE Software License v1.0
+*
+* Copyright (c) 2016-2018, Yuriy Levchenko <[email protected]>
+* All rights reserved.
+*
+* You are granted a perpetual, non-exclusive, non-sublicensable, and
+* non-transferable license to use, install, execute, and perform the libMOVIE
+* software and derivative works solely for personal or internal
+* use. Without the written permission of Yuriy Levchenko, you may not (a) modify, translate,
+* adapt, or develop new applications using the libMOVIE or otherwise
+* create derivative works or improvements of the libMOVIE or (b) remove,
+* delete, alter, or obscure any trademarks or any copyright, trademark, patent,
+* or other intellectual property or proprietary rights notices on or in the
+* Software, including any copy thereof. Redistributions in binary or source
+* form must include this license and terms.
+*
+* THIS SOFTWARE IS PROVIDED BY YURIY LEVCHENKO "AS IS" AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+* EVENT SHALL YURIY LEVCHENKO BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION,
+* OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF
+* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+#include "movie/movie_skeleton.h"
+
+#include "movie_memory.h"
+#include "movie_math.h"
+#include "movie_struct.h"
+#include "movie_debug.h"
+
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_bool_t __test_movie_skeleton_base( aeMovieComposition * _base )
+{
+    ae_float_t duration = _base->composition_data->duration;
+
+    const aeMovieNode * it = _base->nodes;
+    const aeMovieNode * it_end = _base->nodes + _base->node_count;
+
+    for( ;
+        it != it_end;
+        ++it )
+    {
+        const aeMovieNode * node = it;
+
+        if( ae_equal_f_z( node->in_time ) == AE_FALSE )
+        {
+            return AE_FALSE;
+        }
+
+        if( ae_equal_f_f( node->out_time, duration ) == AE_FALSE )
+        {
+            return AE_FALSE;
+        }
+
+        if( ae_equal_f_z( node->start_time ) == AE_FALSE )
+        {
+            return AE_FALSE;
+        }
+    }
+
+    return AE_TRUE;
+}
+//////////////////////////////////////////////////////////////////////////
+aeMovieSkeleton * ae_movie_create_skeleton( aeMovieComposition * _base )
+{
+    if( _base == AE_NULLPTR )
+    {
+        return AE_NULLPTR;
+    }
+
+    if( __test_movie_skeleton_base( _base ) == AE_FALSE )
+    {
+        return AE_NULLPTR;
+    }
+
+    const aeMovieInstance * instance = _base->movie_data->instance;
+
+    aeMovieSkeleton * skeleton = AE_NEW( instance, aeMovieSkeleton );
+
+    AE_MOVIE_PANIC_MEMORY( skeleton, AE_NULLPTR );
+
+    skeleton->base = _base;
+
+    ae_uint32_t i = 0;
+    for( ; i != 8; ++i )
+    {
+        skeleton->animations[i] = AE_NULLPTR;
+    }
+
+    return skeleton;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_bool_t __test_movie_skeleton_animation( aeMovieComposition * _base, aeMovieComposition * _animation )
+{
+    if( _base->node_count != _animation->node_count )
+    {
+        return AE_FALSE;
+    }
+
+    const aeMovieInstance * instance = _base->movie_data->instance;
+
+    const aeMovieNode * it_base = _base->nodes;
+    const aeMovieNode * it_base_end = _base->nodes + _base->node_count;
+    const aeMovieNode * it_animation = _animation->nodes;
+    //const aeMovieNode * it_animation_end = _animation->nodes + _animation->node_count;
+
+    for( ;
+        it_base != it_base_end;
+        ++it_base, ++it_animation )
+    {
+        const aeMovieNode * base_node = it_base;
+        const aeMovieNode * animation_node = it_animation;
+
+        if( base_node->layer->type != animation_node->layer->type )
+        {
+            return AE_FALSE;
+        }
+
+        if( instance->strncmp( instance->instance_userdata, base_node->layer->name, animation_node->layer->name, AE_MOVIE_MAX_LAYER_NAME ) != 0 )
+        {
+            return AE_FALSE;
+        }
+    }
+
+    return AE_TRUE;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_uint32_t __movie_skeleton_find_free_animation_place( aeMovieSkeleton * _skeleton )
+{
+    ae_uint32_t i = 0;
+    for( ; i != 8; ++i )
+    {
+        if( _skeleton->animations[i] != AE_NULLPTR )
+        {
+            continue;
+        }
+
+        return i;
+    }
+
+    return (ae_uint32_t)-1;
+}
+
+ae_bool_t ae_movie_skeleton_add_animation( aeMovieSkeleton * _skeleton, aeMovieComposition * _animation )
+{
+    if( __test_movie_skeleton_base( _animation ) == AE_FALSE )
+    {
+        return AE_FALSE;
+    }
+
+    aeMovieComposition * base = _skeleton->base;
+
+    if( __test_movie_skeleton_animation( base, _animation ) == AE_FALSE )
+    {
+        return AE_FALSE;
+    }
+
+    ae_uint32_t index = __movie_skeleton_find_free_animation_place( _skeleton );
+
+    if( index == (ae_uint32_t)-1 )
+    {
+        return AE_FALSE;
+    }
+
+    _skeleton->animations[index] = _animation;
+
+    return AE_TRUE;
+}
+
+ae_void_t ae_movie_destroy_skeleton( const aeMovieSkeleton * _skeleton )
+{
+    AE_DELETE( _skeleton->base->movie_data->instance, _skeleton );
+}

+ 156 - 0
ae-movie/src/movie_stream.c

@@ -0,0 +1,156 @@
+/******************************************************************************
+* libMOVIE Software License v1.0
+*
+* Copyright (c) 2016-2018, Yuriy Levchenko <[email protected]>
+* All rights reserved.
+*
+* You are granted a perpetual, non-exclusive, non-sublicensable, and
+* non-transferable license to use, install, execute, and perform the libMOVIE
+* software and derivative works solely for personal or internal
+* use. Without the written permission of Yuriy Levchenko, you may not (a) modify, translate,
+* adapt, or develop new applications using the libMOVIE or otherwise
+* create derivative works or improvements of the libMOVIE or (b) remove,
+* delete, alter, or obscure any trademarks or any copyright, trademark, patent,
+* or other intellectual property or proprietary rights notices on or in the
+* Software, including any copy thereof. Redistributions in binary or source
+* form must include this license and terms.
+*
+* THIS SOFTWARE IS PROVIDED BY YURIY LEVCHENKO "AS IS" AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+* EVENT SHALL YURIY LEVCHENKO BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION,
+* OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF
+* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+#include "movie_stream.h"
+
+//////////////////////////////////////////////////////////////////////////
+ae_result_t ae_magic_read_string( aeMovieStream * _stream, ae_string_t * _str )
+{
+    ae_uint32_t size = AE_READZ( _stream );
+
+    ae_string_t buffer = AE_NEWN( _stream->instance, ae_char_t, size + 1U );
+
+    AE_RESULT_PANIC_MEMORY( buffer );
+
+    AE_READN( _stream, buffer, size );
+
+    buffer[size] = '\0';
+
+    *_str = buffer;
+
+    return AE_RESULT_SUCCESSFUL;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_result_t ae_magic_read_polygon( aeMovieStream * _stream, ae_polygon_t * _polygon )
+{
+    ae_uint32_t point_count = AE_READZ( _stream );
+
+    _polygon->point_count = point_count;
+
+    if( point_count == 0 )
+    {
+        _polygon->points = AE_NULLPTR;
+
+        return AE_RESULT_SUCCESSFUL;
+    }
+
+    ae_vector2_t * points = AE_NEWN( _stream->instance, ae_vector2_t, point_count );
+
+    AE_RESULT_PANIC_MEMORY( points );
+
+    AE_READN( _stream, points, point_count );
+
+    _polygon->points = (const ae_vector2_t *)points;
+
+    return AE_RESULT_SUCCESSFUL;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_uint32_t ae_magic_read_size( aeMovieStream * _stream )
+{
+    ae_uint8_t size255;
+    AE_READ( _stream, size255 );
+
+    if( size255 != 255 )
+    {
+        return (ae_uint32_t)size255;
+    }
+
+    ae_uint16_t size65535;
+    AE_READ( _stream, size65535 );
+
+    if( size65535 != 65535 )
+    {
+        return (ae_uint32_t)size65535;
+    }
+
+    ae_uint32_t size;
+    AE_READ( _stream, size );
+
+    return size;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_result_t ae_magic_read_mesh( aeMovieStream * _stream, ae_mesh_t * _mesh )
+{
+    ae_uint32_t vertex_count = AE_READZ( _stream );
+
+    if( vertex_count == 0 || vertex_count > AE_MOVIE_MAX_VERTICES )
+    {
+        _mesh->vertex_count = 0;
+        _mesh->index_count = 0;
+
+        _mesh->positions = AE_NULLPTR;
+        _mesh->uvs = AE_NULLPTR;
+        _mesh->indices = AE_NULLPTR;
+
+        return AE_RESULT_SUCCESSFUL;
+    }
+
+    ae_uint32_t indices_count = AE_READZ( _stream );
+
+    _mesh->vertex_count = vertex_count;
+    _mesh->index_count = indices_count;
+
+    ae_vector2_t * positions = AE_NEWN( _stream->instance, ae_vector2_t, vertex_count );
+
+    AE_RESULT_PANIC_MEMORY( positions );
+
+    AE_READN( _stream, positions, vertex_count );
+    _mesh->positions = (const ae_vector2_t *)positions;
+
+    ae_vector2_t * uvs = AE_NEWN( _stream->instance, ae_vector2_t, vertex_count );
+
+    AE_RESULT_PANIC_MEMORY( uvs );
+
+    AE_READN( _stream, uvs, vertex_count );
+    _mesh->uvs = (const ae_vector2_t *)uvs;
+
+    ae_uint16_t * indices = AE_NEWN( _stream->instance, ae_uint16_t, indices_count );
+
+    AE_RESULT_PANIC_MEMORY( indices );
+
+    AE_READN( _stream, indices, indices_count );
+    _mesh->indices = indices;
+
+    return AE_RESULT_SUCCESSFUL;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_void_t ae_magic_read_color( aeMovieStream * _stream, ae_color_t * _color )
+{
+    AE_READ_COLOR_CHANNEL( _stream, _color->r );
+    AE_READ_COLOR_CHANNEL( _stream, _color->g );
+    AE_READ_COLOR_CHANNEL( _stream, _color->b );
+}
+//////////////////////////////////////////////////////////////////////////
+ae_void_t ae_magic_read_viewport( aeMovieStream * _stream, ae_viewport_t * _viewport )
+{
+    AE_READF( _stream, _viewport->begin_x );
+    AE_READF( _stream, _viewport->begin_y );
+    AE_READF( _stream, _viewport->end_x );
+    AE_READF( _stream, _viewport->end_y );
+}

+ 100 - 0
ae-movie/src/movie_stream.h

@@ -0,0 +1,100 @@
+/******************************************************************************
+* libMOVIE Software License v1.0
+*
+* Copyright (c) 2016-2018, Yuriy Levchenko <[email protected]>
+* All rights reserved.
+*
+* You are granted a perpetual, non-exclusive, non-sublicensable, and
+* non-transferable license to use, install, execute, and perform the libMOVIE
+* software and derivative works solely for personal or internal
+* use. Without the written permission of Yuriy Levchenko, you may not (a) modify, translate,
+* adapt, or develop new applications using the libMOVIE or otherwise
+* create derivative works or improvements of the libMOVIE or (b) remove,
+* delete, alter, or obscure any trademarks or any copyright, trademark, patent,
+* or other intellectual property or proprietary rights notices on or in the
+* Software, including any copy thereof. Redistributions in binary or source
+* form must include this license and terms.
+*
+* THIS SOFTWARE IS PROVIDED BY YURIY LEVCHENKO "AS IS" AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+* EVENT SHALL YURIY LEVCHENKO BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION,
+* OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF
+* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+#ifndef MOVIE_STREAM_H_
+#define MOVIE_STREAM_H_
+
+#include "movie/movie_type.h"
+
+#include "movie_memory.h"
+#include "movie_struct.h"
+#include "movie_debug.h"
+
+#include <stddef.h>
+
+//////////////////////////////////////////////////////////////////////////
+#define AE_READ(stream, value) ae_magic_read_value(stream, &(value), sizeof(value))
+#define AE_READP(stream, value) ae_magic_read_value(stream, (value), sizeof(*(value)))
+#define AE_READF(stream, value) ae_magic_read_value(stream, &(value), sizeof(value))
+#define AE_READF2(stream, value) ae_magic_read_value(stream, &(value), sizeof(value))
+#define AE_READF3(stream, value) ae_magic_read_value(stream, &(value), sizeof(value))
+#define AE_READF4(stream, value) ae_magic_read_value(stream, &(value), sizeof(value))
+#define AE_READV(stream, value, size) ae_magic_read_value(stream, value, size)
+#define AE_READN(stream, ptr, n) ae_magic_read_value(stream, ptr, sizeof(*ptr) * n)
+//////////////////////////////////////////////////////////////////////////
+#define AE_READB(stream) ae_magic_read_bool(stream)
+#define AE_READZ(stream) ae_magic_read_size(stream)
+#define AE_READ8(stream) ae_magic_read_8(stream)
+//////////////////////////////////////////////////////////////////////////
+#define AE_READ_COLOR(stream, ptr) ae_magic_read_color(stream, (ptr))
+#define AE_READ_COLOR_CHANNEL(stream, ptr) AE_READ(stream, (ptr))
+#define AE_READ_VIEWPORT(stream, ptr) ae_magic_read_viewport, (stream, (ptr))
+//////////////////////////////////////////////////////////////////////////
+#define AE_READ_STRING(stream, ptr) AE_RESULT(ae_magic_read_string, (stream, &(ptr)))
+#define AE_READ_POLYGON(stream, ptr) AE_RESULT(ae_magic_read_polygon, (stream, (ptr)))
+#define AE_READ_MESH(stream, ptr) AE_RESULT(ae_magic_read_mesh, (stream, (ptr)))
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t ae_magic_read_value( aeMovieStream * _stream, ae_voidptr_t _ptr, ae_size_t _size )
+{
+    ae_size_t bytesRead = _stream->memory_read( _stream->read_userdata, _ptr, _stream->carriage, _size );
+
+    _stream->carriage += bytesRead;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_bool_t ae_magic_read_bool( aeMovieStream * _stream )
+{
+    ae_uint8_t value;
+    AE_READ( _stream, value );
+
+#ifdef AE_MOVIE_DEBUG
+    if( value != 0 && value != 1 )
+    {
+        __movie_break_point();
+    }
+#endif
+
+    return value;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_uint32_t ae_magic_read_8( aeMovieStream * _stream )
+{
+    ae_uint8_t value;
+    AE_READ( _stream, value );
+
+    return (ae_uint32_t)value;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_uint32_t ae_magic_read_size( aeMovieStream * _stream );
+ae_result_t ae_magic_read_string( aeMovieStream * _stream, ae_string_t * _str );
+ae_result_t ae_magic_read_polygon( aeMovieStream * _stream, ae_polygon_t * _polygon );
+ae_void_t ae_magic_read_color( aeMovieStream * _stream, ae_color_t * _color );
+ae_void_t ae_magic_read_viewport( aeMovieStream * _stream, ae_viewport_t * _viewport );
+ae_result_t ae_magic_read_mesh( aeMovieStream * _stream, ae_mesh_t * _mesh );
+//////////////////////////////////////////////////////////////////////////
+#endif

+ 505 - 0
ae-movie/src/movie_struct.h

@@ -0,0 +1,505 @@
+/******************************************************************************
+* libMOVIE Software License v1.0
+*
+* Copyright (c) 2016-2018, Yuriy Levchenko <[email protected]>
+* All rights reserved.
+*
+* You are granted a perpetual, non-exclusive, non-sublicensable, and
+* non-transferable license to use, install, execute, and perform the libMOVIE
+* software and derivative works solely for personal or internal
+* use. Without the written permission of Yuriy Levchenko, you may not (a) modify, translate,
+* adapt, or develop new applications using the libMOVIE or otherwise
+* create derivative works or improvements of the libMOVIE or (b) remove,
+* delete, alter, or obscure any trademarks or any copyright, trademark, patent,
+* or other intellectual property or proprietary rights notices on or in the
+* Software, including any copy thereof. Redistributions in binary or source
+* form must include this license and terms.
+*
+* THIS SOFTWARE IS PROVIDED BY YURIY LEVCHENKO "AS IS" AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+* EVENT SHALL YURIY LEVCHENKO BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION,
+* OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF
+* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+#ifndef MOVIE_STRUCT_H_
+#define MOVIE_STRUCT_H_
+
+#include "movie/movie_type.h"
+#include "movie/movie_composition.h"
+
+#include "movie_bezier.h"
+
+//////////////////////////////////////////////////////////////////////////
+typedef struct aeMovieBezierWarp
+{
+    ae_vector2_t corners[4];
+    ae_vector2_t beziers[8];
+} aeMovieBezierWarp;
+//////////////////////////////////////////////////////////////////////////
+typedef enum aeMovieLayerExtensionEnum
+{
+    AE_LAYER_EXTENSION_TIMEREMAP = 1,
+    AE_LAYER_EXTENSION_MESH = 2,
+    AE_LAYER_EXTENSION_BEZIERWARP = 3,
+    AE_LAYER_EXTENSION_COLORVERTEX = 4,
+    AE_LAYER_EXTENSION_POLYGON = 5,
+    AE_LAYER_EXTENSION_SHADER = 6,
+    AE_LAYER_EXTENSION_VIEWPORT = 7,
+    AE_LAYER_EXTENSION_VOLUME = 8,
+} aeMovieLayerExtensionEnum;
+//////////////////////////////////////////////////////////////////////////
+typedef enum aeMovieNodeAnimationStateEnum
+{
+    AE_MOVIE_NODE_ANIMATE_STATIC,
+    AE_MOVIE_NODE_ANIMATE_BEGIN,
+    AE_MOVIE_NODE_ANIMATE_PROCESS,
+    AE_MOVIE_NODE_ANIMATE_END,
+} aeMovieNodeAnimationStateEnum;
+//////////////////////////////////////////////////////////////////////////
+typedef struct aeMovieLayerExtensions
+{
+    const aeMovieLayerExtensionTimeremap * timeremap;
+    const aeMovieLayerExtensionMesh * mesh;
+    const aeMovieLayerExtensionBezierWarp * bezier_warp;
+    const aeMovieLayerExtensionPolygon * polygon;
+    const aeMovieLayerExtensionShader * shader;
+    const aeMovieLayerExtensionViewport * viewport;
+    const aeMovieLayerExtensionVolume * volume;
+} aeMovieLayerExtensions;
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __clear_layer_extensions( aeMovieLayerExtensions * _extensions )
+{
+    _extensions->timeremap = AE_NULLPTR;
+    _extensions->mesh = AE_NULLPTR;
+    _extensions->bezier_warp = AE_NULLPTR;
+    _extensions->polygon = AE_NULLPTR;
+    _extensions->shader = AE_NULLPTR;
+    _extensions->viewport = AE_NULLPTR;
+    _extensions->volume = AE_NULLPTR;
+}
+//////////////////////////////////////////////////////////////////////////
+struct aeMovieInstance
+{
+    ae_uint32_t hashmask[5];
+
+    ae_movie_alloc_t memory_alloc;
+    ae_movie_alloc_n_t memory_alloc_n;
+    ae_movie_free_t memory_free;
+    ae_movie_free_n_t memory_free_n;
+    ae_movie_strncmp_t strncmp;
+    ae_movie_logger_t logger;
+    ae_userdata_t instance_userdata;
+
+    ae_vector2_t sprite_uv[4];
+    ae_uint16_t sprite_indices[6];
+
+    const ae_vector2_t * bezier_warp_uvs[AE_MOVIE_BEZIER_MAX_QUALITY];
+    const ae_uint16_t * bezier_warp_indices[AE_MOVIE_BEZIER_MAX_QUALITY];
+
+    aeMovieLayerExtensions layer_extensions_default;
+};
+//////////////////////////////////////////////////////////////////////////
+struct aeMovieStream
+{
+    const aeMovieInstance * instance;
+
+    ae_movie_stream_memory_read_t memory_read;
+    ae_movie_stream_memory_copy_t memory_copy;
+    ae_userdata_t read_userdata;
+    ae_userdata_t copy_userdata;
+
+    ae_constvoidptr_t buffer;
+    ae_size_t carriage;
+};
+//////////////////////////////////////////////////////////////////////////
+struct aeMovieCompositionAnimation
+{
+    ae_bool_t enable;
+
+    ae_bool_t play;
+    ae_bool_t pause;
+    ae_bool_t interrupt;
+    ae_bool_t loop;
+
+    ae_time_t time;
+
+    ae_time_t loop_segment_begin;
+    ae_time_t loop_segment_end;
+
+    ae_time_t work_area_begin;
+    ae_time_t work_area_end;
+};
+//////////////////////////////////////////////////////////////////////////
+struct aeMovieSubComposition
+{
+    const aeMovieLayerData * layer;
+    const aeMovieCompositionData * composition_data;
+    const aeMovieCompositionData * subcomposition_data;
+
+    struct aeMovieCompositionAnimation * animation;
+
+    ae_userdata_t subcomposition_userdata;
+};
+//////////////////////////////////////////////////////////////////////////
+struct aeMovieNode
+{
+    const aeMovieLayerData * layer;
+
+    struct aeMovieNode * relative_node;
+    struct aeMovieNode * track_matte_node;
+
+    const ae_viewport_t * viewport;
+
+    const aeMovieSubComposition * subcomposition;
+
+    ae_float_t start_time;
+    ae_float_t in_time;
+    ae_float_t out_time;
+
+    ae_float_t stretchInv;
+    ae_float_t current_time;
+    ae_uint32_t current_frame;
+    ae_float_t current_frame_t;
+
+    ae_bool_t active;
+    ae_bool_t ignore;
+    ae_bool_t enable;
+    ae_bool_t incessantly;
+    ae_bool_t immutable_matrix;
+    ae_bool_t immutable_color;
+
+    ae_uint32_t animate;
+
+    ae_uint32_t update_revision;
+    ae_matrix34_t matrix;
+
+    ae_color_t composition_color;
+    ae_float_t composition_opacity;
+
+    ae_color_t color;
+    ae_color_channel_t opacity;
+
+    ae_bool_t transparent;
+
+    ae_float_t volume;
+
+    ae_blend_mode_t blend_mode;
+
+    ae_userdata_t element_userdata;
+    ae_userdata_t camera_userdata;    
+    ae_userdata_t shader_userdata;
+    ae_userdata_t track_matte_userdata;
+};
+//////////////////////////////////////////////////////////////////////////
+struct aeMovieComposition
+{
+    const aeMovieData * movie_data;
+    const aeMovieCompositionData * composition_data;
+
+    struct aeMovieCompositionAnimation * animation;
+
+    ae_userdata_t camera_userdata;
+
+    ae_uint32_t * update_revision;
+
+    ae_bool_t interpolate;
+
+    ae_uint32_t node_count;
+    aeMovieNode * nodes;
+
+    aeMovieNode * scene_effect_node;
+    ae_userdata_t scene_effect_userdata;
+
+    ae_uint32_t subcomposition_count;
+    aeMovieSubComposition * subcompositions;
+
+    aeMovieCompositionProviders providers;
+    ae_userdata_t provider_userdata;
+};
+//////////////////////////////////////////////////////////////////////////
+typedef struct aeMovieCompositionCameraImuttable
+{
+    ae_float_t target_x;
+    ae_float_t target_y;
+    ae_float_t target_z;
+    ae_float_t position_x;
+    ae_float_t position_y;
+    ae_float_t position_z;
+    ae_float_t quaternion_x;
+    ae_float_t quaternion_y;
+    ae_float_t quaternion_z;
+    ae_float_t quaternion_w;
+} aeMovieCompositionCameraImuttable;
+//////////////////////////////////////////////////////////////////////////
+typedef struct aeMovieCompositionCameraTimeline
+{
+    ae_constvoidptr_t target_x;
+    ae_constvoidptr_t target_y;
+    ae_constvoidptr_t target_z;
+    ae_constvoidptr_t position_x;
+    ae_constvoidptr_t position_y;
+    ae_constvoidptr_t position_z;
+    ae_constvoidptr_t quaternion_x;
+    ae_constvoidptr_t quaternion_y;
+    ae_constvoidptr_t quaternion_z;
+    ae_constvoidptr_t quaternion_w;
+} aeMovieCompositionCameraTimeline;
+//////////////////////////////////////////////////////////////////////////
+struct aeMovieCompositionCamera
+{
+    ae_string_t name;
+
+    ae_float_t zoom;
+    ae_float_t fov;
+
+    ae_uint32_t immutable_property_mask;
+    ae_uint32_t identity_property_mask;
+
+    aeMovieCompositionCameraImuttable immutable;
+    aeMovieCompositionCameraTimeline * timeline;
+};
+//////////////////////////////////////////////////////////////////////////
+struct aeMovieCompositionData
+{
+    ae_string_t name;
+
+    ae_bool_t master;
+
+    ae_float_t width;
+    ae_float_t height;
+
+    ae_time_t duration;
+
+    ae_time_t frameDuration;
+    ae_time_t frameDurationInv;
+
+    ae_uint32_t frameCount;
+
+    ae_uint32_t flags;
+
+    ae_vector2_t loop_segment;
+    ae_vector3_t anchor_point;
+    ae_vector3_t offset_point;
+    ae_viewport_t bounds;
+
+    const aeMovieCompositionCamera * camera;
+
+    ae_uint32_t layer_count;
+    const aeMovieLayerData * layers;
+};
+//////////////////////////////////////////////////////////////////////////
+struct aeMovieData
+{
+    const aeMovieInstance * instance;
+
+    ae_string_t name;
+
+    ae_bool_t common_store;
+
+    aeMovieDataProviders providers;
+    ae_userdata_t provider_userdata;
+
+    ae_uint32_t atlas_count;
+    const aeMovieResource * const * atlases;
+
+    ae_uint32_t resource_count;
+    const aeMovieResource * const * resources;
+
+    ae_uint32_t composition_count;
+    const aeMovieCompositionData * compositions;
+};
+//////////////////////////////////////////////////////////////////////////
+struct aeMovieLayerData
+{
+    ae_string_t name;
+
+    ae_uint32_t index;
+    aeMovieLayerTypeEnum type;
+
+    ae_bool_t renderable;
+
+    const struct aeMovieCompositionData * composition_data;
+
+    ae_bool_t is_track_matte;
+    ae_bool_t has_track_matte;
+    ae_track_matte_mode_t track_matte_mode;
+    const struct aeMovieLayerData * track_matte_layer;
+
+    ae_uint32_t frame_count;
+
+    const aeMovieLayerExtensions * extensions;
+
+    const aeMovieResource * resource;
+    const aeMovieCompositionData * subcomposition_data;
+
+    ae_uint32_t parent_index;
+
+    ae_float_t in_time;
+    ae_float_t out_time;
+    ae_float_t start_time;
+    ae_float_t finish_time;
+
+    ae_bool_t reverse_time;
+    ae_bool_t trimmed_time;
+
+    ae_blend_mode_t blend_mode;
+    ae_bool_t threeD;
+
+    ae_bool_t incessantly;
+
+    ae_uint32_t options_count;
+    ae_uint32_t options[AE_MOVIE_LAYER_MAX_OPTIONS];
+
+    ae_uint32_t play_count;
+
+    ae_float_t stretch;
+
+    const struct aeMovieLayerTransformation * transformation;
+    const struct aeMovieLayerCache * cache;
+};
+//////////////////////////////////////////////////////////////////////////
+struct aeMovieLayerExtensionTimeremap
+{
+    const ae_float_t * times;
+};
+//////////////////////////////////////////////////////////////////////////
+struct aeMovieLayerExtensionMesh
+{
+    ae_bool_t immutable;
+    ae_mesh_t immutable_mesh;
+
+    const ae_mesh_t * meshes;
+};
+//////////////////////////////////////////////////////////////////////////
+struct aeMovieLayerExtensionBezierWarp
+{
+    ae_bool_t immutable;
+    aeMovieBezierWarp immutable_bezier_warp;
+
+    const aeMovieBezierWarp * bezier_warps;
+
+    ae_uint32_t quality;
+};
+//////////////////////////////////////////////////////////////////////////
+struct aeMoviePropertyValue
+{
+    ae_bool_t immutable;
+
+    ae_float_t immutable_value;
+
+    const ae_float_t * values;
+};
+//////////////////////////////////////////////////////////////////////////
+struct aeMoviePropertyColorChannel
+{
+    ae_bool_t immutable;
+
+    ae_color_channel_t immutable_value;
+
+    const ae_color_channel_t * values;
+};
+//////////////////////////////////////////////////////////////////////////
+struct aeMoviePropertyColor
+{
+    const struct aeMoviePropertyColorChannel * color_channel_r;
+    const struct aeMoviePropertyColorChannel * color_channel_g;
+    const struct aeMoviePropertyColorChannel * color_channel_b;
+};
+//////////////////////////////////////////////////////////////////////////
+#	define AE_MOVIE_SHADER_PARAMETER_BASE()\
+    ae_string_t name;\
+    ae_string_t uniform;\
+    aeMovieShaderParameterTypeEnum type
+//////////////////////////////////////////////////////////////////////////
+struct aeMovieLayerShaderParameter
+{
+    AE_MOVIE_SHADER_PARAMETER_BASE();
+};
+//////////////////////////////////////////////////////////////////////////
+struct aeMovieLayerShaderParameterSlider
+{
+    AE_MOVIE_SHADER_PARAMETER_BASE();
+
+    const struct aeMoviePropertyValue * property_value;
+};
+//////////////////////////////////////////////////////////////////////////
+struct aeMovieLayerShaderParameterAngle
+{
+    AE_MOVIE_SHADER_PARAMETER_BASE();
+
+    const struct aeMoviePropertyValue * property_value;
+};
+//////////////////////////////////////////////////////////////////////////
+struct aeMovieLayerShaderParameterColor
+{
+    AE_MOVIE_SHADER_PARAMETER_BASE();
+
+    const struct aeMoviePropertyColor * property_color;
+};
+//////////////////////////////////////////////////////////////////////////
+struct aeMovieLayerShaderParameterTime
+{
+    AE_MOVIE_SHADER_PARAMETER_BASE();
+
+    ae_float_t scale;
+};
+//////////////////////////////////////////////////////////////////////////
+struct aeMovieLayerExtensionShader
+{
+    ae_string_t name;
+    ae_string_t description;
+    ae_uint32_t version;
+    ae_uint32_t flags;
+
+    ae_uint32_t parameter_count;
+    const struct aeMovieLayerShaderParameter ** parameters;
+};
+//////////////////////////////////////////////////////////////////////////
+struct aeMovieLayerExtensionViewport
+{
+    ae_viewport_t viewport;
+};
+//////////////////////////////////////////////////////////////////////////
+struct aeMovieLayerExtensionVolume
+{
+    const struct aeMoviePropertyValue * property_volume;
+};
+//////////////////////////////////////////////////////////////////////////
+struct aeMovieLayerExtensionPolygon
+{
+    ae_bool_t immutable;
+    ae_polygon_t immutable_polygon;
+
+    const ae_polygon_t * polygons;
+};
+//////////////////////////////////////////////////////////////////////////
+struct aeMovieResourceImageCache
+{
+    ae_userdata_t uv_cache_userdata;
+    ae_userdata_t mesh_uv_cache_userdata;
+    ae_userdata_t bezier_warp_uv_cache_userdata[AE_MOVIE_BEZIER_MAX_QUALITY];
+};
+//////////////////////////////////////////////////////////////////////////
+struct aeMovieResourceVideoCache
+{
+    ae_userdata_t uv_cache_userdata;
+    ae_userdata_t bezier_warp_uv_cache_userdata[AE_MOVIE_BEZIER_MAX_QUALITY];
+};
+//////////////////////////////////////////////////////////////////////////
+struct aeMovieLayerCache
+{
+    ae_userdata_t immutable_mesh_uv_cache_userdata;
+    ae_userdata_t * mesh_uv_cache_userdata;
+};
+//////////////////////////////////////////////////////////////////////////
+#define AE_RESULT( Function, Args ) { ae_result_t result = (Function) Args; if( result != AE_RESULT_SUCCESSFUL ) { return result;}}
+#define AE_SUCCESSFUL( Function, Args ) { ae_bool_t successful = (Function) Args; if( successful == AE_FALSE ) {return AE_FALSE;}}
+#define AE_RESULT_PANIC_MEMORY( Memory ) AE_MOVIE_PANIC_MEMORY( Memory, AE_RESULT_INVALID_MEMORY )
+//////////////////////////////////////////////////////////////////////////
+#endif

+ 1567 - 0
ae-movie/src/movie_transformation.c

@@ -0,0 +1,1567 @@
+/******************************************************************************
+* libMOVIE Software License v1.0
+*
+* Copyright (c) 2016-2018, Yuriy Levchenko <[email protected]>
+* All rights reserved.
+*
+* You are granted a perpetual, non-exclusive, non-sublicensable, and
+* non-transferable license to use, install, execute, and perform the libMOVIE
+* software and derivative works solely for personal or internal
+* use. Without the written permission of Yuriy Levchenko, you may not (a) modify, translate,
+* adapt, or develop new applications using the libMOVIE or otherwise
+* create derivative works or improvements of the libMOVIE or (b) remove,
+* delete, alter, or obscure any trademarks or any copyright, trademark, patent,
+* or other intellectual property or proprietary rights notices on or in the
+* Software, including any copy thereof. Redistributions in binary or source
+* form must include this license and terms.
+*
+* THIS SOFTWARE IS PROVIDED BY YURIY LEVCHENKO "AS IS" AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+* EVENT SHALL YURIY LEVCHENKO BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION,
+* OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF
+* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+#include "movie_transformation.h"
+
+#include "movie_stream.h"
+#include "movie_math.h"
+
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_constvoidptr_t __load_movie_layer_transformation_timeline( aeMovieStream * _stream, const ae_char_t * _doc )
+{
+    AE_UNUSED( _doc );
+
+    ae_uint32_t zp_data_size;
+    AE_READ( _stream, zp_data_size );
+
+    ae_uint32_t hashmask_iterator = AE_READ8( _stream );
+
+    ae_voidptr_t timeline = AE_NEWV( _stream->instance, zp_data_size, _doc );
+
+    AE_MOVIE_PANIC_MEMORY( timeline, AE_NULLPTR );
+
+    AE_READV( _stream, timeline, (ae_size_t)zp_data_size );
+
+    const ae_uint32_t * hashmask = _stream->instance->hashmask;
+
+    ae_uint32_t * it_timeline = (ae_uint32_t *)timeline;
+    ae_uint32_t * it_timeline_end = (ae_uint32_t *)timeline + zp_data_size / 4U;
+    for( ; it_timeline != it_timeline_end; ++it_timeline )
+    {
+        ae_uint32_t hashmask_index = (hashmask_iterator++) % 5U;
+
+        ae_uint32_t hash = hashmask[hashmask_index];
+
+        *it_timeline ^= hash;
+    }
+
+    return timeline;
+}
+//////////////////////////////////////////////////////////////////////////
+static const ae_float_t one_div_index256[] =
+{ 0.f, 1.f / 1.f, 1.f / 2.f, 1.f / 3.f, 1.f / 4.f, 1.f / 5.f, 1.f / 6.f, 1.f / 7.f, 1.f / 8.f, 1.f / 9.f
+, 1.f / 10.f, 1.f / 11.f, 1.f / 12.f, 1.f / 13.f, 1.f / 14.f, 1.f / 15.f, 1.f / 16.f, 1.f / 17.f, 1.f / 18.f, 1.f / 19.f
+, 1.f / 20.f, 1.f / 21.f, 1.f / 22.f, 1.f / 23.f, 1.f / 24.f, 1.f / 25.f, 1.f / 26.f, 1.f / 27.f, 1.f / 28.f, 1.f / 29.f
+, 1.f / 30.f, 1.f / 31.f, 1.f / 32.f, 1.f / 33.f, 1.f / 34.f, 1.f / 35.f, 1.f / 36.f, 1.f / 37.f, 1.f / 38.f, 1.f / 39.f
+, 1.f / 40.f, 1.f / 41.f, 1.f / 42.f, 1.f / 43.f, 1.f / 44.f, 1.f / 45.f, 1.f / 46.f, 1.f / 47.f, 1.f / 48.f, 1.f / 49.f
+, 1.f / 50.f, 1.f / 51.f, 1.f / 52.f, 1.f / 53.f, 1.f / 54.f, 1.f / 55.f, 1.f / 56.f, 1.f / 57.f, 1.f / 58.f, 1.f / 59.f
+, 1.f / 60.f, 1.f / 61.f, 1.f / 62.f, 1.f / 63.f, 1.f / 64.f, 1.f / 65.f, 1.f / 66.f, 1.f / 67.f, 1.f / 68.f, 1.f / 69.f
+, 1.f / 70.f, 1.f / 71.f, 1.f / 72.f, 1.f / 73.f, 1.f / 74.f, 1.f / 75.f, 1.f / 76.f, 1.f / 77.f, 1.f / 78.f, 1.f / 79.f
+, 1.f / 80.f, 1.f / 81.f, 1.f / 82.f, 1.f / 83.f, 1.f / 84.f, 1.f / 85.f, 1.f / 86.f, 1.f / 87.f, 1.f / 88.f, 1.f / 89.f
+, 1.f / 90.f, 1.f / 91.f, 1.f / 92.f, 1.f / 93.f, 1.f / 94.f, 1.f / 95.f, 1.f / 96.f, 1.f / 97.f, 1.f / 98.f, 1.f / 99.f
+, 1.f / 100.f, 1.f / 101.f, 1.f / 102.f, 1.f / 103.f, 1.f / 104, 1.f / 105.f, 1.f / 106.f, 1.f / 107.f, 1.f / 108.f, 1.f / 109.f
+, 1.f / 110.f, 1.f / 111.f, 1.f / 112.f, 1.f / 113.f, 1.f / 114, 1.f / 115.f, 1.f / 116.f, 1.f / 117.f, 1.f / 118.f, 1.f / 119.f
+, 1.f / 120.f, 1.f / 121.f, 1.f / 122.f, 1.f / 123.f, 1.f / 124, 1.f / 125.f, 1.f / 126.f, 1.f / 127.f, 1.f / 128.f, 1.f / 129.f
+, 1.f / 130.f, 1.f / 131.f, 1.f / 132.f, 1.f / 133.f, 1.f / 134, 1.f / 135.f, 1.f / 136.f, 1.f / 137.f, 1.f / 138.f, 1.f / 139.f
+, 1.f / 140.f, 1.f / 141.f, 1.f / 142.f, 1.f / 143.f, 1.f / 144, 1.f / 145.f, 1.f / 146.f, 1.f / 147.f, 1.f / 148.f, 1.f / 149.f
+, 1.f / 150.f, 1.f / 151.f, 1.f / 152.f, 1.f / 153.f, 1.f / 154, 1.f / 155.f, 1.f / 156.f, 1.f / 157.f, 1.f / 158.f, 1.f / 159.f
+, 1.f / 160.f, 1.f / 161.f, 1.f / 162.f, 1.f / 163.f, 1.f / 164, 1.f / 165.f, 1.f / 166.f, 1.f / 167.f, 1.f / 168.f, 1.f / 169.f
+, 1.f / 170.f, 1.f / 171.f, 1.f / 172.f, 1.f / 173.f, 1.f / 174, 1.f / 175.f, 1.f / 176.f, 1.f / 177.f, 1.f / 178.f, 1.f / 179.f
+, 1.f / 180.f, 1.f / 181.f, 1.f / 182.f, 1.f / 183.f, 1.f / 184, 1.f / 185.f, 1.f / 186.f, 1.f / 187.f, 1.f / 188.f, 1.f / 189.f
+, 1.f / 190.f, 1.f / 191.f, 1.f / 192.f, 1.f / 193.f, 1.f / 194, 1.f / 195.f, 1.f / 196.f, 1.f / 197.f, 1.f / 198.f, 1.f / 199.f
+, 1.f / 200.f, 1.f / 201.f, 1.f / 202.f, 1.f / 203.f, 1.f / 204, 1.f / 205.f, 1.f / 206.f, 1.f / 207.f, 1.f / 208.f, 1.f / 209.f
+, 1.f / 210.f, 1.f / 211.f, 1.f / 212.f, 1.f / 213.f, 1.f / 214, 1.f / 215.f, 1.f / 216.f, 1.f / 217.f, 1.f / 218.f, 1.f / 219.f
+, 1.f / 220.f, 1.f / 221.f, 1.f / 222.f, 1.f / 223.f, 1.f / 224, 1.f / 225.f, 1.f / 226.f, 1.f / 227.f, 1.f / 228.f, 1.f / 229.f
+, 1.f / 230.f, 1.f / 231.f, 1.f / 232.f, 1.f / 233.f, 1.f / 234, 1.f / 235.f, 1.f / 236.f, 1.f / 237.f, 1.f / 238.f, 1.f / 239.f
+, 1.f / 240.f, 1.f / 241.f, 1.f / 242.f, 1.f / 243.f, 1.f / 244, 1.f / 245.f, 1.f / 246.f, 1.f / 247.f, 1.f / 248.f, 1.f / 249.f
+, 1.f / 250.f, 1.f / 251.f, 1.f / 252.f, 1.f / 253.f, 1.f / 254, 1.f / 255.f, 1.f / 256.f, 1.f / 257.f, 1.f / 258.f, 1.f / 259.f };
+//////////////////////////////////////////////////////////////////////////
+static const ae_float_t index256_to_float[] =
+{ 0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f, 9.f
+, 10.f, 11.f, 12.f, 13.f, 14.f, 15.f, 16.f, 17.f, 18.f, 19.f
+, 20.f, 21.f, 22.f, 23.f, 24.f, 25.f, 26.f, 27.f, 28.f, 29.f
+, 30.f, 31.f, 32.f, 33.f, 34.f, 35.f, 36.f, 37.f, 38.f, 39.f
+, 40.f, 41.f, 42.f, 43.f, 44.f, 45.f, 46.f, 47.f, 48.f, 49.f
+, 50.f, 51.f, 52.f, 53.f, 54.f, 55.f, 56.f, 57.f, 58.f, 59.f
+, 60.f, 61.f, 62.f, 63.f, 64.f, 65.f, 66.f, 67.f, 68.f, 69.f
+, 70.f, 71.f, 72.f, 73.f, 74.f, 75.f, 76.f, 77.f, 78.f, 79.f
+, 80.f, 81.f, 82.f, 83.f, 84.f, 85.f, 86.f, 87.f, 88.f, 89.f
+, 90.f, 91.f, 92.f, 93.f, 94.f, 95.f, 96.f, 97.f, 98.f, 99.f
+, 100.f, 101.f, 102.f, 103.f, 104.f, 105.f, 106.f, 107.f, 108.f, 109.f
+, 110.f, 111.f, 112.f, 113.f, 114.f, 115.f, 116.f, 117.f, 118.f, 119.f
+, 120.f, 121.f, 122.f, 123.f, 124.f, 125.f, 126.f, 127.f, 128.f, 129.f
+, 130.f, 131.f, 132.f, 133.f, 134.f, 135.f, 136.f, 137.f, 138.f, 139.f
+, 140.f, 141.f, 142.f, 143.f, 144.f, 145.f, 146.f, 147.f, 148.f, 149.f
+, 150.f, 151.f, 152.f, 153.f, 154.f, 155.f, 156.f, 157.f, 158.f, 159.f
+, 160.f, 161.f, 162.f, 163.f, 164.f, 165.f, 166.f, 167.f, 168.f, 169.f
+, 170.f, 171.f, 172.f, 173.f, 174.f, 175.f, 176.f, 177.f, 178.f, 179.f
+, 180.f, 181.f, 182.f, 183.f, 184.f, 185.f, 186.f, 187.f, 188.f, 189.f
+, 190.f, 191.f, 192.f, 193.f, 194.f, 195.f, 196.f, 197.f, 198.f, 199.f
+, 200.f, 201.f, 202.f, 203.f, 204.f, 205.f, 206.f, 207.f, 208.f, 209.f
+, 210.f, 211.f, 212.f, 213.f, 214.f, 215.f, 216.f, 217.f, 218.f, 219.f
+, 220.f, 221.f, 222.f, 223.f, 224.f, 225.f, 226.f, 227.f, 228.f, 229.f
+, 230.f, 231.f, 232.f, 233.f, 234.f, 235.f, 236.f, 237.f, 238.f, 239.f
+, 240.f, 241.f, 242.f, 243.f, 244.f, 245.f, 246.f, 247.f, 248.f, 249.f
+, 250.f, 251.f, 252.f, 253.f, 254.f, 255.f, 256.f, 257.f, 258.f, 259.f };
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_float_t __get_movie_layer_transformation_property_fixed( ae_constvoidptr_t _property, ae_uint32_t _index )
+{
+    ae_uint32_t property_block_offset[4] = { 1U, 3U, 2U, 0U };
+
+    ae_uint32_t property_index = 0U;
+
+    const ae_uint32_t * property_ae_uint32_t = (const ae_uint32_t *)_property;
+
+    ae_uint32_t zp_block_type_count_data = *(property_ae_uint32_t++);
+
+    ae_uint32_t zp_block_type = zp_block_type_count_data >> 24U;
+    ae_uint32_t zp_block_count = zp_block_type_count_data & 0x00FFFFFF;
+
+    while( property_index + zp_block_count <= _index )
+    {
+        property_block_offset[3] = zp_block_count;
+
+        property_ae_uint32_t += property_block_offset[zp_block_type];
+
+        property_index += zp_block_count;
+
+        ae_uint32_t zp_block_type_count_data_next = *(property_ae_uint32_t++);
+
+        zp_block_type = zp_block_type_count_data_next >> 24U;
+        zp_block_count = zp_block_type_count_data_next & 0x00FFFFFF;
+    }
+
+    const ae_float_t * property_ae_float_t = (const ae_float_t *)(ae_constvoidptr_t)(property_ae_uint32_t);
+
+    switch( zp_block_type )
+    {
+    case 0:
+        {
+            ae_float_t block_value = property_ae_float_t[0];
+
+            return block_value;
+        }break;
+    case 1:
+        {
+            ae_float_t block_inv = property_ae_float_t[0];
+            ae_float_t block_begin = property_ae_float_t[1];
+            ae_float_t block_end = property_ae_float_t[2];
+
+            ae_uint32_t block_index = _index - property_index;
+            ae_float_t block_index_f = (ae_float_t)block_index;
+
+            ae_float_t block_t = block_index_f * block_inv;
+
+            ae_float_t block_value = block_begin + (block_end - block_begin) * block_t;
+
+            return block_value;
+        }break;
+    case 2:
+        {
+            const ae_float_t block_inv = one_div_index256[zp_block_count - 1];
+            ae_float_t block_begin = property_ae_float_t[0];
+            ae_float_t block_end = property_ae_float_t[1];
+
+            ae_uint32_t block_index = _index - property_index;
+            const ae_float_t block_index_f = index256_to_float[block_index];
+
+            ae_float_t block_t = block_index_f * block_inv;
+
+            ae_float_t block_value = block_begin + (block_end - block_begin) * block_t;
+
+            return block_value;
+        }break;
+    case 3:
+        {
+            ae_uint32_t block_index = _index - property_index;
+
+            ae_float_t block_value = property_ae_float_t[block_index];
+
+            return block_value;
+        }break;
+    default:
+        {
+            //Error
+        }break;
+    }
+
+    __movie_break_point();
+
+    return 0.f;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_float_t __get_movie_layer_transformation_property_interpolate( ae_constvoidptr_t _property, ae_uint32_t _index, ae_float_t _t )
+{
+    ae_float_t data_0 = __get_movie_layer_transformation_property_fixed( _property, _index + 0 );
+    ae_float_t data_1 = __get_movie_layer_transformation_property_fixed( _property, _index + 1 );
+
+    ae_float_t data = ae_linerp_f1( data_0, data_1, _t );
+
+    return data;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __make_movie_layer_transformation2d_immutable( ae_matrix34_t _out, const aeMovieLayerTransformation2D * _transformation )
+{
+    ae_vector2_t anchor_point;
+    anchor_point[0] = _transformation->immutable.anchor_point_x;
+    anchor_point[1] = _transformation->immutable.anchor_point_y;
+
+    ae_vector2_t position;
+    position[0] = _transformation->immutable.position_x;
+    position[1] = _transformation->immutable.position_y;
+
+    ae_vector2_t scale;
+    scale[0] = _transformation->immutable.scale_x;
+    scale[1] = _transformation->immutable.scale_y;
+
+    ae_quaternionzw_t quaternionzw;
+    quaternionzw[0] = _transformation->immutable.quaternion_z;
+    quaternionzw[1] = _transformation->immutable.quaternion_w;
+
+    ae_skew_t skew;
+    skew[0] = _transformation->immutable.skew;
+    skew[1] = _transformation->immutable.skew_quaternion_z;
+    skew[2] = _transformation->immutable.skew_quaternion_w;
+
+    ae_movie_make_transformation2d_m34( _out, position, anchor_point, scale, quaternionzw, skew );
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __make_movie_layer_transformation3d_immutable( ae_matrix34_t _out, const aeMovieLayerTransformation3D * _transformation )
+{
+    ae_vector3_t anchor_point;
+    anchor_point[0] = _transformation->immutable.anchor_point_x;
+    anchor_point[1] = _transformation->immutable.anchor_point_y;
+    anchor_point[2] = _transformation->immutable.anchor_point_z;
+
+    ae_vector3_t position;
+    position[0] = _transformation->immutable.position_x;
+    position[1] = _transformation->immutable.position_y;
+    position[2] = _transformation->immutable.position_z;
+
+    ae_vector3_t scale;
+    scale[0] = _transformation->immutable.scale_x;
+    scale[1] = _transformation->immutable.scale_y;
+    scale[2] = _transformation->immutable.scale_z;
+
+    ae_quaternion_t quaternion;
+    quaternion[0] = _transformation->immutable.quaternion_x;
+    quaternion[1] = _transformation->immutable.quaternion_y;
+    quaternion[2] = _transformation->immutable.quaternion_z;
+    quaternion[3] = _transformation->immutable.quaternion_w;
+
+    ae_skew_t skew;
+    skew[0] = _transformation->immutable.skew;
+    skew[1] = _transformation->immutable.skew_quaternion_z;
+    skew[2] = _transformation->immutable.skew_quaternion_w;
+
+    ae_movie_make_transformation3d_m34( _out, position, anchor_point, scale, quaternion, skew );
+}
+//////////////////////////////////////////////////////////////////////////
+#define AE_STREAM_PROPERTY(Mask, Name, Default)\
+    if( identity_property_mask & Mask )\
+    {\
+        _transformation->immutable.Name = Default;\
+        if( _transformation->timeline != AE_NULLPTR ) {_transformation->timeline->Name = AE_NULLPTR;}\
+    }\
+	else if( immutable_property_mask & Mask )\
+	{\
+		AE_READ( _stream, _transformation->immutable.Name );\
+		if( _transformation->timeline != AE_NULLPTR ) {_transformation->timeline->Name = AE_NULLPTR;}\
+	}\
+	else\
+	{\
+		_transformation->immutable.Name = 0.f;\
+		_transformation->timeline->Name = __load_movie_layer_transformation_timeline(_stream, #Name);\
+        AE_RESULT_PANIC_MEMORY(_transformation->timeline->Name);\
+	}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_result_t __load_movie_layer_transformation2d( aeMovieStream * _stream, aeMovieLayerTransformation2D * _transformation )
+{
+    ae_uint32_t immutable_property_mask = _transformation->immutable_property_mask;
+    ae_uint32_t identity_property_mask = _transformation->identity_property_mask;
+
+    AE_STREAM_PROPERTY( AE_MOVIE_PROPERTY_ANCHOR_POINT_X, anchor_point_x, 0.f );
+    AE_STREAM_PROPERTY( AE_MOVIE_PROPERTY_ANCHOR_POINT_Y, anchor_point_y, 0.f );
+
+    AE_STREAM_PROPERTY( AE_MOVIE_PROPERTY_POSITION_X, position_x, 0.f );
+    AE_STREAM_PROPERTY( AE_MOVIE_PROPERTY_POSITION_Y, position_y, 0.f );
+
+    AE_STREAM_PROPERTY( AE_MOVIE_PROPERTY_SCALE_X, scale_x, 1.f );
+    AE_STREAM_PROPERTY( AE_MOVIE_PROPERTY_SCALE_Y, scale_y, 1.f );
+
+    AE_STREAM_PROPERTY( AE_MOVIE_PROPERTY_QUATERNION_Z, quaternion_z, 0.f );
+    AE_STREAM_PROPERTY( AE_MOVIE_PROPERTY_QUATERNION_W, quaternion_w, 1.f );
+
+    AE_STREAM_PROPERTY( AE_MOVIE_PROPERTY_SKEW, skew, 0.f );
+    AE_STREAM_PROPERTY( AE_MOVIE_PROPERTY_SKEW_QUATERNION_Z, skew_quaternion_z, 0.f );
+    AE_STREAM_PROPERTY( AE_MOVIE_PROPERTY_SKEW_QUATERNION_W, skew_quaternion_w, 1.f );
+
+    if( (_transformation->immutable_property_mask & AE_MOVIE_PROPERTY_TRANSFORM_SUPER_ALL) == AE_MOVIE_PROPERTY_TRANSFORM_SUPER_ALL )
+    {
+        ae_matrix34_t * immutable_matrix = AE_NEW( _stream->instance, ae_matrix34_t );
+
+        AE_MOVIE_PANIC_MEMORY( immutable_matrix, AE_RESULT_INVALID_MEMORY );
+
+        __make_movie_layer_transformation2d_immutable( *immutable_matrix, _transformation );
+
+        _transformation->immutable_matrix = immutable_matrix;
+    }
+    else
+    {
+        _transformation->immutable_matrix = AE_NULLPTR;
+    }
+
+    return AE_RESULT_SUCCESSFUL;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_result_t __load_movie_layer_transformation3d( aeMovieStream * _stream, aeMovieLayerTransformation3D * _transformation )
+{
+    ae_uint32_t immutable_property_mask = _transformation->immutable_property_mask;
+    ae_uint32_t identity_property_mask = _transformation->identity_property_mask;
+
+    AE_STREAM_PROPERTY( AE_MOVIE_PROPERTY_ANCHOR_POINT_X, anchor_point_x, 0.f );
+    AE_STREAM_PROPERTY( AE_MOVIE_PROPERTY_ANCHOR_POINT_Y, anchor_point_y, 0.f );
+    AE_STREAM_PROPERTY( AE_MOVIE_PROPERTY_ANCHOR_POINT_Z, anchor_point_z, 0.f );
+
+    AE_STREAM_PROPERTY( AE_MOVIE_PROPERTY_POSITION_X, position_x, 0.f );
+    AE_STREAM_PROPERTY( AE_MOVIE_PROPERTY_POSITION_Y, position_y, 0.f );
+    AE_STREAM_PROPERTY( AE_MOVIE_PROPERTY_POSITION_Z, position_z, 0.f );
+
+    AE_STREAM_PROPERTY( AE_MOVIE_PROPERTY_SCALE_X, scale_x, 1.f );
+    AE_STREAM_PROPERTY( AE_MOVIE_PROPERTY_SCALE_Y, scale_y, 1.f );
+    AE_STREAM_PROPERTY( AE_MOVIE_PROPERTY_SCALE_Z, scale_z, 1.f );
+
+    AE_STREAM_PROPERTY( AE_MOVIE_PROPERTY_QUATERNION_X, quaternion_x, 0.f );
+    AE_STREAM_PROPERTY( AE_MOVIE_PROPERTY_QUATERNION_Y, quaternion_y, 0.f );
+    AE_STREAM_PROPERTY( AE_MOVIE_PROPERTY_QUATERNION_Z, quaternion_z, 0.f );
+    AE_STREAM_PROPERTY( AE_MOVIE_PROPERTY_QUATERNION_W, quaternion_w, 1.f );
+
+    AE_STREAM_PROPERTY( AE_MOVIE_PROPERTY_SKEW, skew, 0.f );
+    AE_STREAM_PROPERTY( AE_MOVIE_PROPERTY_SKEW_QUATERNION_Z, skew_quaternion_z, 0.f );
+    AE_STREAM_PROPERTY( AE_MOVIE_PROPERTY_SKEW_QUATERNION_W, skew_quaternion_w, 1.f );
+
+    if( (_transformation->immutable_property_mask & AE_MOVIE_PROPERTY_TRANSFORM_SUPER_ALL) == AE_MOVIE_PROPERTY_TRANSFORM_SUPER_ALL )
+    {
+        ae_matrix34_t * immutable_matrix = AE_NEW( _stream->instance, ae_matrix34_t );
+
+        AE_MOVIE_PANIC_MEMORY( immutable_matrix, AE_RESULT_INVALID_MEMORY );
+
+        __make_movie_layer_transformation3d_immutable( *immutable_matrix, _transformation );
+
+        _transformation->immutable_matrix = immutable_matrix;
+    }
+    else
+    {
+        _transformation->immutable_matrix = AE_NULLPTR;
+    }
+
+    return AE_RESULT_SUCCESSFUL;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_CALLBACK ae_void_t __make_layer_transformation_interpolate_identity( ae_matrix34_t _out, const aeMovieLayerTransformation * _transformation, ae_uint32_t _index, ae_float_t _t )
+{
+    AE_UNUSED( _out );
+    AE_UNUSED( _transformation );
+    AE_UNUSED( _index );
+    AE_UNUSED( _t );
+}
+//////////////////////////////////////////////////////////////////////////
+AE_CALLBACK ae_void_t __make_layer_transformation_fixed_identity( ae_matrix34_t _out, const aeMovieLayerTransformation * _transformation, ae_uint32_t _index )
+{
+    AE_UNUSED( _out );
+    AE_UNUSED( _transformation );
+    AE_UNUSED( _index );
+}
+//////////////////////////////////////////////////////////////////////////
+AE_CALLBACK ae_void_t __make_layer_transformation_interpolate_immutable( ae_matrix34_t _out, const aeMovieLayerTransformation * _transformation, ae_uint32_t _index, ae_float_t _t )
+{
+    AE_UNUSED( _index );
+    AE_UNUSED( _t );
+
+    ae_copy_m34( _out, *_transformation->immutable_matrix );
+}
+//////////////////////////////////////////////////////////////////////////
+AE_CALLBACK ae_void_t __make_layer_transformation_fixed_immutable( ae_matrix34_t _out, const aeMovieLayerTransformation * _transformation, ae_uint32_t _index )
+{
+    AE_UNUSED( _index );
+
+    ae_copy_m34( _out, *_transformation->immutable_matrix );
+}
+//////////////////////////////////////////////////////////////////////////
+#define AE_INTERPOLATE_PROPERTY( Transformation, Name, OutName )\
+	OutName = (Transformation->timeline == AE_NULLPTR || Transformation->timeline->Name == AE_NULLPTR) ? Transformation->immutable.Name : __get_movie_layer_transformation_property_interpolate(\
+		Transformation->timeline->Name,\
+		_index, _t )
+//////////////////////////////////////////////////////////////////////////
+#define AE_FIXED_PROPERTY( Transformation, Name, Index, OutName)\
+	OutName = (Transformation->timeline == AE_NULLPTR || Transformation->timeline->Name == AE_NULLPTR) ? Transformation->immutable.Name : __get_movie_layer_transformation_property_fixed(\
+		Transformation->timeline->Name,\
+		_index + Index )
+//////////////////////////////////////////////////////////////////////////
+AE_CALLBACK ae_void_t __make_layer_transformation2d_interpolate( ae_matrix34_t _out, const aeMovieLayerTransformation * _transformation, ae_uint32_t _index, ae_float_t _t )
+{
+    const aeMovieLayerTransformation2D * transformation2d = (const aeMovieLayerTransformation2D *)_transformation;
+
+    ae_vector2_t anchor_point;
+    ae_vector2_t position;
+    ae_vector2_t scale;
+    ae_quaternionzw_t quaternion;
+    ae_skew_t skew;
+
+    AE_INTERPOLATE_PROPERTY( transformation2d, anchor_point_x, anchor_point[0] );
+    AE_INTERPOLATE_PROPERTY( transformation2d, anchor_point_y, anchor_point[1] );
+
+    AE_INTERPOLATE_PROPERTY( transformation2d, position_x, position[0] );
+    AE_INTERPOLATE_PROPERTY( transformation2d, position_y, position[1] );
+
+    AE_INTERPOLATE_PROPERTY( transformation2d, scale_x, scale[0] );
+    AE_INTERPOLATE_PROPERTY( transformation2d, scale_y, scale[1] );
+
+    ae_quaternionzw_t q1;
+    AE_FIXED_PROPERTY( transformation2d, quaternion_z, 0, q1[0] );
+    AE_FIXED_PROPERTY( transformation2d, quaternion_w, 0, q1[1] );
+
+    ae_quaternionzw_t q2;
+    AE_FIXED_PROPERTY( transformation2d, quaternion_z, 1, q2[0] );
+    AE_FIXED_PROPERTY( transformation2d, quaternion_w, 1, q2[1] );
+
+    ae_linerp_qzw( quaternion, q1, q2, _t );
+
+    AE_INTERPOLATE_PROPERTY( transformation2d, skew, skew[0] );
+    AE_INTERPOLATE_PROPERTY( transformation2d, skew_quaternion_z, skew[1] );
+    AE_INTERPOLATE_PROPERTY( transformation2d, skew_quaternion_w, skew[2] );
+
+    ae_movie_make_transformation2d_m34( _out, position, anchor_point, scale, quaternion, skew );
+}
+//////////////////////////////////////////////////////////////////////////
+AE_CALLBACK ae_void_t __make_layer_transformation2d_interpolate_fq( ae_matrix34_t _out, const aeMovieLayerTransformation * _transformation, ae_uint32_t _index, ae_float_t _t )
+{
+    const aeMovieLayerTransformation2D * transformation2d = (const aeMovieLayerTransformation2D *)_transformation;
+
+    ae_vector2_t anchor_point;
+    ae_vector2_t position;
+    ae_vector2_t scale;
+    ae_quaternionzw_t quaternion;
+    ae_skew_t skew;
+
+    AE_INTERPOLATE_PROPERTY( transformation2d, anchor_point_x, anchor_point[0] );
+    AE_INTERPOLATE_PROPERTY( transformation2d, anchor_point_y, anchor_point[1] );
+
+    AE_INTERPOLATE_PROPERTY( transformation2d, position_x, position[0] );
+    AE_INTERPOLATE_PROPERTY( transformation2d, position_y, position[1] );
+
+    AE_INTERPOLATE_PROPERTY( transformation2d, scale_x, scale[0] );
+    AE_INTERPOLATE_PROPERTY( transformation2d, scale_y, scale[1] );
+
+    AE_FIXED_PROPERTY( transformation2d, quaternion_z, 0, quaternion[0] );
+    AE_FIXED_PROPERTY( transformation2d, quaternion_w, 0, quaternion[1] );
+
+    AE_INTERPOLATE_PROPERTY( transformation2d, skew, skew[0] );
+    AE_INTERPOLATE_PROPERTY( transformation2d, skew_quaternion_z, skew[1] );
+    AE_INTERPOLATE_PROPERTY( transformation2d, skew_quaternion_w, skew[2] );
+
+    ae_movie_make_transformation2d_m34( _out, position, anchor_point, scale, quaternion, skew );
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __make_layer_transformation2d_interpolate_wskfq( ae_matrix34_t _out, const aeMovieLayerTransformation * _transformation, ae_uint32_t _index, ae_float_t _t )
+{
+    const aeMovieLayerTransformation2D * transformation2d = (const aeMovieLayerTransformation2D *)_transformation;
+
+    ae_vector2_t anchor_point;
+    ae_vector2_t position;
+    ae_vector2_t scale;
+    ae_quaternionzw_t quaternion;
+
+    AE_INTERPOLATE_PROPERTY( transformation2d, anchor_point_x, anchor_point[0] );
+    AE_INTERPOLATE_PROPERTY( transformation2d, anchor_point_y, anchor_point[1] );
+
+    AE_INTERPOLATE_PROPERTY( transformation2d, position_x, position[0] );
+    AE_INTERPOLATE_PROPERTY( transformation2d, position_y, position[1] );
+
+    AE_INTERPOLATE_PROPERTY( transformation2d, scale_x, scale[0] );
+    AE_INTERPOLATE_PROPERTY( transformation2d, scale_y, scale[1] );
+
+    AE_FIXED_PROPERTY( transformation2d, quaternion_z, 0, quaternion[0] );
+    AE_FIXED_PROPERTY( transformation2d, quaternion_w, 0, quaternion[1] );
+
+    ae_movie_make_transformation2d_m34wsk( _out, position, anchor_point, scale, quaternion );
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __make_layer_transformation2d_fixed( ae_matrix34_t _out, const aeMovieLayerTransformation * _transformation, ae_uint32_t _index )
+{
+    const aeMovieLayerTransformation2D * transformation2d = (const aeMovieLayerTransformation2D *)_transformation;
+
+    ae_vector2_t anchor_point;
+    ae_vector2_t position;
+    ae_vector2_t scale;
+    ae_quaternionzw_t quaternion;
+    ae_skew_t skew;
+
+    AE_FIXED_PROPERTY( transformation2d, anchor_point_x, 0, anchor_point[0] );
+    AE_FIXED_PROPERTY( transformation2d, anchor_point_y, 0, anchor_point[1] );
+
+    AE_FIXED_PROPERTY( transformation2d, position_x, 0, position[0] );
+    AE_FIXED_PROPERTY( transformation2d, position_y, 0, position[1] );
+
+    AE_FIXED_PROPERTY( transformation2d, scale_x, 0, scale[0] );
+    AE_FIXED_PROPERTY( transformation2d, scale_y, 0, scale[1] );
+
+    AE_FIXED_PROPERTY( transformation2d, quaternion_z, 0, quaternion[0] );
+    AE_FIXED_PROPERTY( transformation2d, quaternion_w, 0, quaternion[1] );
+
+    AE_FIXED_PROPERTY( transformation2d, skew, 0, skew[0] );
+    AE_FIXED_PROPERTY( transformation2d, skew_quaternion_z, 0, skew[1] );
+    AE_FIXED_PROPERTY( transformation2d, skew_quaternion_w, 0, skew[2] );
+
+    ae_movie_make_transformation2d_m34( _out, position, anchor_point, scale, quaternion, skew );
+}
+//////////////////////////////////////////////////////////////////////////
+AE_CALLBACK ae_void_t __make_layer_transformation2d_interpolate_wq( ae_matrix34_t _out, const aeMovieLayerTransformation * _transformation, ae_uint32_t _index, ae_float_t _t )
+{
+    const aeMovieLayerTransformation2D * transformation2d = (const aeMovieLayerTransformation2D *)_transformation;
+
+    ae_vector2_t anchor_point;
+    ae_vector2_t position;
+    ae_vector2_t scale;
+    ae_skew_t skew;
+
+    AE_INTERPOLATE_PROPERTY( transformation2d, anchor_point_x, anchor_point[0] );
+    AE_INTERPOLATE_PROPERTY( transformation2d, anchor_point_y, anchor_point[1] );
+
+    AE_INTERPOLATE_PROPERTY( transformation2d, position_x, position[0] );
+    AE_INTERPOLATE_PROPERTY( transformation2d, position_y, position[1] );
+
+    AE_INTERPOLATE_PROPERTY( transformation2d, scale_x, scale[0] );
+    AE_INTERPOLATE_PROPERTY( transformation2d, scale_y, scale[1] );
+
+    AE_INTERPOLATE_PROPERTY( transformation2d, skew, skew[0] );
+    AE_INTERPOLATE_PROPERTY( transformation2d, skew_quaternion_z, skew[1] );
+    AE_INTERPOLATE_PROPERTY( transformation2d, skew_quaternion_w, skew[2] );
+
+    ae_movie_make_transformation2d_m34wq( _out, position, anchor_point, scale, skew );
+}
+//////////////////////////////////////////////////////////////////////////
+AE_CALLBACK ae_void_t __make_layer_transformation2d_fixed_wq( ae_matrix34_t _out, const aeMovieLayerTransformation * _transformation, ae_uint32_t _index )
+{
+    const aeMovieLayerTransformation2D * transformation2d = (const aeMovieLayerTransformation2D *)_transformation;
+
+    ae_vector2_t anchor_point;
+    ae_vector2_t position;
+    ae_vector2_t scale;
+    ae_skew_t skew;
+
+    AE_FIXED_PROPERTY( transformation2d, anchor_point_x, 0, anchor_point[0] );
+    AE_FIXED_PROPERTY( transformation2d, anchor_point_y, 0, anchor_point[1] );
+
+    AE_FIXED_PROPERTY( transformation2d, position_x, 0, position[0] );
+    AE_FIXED_PROPERTY( transformation2d, position_y, 0, position[1] );
+
+    AE_FIXED_PROPERTY( transformation2d, scale_x, 0, scale[0] );
+    AE_FIXED_PROPERTY( transformation2d, scale_y, 0, scale[1] );
+
+    AE_FIXED_PROPERTY( transformation2d, skew, 0, skew[0] );
+    AE_FIXED_PROPERTY( transformation2d, skew_quaternion_z, 0, skew[1] );
+    AE_FIXED_PROPERTY( transformation2d, skew_quaternion_w, 0, skew[2] );
+
+    ae_movie_make_transformation2d_m34wq( _out, position, anchor_point, scale, skew );
+}
+//////////////////////////////////////////////////////////////////////////
+AE_CALLBACK ae_void_t __make_layer_transformation2d_interpolate_wskq( ae_matrix34_t _out, const aeMovieLayerTransformation * _transformation, ae_uint32_t _index, ae_float_t _t )
+{
+    const aeMovieLayerTransformation2D * transformation2d = (const aeMovieLayerTransformation2D *)_transformation;
+
+    ae_vector2_t anchor_point;
+    ae_vector2_t position;
+    ae_vector2_t scale;
+
+    AE_INTERPOLATE_PROPERTY( transformation2d, anchor_point_x, anchor_point[0] );
+    AE_INTERPOLATE_PROPERTY( transformation2d, anchor_point_y, anchor_point[1] );
+
+    AE_INTERPOLATE_PROPERTY( transformation2d, position_x, position[0] );
+    AE_INTERPOLATE_PROPERTY( transformation2d, position_y, position[1] );
+
+    AE_INTERPOLATE_PROPERTY( transformation2d, scale_x, scale[0] );
+    AE_INTERPOLATE_PROPERTY( transformation2d, scale_y, scale[1] );
+
+    ae_movie_make_transformation2d_m34wskq( _out, position, anchor_point, scale );
+}
+//////////////////////////////////////////////////////////////////////////
+AE_CALLBACK ae_void_t __make_layer_transformation2d_fixed_wskq( ae_matrix34_t _out, const aeMovieLayerTransformation * _transformation, ae_uint32_t _index )
+{
+    const aeMovieLayerTransformation2D * transformation2d = (const aeMovieLayerTransformation2D *)_transformation;
+
+    ae_vector2_t anchor_point;
+    ae_vector2_t position;
+    ae_vector2_t scale;
+
+    AE_FIXED_PROPERTY( transformation2d, anchor_point_x, 0, anchor_point[0] );
+    AE_FIXED_PROPERTY( transformation2d, anchor_point_y, 0, anchor_point[1] );
+
+    AE_FIXED_PROPERTY( transformation2d, position_x, 0, position[0] );
+    AE_FIXED_PROPERTY( transformation2d, position_y, 0, position[1] );
+
+    AE_FIXED_PROPERTY( transformation2d, scale_x, 0, scale[0] );
+    AE_FIXED_PROPERTY( transformation2d, scale_y, 0, scale[1] );
+
+    ae_movie_make_transformation2d_m34wskq( _out, position, anchor_point, scale );
+}
+//////////////////////////////////////////////////////////////////////////
+AE_CALLBACK ae_void_t __make_layer_transformation2d_interpolate_wsk( ae_matrix34_t _out, const aeMovieLayerTransformation * _transformation, ae_uint32_t _index, ae_float_t _t )
+{
+    const aeMovieLayerTransformation2D * transformation2d = (const aeMovieLayerTransformation2D *)_transformation;
+
+    ae_vector2_t anchor_point;
+    ae_vector2_t position;
+    ae_vector2_t scale;
+    ae_quaternionzw_t quaternion;
+
+    AE_INTERPOLATE_PROPERTY( transformation2d, anchor_point_x, anchor_point[0] );
+    AE_INTERPOLATE_PROPERTY( transformation2d, anchor_point_y, anchor_point[1] );
+
+    AE_INTERPOLATE_PROPERTY( transformation2d, position_x, position[0] );
+    AE_INTERPOLATE_PROPERTY( transformation2d, position_y, position[1] );
+
+    AE_INTERPOLATE_PROPERTY( transformation2d, scale_x, scale[0] );
+    AE_INTERPOLATE_PROPERTY( transformation2d, scale_y, scale[1] );
+
+    ae_quaternionzw_t q1;
+    AE_FIXED_PROPERTY( transformation2d, quaternion_z, 0, q1[0] );
+    AE_FIXED_PROPERTY( transformation2d, quaternion_w, 0, q1[1] );
+
+    ae_quaternionzw_t q2;
+    AE_FIXED_PROPERTY( transformation2d, quaternion_z, 1, q2[0] );
+    AE_FIXED_PROPERTY( transformation2d, quaternion_w, 1, q2[1] );
+
+    ae_linerp_qzw( quaternion, q1, q2, _t );
+
+    ae_movie_make_transformation2d_m34wsk( _out, position, anchor_point, scale, quaternion );
+}
+//////////////////////////////////////////////////////////////////////////
+AE_CALLBACK ae_void_t __make_layer_transformation2d_fixed_wsk( ae_matrix34_t _out, const aeMovieLayerTransformation * _transformation, ae_uint32_t _index )
+{
+    const aeMovieLayerTransformation2D * transformation2d = (const aeMovieLayerTransformation2D *)_transformation;
+
+    ae_vector2_t anchor_point;
+    ae_vector2_t position;
+    ae_vector2_t scale;
+    ae_quaternionzw_t quaternion;
+
+    AE_FIXED_PROPERTY( transformation2d, anchor_point_x, 0, anchor_point[0] );
+    AE_FIXED_PROPERTY( transformation2d, anchor_point_y, 0, anchor_point[1] );
+
+    AE_FIXED_PROPERTY( transformation2d, position_x, 0, position[0] );
+    AE_FIXED_PROPERTY( transformation2d, position_y, 0, position[1] );
+
+    AE_FIXED_PROPERTY( transformation2d, scale_x, 0, scale[0] );
+    AE_FIXED_PROPERTY( transformation2d, scale_y, 0, scale[1] );
+
+    AE_FIXED_PROPERTY( transformation2d, quaternion_z, 0, quaternion[0] );
+    AE_FIXED_PROPERTY( transformation2d, quaternion_w, 0, quaternion[1] );
+
+    ae_movie_make_transformation2d_m34wsk( _out, position, anchor_point, scale, quaternion );
+}
+//////////////////////////////////////////////////////////////////////////
+AE_CALLBACK ae_void_t __make_layer_transformation3d_fixed( ae_matrix34_t _out, const aeMovieLayerTransformation * _transformation, ae_uint32_t _index )
+{
+    const aeMovieLayerTransformation3D * transformation3d = (const aeMovieLayerTransformation3D *)_transformation;
+
+    ae_vector3_t anchor_point;
+    ae_vector3_t position;
+    ae_vector3_t scale;
+    ae_quaternion_t quaternion;
+    ae_skew_t skew;
+
+    AE_FIXED_PROPERTY( transformation3d, anchor_point_x, 0, anchor_point[0] );
+    AE_FIXED_PROPERTY( transformation3d, anchor_point_y, 0, anchor_point[1] );
+    AE_FIXED_PROPERTY( transformation3d, anchor_point_z, 0, anchor_point[2] );
+
+    AE_FIXED_PROPERTY( transformation3d, position_x, 0, position[0] );
+    AE_FIXED_PROPERTY( transformation3d, position_y, 0, position[1] );
+    AE_FIXED_PROPERTY( transformation3d, position_z, 0, position[2] );
+
+    AE_FIXED_PROPERTY( transformation3d, scale_x, 0, scale[0] );
+    AE_FIXED_PROPERTY( transformation3d, scale_y, 0, scale[1] );
+    AE_FIXED_PROPERTY( transformation3d, scale_z, 0, scale[2] );
+
+    AE_FIXED_PROPERTY( transformation3d, quaternion_x, 0, quaternion[0] );
+    AE_FIXED_PROPERTY( transformation3d, quaternion_y, 0, quaternion[1] );
+    AE_FIXED_PROPERTY( transformation3d, quaternion_z, 0, quaternion[2] );
+    AE_FIXED_PROPERTY( transformation3d, quaternion_w, 0, quaternion[3] );
+
+    AE_FIXED_PROPERTY( transformation3d, skew, 0, skew[0] );
+    AE_FIXED_PROPERTY( transformation3d, skew_quaternion_z, 0, skew[1] );
+    AE_FIXED_PROPERTY( transformation3d, skew_quaternion_w, 0, skew[2] );
+
+    ae_movie_make_transformation3d_m34( _out, position, anchor_point, scale, quaternion, skew );
+}
+//////////////////////////////////////////////////////////////////////////
+AE_CALLBACK ae_void_t __make_layer_transformation3d_fixed_wq( ae_matrix34_t _out, const aeMovieLayerTransformation * _transformation, ae_uint32_t _index )
+{
+    const aeMovieLayerTransformation3D * transformation3d = (const aeMovieLayerTransformation3D *)_transformation;
+
+    ae_vector3_t anchor_point;
+    ae_vector3_t position;
+    ae_vector3_t scale;
+    ae_skew_t skew;
+
+    AE_FIXED_PROPERTY( transformation3d, anchor_point_x, 0, anchor_point[0] );
+    AE_FIXED_PROPERTY( transformation3d, anchor_point_y, 0, anchor_point[1] );
+    AE_FIXED_PROPERTY( transformation3d, anchor_point_z, 0, anchor_point[2] );
+
+    AE_FIXED_PROPERTY( transformation3d, position_x, 0, position[0] );
+    AE_FIXED_PROPERTY( transformation3d, position_y, 0, position[1] );
+    AE_FIXED_PROPERTY( transformation3d, position_z, 0, position[2] );
+
+    AE_FIXED_PROPERTY( transformation3d, scale_x, 0, scale[0] );
+    AE_FIXED_PROPERTY( transformation3d, scale_y, 0, scale[1] );
+    AE_FIXED_PROPERTY( transformation3d, scale_z, 0, scale[2] );
+
+    AE_FIXED_PROPERTY( transformation3d, skew, 0, skew[0] );
+    AE_FIXED_PROPERTY( transformation3d, skew_quaternion_z, 0, skew[1] );
+    AE_FIXED_PROPERTY( transformation3d, skew_quaternion_w, 0, skew[2] );
+
+    ae_movie_make_transformation3d_m34wq( _out, position, anchor_point, scale, skew );
+}
+//////////////////////////////////////////////////////////////////////////
+AE_CALLBACK ae_void_t __make_layer_transformation3d_interpolate_wq( ae_matrix34_t _out, const aeMovieLayerTransformation * _transformation, ae_uint32_t _index, ae_float_t _t )
+{
+    const aeMovieLayerTransformation3D * transformation3d = (const aeMovieLayerTransformation3D *)_transformation;
+
+    ae_vector3_t anchor_point;
+    ae_vector3_t position;
+    ae_vector3_t scale;
+    ae_skew_t skew;
+
+    AE_INTERPOLATE_PROPERTY( transformation3d, anchor_point_x, anchor_point[0] );
+    AE_INTERPOLATE_PROPERTY( transformation3d, anchor_point_y, anchor_point[1] );
+    AE_INTERPOLATE_PROPERTY( transformation3d, anchor_point_z, anchor_point[2] );
+
+    AE_INTERPOLATE_PROPERTY( transformation3d, position_x, position[0] );
+    AE_INTERPOLATE_PROPERTY( transformation3d, position_y, position[1] );
+    AE_INTERPOLATE_PROPERTY( transformation3d, position_z, position[2] );
+
+    AE_INTERPOLATE_PROPERTY( transformation3d, scale_x, scale[0] );
+    AE_INTERPOLATE_PROPERTY( transformation3d, scale_y, scale[1] );
+    AE_INTERPOLATE_PROPERTY( transformation3d, scale_z, scale[2] );
+
+    AE_INTERPOLATE_PROPERTY( transformation3d, skew, skew[0] );
+    AE_INTERPOLATE_PROPERTY( transformation3d, skew_quaternion_z, skew[1] );
+    AE_INTERPOLATE_PROPERTY( transformation3d, skew_quaternion_w, skew[2] );
+
+    ae_movie_make_transformation3d_m34wq( _out, position, anchor_point, scale, skew );
+}
+//////////////////////////////////////////////////////////////////////////
+AE_CALLBACK ae_void_t __make_layer_transformation3d_interpolate_wskq( ae_matrix34_t _out, const aeMovieLayerTransformation * _transformation, ae_uint32_t _index, ae_float_t _t )
+{
+    const aeMovieLayerTransformation3D * transformation3d = (const aeMovieLayerTransformation3D *)_transformation;
+
+    ae_vector3_t anchor_point;
+    ae_vector3_t position;
+    ae_vector3_t scale;
+
+    AE_INTERPOLATE_PROPERTY( transformation3d, anchor_point_x, anchor_point[0] );
+    AE_INTERPOLATE_PROPERTY( transformation3d, anchor_point_y, anchor_point[1] );
+    AE_INTERPOLATE_PROPERTY( transformation3d, anchor_point_z, anchor_point[2] );
+
+    AE_INTERPOLATE_PROPERTY( transformation3d, position_x, position[0] );
+    AE_INTERPOLATE_PROPERTY( transformation3d, position_y, position[1] );
+    AE_INTERPOLATE_PROPERTY( transformation3d, position_z, position[2] );
+
+    AE_INTERPOLATE_PROPERTY( transformation3d, scale_x, scale[0] );
+    AE_INTERPOLATE_PROPERTY( transformation3d, scale_y, scale[1] );
+    AE_INTERPOLATE_PROPERTY( transformation3d, scale_z, scale[2] );
+
+    ae_movie_make_transformation3d_m34wskq( _out, position, anchor_point, scale );
+}
+//////////////////////////////////////////////////////////////////////////
+AE_CALLBACK ae_void_t __make_layer_transformation3d_fixed_wskq( ae_matrix34_t _out, const aeMovieLayerTransformation * _transformation, ae_uint32_t _index )
+{
+    const aeMovieLayerTransformation3D * transformation3d = (const aeMovieLayerTransformation3D *)_transformation;
+
+    ae_vector3_t anchor_point;
+    ae_vector3_t position;
+    ae_vector3_t scale;
+
+    AE_FIXED_PROPERTY( transformation3d, anchor_point_x, 0, anchor_point[0] );
+    AE_FIXED_PROPERTY( transformation3d, anchor_point_y, 0, anchor_point[1] );
+    AE_FIXED_PROPERTY( transformation3d, anchor_point_z, 0, anchor_point[2] );
+
+    AE_FIXED_PROPERTY( transformation3d, position_x, 0, position[0] );
+    AE_FIXED_PROPERTY( transformation3d, position_y, 0, position[1] );
+    AE_FIXED_PROPERTY( transformation3d, position_z, 0, position[2] );
+
+    AE_FIXED_PROPERTY( transformation3d, scale_x, 0, scale[0] );
+    AE_FIXED_PROPERTY( transformation3d, scale_y, 0, scale[1] );
+    AE_FIXED_PROPERTY( transformation3d, scale_z, 0, scale[2] );
+
+    ae_movie_make_transformation3d_m34wskq( _out, position, anchor_point, scale );
+}
+//////////////////////////////////////////////////////////////////////////
+AE_CALLBACK ae_void_t __make_layer_transformation3d_interpolate_wsk( ae_matrix34_t _out, const aeMovieLayerTransformation * _transformation, ae_uint32_t _index, ae_float_t _t )
+{
+    const aeMovieLayerTransformation3D * transformation3d = (const aeMovieLayerTransformation3D *)_transformation;
+
+    ae_vector3_t anchor_point;
+    ae_vector3_t position;
+    ae_vector3_t scale;
+    ae_quaternion_t quaternion;
+
+    AE_INTERPOLATE_PROPERTY( transformation3d, anchor_point_x, anchor_point[0] );
+    AE_INTERPOLATE_PROPERTY( transformation3d, anchor_point_y, anchor_point[1] );
+    AE_INTERPOLATE_PROPERTY( transformation3d, anchor_point_z, anchor_point[2] );
+
+    AE_INTERPOLATE_PROPERTY( transformation3d, position_x, position[0] );
+    AE_INTERPOLATE_PROPERTY( transformation3d, position_y, position[1] );
+    AE_INTERPOLATE_PROPERTY( transformation3d, position_z, position[2] );
+
+    AE_INTERPOLATE_PROPERTY( transformation3d, scale_x, scale[0] );
+    AE_INTERPOLATE_PROPERTY( transformation3d, scale_y, scale[1] );
+    AE_INTERPOLATE_PROPERTY( transformation3d, scale_z, scale[2] );
+
+    ae_quaternion_t q1;
+    AE_FIXED_PROPERTY( transformation3d, quaternion_x, 0, q1[0] );
+    AE_FIXED_PROPERTY( transformation3d, quaternion_y, 0, q1[1] );
+    AE_FIXED_PROPERTY( transformation3d, quaternion_z, 0, q1[2] );
+    AE_FIXED_PROPERTY( transformation3d, quaternion_w, 0, q1[3] );
+
+    ae_quaternion_t q2;
+    AE_FIXED_PROPERTY( transformation3d, quaternion_x, 1, q2[0] );
+    AE_FIXED_PROPERTY( transformation3d, quaternion_y, 1, q2[1] );
+    AE_FIXED_PROPERTY( transformation3d, quaternion_z, 1, q2[2] );
+    AE_FIXED_PROPERTY( transformation3d, quaternion_w, 1, q2[3] );
+
+    ae_linerp_q( quaternion, q1, q2, _t );
+
+    ae_movie_make_transformation3d_m34wsk( _out, position, anchor_point, scale, quaternion );
+}
+//////////////////////////////////////////////////////////////////////////
+AE_CALLBACK ae_void_t __make_layer_transformation3d_interpolate_wskfq( ae_matrix34_t _out, const aeMovieLayerTransformation * _transformation, ae_uint32_t _index, ae_float_t _t )
+{
+    const aeMovieLayerTransformation3D * transformation3d = (const aeMovieLayerTransformation3D *)_transformation;
+
+    ae_vector3_t anchor_point;
+    ae_vector3_t position;
+    ae_vector3_t scale;
+    ae_quaternion_t quaternion;
+
+    AE_INTERPOLATE_PROPERTY( transformation3d, anchor_point_x, anchor_point[0] );
+    AE_INTERPOLATE_PROPERTY( transformation3d, anchor_point_y, anchor_point[1] );
+    AE_INTERPOLATE_PROPERTY( transformation3d, anchor_point_z, anchor_point[2] );
+
+    AE_INTERPOLATE_PROPERTY( transformation3d, position_x, position[0] );
+    AE_INTERPOLATE_PROPERTY( transformation3d, position_y, position[1] );
+    AE_INTERPOLATE_PROPERTY( transformation3d, position_z, position[2] );
+
+    AE_INTERPOLATE_PROPERTY( transformation3d, scale_x, scale[0] );
+    AE_INTERPOLATE_PROPERTY( transformation3d, scale_y, scale[1] );
+    AE_INTERPOLATE_PROPERTY( transformation3d, scale_z, scale[2] );
+
+    AE_FIXED_PROPERTY( transformation3d, quaternion_x, 0, quaternion[0] );
+    AE_FIXED_PROPERTY( transformation3d, quaternion_y, 0, quaternion[1] );
+    AE_FIXED_PROPERTY( transformation3d, quaternion_z, 0, quaternion[2] );
+    AE_FIXED_PROPERTY( transformation3d, quaternion_w, 0, quaternion[3] );
+
+    ae_movie_make_transformation3d_m34wsk( _out, position, anchor_point, scale, quaternion );
+}
+//////////////////////////////////////////////////////////////////////////
+AE_CALLBACK ae_void_t __make_layer_transformation3d_fixed_wsk( ae_matrix34_t _out, const aeMovieLayerTransformation * _transformation, ae_uint32_t _index )
+{
+    const aeMovieLayerTransformation3D * transformation3d = (const aeMovieLayerTransformation3D *)_transformation;
+
+    ae_vector3_t anchor_point;
+    ae_vector3_t position;
+    ae_vector3_t scale;
+    ae_quaternion_t quaternion;
+
+    AE_FIXED_PROPERTY( transformation3d, anchor_point_x, 0, anchor_point[0] );
+    AE_FIXED_PROPERTY( transformation3d, anchor_point_y, 0, anchor_point[1] );
+    AE_FIXED_PROPERTY( transformation3d, anchor_point_z, 0, anchor_point[2] );
+
+    AE_FIXED_PROPERTY( transformation3d, position_x, 0, position[0] );
+    AE_FIXED_PROPERTY( transformation3d, position_y, 0, position[1] );
+    AE_FIXED_PROPERTY( transformation3d, position_z, 0, position[2] );
+
+    AE_FIXED_PROPERTY( transformation3d, scale_x, 0, scale[0] );
+    AE_FIXED_PROPERTY( transformation3d, scale_y, 0, scale[1] );
+    AE_FIXED_PROPERTY( transformation3d, scale_z, 0, scale[2] );
+
+    AE_FIXED_PROPERTY( transformation3d, quaternion_x, 0, quaternion[0] );
+    AE_FIXED_PROPERTY( transformation3d, quaternion_y, 0, quaternion[1] );
+    AE_FIXED_PROPERTY( transformation3d, quaternion_z, 0, quaternion[2] );
+    AE_FIXED_PROPERTY( transformation3d, quaternion_w, 0, quaternion[3] );
+
+    ae_movie_make_transformation3d_m34wsk( _out, position, anchor_point, scale, quaternion );
+}
+//////////////////////////////////////////////////////////////////////////
+AE_CALLBACK ae_void_t __make_layer_transformation3d_interpolate_fq( ae_matrix34_t _out, const aeMovieLayerTransformation * _transformation, ae_uint32_t _index, ae_float_t _t )
+{
+    const aeMovieLayerTransformation3D * transformation3d = (const aeMovieLayerTransformation3D *)_transformation;
+
+    ae_vector3_t anchor_point;
+    ae_vector3_t position;
+    ae_vector3_t scale;
+    ae_quaternion_t quaternion;
+    ae_skew_t skew;
+
+    AE_INTERPOLATE_PROPERTY( transformation3d, anchor_point_x, anchor_point[0] );
+    AE_INTERPOLATE_PROPERTY( transformation3d, anchor_point_y, anchor_point[1] );
+    AE_INTERPOLATE_PROPERTY( transformation3d, anchor_point_z, anchor_point[2] );
+
+    AE_INTERPOLATE_PROPERTY( transformation3d, position_x, position[0] );
+    AE_INTERPOLATE_PROPERTY( transformation3d, position_y, position[1] );
+    AE_INTERPOLATE_PROPERTY( transformation3d, position_z, position[2] );
+
+    AE_INTERPOLATE_PROPERTY( transformation3d, scale_x, scale[0] );
+    AE_INTERPOLATE_PROPERTY( transformation3d, scale_y, scale[1] );
+    AE_INTERPOLATE_PROPERTY( transformation3d, scale_z, scale[2] );
+
+    AE_FIXED_PROPERTY( transformation3d, quaternion_x, 0, quaternion[0] );
+    AE_FIXED_PROPERTY( transformation3d, quaternion_y, 0, quaternion[1] );
+    AE_FIXED_PROPERTY( transformation3d, quaternion_z, 0, quaternion[2] );
+    AE_FIXED_PROPERTY( transformation3d, quaternion_w, 0, quaternion[3] );
+
+    AE_INTERPOLATE_PROPERTY( transformation3d, skew, skew[0] );
+    AE_INTERPOLATE_PROPERTY( transformation3d, skew_quaternion_z, skew[1] );
+    AE_INTERPOLATE_PROPERTY( transformation3d, skew_quaternion_w, skew[2] );
+
+    ae_movie_make_transformation3d_m34( _out, position, anchor_point, scale, quaternion, skew );
+}
+//////////////////////////////////////////////////////////////////////////
+AE_CALLBACK ae_void_t __make_layer_transformation3d_interpolate( ae_matrix34_t _out, const aeMovieLayerTransformation * _transformation, ae_uint32_t _index, ae_float_t _t )
+{
+    const aeMovieLayerTransformation3D * transformation3d = (const aeMovieLayerTransformation3D *)_transformation;
+
+    ae_vector3_t anchor_point;
+    ae_vector3_t position;
+    ae_vector3_t scale;
+    ae_quaternion_t quaternion;
+    ae_skew_t skew;
+
+    AE_INTERPOLATE_PROPERTY( transformation3d, anchor_point_x, anchor_point[0] );
+    AE_INTERPOLATE_PROPERTY( transformation3d, anchor_point_y, anchor_point[1] );
+    AE_INTERPOLATE_PROPERTY( transformation3d, anchor_point_z, anchor_point[2] );
+
+    AE_INTERPOLATE_PROPERTY( transformation3d, position_x, position[0] );
+    AE_INTERPOLATE_PROPERTY( transformation3d, position_y, position[1] );
+    AE_INTERPOLATE_PROPERTY( transformation3d, position_z, position[2] );
+
+    AE_INTERPOLATE_PROPERTY( transformation3d, scale_x, scale[0] );
+    AE_INTERPOLATE_PROPERTY( transformation3d, scale_y, scale[1] );
+    AE_INTERPOLATE_PROPERTY( transformation3d, scale_z, scale[2] );
+
+    ae_quaternion_t q1;
+    AE_FIXED_PROPERTY( transformation3d, quaternion_x, 0, q1[0] );
+    AE_FIXED_PROPERTY( transformation3d, quaternion_y, 0, q1[1] );
+    AE_FIXED_PROPERTY( transformation3d, quaternion_z, 0, q1[2] );
+    AE_FIXED_PROPERTY( transformation3d, quaternion_w, 0, q1[3] );
+
+    ae_quaternion_t q2;
+    AE_FIXED_PROPERTY( transformation3d, quaternion_x, 1, q2[0] );
+    AE_FIXED_PROPERTY( transformation3d, quaternion_y, 1, q2[1] );
+    AE_FIXED_PROPERTY( transformation3d, quaternion_z, 1, q2[2] );
+    AE_FIXED_PROPERTY( transformation3d, quaternion_w, 1, q2[3] );
+
+    ae_linerp_q( quaternion, q1, q2, _t );
+
+    AE_INTERPOLATE_PROPERTY( transformation3d, skew, skew[0] );
+    AE_INTERPOLATE_PROPERTY( transformation3d, skew_quaternion_z, skew[1] );
+    AE_INTERPOLATE_PROPERTY( transformation3d, skew_quaternion_w, skew[2] );
+
+    ae_movie_make_transformation3d_m34( _out, position, anchor_point, scale, quaternion, skew );
+}
+//////////////////////////////////////////////////////////////////////////
+ae_result_t ae_movie_load_layer_transformation( aeMovieStream * _stream, aeMovieLayerTransformation * _transformation, ae_bool_t _threeD )
+{
+    ae_uint32_t immutable_property_mask;
+    AE_READ( _stream, immutable_property_mask );
+
+    _transformation->immutable_property_mask = immutable_property_mask;
+
+    ae_uint32_t identity_property_mask;
+    AE_READ( _stream, identity_property_mask );
+        
+    _transformation->identity_property_mask = identity_property_mask;
+
+    if( _threeD == AE_FALSE )
+    {
+        aeMovieLayerTransformation2D * transformation2d = (aeMovieLayerTransformation2D *)_transformation;
+
+        aeMovieLayerTransformation2DTimeline * timeline = AE_NULLPTR;
+
+        if( (immutable_property_mask & AE_MOVIE_PROPERTY_TRANSFORM_SUPER_ALL) != AE_MOVIE_PROPERTY_TRANSFORM_SUPER_ALL )
+        {
+            timeline = AE_NEW( _stream->instance, aeMovieLayerTransformation2DTimeline );
+
+            AE_RESULT_PANIC_MEMORY( timeline );
+        }
+
+        transformation2d->timeline = timeline;
+
+        AE_RESULT( __load_movie_layer_transformation2d, (_stream, transformation2d) );
+
+        if( (identity_property_mask & AE_MOVIE_PROPERTY_TRANSFORM_SUPER_ALL) == AE_MOVIE_PROPERTY_TRANSFORM_SUPER_ALL )
+        {
+            _transformation->transforamtion_interpolate_matrix = &__make_layer_transformation_interpolate_identity;
+            _transformation->transforamtion_fixed_matrix = &__make_layer_transformation_fixed_identity;
+        }
+        else if( (immutable_property_mask & AE_MOVIE_PROPERTY_TRANSFORM_SUPER_ALL) == AE_MOVIE_PROPERTY_TRANSFORM_SUPER_ALL )
+        {
+            _transformation->transforamtion_interpolate_matrix = &__make_layer_transformation_interpolate_immutable;
+            _transformation->transforamtion_fixed_matrix = &__make_layer_transformation_fixed_immutable;
+        }
+        else
+        {
+            ae_uint32_t fixed_transformation = 0;
+
+            if( (identity_property_mask & AE_MOVIE_PROPERTY_TRANSFORM_SUPER_ALL_SKEW) == AE_MOVIE_PROPERTY_TRANSFORM_SUPER_ALL_SKEW )
+            {
+                fixed_transformation += 0x00000001;
+            }
+
+            if( (identity_property_mask & AE_MOVIE_PROPERTY_TRANSFORM_SUPER_ALL_QUATERNION) == AE_MOVIE_PROPERTY_TRANSFORM_SUPER_ALL_QUATERNION )
+            {
+                fixed_transformation += 0x00000002;
+            }
+            else if( (immutable_property_mask & AE_MOVIE_PROPERTY_TRANSFORM_SUPER_ALL_QUATERNION) == AE_MOVIE_PROPERTY_TRANSFORM_SUPER_ALL_QUATERNION )
+            {
+                fixed_transformation += 0x00000004;
+            }
+
+            switch( fixed_transformation )
+            {
+            case 0:
+                {
+                    _transformation->transforamtion_interpolate_matrix = &__make_layer_transformation2d_interpolate;
+                    _transformation->transforamtion_fixed_matrix = &__make_layer_transformation2d_fixed;
+                }break;
+            case 1:
+                {
+                    _transformation->transforamtion_interpolate_matrix = &__make_layer_transformation2d_interpolate_wsk;
+                    _transformation->transforamtion_fixed_matrix = &__make_layer_transformation2d_fixed_wsk;
+                }break;
+            case 2:
+                {
+                    _transformation->transforamtion_interpolate_matrix = &__make_layer_transformation2d_interpolate_wq;
+                    _transformation->transforamtion_fixed_matrix = &__make_layer_transformation2d_fixed_wq;
+                }break;
+            case 3:
+                {
+                    _transformation->transforamtion_interpolate_matrix = &__make_layer_transformation2d_interpolate_wskq;
+                    _transformation->transforamtion_fixed_matrix = &__make_layer_transformation2d_fixed_wskq;
+                }break;
+            case 4:
+                {
+                    _transformation->transforamtion_interpolate_matrix = &__make_layer_transformation2d_interpolate_fq;
+                    _transformation->transforamtion_fixed_matrix = &__make_layer_transformation2d_fixed;
+                }break;
+            case 5:
+                {
+                    _transformation->transforamtion_interpolate_matrix = &__make_layer_transformation2d_interpolate_wskfq;
+                    _transformation->transforamtion_fixed_matrix = &__make_layer_transformation2d_fixed_wsk;
+                }break;
+            default:
+                {
+                    return AE_RESULT_INTERNAL_ERROR;
+                }break;
+            }
+        }
+    }
+    else
+    {
+        aeMovieLayerTransformation3D * transformation3d = (aeMovieLayerTransformation3D *)_transformation;
+
+        aeMovieLayerTransformation3DTimeline * timeline = AE_NULLPTR;
+
+        if( (immutable_property_mask & AE_MOVIE_PROPERTY_TRANSFORM_SUPER_ALL) != AE_MOVIE_PROPERTY_TRANSFORM_SUPER_ALL )
+        {
+            timeline = AE_NEW( _stream->instance, aeMovieLayerTransformation3DTimeline );
+
+            AE_RESULT_PANIC_MEMORY( timeline );
+        }
+
+        transformation3d->timeline = timeline;
+
+        AE_RESULT( __load_movie_layer_transformation3d, (_stream, transformation3d) );
+
+        if( (identity_property_mask & AE_MOVIE_PROPERTY_TRANSFORM_SUPER_ALL) == AE_MOVIE_PROPERTY_TRANSFORM_SUPER_ALL )
+        {
+            _transformation->transforamtion_interpolate_matrix = &__make_layer_transformation_interpolate_identity;
+            _transformation->transforamtion_fixed_matrix = &__make_layer_transformation_fixed_identity;
+        }
+        else if( (immutable_property_mask & AE_MOVIE_PROPERTY_TRANSFORM_SUPER_ALL) == AE_MOVIE_PROPERTY_TRANSFORM_SUPER_ALL )
+        {
+            _transformation->transforamtion_interpolate_matrix = &__make_layer_transformation_interpolate_immutable;
+            _transformation->transforamtion_fixed_matrix = &__make_layer_transformation_fixed_immutable;
+        }
+        else
+        {
+            ae_uint32_t fixed_transformation = 0;
+
+            if( (identity_property_mask & AE_MOVIE_PROPERTY_TRANSFORM_SUPER_ALL_SKEW) == AE_MOVIE_PROPERTY_TRANSFORM_SUPER_ALL_SKEW )
+            {
+                fixed_transformation += 0x00000001;
+            }
+
+            if( (identity_property_mask & AE_MOVIE_PROPERTY_TRANSFORM_SUPER_ALL_QUATERNION) == AE_MOVIE_PROPERTY_TRANSFORM_SUPER_ALL_QUATERNION )
+            {
+                fixed_transformation += 0x00000002;
+            } 
+            else if( (immutable_property_mask & AE_MOVIE_PROPERTY_TRANSFORM_SUPER_ALL_QUATERNION) == AE_MOVIE_PROPERTY_TRANSFORM_SUPER_ALL_QUATERNION )
+            {
+                fixed_transformation += 0x00000004;
+            }
+            
+            switch( fixed_transformation )
+            {
+            case 0:
+                {
+                    _transformation->transforamtion_interpolate_matrix = &__make_layer_transformation3d_interpolate;
+                    _transformation->transforamtion_fixed_matrix = &__make_layer_transformation3d_fixed;
+                }break;
+            case 1:
+                {
+                    _transformation->transforamtion_interpolate_matrix = &__make_layer_transformation3d_interpolate_wsk;
+                    _transformation->transforamtion_fixed_matrix = &__make_layer_transformation3d_fixed_wsk;
+                }break;
+            case 2:
+                {
+                    _transformation->transforamtion_interpolate_matrix = &__make_layer_transformation3d_interpolate_wq;
+                    _transformation->transforamtion_fixed_matrix = &__make_layer_transformation3d_fixed_wq;
+                }break;
+            case 3:
+                {
+                    _transformation->transforamtion_interpolate_matrix = &__make_layer_transformation3d_interpolate_wskq;
+                    _transformation->transforamtion_fixed_matrix = &__make_layer_transformation3d_fixed_wskq;
+                }break;
+            case 4:
+                {
+                    _transformation->transforamtion_interpolate_matrix = &__make_layer_transformation3d_interpolate_fq;
+                    _transformation->transforamtion_fixed_matrix = &__make_layer_transformation3d_fixed;
+                }break;
+            case 5:
+                {
+                    _transformation->transforamtion_interpolate_matrix = &__make_layer_transformation3d_interpolate_wskfq;
+                    _transformation->transforamtion_fixed_matrix = &__make_layer_transformation3d_fixed_wsk;
+                }break;
+            default:
+                {
+                    return AE_RESULT_INTERNAL_ERROR;
+                }break;
+            };
+        }
+    }
+
+    if( identity_property_mask & AE_MOVIE_PROPERTY_COLOR_R )
+    {
+        _transformation->immutable_color.color_r = 1.f;
+        _transformation->timeline_color.color_r = AE_NULLPTR;
+    }
+    else if( immutable_property_mask & AE_MOVIE_PROPERTY_COLOR_R )
+    {
+        AE_READF( _stream, _transformation->immutable_color.color_r );
+        _transformation->timeline_color.color_r = AE_NULLPTR;
+    }
+    else
+    {
+        _transformation->timeline_color.color_r = __load_movie_layer_transformation_timeline( _stream, "immutable_color_r" );
+    }
+
+    if( identity_property_mask & AE_MOVIE_PROPERTY_COLOR_G )
+    {
+        _transformation->immutable_color.color_g = 1.f;
+        _transformation->timeline_color.color_g = AE_NULLPTR;
+    }
+    else if( immutable_property_mask & AE_MOVIE_PROPERTY_COLOR_G )
+    {
+        AE_READF( _stream, _transformation->immutable_color.color_g );
+        _transformation->timeline_color.color_g = AE_NULLPTR;
+    }
+    else
+    {
+        _transformation->timeline_color.color_g = __load_movie_layer_transformation_timeline( _stream, "immutable_color_g" );
+    }
+
+    if( identity_property_mask & AE_MOVIE_PROPERTY_COLOR_B )
+    {
+        _transformation->immutable_color.color_b = 1.f;
+        _transformation->timeline_color.color_b = AE_NULLPTR;
+    }
+    else if( immutable_property_mask & AE_MOVIE_PROPERTY_COLOR_B )
+    {
+        AE_READF( _stream, _transformation->immutable_color.color_b );
+        _transformation->timeline_color.color_b = AE_NULLPTR;
+    }
+    else
+    {
+        _transformation->timeline_color.color_b = __load_movie_layer_transformation_timeline( _stream, "immutable_color_b" );
+    }
+
+    if( identity_property_mask & AE_MOVIE_PROPERTY_OPACITY )
+    {
+        _transformation->immutable_opacity = 1.f;
+        _transformation->timeline_opacity = AE_NULLPTR;
+    }
+    else if( immutable_property_mask & AE_MOVIE_PROPERTY_OPACITY )
+    {
+        AE_READF( _stream, _transformation->immutable_opacity );
+        _transformation->timeline_opacity = AE_NULLPTR;
+    }
+    else
+    {
+        _transformation->timeline_opacity = __load_movie_layer_transformation_timeline( _stream, "immutable_opacity" );
+    }
+
+    return AE_RESULT_SUCCESSFUL;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_result_t __load_camera_transformation_property( aeMovieStream * _stream, aeMovieCompositionCamera * _transformation )
+{
+    ae_uint32_t immutable_property_mask = _transformation->immutable_property_mask;
+    ae_uint32_t identity_property_mask = _transformation->identity_property_mask;
+
+    AE_STREAM_PROPERTY( AE_MOVIE_PROPERTY_ANCHOR_POINT_X, target_x, 0.f );
+    AE_STREAM_PROPERTY( AE_MOVIE_PROPERTY_ANCHOR_POINT_Y, target_y, 0.f );
+    AE_STREAM_PROPERTY( AE_MOVIE_PROPERTY_ANCHOR_POINT_Z, target_z, 1.f );
+
+    AE_STREAM_PROPERTY( AE_MOVIE_PROPERTY_POSITION_X, position_x, 0.f );
+    AE_STREAM_PROPERTY( AE_MOVIE_PROPERTY_POSITION_Y, position_y, 0.f );
+    AE_STREAM_PROPERTY( AE_MOVIE_PROPERTY_POSITION_Z, position_z, 0.f );
+
+    AE_STREAM_PROPERTY( AE_MOVIE_PROPERTY_QUATERNION_X, quaternion_x, 0.f );
+    AE_STREAM_PROPERTY( AE_MOVIE_PROPERTY_QUATERNION_Y, quaternion_y, 0.f );
+    AE_STREAM_PROPERTY( AE_MOVIE_PROPERTY_QUATERNION_Z, quaternion_z, 0.f );
+    AE_STREAM_PROPERTY( AE_MOVIE_PROPERTY_QUATERNION_W, quaternion_w, 1.f );
+
+    return AE_RESULT_SUCCESSFUL;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_result_t ae_movie_load_camera_transformation( aeMovieStream * _stream, aeMovieCompositionCamera * _camera )
+{
+    ae_uint32_t immutable_property_mask;
+    AE_READ( _stream, immutable_property_mask );
+
+    _camera->immutable_property_mask = immutable_property_mask;
+
+    ae_uint32_t identity_property_mask;
+    AE_READ( _stream, identity_property_mask );
+
+    _camera->identity_property_mask = identity_property_mask;
+
+    aeMovieCompositionCameraTimeline * timeline = AE_NULLPTR;
+
+    if( (immutable_property_mask & AE_MOVIE_PROPERTY_TRANSFORM_SUPER_ALL_CAMERA) != AE_MOVIE_PROPERTY_TRANSFORM_SUPER_ALL_CAMERA )
+    {
+        timeline = AE_NEW( _stream->instance, aeMovieCompositionCameraTimeline );
+
+        AE_RESULT_PANIC_MEMORY( timeline );
+    }
+
+    _camera->timeline = timeline;
+
+    AE_RESULT( __load_camera_transformation_property, (_stream, _camera) );
+
+    return AE_RESULT_SUCCESSFUL;
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __delete_layer_transformation2d( const aeMovieInstance * _instance, const aeMovieLayerTransformation2D * _transformation )
+{
+    if( _transformation->timeline != AE_NULLPTR )
+    {
+        aeMovieLayerTransformation2DTimeline * timeline = _transformation->timeline;
+
+        AE_DELETE( _instance, timeline->anchor_point_x );
+        AE_DELETE( _instance, timeline->anchor_point_y );
+        AE_DELETE( _instance, timeline->position_x );
+        AE_DELETE( _instance, timeline->position_y );
+        AE_DELETE( _instance, timeline->scale_x );
+        AE_DELETE( _instance, timeline->scale_y );
+        AE_DELETE( _instance, timeline->quaternion_z );
+        AE_DELETE( _instance, timeline->quaternion_w );
+        AE_DELETE( _instance, timeline->skew );
+        AE_DELETE( _instance, timeline->skew_quaternion_z );
+        AE_DELETE( _instance, timeline->skew_quaternion_w );
+
+        AE_DELETE( _instance, _transformation->timeline );
+    }
+}
+//////////////////////////////////////////////////////////////////////////
+AE_INTERNAL ae_void_t __delete_layer_transformation3d( const aeMovieInstance * _instance, const aeMovieLayerTransformation3D * _transformation )
+{
+    if( _transformation->timeline != AE_NULLPTR )
+    {
+        aeMovieLayerTransformation3DTimeline * timeline = _transformation->timeline;
+
+        AE_DELETE( _instance, timeline->anchor_point_x );
+        AE_DELETE( _instance, timeline->anchor_point_y );
+        AE_DELETE( _instance, timeline->anchor_point_z );
+        AE_DELETE( _instance, timeline->position_x );
+        AE_DELETE( _instance, timeline->position_y );
+        AE_DELETE( _instance, timeline->position_z );
+        AE_DELETE( _instance, timeline->scale_x );
+        AE_DELETE( _instance, timeline->scale_y );
+        AE_DELETE( _instance, timeline->scale_z );
+        AE_DELETE( _instance, timeline->quaternion_x );
+        AE_DELETE( _instance, timeline->quaternion_y );
+        AE_DELETE( _instance, timeline->quaternion_z );
+        AE_DELETE( _instance, timeline->quaternion_w );
+        AE_DELETE( _instance, timeline->skew );
+        AE_DELETE( _instance, timeline->skew_quaternion_z );
+        AE_DELETE( _instance, timeline->skew_quaternion_w );
+
+        AE_DELETE( _instance, _transformation->timeline );
+    }
+}
+//////////////////////////////////////////////////////////////////////////
+ae_void_t ae_movie_delete_layer_transformation( const aeMovieInstance * _instance, const aeMovieLayerTransformation * _transformation, ae_bool_t _threeD )
+{
+    AE_DELETE( _instance, _transformation->timeline_color.color_r );
+    AE_DELETE( _instance, _transformation->timeline_color.color_g );
+    AE_DELETE( _instance, _transformation->timeline_color.color_b );
+    AE_DELETE( _instance, _transformation->timeline_opacity );
+
+    if( _threeD == AE_FALSE )
+    {
+        __delete_layer_transformation2d( _instance, (const aeMovieLayerTransformation2D *)_transformation );
+    }
+    else
+    {
+        __delete_layer_transformation3d( _instance, (const aeMovieLayerTransformation3D *)_transformation );
+    }
+
+    if( _transformation->immutable_matrix != AE_NULLPTR )
+    {
+        AE_DELETE( _instance, _transformation->immutable_matrix );
+    }
+}
+//////////////////////////////////////////////////////////////////////////
+ae_void_t ae_movie_make_layer_matrix( ae_matrix34_t _out, const aeMovieLayerTransformation * _transformation, ae_bool_t _interpolate, ae_uint32_t _index, ae_float_t _t )
+{
+    if( _interpolate == AE_TRUE )
+    {
+        (*_transformation->transforamtion_interpolate_matrix)(_out, _transformation, _index, _t);
+    }
+    else
+    {
+        (*_transformation->transforamtion_fixed_matrix)(_out, _transformation, _index);
+    }
+}
+//////////////////////////////////////////////////////////////////////////
+ae_void_t ae_movie_make_camera_transformation( ae_vector3_t _target, ae_vector3_t _position, ae_quaternion_t _quaternion, const aeMovieCompositionCamera * _camera, ae_uint32_t _index, ae_bool_t _interpolate, ae_float_t _t )
+{
+    if( _interpolate == AE_TRUE )
+    {
+        AE_INTERPOLATE_PROPERTY( _camera, target_x, _target[0] );
+        AE_INTERPOLATE_PROPERTY( _camera, target_y, _target[1] );
+        AE_INTERPOLATE_PROPERTY( _camera, target_z, _target[2] );
+
+        AE_INTERPOLATE_PROPERTY( _camera, position_x, _position[0] );
+        AE_INTERPOLATE_PROPERTY( _camera, position_y, _position[1] );
+        AE_INTERPOLATE_PROPERTY( _camera, position_z, _position[2] );
+
+        ae_quaternion_t q1;
+        AE_FIXED_PROPERTY( _camera, quaternion_x, 0, q1[0] );
+        AE_FIXED_PROPERTY( _camera, quaternion_y, 0, q1[1] );
+        AE_FIXED_PROPERTY( _camera, quaternion_z, 0, q1[2] );
+        AE_FIXED_PROPERTY( _camera, quaternion_w, 0, q1[3] );
+
+        ae_quaternion_t q2;
+        AE_FIXED_PROPERTY( _camera, quaternion_x, 1, q2[0] );
+        AE_FIXED_PROPERTY( _camera, quaternion_y, 1, q2[1] );
+        AE_FIXED_PROPERTY( _camera, quaternion_z, 1, q2[2] );
+        AE_FIXED_PROPERTY( _camera, quaternion_w, 1, q2[3] );
+
+        ae_linerp_q( _quaternion, q1, q2, _t );
+    }
+    else
+    {
+        AE_FIXED_PROPERTY( _camera, target_x, 0, _target[0] );
+        AE_FIXED_PROPERTY( _camera, target_y, 0, _target[1] );
+        AE_FIXED_PROPERTY( _camera, target_z, 0, _target[2] );
+
+        AE_FIXED_PROPERTY( _camera, position_x, 0, _position[0] );
+        AE_FIXED_PROPERTY( _camera, position_y, 0, _position[1] );
+        AE_FIXED_PROPERTY( _camera, position_z, 0, _position[2] );
+
+        AE_FIXED_PROPERTY( _camera, quaternion_x, 0, _quaternion[0] );
+        AE_FIXED_PROPERTY( _camera, quaternion_y, 0, _quaternion[1] );
+        AE_FIXED_PROPERTY( _camera, quaternion_z, 0, _quaternion[2] );
+        AE_FIXED_PROPERTY( _camera, quaternion_w, 0, _quaternion[3] );
+    }
+}
+//////////////////////////////////////////////////////////////////////////
+ae_color_channel_t ae_movie_make_layer_color_r( const aeMovieLayerTransformation * _transformation, ae_uint32_t _index, ae_bool_t _interpolate, ae_float_t _t )
+{
+    if( _transformation->timeline_color.color_r == AE_NULLPTR )
+    {
+        return _transformation->immutable_color.color_r;
+    }
+
+    ae_color_channel_t value;
+
+    if( _interpolate == AE_TRUE )
+    {
+        value = __get_movie_layer_transformation_property_interpolate( _transformation->timeline_color.color_r, _index, _t );
+    }
+    else
+    {
+        value = __get_movie_layer_transformation_property_fixed( _transformation->timeline_color.color_r, _index );
+    }
+
+    return value;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_color_channel_t ae_movie_make_layer_color_g( const aeMovieLayerTransformation * _transformation, ae_uint32_t _index, ae_bool_t _interpolate, ae_float_t _t )
+{
+    if( _transformation->timeline_color.color_g == AE_NULLPTR )
+    {
+        return _transformation->immutable_color.color_g;
+    }
+
+    ae_color_channel_t value;
+
+    if( _interpolate == AE_TRUE )
+    {
+        value = __get_movie_layer_transformation_property_interpolate( _transformation->timeline_color.color_g, _index, _t );
+    }
+    else
+    {
+        value = __get_movie_layer_transformation_property_fixed( _transformation->timeline_color.color_g, _index );
+    }
+
+    return value;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_color_channel_t ae_movie_make_layer_color_b( const aeMovieLayerTransformation * _transformation, ae_uint32_t _index, ae_bool_t _interpolate, ae_float_t _t )
+{
+    if( _transformation->timeline_color.color_b == AE_NULLPTR )
+    {
+        return _transformation->immutable_color.color_b;
+    }
+
+    ae_color_channel_t value;
+
+    if( _interpolate == AE_TRUE )
+    {
+        value = __get_movie_layer_transformation_property_interpolate( _transformation->timeline_color.color_b, _index, _t );
+    }
+    else
+    {
+        value = __get_movie_layer_transformation_property_fixed( _transformation->timeline_color.color_b, _index );
+    }
+
+    return value;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_color_channel_t ae_movie_make_layer_opacity( const aeMovieLayerTransformation * _transformation, ae_uint32_t _index, ae_bool_t _interpolate, ae_float_t _t )
+{
+    if( _transformation->timeline_opacity == AE_NULLPTR )
+    {
+        return _transformation->immutable_opacity;
+    }
+
+    ae_color_channel_t value;
+
+    if( _interpolate == AE_TRUE )
+    {
+        value = __get_movie_layer_transformation_property_interpolate( _transformation->timeline_opacity, _index, _t );
+    }
+    else
+    {
+        value = __get_movie_layer_transformation_property_fixed( _transformation->timeline_opacity, _index );
+    }
+
+    return value;
+}
+//////////////////////////////////////////////////////////////////////////
+ae_void_t ae_movie_make_layer_transformation2d_interpolate( ae_vector2_t _anchor_point, ae_vector2_t _position, ae_vector2_t _scale, ae_quaternionzw_t _quaternion, ae_skew_t _skew, const aeMovieLayerTransformation2D * _transformation2d, ae_uint32_t _index, ae_float_t _t )
+{
+    AE_INTERPOLATE_PROPERTY( _transformation2d, anchor_point_x, _anchor_point[0] );
+    AE_INTERPOLATE_PROPERTY( _transformation2d, anchor_point_y, _anchor_point[1] );
+
+    AE_INTERPOLATE_PROPERTY( _transformation2d, position_x, _position[0] );
+    AE_INTERPOLATE_PROPERTY( _transformation2d, position_y, _position[1] );
+
+    AE_INTERPOLATE_PROPERTY( _transformation2d, scale_x, _scale[0] );
+    AE_INTERPOLATE_PROPERTY( _transformation2d, scale_y, _scale[1] );
+
+    ae_quaternionzw_t q1;
+    AE_FIXED_PROPERTY( _transformation2d, quaternion_z, 0, q1[0] );
+    AE_FIXED_PROPERTY( _transformation2d, quaternion_w, 0, q1[1] );
+
+    ae_quaternionzw_t q2;
+    AE_FIXED_PROPERTY( _transformation2d, quaternion_z, 1, q2[0] );
+    AE_FIXED_PROPERTY( _transformation2d, quaternion_w, 1, q2[1] );
+
+    ae_linerp_qzw( _quaternion, q1, q2, _t );
+
+    AE_INTERPOLATE_PROPERTY( _transformation2d, skew, _skew[0] );
+    AE_INTERPOLATE_PROPERTY( _transformation2d, skew_quaternion_z, _skew[1] );
+    AE_INTERPOLATE_PROPERTY( _transformation2d, skew_quaternion_w, _skew[2] );
+}
+//////////////////////////////////////////////////////////////////////////
+ae_void_t ae_movie_make_layer_transformation2d_fixed( ae_vector2_t _anchor_point, ae_vector2_t _position, ae_vector2_t _scale, ae_quaternionzw_t _quaternion, ae_skew_t _skew, const aeMovieLayerTransformation2D * _transformation2d, ae_uint32_t _index )
+{
+    AE_FIXED_PROPERTY( _transformation2d, anchor_point_x, 0, _anchor_point[0] );
+    AE_FIXED_PROPERTY( _transformation2d, anchor_point_y, 0, _anchor_point[1] );
+
+    AE_FIXED_PROPERTY( _transformation2d, position_x, 0, _position[0] );
+    AE_FIXED_PROPERTY( _transformation2d, position_y, 0, _position[1] );
+
+    AE_FIXED_PROPERTY( _transformation2d, scale_x, 0, _scale[0] );
+    AE_FIXED_PROPERTY( _transformation2d, scale_y, 0, _scale[1] );
+
+    AE_FIXED_PROPERTY( _transformation2d, quaternion_z, 0, _quaternion[0] );
+    AE_FIXED_PROPERTY( _transformation2d, quaternion_w, 0, _quaternion[1] );
+
+    AE_FIXED_PROPERTY( _transformation2d, skew, 0, _skew[0] );
+    AE_FIXED_PROPERTY( _transformation2d, skew_quaternion_z, 0, _skew[1] );
+    AE_FIXED_PROPERTY( _transformation2d, skew_quaternion_w, 0, _skew[2] );
+
+    AE_FIXED_PROPERTY( _transformation2d, skew_quaternion_w, 0, _skew[2] );
+}
+//////////////////////////////////////////////////////////////////////////
+ae_void_t ae_movie_make_layer_transformation_color_interpolate( ae_color_t * _color, ae_color_channel_t * _opacity, const aeMovieLayerTransformation * _transformation, ae_uint32_t _index, ae_float_t _t )
+{
+    _color->r = (_transformation->timeline_color.color_r == AE_NULLPTR) ?
+        _transformation->immutable_color.color_r : __get_movie_layer_transformation_property_interpolate( _transformation->timeline_color.color_r, _index, _t );
+
+    _color->g = (_transformation->timeline_color.color_g == AE_NULLPTR) ?
+        _transformation->immutable_color.color_g : __get_movie_layer_transformation_property_interpolate( _transformation->timeline_color.color_g, _index, _t );
+
+    _color->b = (_transformation->timeline_color.color_b == AE_NULLPTR) ?
+        _transformation->immutable_color.color_b : __get_movie_layer_transformation_property_interpolate( _transformation->timeline_color.color_b, _index, _t );
+
+    *_opacity = (_transformation->timeline_opacity == AE_NULLPTR) ?
+        _transformation->immutable_opacity : __get_movie_layer_transformation_property_interpolate( _transformation->timeline_opacity, _index, _t );
+}
+//////////////////////////////////////////////////////////////////////////
+ae_void_t ae_movie_make_layer_transformation_color_fixed( ae_color_t * _color, ae_color_channel_t * _opacity, const aeMovieLayerTransformation * _transformation, ae_uint32_t _index )
+{
+    _color->r = (_transformation->timeline_color.color_r == AE_NULLPTR) ?
+        _transformation->immutable_color.color_r : __get_movie_layer_transformation_property_fixed( _transformation->timeline_color.color_r, _index );
+
+    _color->g = (_transformation->timeline_color.color_g == AE_NULLPTR) ?
+        _transformation->immutable_color.color_g : __get_movie_layer_transformation_property_fixed( _transformation->timeline_color.color_g, _index );
+
+    _color->b = (_transformation->timeline_color.color_b == AE_NULLPTR) ?
+        _transformation->immutable_color.color_b : __get_movie_layer_transformation_property_fixed( _transformation->timeline_color.color_b, _index );
+
+    *_opacity = (_transformation->timeline_opacity == AE_NULLPTR) ?
+        _transformation->immutable_opacity : __get_movie_layer_transformation_property_fixed( _transformation->timeline_opacity, _index );
+}

+ 220 - 0
ae-movie/src/movie_transformation.h

@@ -0,0 +1,220 @@
+/******************************************************************************
+* libMOVIE Software License v1.0
+*
+* Copyright (c) 2016-2018, Yuriy Levchenko <[email protected]>
+* All rights reserved.
+*
+* You are granted a perpetual, non-exclusive, non-sublicensable, and
+* non-transferable license to use, install, execute, and perform the libMOVIE
+* software and derivative works solely for personal or internal
+* use. Without the written permission of Yuriy Levchenko, you may not (a) modify, translate,
+* adapt, or develop new applications using the libMOVIE or otherwise
+* create derivative works or improvements of the libMOVIE or (b) remove,
+* delete, alter, or obscure any trademarks or any copyright, trademark, patent,
+* or other intellectual property or proprietary rights notices on or in the
+* Software, including any copy thereof. Redistributions in binary or source
+* form must include this license and terms.
+*
+* THIS SOFTWARE IS PROVIDED BY YURIY LEVCHENKO "AS IS" AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+* EVENT SHALL YURIY LEVCHENKO BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION,
+* OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF
+* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+#ifndef MOVIE_TRANSFORMATION_H_
+#define MOVIE_TRANSFORMATION_H_
+
+#include "movie/movie_instance.h"
+#include "movie/movie_type.h"
+
+typedef enum aeMoviePropertyImmutableEnum
+{
+    AE_MOVIE_PROPERTY_NONE = 0x00000000,
+    AE_MOVIE_PROPERTY_ANCHOR_POINT_X = 0x00000001,
+    AE_MOVIE_PROPERTY_ANCHOR_POINT_Y = 0x00000002,
+    AE_MOVIE_PROPERTY_ANCHOR_POINT_Z = 0x00000004,
+    AE_MOVIE_PROPERTY_POSITION_X = 0x00000010,
+    AE_MOVIE_PROPERTY_POSITION_Y = 0x00000020,
+    AE_MOVIE_PROPERTY_POSITION_Z = 0x00000040,
+    AE_MOVIE_PROPERTY_SCALE_X = 0x00000100,
+    AE_MOVIE_PROPERTY_SCALE_Y = 0x00000200,
+    AE_MOVIE_PROPERTY_SCALE_Z = 0x00000400,
+    AE_MOVIE_PROPERTY_QUATERNION_X = 0x00001000,
+    AE_MOVIE_PROPERTY_QUATERNION_Y = 0x00002000,
+    AE_MOVIE_PROPERTY_QUATERNION_Z = 0x00004000,
+    AE_MOVIE_PROPERTY_QUATERNION_W = 0x00008000,
+    AE_MOVIE_PROPERTY_SKEW = 0x00010000,
+    AE_MOVIE_PROPERTY_SKEW_QUATERNION_Z = 0x00020000,
+    AE_MOVIE_PROPERTY_SKEW_QUATERNION_W = 0x00040000,
+    AE_MOVIE_PROPERTY_COLOR_R = 0x10000000,
+    AE_MOVIE_PROPERTY_COLOR_G = 0x20000000,
+    AE_MOVIE_PROPERTY_COLOR_B = 0x40000000,
+    AE_MOVIE_PROPERTY_OPACITY = 0x80000000,
+
+    AE_MOVIE_PROPERTY_TRANSFORM_SUPER_ALL_SKEW = AE_MOVIE_PROPERTY_NONE
+    | AE_MOVIE_PROPERTY_SKEW | AE_MOVIE_PROPERTY_SKEW_QUATERNION_Z | AE_MOVIE_PROPERTY_SKEW_QUATERNION_W,
+
+    AE_MOVIE_PROPERTY_TRANSFORM_SUPER_ALL_QUATERNION = AE_MOVIE_PROPERTY_NONE
+    | AE_MOVIE_PROPERTY_QUATERNION_X | AE_MOVIE_PROPERTY_QUATERNION_Y | AE_MOVIE_PROPERTY_QUATERNION_Z | AE_MOVIE_PROPERTY_QUATERNION_W,
+
+    AE_MOVIE_PROPERTY_TRANSFORM_SUPER_ALL_CAMERA = AE_MOVIE_PROPERTY_NONE
+    | AE_MOVIE_PROPERTY_ANCHOR_POINT_X | AE_MOVIE_PROPERTY_ANCHOR_POINT_Y | AE_MOVIE_PROPERTY_ANCHOR_POINT_Z
+    | AE_MOVIE_PROPERTY_POSITION_X | AE_MOVIE_PROPERTY_POSITION_Y | AE_MOVIE_PROPERTY_POSITION_Z
+    | AE_MOVIE_PROPERTY_QUATERNION_X | AE_MOVIE_PROPERTY_QUATERNION_Y | AE_MOVIE_PROPERTY_QUATERNION_Z | AE_MOVIE_PROPERTY_QUATERNION_W,
+
+    AE_MOVIE_PROPERTY_TRANSFORM_SUPER_ALL = AE_MOVIE_PROPERTY_NONE
+    | AE_MOVIE_PROPERTY_ANCHOR_POINT_X | AE_MOVIE_PROPERTY_ANCHOR_POINT_Y | AE_MOVIE_PROPERTY_ANCHOR_POINT_Z
+    | AE_MOVIE_PROPERTY_POSITION_X | AE_MOVIE_PROPERTY_POSITION_Y | AE_MOVIE_PROPERTY_POSITION_Z
+    | AE_MOVIE_PROPERTY_SCALE_X | AE_MOVIE_PROPERTY_SCALE_Y | AE_MOVIE_PROPERTY_SCALE_Z
+    | AE_MOVIE_PROPERTY_QUATERNION_X | AE_MOVIE_PROPERTY_QUATERNION_Y | AE_MOVIE_PROPERTY_QUATERNION_Z | AE_MOVIE_PROPERTY_QUATERNION_W
+    | AE_MOVIE_PROPERTY_SKEW | AE_MOVIE_PROPERTY_SKEW_QUATERNION_Z | AE_MOVIE_PROPERTY_SKEW_QUATERNION_W,
+
+    AE_MOVIE_PROPERTY_COLOR_SUPER_ALL = AE_MOVIE_PROPERTY_NONE
+    | AE_MOVIE_PROPERTY_COLOR_R | AE_MOVIE_PROPERTY_COLOR_G | AE_MOVIE_PROPERTY_COLOR_B
+    | AE_MOVIE_PROPERTY_OPACITY,
+} aeMoviePropertyImmutableEnum;
+
+typedef struct aeMovieLayerTransformation2DImuttable
+{
+    ae_float_t anchor_point_x;
+    ae_float_t anchor_point_y;
+    ae_float_t position_x;
+    ae_float_t position_y;
+    ae_float_t scale_x;
+    ae_float_t scale_y;
+    ae_float_t quaternion_z;
+    ae_float_t quaternion_w;
+    ae_float_t skew;
+    ae_float_t skew_quaternion_z;
+    ae_float_t skew_quaternion_w;
+}aeMovieLayerTransformation2DImuttable;
+
+typedef struct aeMovieLayerTransformation3DImuttable
+{
+    ae_float_t anchor_point_x;
+    ae_float_t anchor_point_y;
+    ae_float_t anchor_point_z;
+    ae_float_t position_x;
+    ae_float_t position_y;
+    ae_float_t position_z;
+    ae_float_t scale_x;
+    ae_float_t scale_y;
+    ae_float_t scale_z;
+    ae_float_t quaternion_x;
+    ae_float_t quaternion_y;
+    ae_float_t quaternion_z;
+    ae_float_t quaternion_w;
+    ae_float_t skew;
+    ae_float_t skew_quaternion_z;
+    ae_float_t skew_quaternion_w;
+}aeMovieLayerTransformation3DImuttable;
+
+typedef struct aeMovieLayerTransformation2DTimeline
+{
+    ae_constvoidptr_t anchor_point_x;
+    ae_constvoidptr_t anchor_point_y;
+    ae_constvoidptr_t position_x;
+    ae_constvoidptr_t position_y;
+    ae_constvoidptr_t scale_x;
+    ae_constvoidptr_t scale_y;
+    ae_constvoidptr_t quaternion_z;
+    ae_constvoidptr_t quaternion_w;
+    ae_constvoidptr_t skew;
+    ae_constvoidptr_t skew_quaternion_z;
+    ae_constvoidptr_t skew_quaternion_w;
+}aeMovieLayerTransformation2DTimeline;
+
+typedef struct aeMovieLayerTransformation3DTimeline
+{
+    ae_constvoidptr_t anchor_point_x;
+    ae_constvoidptr_t anchor_point_y;
+    ae_constvoidptr_t anchor_point_z;
+    ae_constvoidptr_t position_x;
+    ae_constvoidptr_t position_y;
+    ae_constvoidptr_t position_z;
+    ae_constvoidptr_t scale_x;
+    ae_constvoidptr_t scale_y;
+    ae_constvoidptr_t scale_z;
+    ae_constvoidptr_t quaternion_x;
+    ae_constvoidptr_t quaternion_y;
+    ae_constvoidptr_t quaternion_z;
+    ae_constvoidptr_t quaternion_w;
+    ae_constvoidptr_t skew;
+    ae_constvoidptr_t skew_quaternion_z;
+    ae_constvoidptr_t skew_quaternion_w;
+}aeMovieLayerTransformation3DTimeline;
+
+typedef struct aeMovieLayerColorImuttable
+{
+    ae_color_channel_t color_r;
+    ae_color_channel_t color_g;
+    ae_color_channel_t color_b;
+}aeMovieLayerColorImuttable;
+
+typedef struct aeMovieLayerColorTimeline
+{
+    ae_constvoidptr_t color_r;
+    ae_constvoidptr_t color_g;
+    ae_constvoidptr_t color_b;
+}aeMovieLayerColorTimeline;
+
+struct aeMovieLayerTransformation;
+
+typedef ae_void_t( *ae_movie_make_layer_transformation_intepolate_t )(ae_matrix34_t _out, const struct aeMovieLayerTransformation * _transformation, ae_uint32_t _index, ae_float_t _t);
+typedef ae_void_t( *ae_movie_make_layer_transformation_fixed_t )(ae_matrix34_t _out, const struct aeMovieLayerTransformation * _transformation, ae_uint32_t _index);
+
+#define AE_MOVIE_LAYER_TRANSFORMATION_BASE()\
+    ae_uint32_t immutable_property_mask;\
+    ae_uint32_t identity_property_mask;\
+    aeMovieLayerColorImuttable immutable_color;\
+    aeMovieLayerColorTimeline timeline_color;\
+    ae_color_channel_t immutable_opacity;\
+    ae_constvoidptr_t timeline_opacity;\
+    ae_movie_make_layer_transformation_intepolate_t transforamtion_interpolate_matrix;\
+    ae_movie_make_layer_transformation_fixed_t transforamtion_fixed_matrix;\
+    ae_matrix34_t * immutable_matrix
+
+typedef struct aeMovieLayerTransformation
+{
+    AE_MOVIE_LAYER_TRANSFORMATION_BASE();
+} aeMovieLayerTransformation;
+
+typedef struct aeMovieLayerTransformation2D
+{
+    AE_MOVIE_LAYER_TRANSFORMATION_BASE();
+
+    aeMovieLayerTransformation2DImuttable immutable;
+    aeMovieLayerTransformation2DTimeline * timeline;
+} aeMovieLayerTransformation2D;
+
+typedef struct aeMovieLayerTransformation3D
+{
+    AE_MOVIE_LAYER_TRANSFORMATION_BASE();
+
+    aeMovieLayerTransformation3DImuttable immutable;
+    aeMovieLayerTransformation3DTimeline * timeline;
+} aeMovieLayerTransformation3D;
+
+ae_result_t ae_movie_load_layer_transformation( aeMovieStream * _stream, aeMovieLayerTransformation * _transformation, ae_bool_t _threeD );
+ae_result_t ae_movie_load_camera_transformation( aeMovieStream * _stream, aeMovieCompositionCamera * _camera );
+ae_void_t ae_movie_delete_layer_transformation( const aeMovieInstance * _instance, const aeMovieLayerTransformation * _transformation, ae_bool_t _threeD );
+ae_color_channel_t ae_movie_make_layer_color_r( const aeMovieLayerTransformation * _transformation, ae_uint32_t _index, ae_bool_t _interpolate, ae_float_t _t );
+ae_color_channel_t ae_movie_make_layer_color_g( const aeMovieLayerTransformation * _transformation, ae_uint32_t _index, ae_bool_t _interpolate, ae_float_t _t );
+ae_color_channel_t ae_movie_make_layer_color_b( const aeMovieLayerTransformation * _transformation, ae_uint32_t _index, ae_bool_t _interpolate, ae_float_t _t );
+ae_color_channel_t ae_movie_make_layer_opacity( const aeMovieLayerTransformation * _transformation, ae_uint32_t _index, ae_bool_t _interpolate, ae_float_t _t );
+ae_void_t ae_movie_make_layer_matrix( ae_matrix34_t _out, const aeMovieLayerTransformation * _transformation, ae_bool_t _interpolate, ae_uint32_t _index, ae_float_t _t );
+ae_void_t ae_movie_make_camera_transformation( ae_vector3_t _target, ae_vector3_t _position, ae_quaternion_t _quaternion, const aeMovieCompositionCamera * _camera, ae_uint32_t _index, ae_bool_t _interpolate, ae_float_t _t );
+
+ae_void_t ae_movie_make_layer_transformation2d_interpolate( ae_vector2_t _anchor_point, ae_vector2_t _position, ae_vector2_t _scale, ae_quaternionzw_t _quaternion, ae_skew_t _skew, const aeMovieLayerTransformation2D * _transformation2d, ae_uint32_t _index, ae_float_t _t );
+ae_void_t ae_movie_make_layer_transformation2d_fixed( ae_vector2_t _anchor_point, ae_vector2_t _position, ae_vector2_t _scale, ae_quaternionzw_t _quaternion, ae_skew_t _skew, const aeMovieLayerTransformation2D * _transformation2d, ae_uint32_t _index );
+
+ae_void_t ae_movie_make_layer_transformation_color_interpolate( ae_color_t * _color, ae_color_channel_t * _opacity, const aeMovieLayerTransformation * _transformation, ae_uint32_t _index, ae_float_t _t );
+ae_void_t ae_movie_make_layer_transformation_color_fixed( ae_color_t * _color, ae_color_channel_t * _opacity, const aeMovieLayerTransformation * _transformation, ae_uint32_t _index );
+
+#endif

BIN
examples/HelloViewerAE/data/HelloViewerAE.exe


+ 2 - 2
examples/proj.android/AndroidManifest.xml → examples/HelloViewerAE/proj.android/AndroidManifest.xml

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <?xml version="1.0" encoding="utf-8"?>
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-      package="org.oxygine.HelloAE"
+      package="org.oxygine.HelloViewerAE"
       android:versionCode="1"
       android:versionCode="1"
       android:versionName="1.0"
       android:versionName="1.0"
       android:installLocation="auto">
       android:installLocation="auto">
@@ -11,7 +11,7 @@
                  android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
                  android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
                  android:hardwareAccelerated="true" >
                  android:hardwareAccelerated="true" >
 
 
-        <activity android:name="org.oxygine.HelloAE.MainActivity"
+        <activity android:name="org.oxygine.HelloViewerAE.MainActivity"
                   android:label="@string/app_name"
                   android:label="@string/app_name"
                   android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
                   android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
                   android:configChanges="locale|orientation|keyboardHidden|screenSize" 
                   android:configChanges="locale|orientation|keyboardHidden|screenSize" 

+ 1 - 1
examples/proj.android/build-run.bat → examples/HelloViewerAE/proj.android/build-run.bat

@@ -1,4 +1,4 @@
 rem call ndk-build NDK_MODULE_PATH="../../../../"
 rem call ndk-build NDK_MODULE_PATH="../../../../"
 call gradlew assembleDebug
 call gradlew assembleDebug
 call adb install -r build/outputs/apk/debug/proj.android-debug.apk
 call adb install -r build/outputs/apk/debug/proj.android-debug.apk
-call adb shell am start -n org.oxygine.HelloAE/org.oxygine.HelloAE.MainActivity
+call adb shell am start -n org.oxygine.HelloViewerAE/org.oxygine.HelloViewerAE.MainActivity

+ 1 - 1
examples/proj.android/build-run.sh → examples/HelloViewerAE/proj.android/build-run.sh

@@ -3,4 +3,4 @@
 #ndk-build NDK_MODULE_PATH="../../../../"
 #ndk-build NDK_MODULE_PATH="../../../../"
 ./gradlew assembleDebug
 ./gradlew assembleDebug
 adb install -r build/outputs/apk/debug/proj.android-debug.apk
 adb install -r build/outputs/apk/debug/proj.android-debug.apk
-adb shell am start -n org.oxygine.HelloAE/org.oxygine.HelloAE.MainActivity
+adb shell am start -n org.oxygine.HelloViewerAE/org.oxygine.HelloViewerAE.MainActivity

+ 1 - 1
examples/proj.android/build.gradle → examples/HelloViewerAE/proj.android/build.gradle

@@ -52,7 +52,7 @@ android {
 
 
         externalNativeBuild {
         externalNativeBuild {
             ndkBuild {
             ndkBuild {
-                arguments 'NDK_MODULE_PATH+=../../../'
+                arguments 'NDK_MODULE_PATH+=../../../../'
             }
             }
         }
         }
     }
     }

+ 0 - 0
examples/proj.android/gradle/wrapper/gradle-wrapper.jar → examples/HelloViewerAE/proj.android/gradle/wrapper/gradle-wrapper.jar


+ 0 - 0
examples/proj.android/gradle/wrapper/gradle-wrapper.properties → examples/HelloViewerAE/proj.android/gradle/wrapper/gradle-wrapper.properties


+ 0 - 0
examples/proj.android/gradlew → examples/HelloViewerAE/proj.android/gradlew


+ 0 - 0
examples/proj.android/gradlew.bat → examples/HelloViewerAE/proj.android/gradlew.bat


+ 0 - 0
examples/proj.android/jni/Android.mk → examples/HelloViewerAE/proj.android/jni/Android.mk


+ 0 - 0
examples/proj.android/jni/Application.mk → examples/HelloViewerAE/proj.android/jni/Application.mk


+ 1 - 1
examples/proj.android/jni/src/Android.mk → examples/HelloViewerAE/proj.android/jni/src/Android.mk

@@ -4,7 +4,7 @@ include $(CLEAR_VARS)
 LOCAL_MODULE := main
 LOCAL_MODULE := main
 
 
 #SDK_ROOT points to folder with SDL and oxygine-framework
 #SDK_ROOT points to folder with SDL and oxygine-framework
-LOCAL_SRC_FILES := ../../../../..//SDL/src/main/android/SDL_android_main.c
+LOCAL_SRC_FILES := ../../../../../..//SDL/src/main/android/SDL_android_main.c
 
 
 LOCAL_SRC_FILES += ../../../src/example.cpp ../../../src/main.cpp 
 LOCAL_SRC_FILES += ../../../src/example.cpp ../../../src/main.cpp 
 
 

+ 0 - 0
examples/proj.android/res/drawable-hdpi/ic_launcher.png → examples/HelloViewerAE/proj.android/res/drawable-hdpi/ic_launcher.png


+ 0 - 0
examples/proj.android/res/drawable-mdpi/ic_launcher.png → examples/HelloViewerAE/proj.android/res/drawable-mdpi/ic_launcher.png


+ 0 - 0
examples/proj.android/res/drawable-xhdpi/ic_launcher.png → examples/HelloViewerAE/proj.android/res/drawable-xhdpi/ic_launcher.png


+ 0 - 0
examples/proj.android/res/drawable-xxhdpi/ic_launcher.png → examples/HelloViewerAE/proj.android/res/drawable-xxhdpi/ic_launcher.png


+ 0 - 0
examples/proj.android/res/layout/main.xml → examples/HelloViewerAE/proj.android/res/layout/main.xml


+ 1 - 1
examples/proj.android/res/values/strings.xml → examples/HelloViewerAE/proj.android/res/values/strings.xml

@@ -1,4 +1,4 @@
 <?xml version="1.0" encoding="utf-8"?>
 <?xml version="1.0" encoding="utf-8"?>
 <resources>
 <resources>
-    <string name="app_name">HelloAE</string>
+    <string name="app_name">HelloViewerAE</string>
 </resources>
 </resources>

+ 5 - 0
examples/HelloViewerAE/proj.android/settings.gradle

@@ -0,0 +1,5 @@
+include 'oxygine-lib'
+project(':oxygine-lib').projectDir = new File('../../../..//oxygine-framework/oxygine/SDL/android/lib')
+
+include 'oxygine-extension'
+project(':oxygine-extension').projectDir = new File('../../../..//oxygine-framework/oxygine/SDL/android/extension')

+ 1 - 1
examples/proj.android/src/org/oxygine/HelloAE/MainActivity.java → examples/HelloViewerAE/proj.android/src/org/oxygine/HelloViewerAE/MainActivity.java

@@ -1,4 +1,4 @@
-package org.oxygine.HelloAE;
+package org.oxygine.HelloViewerAE;
 
 
 import org.oxygine.lib.OxygineActivity;
 import org.oxygine.lib.OxygineActivity;
 
 

+ 54 - 0
examples/HelloViewerAE/proj.cmake/CMakeLists.txt

@@ -0,0 +1,54 @@
+cmake_minimum_required (VERSION 2.6)
+project (HelloViewerAE)
+
+add_subdirectory(../../../../oxygine-framework/ oxygine-framework)
+add_definitions(${OXYGINE_DEFINITIONS})
+include_directories(${OXYGINE_INCLUDE_DIRS})
+link_directories(${OXYGINE_LIBRARY_DIRS})
+
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OXYGINE_CXX_FLAGS}")
+
+
+
+file(GLOB AESRC #RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/
+		../../../ae-movie/src/*.c)
+file(GLOB AEHDR #RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/
+		../../..//ae-movie/src/*.h)
+set (AELIBSOURCES ${AESRC} ${AEHDR})
+source_group(aesdk FILES ${AELIBSOURCES})	
+
+
+file(GLOB OXAESRC #RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/
+		../../../src/ae/*.cpp)
+file(GLOB OXAEHEADERS #RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/
+		../../../src/ae/*.h)
+set (OXAESOURCES ${OXAESRC} ${OXAEHEADERS})
+source_group(oxae FILES ${OXAESOURCES})	
+
+
+
+
+
+add_executable(HelloViewerAE ../src/example.cpp ../src/main.cpp  ../src/example.h ../src/test.cpp ../src/AEMovieWork.cpp ${AELIBSOURCES} ${OXAESOURCES})
+target_link_libraries(HelloViewerAE ${OXYGINE_CORE_LIBS})
+
+include_directories(../../../src/)
+
+
+add_definitions(-DAEVIEWER=1 -DAE_MOVIE_STREAM_NO_CACHE=1 -DAE_TIME_DEFINE=1 -DAE_TIME_MILLISECOND=1 -DAE_MOVIE_SAFE=1)
+include_directories(../../../src/)
+include_directories(../../../ae-movie/include)
+
+
+
+if (WIN32) #disable console mode for VC++
+	set_target_properties(HelloViewerAE PROPERTIES WIN32_EXECUTABLE TRUE)
+endif(WIN32)
+
+
+
+if (EMSCRIPTEN)
+	SET(CMAKE_EXECUTABLE_SUFFIX ".html")	
+	set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s NO_EXIT_RUNTIME=1 -s WASM=0 -s WARN_ON_UNDEFINED_SYMBOLS=1 --memory-init-file 0 -s TOTAL_MEMORY=50331648 -s FORCE_FILESYSTEM=1")
+	em_link_pre_js(HelloViewerAE  ${OXYGINE_JS_LIBRARIES}  ${CMAKE_CURRENT_SOURCE_DIR}/data.js)
+endif(EMSCRIPTEN)

+ 1 - 1
examples/proj.cmake/build_emsc.bat → examples/HelloViewerAE/proj.cmake/build_emsc.bat

@@ -1,6 +1,6 @@
 call emsdk activate latest
 call emsdk activate latest
 
 
-python ../../../oxygine-framework//tools/others/embed_folder_js.py -s ../data
+python ../../../../oxygine-framework//tools/others/embed_folder_js.py -s ../data
 
 
 mkdir build_emsc
 mkdir build_emsc
 cd build_emsc
 cd build_emsc

+ 1 - 1
examples/proj.cmake/build_emsc_release.bat → examples/HelloViewerAE/proj.cmake/build_emsc_release.bat

@@ -1,6 +1,6 @@
 call emsdk activate latest
 call emsdk activate latest
 
 
-python ../../../oxygine-framework//tools/others/embed_folder_js.py -s ../data
+python ../../../../oxygine-framework//tools/others/embed_folder_js.py -s ../data
 
 
 mkdir build_emsc_release
 mkdir build_emsc_release
 cd build_emsc_release
 cd build_emsc_release

+ 1 - 1
examples/proj.cmake/run.sh → examples/HelloViewerAE/proj.cmake/run.sh

@@ -13,4 +13,4 @@ make
 cd ../../data
 cd ../../data
 
 
 #run executable
 #run executable
-./../proj.cmake/build/HelloAE
+./../proj.cmake/build/HelloViewerAE

+ 0 - 0
examples/proj.ios/HelloAE/HelloAE_ios-Info.plist → examples/HelloViewerAE/proj.ios/HelloViewerAE/HelloViewerAE_ios-Info.plist


+ 0 - 0
examples/proj.ios/HelloAE/HelloAE_ios-Prefix.pch → examples/HelloViewerAE/proj.ios/HelloViewerAE/HelloViewerAE_ios-Prefix.pch


+ 0 - 0
examples/proj.ios/HelloAE/Images.xcassets/AppIcon.appiconset/Contents.json → examples/HelloViewerAE/proj.ios/HelloViewerAE/Images.xcassets/AppIcon.appiconset/Contents.json


+ 0 - 0
examples/proj.ios/HelloAE/Images.xcassets/LaunchImage.launchimage/Contents.json → examples/HelloViewerAE/proj.ios/HelloViewerAE/Images.xcassets/LaunchImage.launchimage/Contents.json


+ 0 - 0
examples/proj.ios/HelloAE/LaunchImage.launchimage/Contents.json → examples/HelloViewerAE/proj.ios/HelloViewerAE/LaunchImage.launchimage/Contents.json


+ 0 - 0
examples/proj.ios/HelloAE/LaunchScreen.storyboard → examples/HelloViewerAE/proj.ios/HelloViewerAE/LaunchScreen.storyboard


+ 28 - 28
examples/proj.ios/HelloAE_ios.xcodeproj/project.pbxproj → examples/HelloViewerAE/proj.ios/HelloViewerAE_ios.xcodeproj/project.pbxproj

@@ -69,9 +69,9 @@
 /* End PBXContainerItemProxy section */
 /* End PBXContainerItemProxy section */
 
 
 /* Begin PBXFileReference section */
 /* Begin PBXFileReference section */
-		04998CEC17F8A933003441C3 /* HelloAE_ios.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = HelloAE_ios.app; sourceTree = BUILT_PRODUCTS_DIR; };
-		04998D2F17F8A96E003441C3 /* SDL.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = SDL.xcodeproj; path = "../../..//SDL/Xcode-iOS/SDL/SDL.xcodeproj"; sourceTree = "<group>"; };
-		04998D3917F8A9AA003441C3 /* oxygine_ios.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = oxygine_ios.xcodeproj; path = "../../../oxygine-framework//oxygine/SDL/ios/oxygine/oxygine_ios.xcodeproj"; sourceTree = "<group>"; };
+		04998CEC17F8A933003441C3 /* HelloViewerAE_ios.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = HelloViewerAE_ios.app; sourceTree = BUILT_PRODUCTS_DIR; };
+		04998D2F17F8A96E003441C3 /* SDL.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = SDL.xcodeproj; path = "../../../..//SDL/Xcode-iOS/SDL/SDL.xcodeproj"; sourceTree = "<group>"; };
+		04998D3917F8A9AA003441C3 /* oxygine_ios.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = oxygine_ios.xcodeproj; path = "../../../../oxygine-framework//oxygine/SDL/ios/oxygine/oxygine_ios.xcodeproj"; sourceTree = "<group>"; };
 		04998EE117F8ADB4003441C3 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; };
 		04998EE117F8ADB4003441C3 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; };
 		04998EE217F8ADB4003441C3 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
 		04998EE217F8ADB4003441C3 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
 		04998EE317F8ADB4003441C3 /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; };
 		04998EE317F8ADB4003441C3 /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; };
@@ -83,9 +83,9 @@
 		04998EED17F8ADD4003441C3 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
 		04998EED17F8ADD4003441C3 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
 		9223FE7E1C2D913D000B1FDA /* GameController.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GameController.framework; path = System/Library/Frameworks/GameController.framework; sourceTree = SDKROOT; };
 		9223FE7E1C2D913D000B1FDA /* GameController.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GameController.framework; path = System/Library/Frameworks/GameController.framework; sourceTree = SDKROOT; };
 		AD18619A1D8EC97A0043AFA3 /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; };
 		AD18619A1D8EC97A0043AFA3 /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; };
-		04998EF517F8B6F3003441C3 /* libpng.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libpng.a; path = "../../../oxygine-framework//oxygine/third_party/ios/libraries/libpng.a"; sourceTree = "<group>"; };
-		04998EF617F8B6F3003441C3 /* libjpeg.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libjpeg.a; path = "../../../oxygine-framework//oxygine/third_party/ios/libraries/libjpeg.a"; sourceTree = "<group>"; };
-		04E9AD3E1876FE84006A7317 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name =Images.xcassets; path = HelloAE/Images.xcassets; sourceTree = "<group>"; };
+		04998EF517F8B6F3003441C3 /* libpng.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libpng.a; path = "../../../../oxygine-framework//oxygine/third_party/ios/libraries/libpng.a"; sourceTree = "<group>"; };
+		04998EF617F8B6F3003441C3 /* libjpeg.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libjpeg.a; path = "../../../../oxygine-framework//oxygine/third_party/ios/libraries/libjpeg.a"; sourceTree = "<group>"; };
+		04E9AD3E1876FE84006A7317 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name =Images.xcassets; path = HelloViewerAE/Images.xcassets; sourceTree = "<group>"; };
 		4F7EF5AE200623DE004089D6 /* Metal.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Metal.framework; path = System/Library/Frameworks/Metal.framework; sourceTree = SDKROOT; };
 		4F7EF5AE200623DE004089D6 /* Metal.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Metal.framework; path = System/Library/Frameworks/Metal.framework; sourceTree = SDKROOT; };
 		4F8012E021454FEA00FDBA22 /* CoreBluetooth.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreBluetooth.framework; path = System/Library/Frameworks/CoreBluetooth.framework; sourceTree = SDKROOT; };
 		4F8012E021454FEA00FDBA22 /* CoreBluetooth.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreBluetooth.framework; path = System/Library/Frameworks/CoreBluetooth.framework; sourceTree = SDKROOT; };
 
 
@@ -157,7 +157,7 @@
 		04998CED17F8A933003441C3 /* Products */ = {
 		04998CED17F8A933003441C3 /* Products */ = {
 			isa = PBXGroup;
 			isa = PBXGroup;
 			children = (
 			children = (
-				04998CEC17F8A933003441C3 /* HelloAE_ios.app */,
+				04998CEC17F8A933003441C3 /* HelloViewerAE_ios.app */,
 			);
 			);
 			name = Products;
 			name = Products;
 			sourceTree = "<group>";
 			sourceTree = "<group>";
@@ -233,9 +233,9 @@
 /* End PBXGroup section */
 /* End PBXGroup section */
 
 
 /* Begin PBXNativeTarget section */
 /* Begin PBXNativeTarget section */
-		04998CEB17F8A933003441C3 /* HelloAE_ios */ = {
+		04998CEB17F8A933003441C3 /* HelloViewerAE_ios */ = {
 			isa = PBXNativeTarget;
 			isa = PBXNativeTarget;
-			buildConfigurationList = 04998D2117F8A933003441C3 /* Build configuration list for PBXNativeTarget "HelloAE_ios" */;
+			buildConfigurationList = 04998D2117F8A933003441C3 /* Build configuration list for PBXNativeTarget "HelloViewerAE_ios" */;
 			buildPhases = (
 			buildPhases = (
 				04998CE817F8A933003441C3 /* Sources */,
 				04998CE817F8A933003441C3 /* Sources */,
 				04998CE917F8A933003441C3 /* Frameworks */,
 				04998CE917F8A933003441C3 /* Frameworks */,
@@ -247,9 +247,9 @@
 				04998D3817F8A982003441C3 /* PBXTargetDependency */,
 				04998D3817F8A982003441C3 /* PBXTargetDependency */,
 				049B52B01871EBD100EF3C66 /* PBXTargetDependency */,
 				049B52B01871EBD100EF3C66 /* PBXTargetDependency */,
 			);
 			);
-			name = HelloAE_ios;
-			productName = HelloAE;
-			productReference = 04998CEC17F8A933003441C3 /* HelloAE_ios.app */;
+			name = HelloViewerAE_ios;
+			productName = HelloViewerAE;
+			productReference = 04998CEC17F8A933003441C3 /* HelloViewerAE_ios.app */;
 			productType = "com.apple.product-type.application";
 			productType = "com.apple.product-type.application";
 		};
 		};
 /* End PBXNativeTarget section */
 /* End PBXNativeTarget section */
@@ -261,7 +261,7 @@
 				LastUpgradeCheck = 0510;
 				LastUpgradeCheck = 0510;
 				ORGANIZATIONNAME = Mac;
 				ORGANIZATIONNAME = Mac;
 			};
 			};
-			buildConfigurationList = 04998CE717F8A933003441C3 /* Build configuration list for PBXProject "HelloAE_ios" */;
+			buildConfigurationList = 04998CE717F8A933003441C3 /* Build configuration list for PBXProject "HelloViewerAE_ios" */;
 			compatibilityVersion = "Xcode 3.2";
 			compatibilityVersion = "Xcode 3.2";
 			developmentRegion = English;
 			developmentRegion = English;
 			hasScannedForEncodings = 0;
 			hasScannedForEncodings = 0;
@@ -284,7 +284,7 @@
 			);
 			);
 			projectRoot = "";
 			projectRoot = "";
 			targets = (
 			targets = (
-				04998CEB17F8A933003441C3 /* HelloAE_ios */,
+				04998CEB17F8A933003441C3 /* HelloViewerAE_ios */,
 			);
 			);
 		};
 		};
 /* End PBXProject section */
 /* End PBXProject section */
@@ -387,7 +387,7 @@
 				ONLY_ACTIVE_ARCH = YES;
 				ONLY_ACTIVE_ARCH = YES;
 				SDKROOT = iphoneos;
 				SDKROOT = iphoneos;
 				TARGETED_DEVICE_FAMILY = "1,2";
 				TARGETED_DEVICE_FAMILY = "1,2";
-				USER_HEADER_SEARCH_PATHS = "../../../oxygine-framework//oxygine/src ../../..//SDL/include";
+				USER_HEADER_SEARCH_PATHS = "../../../../oxygine-framework//oxygine/src ../../../..//SDL/include";
 			};
 			};
 			name = Debug;
 			name = Debug;
 		};
 		};
@@ -423,7 +423,7 @@
 				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
 				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
 				SDKROOT = iphoneos;
 				SDKROOT = iphoneos;
 				TARGETED_DEVICE_FAMILY = "1,2";
 				TARGETED_DEVICE_FAMILY = "1,2";
-				USER_HEADER_SEARCH_PATHS = "../../../oxygine-framework//oxygine/src ../../..//SDL/include";
+				USER_HEADER_SEARCH_PATHS = "../../../../oxygine-framework//oxygine/src ../../../..//SDL/include";
 				VALIDATE_PRODUCT = YES;
 				VALIDATE_PRODUCT = YES;
 			};
 			};
 			name = Release;
 			name = Release;
@@ -436,18 +436,18 @@
 				CODE_SIGN_IDENTITY = "iPhone Developer";
 				CODE_SIGN_IDENTITY = "iPhone Developer";
 				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
 				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
 				GCC_PRECOMPILE_PREFIX_HEADER = YES;
 				GCC_PRECOMPILE_PREFIX_HEADER = YES;
-				GCC_PREFIX_HEADER = "HelloAE/HelloAE_ios-Prefix.pch";
+				GCC_PREFIX_HEADER = "HelloViewerAE/HelloViewerAE_ios-Prefix.pch";
 				GCC_WARN_UNUSED_VALUE = YES;
 				GCC_WARN_UNUSED_VALUE = YES;
 				GCC_WARN_UNUSED_VARIABLE = NO;
 				GCC_WARN_UNUSED_VARIABLE = NO;
 				GCC_INLINES_ARE_PRIVATE_EXTERN = NO;
 				GCC_INLINES_ARE_PRIVATE_EXTERN = NO;
-				INFOPLIST_FILE = "HelloAE/HelloAE_ios-Info.plist";
+				INFOPLIST_FILE = "HelloViewerAE/HelloViewerAE_ios-Info.plist";
 				LIBRARY_SEARCH_PATHS = (
 				LIBRARY_SEARCH_PATHS = (
 					"$(inherited)",
 					"$(inherited)",
-					"../../../oxygine-framework//oxygine/third_party/ios/libraries",
+					"../../../../oxygine-framework//oxygine/third_party/ios/libraries",
 				);
 				);
 				ONLY_ACTIVE_ARCH = YES;
 				ONLY_ACTIVE_ARCH = YES;
-				PRODUCT_BUNDLE_IDENTIFIER = org.oxygine.helloae;
-				PRODUCT_NAME = HelloAE_ios;
+				PRODUCT_BUNDLE_IDENTIFIER = org.oxygine.helloviewerae;
+				PRODUCT_NAME = HelloViewerAE_ios;
 				PROVISIONING_PROFILE = "";
 				PROVISIONING_PROFILE = "";
 				TARGETED_DEVICE_FAMILY = "1,2";
 				TARGETED_DEVICE_FAMILY = "1,2";
 				WRAPPER_EXTENSION = app;
 				WRAPPER_EXTENSION = app;
@@ -462,18 +462,18 @@
 				CODE_SIGN_IDENTITY = "iPhone Developer";
 				CODE_SIGN_IDENTITY = "iPhone Developer";
 				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
 				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
 				GCC_PRECOMPILE_PREFIX_HEADER = YES;
 				GCC_PRECOMPILE_PREFIX_HEADER = YES;
-				GCC_PREFIX_HEADER = "HelloAE/HelloAE_ios-Prefix.pch";
+				GCC_PREFIX_HEADER = "HelloViewerAE/HelloViewerAE_ios-Prefix.pch";
 				GCC_WARN_UNUSED_VALUE = YES;
 				GCC_WARN_UNUSED_VALUE = YES;
 				GCC_WARN_UNUSED_VARIABLE = NO;
 				GCC_WARN_UNUSED_VARIABLE = NO;
 				GCC_INLINES_ARE_PRIVATE_EXTERN = NO;
 				GCC_INLINES_ARE_PRIVATE_EXTERN = NO;
-				INFOPLIST_FILE = "HelloAE/HelloAE_ios-Info.plist";
+				INFOPLIST_FILE = "HelloViewerAE/HelloViewerAE_ios-Info.plist";
 				LIBRARY_SEARCH_PATHS = (
 				LIBRARY_SEARCH_PATHS = (
 					"$(inherited)",
 					"$(inherited)",
-					"../../../oxygine-framework//oxygine/third_party/ios/libraries",
+					"../../../../oxygine-framework//oxygine/third_party/ios/libraries",
 				);
 				);
 				ONLY_ACTIVE_ARCH = NO;
 				ONLY_ACTIVE_ARCH = NO;
-				PRODUCT_BUNDLE_IDENTIFIER = org.oxygine.helloae;
-				PRODUCT_NAME = HelloAE_ios;
+				PRODUCT_BUNDLE_IDENTIFIER = org.oxygine.helloviewerae;
+				PRODUCT_NAME = HelloViewerAE_ios;
 				PROVISIONING_PROFILE = "";
 				PROVISIONING_PROFILE = "";
 				TARGETED_DEVICE_FAMILY = "1,2";
 				TARGETED_DEVICE_FAMILY = "1,2";
 				WRAPPER_EXTENSION = app;
 				WRAPPER_EXTENSION = app;
@@ -483,7 +483,7 @@
 /* End XCBuildConfiguration section */
 /* End XCBuildConfiguration section */
 
 
 /* Begin XCConfigurationList section */
 /* Begin XCConfigurationList section */
-		04998CE717F8A933003441C3 /* Build configuration list for PBXProject "HelloAE_ios" */ = {
+		04998CE717F8A933003441C3 /* Build configuration list for PBXProject "HelloViewerAE_ios" */ = {
 			isa = XCConfigurationList;
 			isa = XCConfigurationList;
 			buildConfigurations = (
 			buildConfigurations = (
 				04998D1F17F8A933003441C3 /* Debug */,
 				04998D1F17F8A933003441C3 /* Debug */,
@@ -492,7 +492,7 @@
 			defaultConfigurationIsVisible = 0;
 			defaultConfigurationIsVisible = 0;
 			defaultConfigurationName = Release;
 			defaultConfigurationName = Release;
 		};
 		};
-		04998D2117F8A933003441C3 /* Build configuration list for PBXNativeTarget "HelloAE_ios" */ = {
+		04998D2117F8A933003441C3 /* Build configuration list for PBXNativeTarget "HelloViewerAE_ios" */ = {
 			isa = XCConfigurationList;
 			isa = XCConfigurationList;
 			buildConfigurations = (
 			buildConfigurations = (
 				04998D2217F8A933003441C3 /* Debug */,
 				04998D2217F8A933003441C3 /* Debug */,

+ 0 - 0
examples/proj.macosx/HelloAE/HelloAE_macosx-Prefix.pch → examples/HelloViewerAE/proj.macosx/HelloViewerAE/HelloViewerAE_macosx-Prefix.pch


+ 0 - 0
examples/proj.ios_mac/mac/Assets.xcassets/AppIcon.appiconset/Contents.json → examples/HelloViewerAE/proj.macosx/HelloViewerAE/Images.xcassets/AppIcon.appiconset/Contents.json


+ 0 - 0
examples/proj.macosx/HelloAE_macosx-Info.plist → examples/HelloViewerAE/proj.macosx/HelloViewerAE_macosx-Info.plist


+ 32 - 32
examples/proj.macosx/HelloAE_macosx.xcodeproj/project.pbxproj → examples/HelloViewerAE/proj.macosx/HelloViewerAE_macosx.xcodeproj/project.pbxproj

@@ -79,17 +79,17 @@
 /* Begin PBXFileReference section */
 /* Begin PBXFileReference section */
 		04059FEC187202A200BA6557 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; };
 		04059FEC187202A200BA6557 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; };
 		04059FEE187202AC00BA6557 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; };
 		04059FEE187202AC00BA6557 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; };
-		04059FF01872031A00BA6557 /* libjpeg.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libjpeg.a; path = ../../../oxygine-framework//oxygine/third_party/macosx/libraries/libjpeg.a; sourceTree = "<group>"; };
-		04059FF11872031A00BA6557 /* libpng.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libpng.a; path = ../../../oxygine-framework//oxygine/third_party/macosx/libraries/libpng.a; sourceTree = "<group>"; };
-		04059FF4187203A600BA6557 /* libjpeg.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libjpeg.a; path = ../../../oxygine-framework//oxygine/third_party/ios/libraries/libjpeg.a; sourceTree = "<group>"; };
-		04059FF5187203A600BA6557 /* libpng.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libpng.a; path = ../../../oxygine-framework//oxygine/third_party/ios/libraries/libpng.a; sourceTree = "<group>"; };
-		049B572E1871FBE900EF3C66 /* demo_macosx.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = HelloAE_macosx.app; sourceTree = BUILT_PRODUCTS_DIR; };
+		04059FF01872031A00BA6557 /* libjpeg.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libjpeg.a; path = ../../../../oxygine-framework//oxygine/third_party/macosx/libraries/libjpeg.a; sourceTree = "<group>"; };
+		04059FF11872031A00BA6557 /* libpng.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libpng.a; path = ../../../../oxygine-framework//oxygine/third_party/macosx/libraries/libpng.a; sourceTree = "<group>"; };
+		04059FF4187203A600BA6557 /* libjpeg.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libjpeg.a; path = ../../../../oxygine-framework//oxygine/third_party/ios/libraries/libjpeg.a; sourceTree = "<group>"; };
+		04059FF5187203A600BA6557 /* libpng.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libpng.a; path = ../../../../oxygine-framework//oxygine/third_party/ios/libraries/libpng.a; sourceTree = "<group>"; };
+		049B572E1871FBE900EF3C66 /* demo_macosx.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = HelloViewerAE_macosx.app; sourceTree = BUILT_PRODUCTS_DIR; };
 		049B57311871FBE900EF3C66 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
 		049B57311871FBE900EF3C66 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
 		049B57341871FBE900EF3C66 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; };
 		049B57341871FBE900EF3C66 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; };
 		049B57351871FBE900EF3C66 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; };
 		049B57351871FBE900EF3C66 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; };
 		049B57361871FBE900EF3C66 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
 		049B57361871FBE900EF3C66 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
-		049B57391871FBE900EF3C66 /* demo_macosx-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "HelloAE_macosx-Info.plist"; sourceTree = "<group>"; };
-		049B57491871FBE900EF3C66 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = HelloAE/Images.xcassets; sourceTree = "<group>"; };
+		049B57391871FBE900EF3C66 /* demo_macosx-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "HelloViewerAE_macosx-Info.plist"; sourceTree = "<group>"; };
+		049B57491871FBE900EF3C66 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = HelloViewerAE/Images.xcassets; sourceTree = "<group>"; };
 		049B57501871FBE900EF3C66 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; };
 		049B57501871FBE900EF3C66 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; };
 		360377333740D8A2FD15BBE6 /* ../src/example.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = example.cpp; path = ../src/example.cpp; sourceTree = "<group>"; };
 		360377333740D8A2FD15BBE6 /* ../src/example.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = example.cpp; path = ../src/example.cpp; sourceTree = "<group>"; };
 		0BF9628FC8D38F9748F0CDEB /* ../src/main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = main.cpp; path = ../src/main.cpp; sourceTree = "<group>"; };
 		0BF9628FC8D38F9748F0CDEB /* ../src/main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = main.cpp; path = ../src/main.cpp; sourceTree = "<group>"; };
@@ -98,8 +98,8 @@
 		04FE4D4FB640E0DF92DFB865 /* ../data/images */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = folder; name = images; path = ../data/images; sourceTree = "<group>"; };
 		04FE4D4FB640E0DF92DFB865 /* ../data/images */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = folder; name = images; path = ../data/images; sourceTree = "<group>"; };
 		7F3B12E3C9D554D9FE28101D /* ../data/res.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = wtf; name = res.xml; path = ../data/res.xml; sourceTree = "<group>"; };
 		7F3B12E3C9D554D9FE28101D /* ../data/res.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = wtf; name = res.xml; path = ../data/res.xml; sourceTree = "<group>"; };
 
 
-		04A57D761871FFEB0068B1E5 /* oxygine_macosx.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = oxygine_macosx.xcodeproj; path = ../../../oxygine-framework//oxygine/SDL/macosx/oxygine_macosx/oxygine_macosx.xcodeproj; sourceTree = "<group>"; };
-		04A57D7E1872012A0068B1E5 /* SDL.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = SDL.xcodeproj; path = ../../..//SDL/Xcode/SDL/SDL.xcodeproj; sourceTree = "<group>"; };
+		04A57D761871FFEB0068B1E5 /* oxygine_macosx.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = oxygine_macosx.xcodeproj; path = ../../../../oxygine-framework//oxygine/SDL/macosx/oxygine_macosx/oxygine_macosx.xcodeproj; sourceTree = "<group>"; };
+		04A57D7E1872012A0068B1E5 /* SDL.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = SDL.xcodeproj; path = ../../../..//SDL/Xcode/SDL/SDL.xcodeproj; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 /* End PBXFileReference section */
 
 
 /* Begin PBXFrameworksBuildPhase section */
 /* Begin PBXFrameworksBuildPhase section */
@@ -144,7 +144,7 @@
 		049B572F1871FBE900EF3C66 /* Products */ = {
 		049B572F1871FBE900EF3C66 /* Products */ = {
 			isa = PBXGroup;
 			isa = PBXGroup;
 			children = (
 			children = (
-				049B572E1871FBE900EF3C66 /* HelloAE_macosx.app */,
+				049B572E1871FBE900EF3C66 /* HelloViewerAE_macosx.app */,
 			);
 			);
 			name = Products;
 			name = Products;
 			sourceTree = "<group>";
 			sourceTree = "<group>";
@@ -189,7 +189,7 @@
 				04FE4D4FB640E0DF92DFB865 /* images */, 
 				04FE4D4FB640E0DF92DFB865 /* images */, 
 				7F3B12E3C9D554D9FE28101D /* res.xml */, 
 				7F3B12E3C9D554D9FE28101D /* res.xml */, 
 
 
-				049B57391871FBE900EF3C66 /* HelloAE_macosx-Info.plist */,
+				049B57391871FBE900EF3C66 /* HelloViewerAE_macosx-Info.plist */,
 			);
 			);
 			name = "Supporting Files";
 			name = "Supporting Files";
 			sourceTree = "<group>";
 			sourceTree = "<group>";
@@ -219,9 +219,9 @@
 /* End PBXGroup section */
 /* End PBXGroup section */
 
 
 /* Begin PBXNativeTarget section */
 /* Begin PBXNativeTarget section */
-		049B572D1871FBE900EF3C66 /* HelloAE_macosx */ = {
+		049B572D1871FBE900EF3C66 /* HelloViewerAE_macosx */ = {
 			isa = PBXNativeTarget;
 			isa = PBXNativeTarget;
-			buildConfigurationList = 049B575F1871FBE900EF3C66 /* Build configuration list for PBXNativeTarget "HelloAE_macosx" */;
+			buildConfigurationList = 049B575F1871FBE900EF3C66 /* Build configuration list for PBXNativeTarget "HelloViewerAE_macosx" */;
 			buildPhases = (
 			buildPhases = (
 				049B572A1871FBE900EF3C66 /* Sources */,
 				049B572A1871FBE900EF3C66 /* Sources */,
 				049B572B1871FBE900EF3C66 /* Frameworks */,
 				049B572B1871FBE900EF3C66 /* Frameworks */,
@@ -233,9 +233,9 @@
 				04059FE91872027200BA6557 /* PBXTargetDependency */,
 				04059FE91872027200BA6557 /* PBXTargetDependency */,
 				04A57D8F187201EF0068B1E5 /* PBXTargetDependency */,
 				04A57D8F187201EF0068B1E5 /* PBXTargetDependency */,
 			);
 			);
-			name = HelloAE_macosx;
-			productName = HelloAE;
-			productReference = 049B572E1871FBE900EF3C66 /* HelloAE_macosx.app */;
+			name = HelloViewerAE_macosx;
+			productName = HelloViewerAE;
+			productReference = 049B572E1871FBE900EF3C66 /* HelloViewerAE_macosx.app */;
 			productType = "com.apple.product-type.application";
 			productType = "com.apple.product-type.application";
 		};
 		};
 /* End PBXNativeTarget section */
 /* End PBXNativeTarget section */
@@ -247,7 +247,7 @@
 				LastUpgradeCheck = 0610;
 				LastUpgradeCheck = 0610;
 				ORGANIZATIONNAME = oxygine;
 				ORGANIZATIONNAME = oxygine;
 			};
 			};
-			buildConfigurationList = 049B57291871FBE900EF3C66 /* Build configuration list for PBXProject "HelloAE_macosx" */;
+			buildConfigurationList = 049B57291871FBE900EF3C66 /* Build configuration list for PBXProject "HelloViewerAE_macosx" */;
 			compatibilityVersion = "Xcode 3.2";
 			compatibilityVersion = "Xcode 3.2";
 			developmentRegion = English;
 			developmentRegion = English;
 			hasScannedForEncodings = 0;
 			hasScannedForEncodings = 0;
@@ -270,7 +270,7 @@
 			);
 			);
 			projectRoot = "";
 			projectRoot = "";
 			targets = (
 			targets = (
-				049B572D1871FBE900EF3C66 /* HelloAE_macosx */,
+				049B572D1871FBE900EF3C66 /* HelloViewerAE_macosx */,
 			);
 			);
 		};
 		};
 /* End PBXProject section */
 /* End PBXProject section */
@@ -390,7 +390,7 @@
 				MACOSX_DEPLOYMENT_TARGET = 10.8;
 				MACOSX_DEPLOYMENT_TARGET = 10.8;
 				ONLY_ACTIVE_ARCH = YES;
 				ONLY_ACTIVE_ARCH = YES;
 				SDKROOT = macosx;
 				SDKROOT = macosx;
-				USER_HEADER_SEARCH_PATHS = "../../../oxygine-framework//oxygine/src ../../..//SDL/include";
+				USER_HEADER_SEARCH_PATHS = "../../../../oxygine-framework//oxygine/src ../../../..//SDL/include";
 				VALID_ARCHS = "x86_64";
 				VALID_ARCHS = "x86_64";
 			};
 			};
 			name = Debug;
 			name = Debug;
@@ -425,7 +425,7 @@
 				MACOSX_DEPLOYMENT_TARGET = 10.8;
 				MACOSX_DEPLOYMENT_TARGET = 10.8;
 				ONLY_ACTIVE_ARCH = YES;
 				ONLY_ACTIVE_ARCH = YES;
 				SDKROOT = macosx;
 				SDKROOT = macosx;
-				USER_HEADER_SEARCH_PATHS = "../../../oxygine-framework//oxygine/src ../../..//SDL/include";
+				USER_HEADER_SEARCH_PATHS = "../../../../oxygine-framework//oxygine/src ../../../..//SDL/include";
 				VALID_ARCHS = "x86_64";
 				VALID_ARCHS = "x86_64";
 			};
 			};
 			name = Release;
 			name = Release;
@@ -436,14 +436,14 @@
 				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
 				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
 				COMBINE_HIDPI_IMAGES = YES;
 				COMBINE_HIDPI_IMAGES = YES;
 				GCC_PRECOMPILE_PREFIX_HEADER = YES;
 				GCC_PRECOMPILE_PREFIX_HEADER = YES;
-				GCC_PREFIX_HEADER = "HelloAE/HelloAE_macosx-Prefix.pch";
-				INFOPLIST_FILE = "HelloAE_macosx-Info.plist";
+				GCC_PREFIX_HEADER = "HelloViewerAE/HelloViewerAE_macosx-Prefix.pch";
+				INFOPLIST_FILE = "HelloViewerAE_macosx-Info.plist";
 				LIBRARY_SEARCH_PATHS = (
 				LIBRARY_SEARCH_PATHS = (
 					"$(inherited)",
 					"$(inherited)",
-					"../../../oxygine-framework//oxygine/third_party/macosx/libraries",
-					"../../../oxygine-framework//oxygine/third_party/ios/libraries",
+					"../../../../oxygine-framework//oxygine/third_party/macosx/libraries",
+					"../../../../oxygine-framework//oxygine/third_party/ios/libraries",
 				);
 				);
-				PRODUCT_NAME = HelloAE_macosx;
+				PRODUCT_NAME = HelloViewerAE_macosx;
 				WRAPPER_EXTENSION = app;
 				WRAPPER_EXTENSION = app;
 			};
 			};
 			name = Debug;
 			name = Debug;
@@ -454,14 +454,14 @@
 				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
 				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
 				COMBINE_HIDPI_IMAGES = YES;
 				COMBINE_HIDPI_IMAGES = YES;
 				GCC_PRECOMPILE_PREFIX_HEADER = YES;
 				GCC_PRECOMPILE_PREFIX_HEADER = YES;
-				GCC_PREFIX_HEADER = "HelloAE/HelloAE_macosx-Prefix.pch";
-				INFOPLIST_FILE = "HelloAE_macosx-Info.plist";
+				GCC_PREFIX_HEADER = "HelloViewerAE/HelloViewerAE_macosx-Prefix.pch";
+				INFOPLIST_FILE = "HelloViewerAE_macosx-Info.plist";
 				LIBRARY_SEARCH_PATHS = (
 				LIBRARY_SEARCH_PATHS = (
 					"$(inherited)",
 					"$(inherited)",
-					"../../../oxygine-framework//oxygine/third_party/macosx/libraries",
-					"../../../oxygine-framework//oxygine/third_party/ios/libraries",
+					"../../../../oxygine-framework//oxygine/third_party/macosx/libraries",
+					"../../../../oxygine-framework//oxygine/third_party/ios/libraries",
 				);
 				);
-				PRODUCT_NAME = HelloAE_macosx;
+				PRODUCT_NAME = HelloViewerAE_macosx;
 				WRAPPER_EXTENSION = app;
 				WRAPPER_EXTENSION = app;
 			};
 			};
 			name = Release;
 			name = Release;
@@ -469,7 +469,7 @@
 /* End XCBuildConfiguration section */
 /* End XCBuildConfiguration section */
 
 
 /* Begin XCConfigurationList section */
 /* Begin XCConfigurationList section */
-		049B57291871FBE900EF3C66 /* Build configuration list for PBXProject "HelloAE_macosx" */ = {
+		049B57291871FBE900EF3C66 /* Build configuration list for PBXProject "HelloViewerAE_macosx" */ = {
 			isa = XCConfigurationList;
 			isa = XCConfigurationList;
 			buildConfigurations = (
 			buildConfigurations = (
 				049B575D1871FBE900EF3C66 /* Debug */,
 				049B575D1871FBE900EF3C66 /* Debug */,
@@ -478,7 +478,7 @@
 			defaultConfigurationIsVisible = 0;
 			defaultConfigurationIsVisible = 0;
 			defaultConfigurationName = Release;
 			defaultConfigurationName = Release;
 		};
 		};
-		049B575F1871FBE900EF3C66 /* Build configuration list for PBXNativeTarget "HelloAE_macosx" */ = {
+		049B575F1871FBE900EF3C66 /* Build configuration list for PBXNativeTarget "HelloViewerAE_macosx" */ = {
 			isa = XCConfigurationList;
 			isa = XCConfigurationList;
 			buildConfigurations = (
 			buildConfigurations = (
 				049B57601871FBE900EF3C66 /* Debug */,
 				049B57601871FBE900EF3C66 /* Debug */,

+ 2 - 2
examples/proj.win32/HelloAE.sln → examples/HelloViewerAE/proj.win32/HelloViewerAE.sln

@@ -1,9 +1,9 @@
 
 
 Microsoft Visual Studio Solution File, Format Version 11.00
 Microsoft Visual Studio Solution File, Format Version 11.00
 # Visual Studio 2010
 # Visual Studio 2010
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HelloAE", "HelloAE.vcxproj", "{2B4D7491-A4F8-4606-B0E3-2A1FCE3C46C4}"
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HelloViewerAE", "HelloViewerAE.vcxproj", "{2B4D7491-A4F8-4606-B0E3-2A1FCE3C46C4}"
 EndProject
 EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Oxygine", "../../../oxygine-framework/\oxygine\SDL\win32\oxygine.vcxproj", "{52411305-CFE1-4FA8-9885-5729BFC816CF}"
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Oxygine", "../../../../oxygine-framework/\oxygine\SDL\win32\oxygine.vcxproj", "{52411305-CFE1-4FA8-9885-5729BFC816CF}"
 EndProject
 EndProject
 Global
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution

+ 7 - 7
examples/proj.win32/HelloAE.vcxproj → examples/HelloViewerAE/proj.win32/HelloViewerAE.vcxproj

@@ -13,8 +13,8 @@
   <PropertyGroup Label="Globals">
   <PropertyGroup Label="Globals">
     <ProjectGuid>{2B4D7491-A4F8-4606-B0E3-2A1FCE3C46C4}</ProjectGuid>
     <ProjectGuid>{2B4D7491-A4F8-4606-B0E3-2A1FCE3C46C4}</ProjectGuid>
     <Keyword>Win32Proj</Keyword>
     <Keyword>Win32Proj</Keyword>
-    <RootNamespace>HelloAE</RootNamespace>
-    <ProjectName>HelloAE</ProjectName>
+    <RootNamespace>HelloViewerAE</RootNamespace>
+    <ProjectName>HelloViewerAE</ProjectName>
   </PropertyGroup>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
 
 
@@ -84,13 +84,13 @@
       <WarningLevel>Level3</WarningLevel>
       <WarningLevel>Level3</WarningLevel>
       <Optimization>Disabled</Optimization>
       <Optimization>Disabled</Optimization>
       <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <AdditionalIncludeDirectories>../../../oxygine-framework//oxygine/src;../../..//SDL/include;../../../oxygine-framework//oxygine/third_party/win32/pthreads/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalIncludeDirectories>../../../../oxygine-framework//oxygine/src;../../../..//SDL/include;../../../../oxygine-framework//oxygine/third_party/win32/pthreads/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
     </ClCompile>
     </ClCompile>
     <Link>
     <Link>
       <SubSystem>Windows</SubSystem>
       <SubSystem>Windows</SubSystem>
       <GenerateDebugInformation>true</GenerateDebugInformation>
       <GenerateDebugInformation>true</GenerateDebugInformation>
       <AdditionalDependencies></AdditionalDependencies>
       <AdditionalDependencies></AdditionalDependencies>
-      <AdditionalLibraryDirectories>../../../oxygine-framework//oxygine/third_party/win32/libraries;../../../oxygine-framework//libs;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+      <AdditionalLibraryDirectories>../../../../oxygine-framework//oxygine/third_party/win32/libraries;../../../../oxygine-framework//libs;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
       <AdditionalOptions>/ignore:4099 %(AdditionalOptions)</AdditionalOptions>
       <AdditionalOptions>/ignore:4099 %(AdditionalOptions)</AdditionalOptions>
     </Link>
     </Link>
   </ItemDefinitionGroup>
   </ItemDefinitionGroup>
@@ -103,20 +103,20 @@
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <IntrinsicFunctions>true</IntrinsicFunctions>
       <IntrinsicFunctions>true</IntrinsicFunctions>
       <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <AdditionalIncludeDirectories>../../../oxygine-framework//oxygine/src;../../..//SDL/include;../../../oxygine-framework//oxygine/third_party/win32/pthreads/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalIncludeDirectories>../../../../oxygine-framework//oxygine/src;../../../..//SDL/include;../../../../oxygine-framework//oxygine/third_party/win32/pthreads/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
     </ClCompile>
     </ClCompile>
     <Link>
     <Link>
       <SubSystem>Windows</SubSystem>
       <SubSystem>Windows</SubSystem>
       <GenerateDebugInformation>true</GenerateDebugInformation>
       <GenerateDebugInformation>true</GenerateDebugInformation>
       <EnableCOMDATFolding>true</EnableCOMDATFolding>
       <EnableCOMDATFolding>true</EnableCOMDATFolding>
       <OptimizeReferences>true</OptimizeReferences>
       <OptimizeReferences>true</OptimizeReferences>
-      <AdditionalLibraryDirectories>../../../oxygine-framework//oxygine/third_party/win32/libraries;../../../oxygine-framework//libs;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+      <AdditionalLibraryDirectories>../../../../oxygine-framework//oxygine/third_party/win32/libraries;../../../../oxygine-framework//libs;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
       <AdditionalDependencies></AdditionalDependencies>
       <AdditionalDependencies></AdditionalDependencies>
       <AdditionalOptions>/ignore:4099 %(AdditionalOptions)</AdditionalOptions>
       <AdditionalOptions>/ignore:4099 %(AdditionalOptions)</AdditionalOptions>
     </Link>
     </Link>
   </ItemDefinitionGroup>
   </ItemDefinitionGroup>
   <ItemGroup>    
   <ItemGroup>    
-    <ProjectReference Include="../../../oxygine-framework/\oxygine\SDL\win32\oxygine.vcxproj">
+    <ProjectReference Include="../../../../oxygine-framework/\oxygine\SDL\win32\oxygine.vcxproj">
       <Project>{52411305-cfe1-4fa8-9885-5729bfc816cf}</Project>
       <Project>{52411305-cfe1-4fa8-9885-5729bfc816cf}</Project>
     </ProjectReference>
     </ProjectReference>
   </ItemGroup>
   </ItemGroup>

+ 0 - 0
examples/proj.win32/HelloAE.vcxproj.filters → examples/HelloViewerAE/proj.win32/HelloViewerAE.vcxproj.filters


+ 0 - 0
examples/proj.win32/HelloAE.vcxproj.user → examples/HelloViewerAE/proj.win32/HelloViewerAE.vcxproj.user


+ 390 - 0
examples/HelloViewerAE/src/AEMovieWork.cpp

@@ -0,0 +1,390 @@
+#include "AEMovieWork.h"
+#include <functional>
+#include "ox/Material.hpp"
+#include "movie/movie.hpp"
+//#include "ox/STDMaterial.hpp"
+#include <map>
+#include "ox/stringUtils.hpp"
+//#include "MovieSprite.h"
+#include "ox/UberShaderProgram.hpp"
+//#include "shared.h"
+#include "ae/AERenderer.h"
+//#include "packs/preloader.h"
+#include "ox/stringUtils.hpp"
+#include "ox/Font.hpp"
+#include <atomic>
+//#include "utils/DebugTimer.h"
+#include "oxygine/winnie_alloc/winnie_alloc.h"
+#include "ox/RenderState.hpp"
+#include <stdarg.h>
+#include "ox/DebugActor.hpp"
+
+#ifndef AEVIEWER
+#include "ResSound.h"
+#include "SoundInstance.h"
+#endif
+
+#ifdef HAVE_MP
+#include "mp/mp_init.h"
+#include "mp/mp.h"
+#endif
+
+//#define WORK_AREA_API 1
+using namespace oxygine;
+
+spAEMovieWork AEMovieWork::createWork(AEMovieResource& res, const string& comp, error_policy ep)
+{
+    const aeMovieCompositionData* compositionData = ae_get_movie_composition_data(res.movieData, comp.c_str());
+
+    if (!compositionData)
+    {
+        handleErrorPolicy(ep, "can't find composition %s:%s", res._folder.c_str(), comp.c_str());
+        return 0;
+    }
+
+    spAEMovieWork movie = new AEMovieWork;
+    movie->init2(res, compositionData);
+    movie->setName(res._folder + "/" + comp);
+    return movie;
+}
+
+bool AEMovieWork::computeAllTimelineBounds(RectF & out)
+{
+    if (!_composition) return false;
+
+    Vector2 umin(0.0f, 0.0f);
+    Vector2 umax(0.0f, 0.0f);
+
+    bool uset = false;
+
+    bool hidden = false;
+
+    aeMovieRenderMesh mesh;
+    uint32_t mesh_iterator = 0;
+
+    while (ae_compute_movie_mesh(_composition, &mesh_iterator, &mesh) == AE_TRUE)
+    {
+//        DTManual ae_ren_i("ae-ren-i");
+
+        if (hidden)
+        {
+            if (mesh.layer_type == AE_MOVIE_LAYER_TYPE_SLOT)
+            {
+                Actor* actor = (Actor*)mesh.element_userdata;
+                if (actor->isName(_showHideSlots))
+                    hidden = false;
+            }
+            continue;
+        }
+
+        for (int i = 0; i < (int)mesh.vertexCount; i++) {
+            const ae_vector3_t& p = *(mesh.position + i);
+
+            if (!uset)
+            {
+                uset = true;
+                umin.x = umax.x = p[0];
+                umin.y = umax.y = p[1];
+            }
+            else
+            {
+                umin.x = std::min(umin.x, p[0]);
+                umin.y = std::min(umin.y, p[1]);
+                umax.x = std::max(umax.x, p[0]);
+                umax.y = std::max(umax.y, p[1]);
+            }
+        }
+    }
+
+    out = RectF(umin.x, umin.y, umax.x - umin.x, umax.y - umin.y);
+    return uset;
+}
+
+bool AEMovieWork::calcMinMaxForAllFrames(RectF & out)
+{
+    if (!_composition) return false;
+
+    float d = ae_get_movie_composition_duration(_composition);
+    float step = std::min(10.0f, d * 0.1f);
+
+    bool ret = false;
+
+    float oldt = ae_get_movie_composition_time(_composition);
+
+    float t = 0;
+    ae_set_movie_composition_time(_composition, t);
+    while (true)
+    {
+        RectF r;
+        if (computeAllTimelineBounds(r)) {
+            if (!ret)
+                out = r;
+            else
+                out.unite(r);
+            ret = true;
+        }
+        if (t >= d) break;
+
+        t += step;
+        ae_update_movie_composition(_composition, step);
+    }
+    
+    ae_set_movie_composition_time(_composition, oldt);
+
+    return ret;
+}
+
+/*
+void AEMovieWork::doRender(const RenderState& rs)
+{
+//    AEMovie::doRender(rs);
+
+    if (!_composition)
+        return;
+
+    //if (_render2cache)
+    //{
+    //    int q = 0;
+    //}
+
+    DTAuto ae_ren("ae-ren-o");
+
+    if (_timeLineFrom)
+    {
+        float maintm = ae_get_movie_composition_time(_timeLineFrom->ae());
+        float loctm = ae_get_movie_composition_time(_composition);
+        if (maintm > loctm)
+            ae_update_movie_composition(_composition, maintm - loctm);
+        else
+            ae_set_movie_composition_time(_composition, maintm);
+    }
+
+    Material::setCurrent(0);
+
+    STDRenderer* stdr = ((STDMaterial*)rs.material)->getRenderer();
+    IVideoDriver* driver = stdr->getDriver();
+    stdr->resetSettings();
+
+    const VertexDeclaration* decl = driver->getVertexDeclaration(VERTEX_PCT2);
+
+
+    Matrix vp = stdr->getViewProjection();
+    Matrix wvp = rs.transform.toMatrix() * vp;
+
+
+    //_res->g
+    int shaderFlags = _res->_shaderFlags;
+    AERenderer renderer(driver, [=](int f)
+    {
+        return STDRenderer::uberShader.getShaderProgram(shaderFlags | f);
+    }, wvp);
+
+
+    renderer.setColor(_color);
+    renderer.reset();
+
+    bool hidden = false;
+
+
+    aeMovieRenderMesh mesh;
+    uint32_t mesh_iterator = 0;
+
+
+    if (test::AeHalfFillrate)
+    {
+        Rect r;
+
+        if (test::AeHalfFillrate == 1)
+            r = Rect(0, 0, (int)(getWidth() / 2), (int)getHeight());
+        if (test::AeHalfFillrate == 2)
+            r = Rect(0, 0, (int)(getWidth() / 2), (int)(getHeight() / 2));
+        if (test::AeHalfFillrate == 3)
+            r = Rect(0, 0, 0, 0);
+
+        driver->setScissorRect(&r);
+    }
+
+    while (ae_compute_movie_mesh(_composition, &mesh_iterator, &mesh) == AE_TRUE)
+    {
+        DTManual ae_ren_i("ae-ren-i");
+
+        if (hidden)
+        {
+            if (mesh.layer_type == AE_MOVIE_LAYER_TYPE_SLOT)
+            {
+                Actor* actor = (Actor*)mesh.element_data;
+                if (actor->isName(_showHideSlots))
+                    hidden = false;
+            }
+            continue;
+        }
+
+        const Mask* msk = (const Mask*)mesh.track_matte_data;
+        if (test::AeMasksDisabled)
+            msk = 0;
+        if (msk)
+        {
+            //mesh = msk->_mask;
+            //  mesh.layer_type = AE_MOVIE_LAYER_TYPE_IMAGE;
+
+            if (0)
+            {
+                renderer.setMask(0);
+                renderer.drawBatch();
+                aeMovieRenderMesh meshMask = msk->_mask;
+                ResAnim* rs = (ResAnim*)meshMask.resource_data;
+#ifdef ONLINE
+                preloader::preload(rs);
+#endif
+                meshMask.r = 1.0f;
+                meshMask.g = 1.0f;
+                meshMask.b = 1.0f;
+                meshMask.a = 1.0f;
+
+                const AnimationFrame& frame = rs->getFrame(0);
+                const RectF& src = frame.getSrcRect();
+                if(_show_texture)
+                    renderer.setTexture(frame.getDiffuse().base, 0);
+                else
+                    renderer.setTexture(STDRenderer::white, 0);
+                driver->setState(IVideoDriver::STATE_BLEND, 0);
+                //buildVD(renderer, mesh, src);
+                renderer.drawBatch();
+                driver->setState(IVideoDriver::STATE_BLEND, 1);
+            }
+        }
+
+        if (!_show_texture)
+            renderer.setBlendMode(IVideoDriver::BT_ONE, IVideoDriver::BT_ONE);
+        else
+        switch (mesh.blend_mode)
+        {
+        case AE_MOVIE_BLEND_SCREEN:
+            renderer.setBlendMode(IVideoDriver::BT_ONE, IVideoDriver::BT_ONE_MINUS_SRC_COLOR);
+            break;
+        case AE_MOVIE_BLEND_ADD:
+            renderer.setBlendMode(IVideoDriver::BT_ONE, IVideoDriver::BT_ONE);
+            break;
+        case AE_MOVIE_BLEND_NORMAL:
+            renderer.setBlendMode(IVideoDriver::BT_ONE, IVideoDriver::BT_ONE_MINUS_SRC_ALPHA);
+            break;
+        case AE_MOVIE_BLEND_MULTIPLY:
+            renderer.setBlendMode(IVideoDriver::BT_DST_COLOR, IVideoDriver::BT_ONE_MINUS_SRC_ALPHA);
+            break;
+        };
+
+        if(_show_texture)
+            renderer.setMask(msk);
+
+        switch (mesh.layer_type)
+        {
+        case AE_MOVIE_LAYER_TYPE_SLOT:
+        {
+            Actor* actor = (Actor*)mesh.element_data;
+            if (actor)
+            {
+                renderer.drawBatch();
+
+                Material::setCurrent(0);
+                actor->render(rs);
+                Material::setCurrent(0);
+
+                renderer.reset();
+
+                if (actor->isName(_showHideSlots))
+                    hidden = true;
+            }
+        }
+        break;
+
+        case AE_MOVIE_LAYER_TYPE_PARTICLE:
+        {
+            renderer.drawBatch();
+
+            Actor* actor = (Actor*)mesh.element_data;
+            actor->render(rs);
+            Material::setCurrent(0);
+
+            renderer.reset();
+        } break;
+        case AE_MOVIE_LAYER_TYPE_SOLID:
+        {
+            renderer.setTexture(STDRenderer::white, STDRenderer::white);
+            RectF src(0, 0, 1, 1);
+            buildVD(renderer, mesh, src, _color);
+        }
+        break;
+
+        case AE_MOVIE_LAYER_TYPE_IMAGE:
+        case AE_MOVIE_LAYER_TYPE_SEQUENCE:
+        {
+            ResAnim* rs = (ResAnim*)mesh.resource_data;
+#ifdef ONLINE
+            preloader::preload(rs);
+#endif
+
+            const AnimationFrame& frame = rs->getFrame(0);
+            const RectF& src = frame.getSrcRect();
+            if (_show_texture)
+            {
+                renderer.setTexture(frame.getDiffuse().base, frame.getDiffuse().alpha);
+                buildVD(renderer, mesh, src, _color);
+            }
+            else
+            {
+                renderer.setTexture(STDRenderer::white, STDRenderer::white);
+                Color clr = _color;
+                if (clr.a >= 64)
+                    clr.a /= msk ? 4 : 8;
+                buildVD(renderer, mesh, src, clr);
+            }
+
+        } break;
+
+        case AE_MOVIE_LAYER_TYPE_VIDEO:
+        {
+            MovieSprite* movie = (MovieSprite*)mesh.element_data;
+            if (movie)
+            {
+                renderer.drawBatch();
+
+                const AnimationFrame& frame = movie->getAnimFrame();
+                const RectF& src = frame.getSrcRect();
+
+                movie->convert();
+
+                if (msk)
+                    renderer.applyMask(*movie->_shader, msk);
+                else
+                    renderer.apply(*movie->_shader);
+
+
+                const Diffuse& d = frame.getDiffuse();
+
+                movie->_shader->apply(driver, d.base, d.alpha);
+                Vector2 yaScale(1, 1);
+                driver->setUniform("yaScale", &yaScale, 1);
+
+                buildVD(renderer, mesh, src, _color);
+
+                renderer.drawBatch();
+                renderer.reset();
+            }
+
+        } break;
+        }
+    }
+
+    renderer.drawBatch();
+
+    if (test::AeHalfFillrate)
+    {
+        driver->setScissorRect(0);
+    }
+
+
+    DebugActor::addDebugString("AE batches: %d", renderer._batches);
+
+    Material::setCurrent(0);
+}
+*/

+ 21 - 0
examples/HelloViewerAE/src/AEMovieWork.h

@@ -0,0 +1,21 @@
+#pragma once
+#include "ae/AEMovie.h"
+#include "ae/AEMovieResource.h"
+
+using namespace std;
+
+DECLARE_SMART(AEMovieWork, spAEMovieWork);
+class AEMovieWork : public AEMovie
+{
+public:
+    static spAEMovieWork createWork(AEMovieResource& res, const string& comp, error_policy ep = ep_show_error);
+
+    AEMovieWork() : _show_texture(true) {}
+
+    //void doRender(const RenderState& rs) override;
+
+    bool computeAllTimelineBounds(RectF & out);
+    bool calcMinMaxForAllFrames(RectF & out);
+
+    bool _show_texture;
+};

+ 496 - 0
examples/HelloViewerAE/src/example.cpp

@@ -0,0 +1,496 @@
+#include "oxygine-framework.h"
+
+#include "test.h"
+#include "ae/AEMovie.h"
+#include "AEMovieWork.h"
+#include "ox/ZipFileSystem.hpp"
+//#include "MovieSprite.h"
+
+using namespace oxygine;
+
+
+
+//#define MULTIWINDOW 1
+
+#if MULTIWINDOW
+spStage stage2;
+#endif
+
+AEMovieResource movieRes;
+
+extern std::string aeProject;
+extern std::string aeCurrent;
+extern Vector2 aeWorkArea;
+
+DECLARE_SMART(Preview, spPreview);
+
+namespace test
+{
+	bool AeMasksDisabled = false;
+	bool AeDontDraw = false;
+	int AeHalfFillrate = 0;
+}
+
+
+class Preview : public Test
+{
+public:
+	static spPreview instance;
+
+	spAEMovieWork movie;
+    spColorRectSprite _cr;
+    spColorRectSprite _cr2;
+	bool _looped = false;
+    static bool _bb;
+    static bool _show_all;
+    float _allscale = 1.0f;
+
+	Preview(const string &id)
+	{
+		addButton("play_loop", "play loop");
+        addButton("play_once", "play once");
+        addButton("interrupt", "interrupt");
+        addButton("pause", "pause");
+        addButton("resume", "resume");
+        addButton("wa", "ae work area");
+        addButton("wireframe", "wireframe");
+
+		//addButton("int_off", "interpolation off");
+		//addButton("int_on", "interpolation on");
+
+        addButton("show_all", _show_all ? "show all: on" : "show all: off");
+
+        addButton("bounding_box", _bb ? "bounding box: on" : "bounding box: off");
+
+        addButton("overdraw", "show overdraw");
+        addButton("mask", "disable mask");
+
+		_color = Color::Red;
+		_txtColor = Color::White;
+		//()
+		
+
+		Test::toggle t[2] = { {"use work area", 1}, {"no work area", 2} };
+		//addToggle("wa", t, 2);
+
+		addClickListener([=](Event*) {
+
+		});
+
+        addEventListener(TouchEvent::WHEEL_DIR, [=] (Event* ev) {
+            TouchEvent *te = safeCast<TouchEvent*>(ev);
+            
+            int b = movie->getWireframeMode();
+            if (te->wheelDirection.y < 0)
+            {
+                b += 1;
+            }
+
+            if (te->wheelDirection.y > 0)
+            {
+                b -= 1;
+            }
+
+            if (b < -1)
+                b = movie->getLastBatches();
+
+            if (b > 0)
+            {
+                b = b % (movie->getLastBatches() + 1 );
+            }
+
+            movie->setWireframeMode(b);
+
+        });
+
+		set(id);
+
+	}
+
+	void toggleClicked(string id, const toggle* data)
+	{
+	}
+
+	void clicked(string id)
+	{
+		size_t p = id.find(':');
+		if (p != id.npos)
+		{
+			string ev = id.substr(p + 1);
+			movie->playEvent(ev.c_str(), true);
+		}
+
+		if (id == "wa")
+		{
+			movie->playArea(aeWorkArea.x * 1000.0f, aeWorkArea.y * 1000.0f, true);
+		}
+
+        if (id == "play_loop")
+        {
+            movie->play(true);
+        }
+
+        if (id == "play_once")
+        {
+            movie->play(false);
+        }
+
+        if (id == "pause")
+        {
+            movie->pause();
+        }
+
+        if (id == "resume")
+        {
+            movie->resume();
+        }
+
+        if (id == "wireframe")
+        {
+
+        }
+
+        if (id == "mask")
+        {
+            test::AeMasksDisabled = !test::AeMasksDisabled;
+            updateText("mask", test::AeMasksDisabled ? "enable mask" : "disable mask");
+        }
+
+		if (id == "interrupt")
+		{
+			movie->interrupt();
+		}
+
+		if (id == "int_on")
+		{
+//			movie->setInterpolation(true);
+		}
+
+		if (id == "int_off")
+		{
+	//		movie->setInterpolation(false);
+		}
+
+        if (id == "bounding_box") {
+            _bb = !_bb;
+            updateText("bounding_box", _bb ? "bounding box: on" : "bounding box: off");
+        }
+
+        if (id == "overdraw") 
+        {
+            movie->setShowOverdraw(!movie->getShowOverdraw());
+            updateText("overdraw", !movie->getShowOverdraw() ? "show overdraw" : "hide overdraw");
+        }
+
+        if (id == "show_all")
+        {
+            _show_all = !_show_all;
+            updateText("show_all", _show_all ? "show all: on" : "show all: off");
+        }
+    }
+
+	void update(const UpdateState& us)
+	{
+		Test::update(us);
+		if (!movie)
+			return;
+
+        char str[255];
+        safe_sprintf(str, "wireframe: %d / %d", movie->getWireframeMode(), movie->getLastBatches());
+        updateText("wireframe", str);
+
+		if (key::wasPressed(SDL_SCANCODE_SPACE))
+		{
+			if (!movie->isPaused())
+			{
+				movie->pause();
+				notify("pause");
+			}
+			else
+			{
+				movie->resume();
+				notify("resume");
+			}
+		}
+
+
+        float sx, sy;
+        float scale = 1.0f;
+        if (_bb)
+        {
+            RectF rc;
+            if (movie->computeAllTimelineBounds(rc))
+            {
+                Vector2 off = movie->getSize() * 0.5f;
+
+                Matrix m = movie->getParent()->computeGlobalTransform().toMatrix();
+                Vector4 p0 = m.transformVec4(Vector4(rc.getLeft() - off.x, rc.getTop() - off.y, 0.0f, 1.0f));
+                Vector4 p1 = m.transformVec4(Vector4(rc.getRight() - off.x, rc.getBottom() - off.y, 0.0f, 1.0f));
+
+                sx = std::max(fabs(p0.x), fabs(p1.x))*1.1f;
+                sy = std::max(fabs(p0.y), fabs(p1.y))*1.1f;
+
+                sx = (0.5f * getStage()->getWidth()) / sx;
+                sy = (0.5f * getStage()->getHeight()) / sy;
+                scale = std::min(sx, sy);
+
+                if (_show_all)
+                {
+                    scale = std::min(scale, _allscale);
+                }
+                else
+                {
+                    sx = getStage()->getWidth() / movie->getWidth();
+                    sy = getStage()->getHeight() / movie->getHeight();
+                    scale = std::min(scale, std::min(sx, sy));
+                }
+
+                movie->setScale(std::min(scale, 1.0f));
+                movie->setPosition(getStage()->getSize() / 2 - movie->getScaledSize() / 2);
+
+                m = movie->computeGlobalTransform().toMatrix();
+                Vector4 pp0 = m.transformVec4(Vector4(rc.getLeft(), rc.getTop(), 0.0f, 1.0f));
+                Vector4 pp1 = m.transformVec4(Vector4(rc.getRight(), rc.getBottom(), 0.0f, 1.0f));
+                _cr2->setPosition(Vector2(pp0.x - 2.0f, pp0.y - 2.0f));
+                _cr2->setSize(Vector2(pp1.x - pp0.x + 4.0f, pp1.y - pp0.y + 4.0f));
+                _cr2->setVisible(true);
+
+                _cr->setPosition(Vector2(pp0.x, pp0.y));
+                _cr->setSize(Vector2(pp1.x - pp0.x, pp1.y - pp0.y));
+                _cr->setVisible(true);
+            }
+        }
+        else
+        {
+            if (_show_all)
+            {
+                movie->setScale(_allscale);
+            }
+            else
+            {
+                sx = getStage()->getWidth() / movie->getWidth();
+                sy = getStage()->getHeight() / movie->getHeight();
+                movie->setScale(std::min(1.0f, std::min(sx, sy)) * 0.9f);
+            }
+
+            movie->setPosition(getStage()->getSize() / 2 - movie->getScaledSize() / 2);
+
+            _cr->setVisible(false);
+            _cr2->setVisible(false);
+        }
+	}
+
+	void set(const string &id)
+	{
+		if (movie)
+			movie->detach();
+
+        _cr2 = new ColorRectSprite;
+        _cr2->setColor(Color(255, 0, 0, 255));
+        _cr2->attachTo(this);
+        _cr2->setPriority(-3);
+        _cr2->setVisible(false);
+
+        _cr = new ColorRectSprite;
+        _cr->setColor(Color(0,0,0,255));
+        _cr->attachTo(this);
+        _cr->setPriority(-2);
+        _cr->setVisible(false);
+
+		movie = AEMovieWork::createWork(movieRes, id);
+		if (!movie)
+			return;
+		movie->attachTo(this);
+		movie->setPriority(-1);
+		movie->setAnchor(0.0f, 0.0f);
+		movie->play(true);
+
+
+
+
+
+        float sx, sy, scale;
+        RectF rc;
+        if (movie->calcMinMaxForAllFrames(rc))
+        {
+            Vector2 off = movie->getSize() * 0.5f;
+
+            Matrix m = movie->getParent()->computeGlobalTransform().toMatrix();
+            Vector4 p0 = m.transformVec4(Vector4(rc.getLeft() - off.x, rc.getTop() - off.y, 0.0f, 1.0f));
+            Vector4 p1 = m.transformVec4(Vector4(rc.getRight() - off.x, rc.getBottom() - off.y, 0.0f, 1.0f));
+
+            sx = std::max(fabs(p0.x), fabs(p1.x))*1.1f;
+            sy = std::max(fabs(p0.y), fabs(p1.y))*1.1f;
+
+            sx = (0.5f * getStage()->getWidth()) / sx;
+            sy = (0.5f * getStage()->getHeight()) / sy;
+            scale = std::min(sx, sy);
+
+            sx = getStage()->getWidth() / movie->getWidth();
+            sy = getStage()->getHeight() / movie->getHeight();
+            scale = std::min(scale, std::min(sx, sy));
+
+            _allscale = std::min(scale, 1.0f);
+        }
+
+        if (_show_all)
+        {
+            movie->setScale(_allscale);
+        }
+        else
+        {
+            sx = getStage()->getWidth() / movie->getWidth();
+            sy = getStage()->getHeight() / movie->getHeight();
+            movie->setScale(std::min(1.0f, std::min(sx, sy)) * 0.9f);
+        }
+        movie->setPosition(getStage()->getSize() / 2 - movie->getScaledSize() / 2);
+
+
+		movie->addEventListener(Event::COMPLETE, [=](Event*) {
+			notify("COMPLETE");
+		});
+
+
+
+		int events = ae_get_movie_composition_data_event_count(movie->getAEData());
+		for (int i = 0; i < events; ++i)
+		{
+			const char *name = ae_get_movie_composition_data_event_name(movie->getAEData(), i);
+
+			addButton("event:" + string(name), name);
+		}
+	}
+};
+
+bool Preview::_bb = false;
+bool Preview::_show_all = false;
+
+spPreview Preview::instance;
+
+
+class TestActor: public Test
+{
+public:
+
+    TestActor()
+    {
+        _x = 90;//getStage()->getWidth()/2.0f;
+        _y = 80;
+
+		if (!movieRes.movieData)
+			return;
+
+		int num = ae_get_movie_composition_data_count(movieRes.movieData);
+		for (int i = 0; i < num; ++i)
+		{
+			const aeMovieCompositionData *comp = ae_get_movie_composition_data_by_index(movieRes.movieData, i);
+            bool main = ae_is_movie_composition_data_master(comp);
+            _color = main ? Color(Color::White) : Color(Color::Gray);
+            _txtColor = main ? Color(Color::Blue) : Color(Color::Gray);
+            const char *name = ae_get_movie_composition_data_name(comp);
+			addButton(name, name);
+		}
+
+		if (!aeCurrent.empty())
+		{
+			getStage()->addTween(TweenDummy(), 1)->addDoneCallback([=](Event*) {
+				clicked(aeCurrent);
+			});			
+		}
+    }
+
+    void showTest(spActor actor)
+    {
+        spStage stage = getStage();
+#if MULTIWINDOW
+        stage = stage2;
+#else
+        setVisible(false);
+#endif
+        stage->addChild(actor);
+    }
+
+
+    void clicked(string id)
+    {
+		Preview::instance = new Preview(id);
+		setVisible(false);
+		Preview::instance->attachTo(getStage());
+    }
+};
+
+void example_preinit()
+{
+}
+
+
+oxygine::file::ZipFileSystem zfs;
+
+void example_init()
+{
+    Test::init();
+	key::init();
+    AEMovieResource::initLibrary();
+
+
+    bool isZip = path::extractFileExt(aeProject) == "zip";
+
+    if (isZip)
+    {
+        if (file::exists(aeProject))
+            zfs.add(aeProject.c_str());
+        file::fs().mount(&zfs);
+        movieRes.load("project", ep_show_warning);
+    }
+    else
+    {
+        movieRes.load(aeProject, ep_show_warning);
+    }
+	
+
+
+    Test::instance = new TestActor;
+    getStage()->addChild(Test::instance);
+
+	//Preview::instance = new Preview;
+
+    //Initialize http requests
+    HttpRequestTask::init();
+
+#if MULTIWINDOW
+    SDL_Window* window2 = SDL_CreateWindow("Second Oxygine Window", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, getStage()->getWidth(), getStage()->getHeight(), SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN);
+    stage2 = new Stage(false);
+    stage2->setSize(getStage()->getSize());
+    stage2->associateWithWindow(window2);
+#endif
+}
+
+void example_update()
+{
+    AEMovieResource::updateLibrary();
+#if MULTIWINDOW
+    stage2->update();
+    SDL_Window* wnd = stage2->getAssociatedWindow();
+    if (core::beginRendering(wnd))
+    {
+        Color clearColor(32, 32, 32, 255);
+        Rect viewport(Point(0, 0), core::getDisplaySize());
+        //render all actors. Actor::render would be called also for all children
+        stage2->render(clearColor, viewport);
+
+        core::swapDisplayBuffers(wnd);
+    }
+#endif
+}
+
+void example_destroy()
+{
+	key::release();
+	if (Preview::instance)
+		Preview::instance->detach();
+	Preview::instance = 0;
+	movieRes.clear();
+    Test::free();
+    HttpRequestTask::release();
+    AEMovieResource::freeLibrary();
+}

+ 1 - 2
examples/src/example.h → examples/HelloViewerAE/src/example.h

@@ -1,5 +1,4 @@
 void example_preinit();
 void example_preinit();
 void example_init();
 void example_init();
 void example_destroy();
 void example_destroy();
-void example_update();
-void example_flush();
+void example_update();

+ 62 - 7
examples/src/main.cpp → examples/HelloViewerAE/src/main.cpp

@@ -8,10 +8,32 @@
 #include "ox/Stage.hpp"
 #include "ox/Stage.hpp"
 #include "ox/DebugActor.hpp"
 #include "ox/DebugActor.hpp"
 #include "example.h"
 #include "example.h"
+#include <string>
+#include "ox/key.hpp"
 
 
+/*
+
+#pragma comment(lib,"Version.lib")
+
+#pragma comment(lib,"winmm.lib")
+
+#pragma comment(lib,"imm32.lib")
+
+#pragma comment(lib,"user32.lib")
+
+#pragma comment(lib,"gdi32.lib")
+
+#pragma comment(lib,"ole32.lib")
+
+#pragma comment(lib,"shell32.lib")
+
+#pragma comment(lib,"oleaut32.lib")
+*/
 
 
 using namespace oxygine;
 using namespace oxygine;
 
 
+using namespace std;
+
 
 
 // This function is called each frame
 // This function is called each frame
 int mainloop()
 int mainloop()
@@ -48,11 +70,14 @@ void run()
 
 
     // Initialize Oxygine's internal stuff
     // Initialize Oxygine's internal stuff
     core::init_desc desc;
     core::init_desc desc;
-    desc.title = "Oxygine Application";
+    desc.title = "Oxygine After Effects Viewer";
 
 
-    // The initial window size can be set up here on SDL builds, ignored on Mobile devices
-    desc.w = 960;
-    desc.h = 640;
+#if OXYGINE_SDL || OXYGINE_EMSCRIPTEN
+    // The initial window size can be set up here on SDL builds
+    desc.w = 1024;
+    desc.h = 768;
+    // Marmalade settings can be modified from the emulator's menu
+#endif
 
 
 
 
     example_preinit();
     example_preinit();
@@ -60,7 +85,7 @@ void run()
 
 
 
 
     // Create the stage. Stage is a root node for all updateable and drawable objects
     // Create the stage. Stage is a root node for all updateable and drawable objects
-    Stage::instance = new Stage();
+    Stage::instance = new Stage(true);
     Point size = core::getDisplaySize();
     Point size = core::getDisplaySize();
     getStage()->setSize(size);
     getStage()->setSize(size);
 
 
@@ -82,7 +107,7 @@ void run()
 
 
 #if TARGET_OS_IPHONE || TARGET_OS_SIMULATOR
 #if TARGET_OS_IPHONE || TARGET_OS_SIMULATOR
     // On iPhone mainloop is called automatically by CADisplayLink, see int main() below
     // On iPhone mainloop is called automatically by CADisplayLink, see int main() below
-    //return;
+    return;
 #endif
 #endif
 
 
     // This is the main game loop.
     // This is the main game loop.
@@ -92,6 +117,9 @@ void run()
         if (done)
         if (done)
             break;
             break;
     }
     }
+
+
+
     /*
     /*
      If we get here, the user has requested the Application to terminate.
      If we get here, the user has requested the Application to terminate.
      We dump and log all our created objects that have not been freed yet
      We dump and log all our created objects that have not been freed yet
@@ -120,13 +148,29 @@ void run()
 
 
     ObjectBase::__stopTracingLeaks();
     ObjectBase::__stopTracingLeaks();
     //end
     //end
+
+
+	std::quick_exit(1);
 }
 }
 
 
+#ifdef __S3E__
+int main(int argc, char* argv[])
+{
+    run();
+    return 0;
+}
+#endif
+
+
 #ifdef OXYGINE_SDL
 #ifdef OXYGINE_SDL
 
 
 #include "SDL_main.h"
 #include "SDL_main.h"
 #include "SDL.h"
 #include "SDL.h"
 
 
+std::string aeProject;
+std::string aeCurrent;
+Vector2 aeWorkArea(0,0);
+
 extern "C"
 extern "C"
 {
 {
     void one(void* param) { mainloop(); }
     void one(void* param) { mainloop(); }
@@ -134,12 +178,23 @@ extern "C"
 
 
     int main(int argc, char* argv[])
     int main(int argc, char* argv[])
     {
     {
+        if (argc > 1)
+        {
+            aeProject = argv[1];
+
+            if (argc > 2)
+            {
+                aeCurrent = argv[2];
+                if (argc > 3)
+                    sscanf(argv[3], "%f;%f", &aeWorkArea.x, &aeWorkArea.y);
+            }            
+        }
 
 
         run();
         run();
 
 
 #if TARGET_OS_IPHONE || TARGET_OS_SIMULATOR
 #if TARGET_OS_IPHONE || TARGET_OS_SIMULATOR
         // If parameter 2 is set to 1, refresh rate will be 60 fps, 2 - 30 fps, 3 - 15 fps.
         // If parameter 2 is set to 1, refresh rate will be 60 fps, 2 - 30 fps, 3 - 15 fps.
-        //SDL_iPhoneSetAnimationCallback(core::getWindow(), 1, one, nullptr);
+        SDL_iPhoneSetAnimationCallback(core::getWindow(), 1, one, nullptr);
 #endif
 #endif
 
 
 #if EMSCRIPTEN
 #if EMSCRIPTEN

File diff suppressed because it is too large
+ 5 - 0
examples/HelloViewerAE/src/test.cpp


+ 60 - 0
examples/HelloViewerAE/src/test.h

@@ -0,0 +1,60 @@
+#pragma once
+
+#include "oxygine-framework.h"
+
+using namespace oxygine;
+using namespace std;
+
+
+spTextField createText(const std::string& txt);
+spButton createButtonHelper(spButton, const std::string& txt, EventCallback cb);
+
+DECLARE_SMART(Test, spTest);
+class Test: public Actor
+{
+public:
+    Test();
+    ~Test();
+
+    static void init();
+    static void free();
+
+    static spTest instance;
+    static Resources _resources;
+
+    struct toggle
+    {
+        string text;
+        int value;
+        const void* data;
+        toggle() {}
+        toggle(const char* text_, int v_ = 0, const void* data_ = 0): text(text_), value(v_), data(data_) {}
+    };
+
+    spButton addButton(string id, string txt);
+    void addToggle(string id, const toggle* t, int num);
+    void updateText(string id, string txt);
+    virtual void clicked(string id) {}
+    virtual void toggleClicked(string id, const toggle* data) {}
+
+
+    void notify(string text, int time = 400);
+
+protected:
+    void notifyDone(Event* ev);
+    void _clicked(Event* event);
+    void _toggleClicked(Event* event);
+    void _back(Event* event);
+
+    Color _color;
+    Color _txtColor;
+
+    spActor _content;
+    spActor _ui;
+
+    float _x;
+    float _y;
+
+    enum {MAX_NOTIFIES = 8};
+    int _notifies[MAX_NOTIFIES];
+};

+ 0 - 239
examples/data/fonts/main.fnt

@@ -1,239 +0,0 @@
-info face="Easterbuns" size=24 bold=0 italic=0 charset="" unicode=0 stretchH=100 smooth=1 aa=1 padding=4,3,4,3 spacing=-7,-8
-common lineHeight=30 base=22 scaleW=256 scaleH=512 pages=1 packed=0
-page id=0 file="main_0.png"
-chars count=234
-char id=32   x=0     y=0     width=0     height=0     xoffset=0     yoffset=22    xadvance=4     page=0  chnl=0 
-char id=960   x=0     y=0     width=25     height=34     xoffset=-4     yoffset=-3    xadvance=16     page=0  chnl=0 
-char id=255   x=25     y=0     width=19     height=33     xoffset=-3     yoffset=1    xadvance=11     page=0  chnl=0 
-char id=254   x=44     y=0     width=17     height=33     xoffset=-3     yoffset=1    xadvance=10     page=0  chnl=0 
-char id=253   x=61     y=0     width=19     height=33     xoffset=-3     yoffset=1    xadvance=11     page=0  chnl=0 
-char id=8747   x=80     y=0     width=19     height=32     xoffset=-6     yoffset=0    xadvance=6     page=0  chnl=0 
-char id=381   x=99     y=0     width=21     height=32     xoffset=-3     yoffset=-4    xadvance=13     page=0  chnl=0 
-char id=352   x=120     y=0     width=19     height=32     xoffset=-3     yoffset=-4    xadvance=11     page=0  chnl=0 
-char id=221   x=139     y=0     width=21     height=32     xoffset=-3     yoffset=-3    xadvance=13     page=0  chnl=0 
-char id=216   x=160     y=0     width=23     height=32     xoffset=-3     yoffset=-1    xadvance=15     page=0  chnl=0 
-char id=210   x=183     y=0     width=23     height=32     xoffset=-3     yoffset=-4    xadvance=15     page=0  chnl=0 
-char id=205   x=206     y=0     width=17     height=32     xoffset=-3     yoffset=-5    xadvance=9     page=0  chnl=0 
-char id=197   x=223     y=0     width=21     height=32     xoffset=-3     yoffset=-4    xadvance=12     page=0  chnl=0 
-char id=106   x=0     y=34     width=18     height=32     xoffset=-6     yoffset=2    xadvance=4     page=0  chnl=0 
-char id=402   x=18     y=34     width=17     height=31     xoffset=-4     yoffset=1    xadvance=8     page=0  chnl=0 
-char id=376   x=35     y=34     width=21     height=31     xoffset=-3     yoffset=-2    xadvance=13     page=0  chnl=0 
-char id=219   x=56     y=34     width=21     height=31     xoffset=-3     yoffset=-3    xadvance=13     page=0  chnl=0 
-char id=218   x=77     y=34     width=21     height=31     xoffset=-3     yoffset=-3    xadvance=13     page=0  chnl=0 
-char id=217   x=98     y=34     width=21     height=31     xoffset=-3     yoffset=-3    xadvance=13     page=0  chnl=0 
-char id=213   x=119     y=34     width=23     height=31     xoffset=-3     yoffset=-3    xadvance=15     page=0  chnl=0 
-char id=212   x=142     y=34     width=23     height=31     xoffset=-3     yoffset=-3    xadvance=15     page=0  chnl=0 
-char id=211   x=165     y=34     width=23     height=31     xoffset=-3     yoffset=-3    xadvance=15     page=0  chnl=0 
-char id=206   x=188     y=34     width=17     height=31     xoffset=-3     yoffset=-4    xadvance=9     page=0  chnl=0 
-char id=204   x=205     y=34     width=17     height=31     xoffset=-3     yoffset=-4    xadvance=9     page=0  chnl=0 
-char id=199   x=222     y=34     width=20     height=31     xoffset=-3     yoffset=2    xadvance=11     page=0  chnl=0 
-char id=194   x=0     y=66     width=21     height=31     xoffset=-3     yoffset=-3    xadvance=12     page=0  chnl=0 
-char id=193   x=21     y=66     width=21     height=31     xoffset=-3     yoffset=-3    xadvance=12     page=0  chnl=0 
-char id=192   x=42     y=66     width=21     height=31     xoffset=-3     yoffset=-3    xadvance=12     page=0  chnl=0 
-char id=191   x=63     y=66     width=18     height=31     xoffset=-3     yoffset=-1    xadvance=9     page=0  chnl=0 
-char id=214   x=81     y=66     width=23     height=30     xoffset=-2     yoffset=-2    xadvance=15     page=0  chnl=0 
-char id=209   x=104     y=66     width=21     height=30     xoffset=-3     yoffset=-3    xadvance=14     page=0  chnl=0 
-char id=207   x=125     y=66     width=17     height=30     xoffset=-3     yoffset=-3    xadvance=9     page=0  chnl=0 
-char id=202   x=142     y=66     width=18     height=30     xoffset=-3     yoffset=-3    xadvance=10     page=0  chnl=0 
-char id=200   x=160     y=66     width=18     height=30     xoffset=-3     yoffset=-3    xadvance=10     page=0  chnl=0 
-char id=195   x=178     y=66     width=21     height=30     xoffset=-3     yoffset=-2    xadvance=12     page=0  chnl=0 
-char id=81   x=199     y=66     width=24     height=30     xoffset=-3     yoffset=1    xadvance=17     page=0  chnl=0 
-char id=256   x=223     y=66     width=20     height=29     xoffset=-2     yoffset=-2    xadvance=13     page=0  chnl=0 
-char id=229   x=0     y=97     width=17     height=29     xoffset=-3     yoffset=-1    xadvance=9     page=0  chnl=0 
-char id=223   x=17     y=97     width=20     height=29     xoffset=-4     yoffset=2    xadvance=10     page=0  chnl=0 
-char id=220   x=37     y=97     width=21     height=29     xoffset=-3     yoffset=-1    xadvance=13     page=0  chnl=0 
-char id=201   x=58     y=97     width=18     height=29     xoffset=-3     yoffset=-2    xadvance=10     page=0  chnl=0 
-char id=196   x=76     y=97     width=21     height=29     xoffset=-3     yoffset=-1    xadvance=12     page=0  chnl=0 
-char id=161   x=97     y=97     width=14     height=29     xoffset=-3     yoffset=0    xadvance=6     page=0  chnl=0 
-char id=36   x=111     y=97     width=20     height=29     xoffset=-3     yoffset=0    xadvance=12     page=0  chnl=0 
-char id=64258   x=131     y=97     width=20     height=28     xoffset=-3     yoffset=0    xadvance=12     page=0  chnl=0 
-char id=353   x=151     y=97     width=17     height=28     xoffset=-3     yoffset=0    xadvance=9     page=0  chnl=0 
-char id=251   x=168     y=97     width=17     height=28     xoffset=-3     yoffset=0    xadvance=11     page=0  chnl=0 
-char id=234   x=185     y=97     width=17     height=28     xoffset=-3     yoffset=0    xadvance=9     page=0  chnl=0 
-char id=233   x=202     y=97     width=17     height=28     xoffset=-3     yoffset=0    xadvance=9     page=0  chnl=0 
-char id=232   x=219     y=97     width=17     height=28     xoffset=-3     yoffset=0    xadvance=9     page=0  chnl=0 
-char id=226   x=236     y=97     width=17     height=28     xoffset=-3     yoffset=0    xadvance=9     page=0  chnl=0 
-char id=225   x=0     y=126     width=17     height=28     xoffset=-3     yoffset=0    xadvance=9     page=0  chnl=0 
-char id=224   x=17     y=126     width=17     height=28     xoffset=-3     yoffset=0    xadvance=10     page=0  chnl=0 
-char id=203   x=34     y=126     width=18     height=28     xoffset=-3     yoffset=-1    xadvance=10     page=0  chnl=0 
-char id=166   x=52     y=126     width=11     height=28     xoffset=-2     yoffset=0    xadvance=4     page=0  chnl=0 
-char id=113   x=63     y=126     width=26     height=28     xoffset=-3     yoffset=6    xadvance=11     page=0  chnl=0 
-char id=104   x=89     y=126     width=18     height=28     xoffset=-3     yoffset=0    xadvance=11     page=0  chnl=0 
-char id=103   x=107     y=126     width=19     height=28     xoffset=-3     yoffset=6    xadvance=11     page=0  chnl=0 
-char id=41   x=126     y=126     width=14     height=28     xoffset=-3     yoffset=1    xadvance=6     page=0  chnl=0 
-char id=112   x=140     y=126     width=18     height=28     xoffset=-3     yoffset=6    xadvance=10     page=0  chnl=0 
-char id=38   x=158     y=126     width=22     height=28     xoffset=-4     yoffset=0    xadvance=13     page=0  chnl=0 
-char id=64257   x=180     y=126     width=20     height=27     xoffset=-3     yoffset=0    xadvance=12     page=0  chnl=0 
-char id=8730   x=200     y=126     width=21     height=27     xoffset=-3     yoffset=0    xadvance=13     page=0  chnl=0 
-char id=8721   x=221     y=126     width=19     height=27     xoffset=-3     yoffset=1    xadvance=11     page=0  chnl=0 
-char id=8706   x=0     y=154     width=19     height=27     xoffset=-3     yoffset=1    xadvance=11     page=0  chnl=0 
-char id=8225   x=19     y=154     width=18     height=27     xoffset=-4     yoffset=0    xadvance=8     page=0  chnl=0 
-char id=937   x=37     y=154     width=25     height=27     xoffset=-2     yoffset=0    xadvance=19     page=0  chnl=0 
-char id=382   x=62     y=154     width=18     height=27     xoffset=-3     yoffset=0    xadvance=10     page=0  chnl=0 
-char id=322   x=80     y=154     width=17     height=27     xoffset=-4     yoffset=0    xadvance=6     page=0  chnl=0 
-char id=250   x=97     y=154     width=17     height=27     xoffset=-3     yoffset=1    xadvance=11     page=0  chnl=0 
-char id=249   x=114     y=154     width=17     height=27     xoffset=-3     yoffset=1    xadvance=11     page=0  chnl=0 
-char id=245   x=131     y=154     width=19     height=27     xoffset=-3     yoffset=1    xadvance=11     page=0  chnl=0 
-char id=244   x=150     y=154     width=19     height=27     xoffset=-3     yoffset=1    xadvance=11     page=0  chnl=0 
-char id=242   x=169     y=154     width=19     height=27     xoffset=-3     yoffset=1    xadvance=11     page=0  chnl=0 
-char id=240   x=188     y=154     width=19     height=27     xoffset=-3     yoffset=0    xadvance=11     page=0  chnl=0 
-char id=231   x=207     y=154     width=17     height=27     xoffset=-3     yoffset=5    xadvance=9     page=0  chnl=0 
-char id=228   x=224     y=154     width=17     height=27     xoffset=-3     yoffset=1    xadvance=10     page=0  chnl=0 
-char id=227   x=0     y=181     width=18     height=27     xoffset=-3     yoffset=1    xadvance=9     page=0  chnl=0 
-char id=181   x=18     y=181     width=20     height=27     xoffset=-3     yoffset=6    xadvance=12     page=0  chnl=0 
-char id=167   x=38     y=181     width=18     height=27     xoffset=-3     yoffset=0    xadvance=11     page=0  chnl=0 
-char id=124   x=56     y=181     width=11     height=27     xoffset=-3     yoffset=1    xadvance=3     page=0  chnl=0 
-char id=123   x=67     y=181     width=15     height=27     xoffset=-3     yoffset=2    xadvance=6     page=0  chnl=0 
-char id=121   x=82     y=181     width=19     height=27     xoffset=-3     yoffset=7    xadvance=11     page=0  chnl=0 
-char id=102   x=101     y=181     width=17     height=27     xoffset=-3     yoffset=0    xadvance=8     page=0  chnl=0 
-char id=100   x=118     y=181     width=19     height=27     xoffset=-4     yoffset=0    xadvance=10     page=0  chnl=0 
-char id=98   x=137     y=181     width=19     height=27     xoffset=-3     yoffset=1    xadvance=11     page=0  chnl=0 
-char id=93   x=156     y=181     width=13     height=27     xoffset=-3     yoffset=1    xadvance=6     page=0  chnl=0 
-char id=91   x=169     y=181     width=14     height=27     xoffset=-3     yoffset=1    xadvance=6     page=0  chnl=0 
-char id=33   x=183     y=181     width=13     height=27     xoffset=-3     yoffset=1    xadvance=6     page=0  chnl=0 
-char id=116   x=196     y=181     width=17     height=27     xoffset=-4     yoffset=0    xadvance=8     page=0  chnl=0 
-char id=108   x=213     y=181     width=12     height=27     xoffset=-3     yoffset=0    xadvance=4     page=0  chnl=0 
-char id=8260   x=225     y=181     width=19     height=26     xoffset=-3     yoffset=1    xadvance=11     page=0  chnl=0 
-char id=8224   x=0     y=208     width=18     height=26     xoffset=-3     yoffset=-1    xadvance=11     page=0  chnl=0 
-char id=916   x=18     y=208     width=23     height=26     xoffset=-3     yoffset=1    xadvance=15     page=0  chnl=0 
-char id=338   x=41     y=208     width=29     height=26     xoffset=-2     yoffset=2    xadvance=22     page=0  chnl=0 
-char id=243   x=70     y=208     width=19     height=26     xoffset=-3     yoffset=2    xadvance=11     page=0  chnl=0 
-char id=241   x=89     y=208     width=19     height=26     xoffset=-4     yoffset=1    xadvance=10     page=0  chnl=0 
-char id=235   x=108     y=208     width=17     height=26     xoffset=-3     yoffset=2    xadvance=9     page=0  chnl=0 
-char id=208   x=125     y=208     width=23     height=26     xoffset=-5     yoffset=1    xadvance=13     page=0  chnl=0 
-char id=198   x=148     y=208     width=26     height=26     xoffset=-3     yoffset=2    xadvance=19     page=0  chnl=0 
-char id=190   x=174     y=208     width=28     height=26     xoffset=-3     yoffset=3    xadvance=20     page=0  chnl=0 
-char id=164   x=202     y=208     width=24     height=26     xoffset=-2     yoffset=1    xadvance=19     page=0  chnl=0 
-char id=163   x=226     y=208     width=20     height=26     xoffset=-3     yoffset=1    xadvance=13     page=0  chnl=0 
-char id=162   x=0     y=234     width=18     height=26     xoffset=-3     yoffset=1    xadvance=9     page=0  chnl=0 
-char id=125   x=18     y=234     width=15     height=26     xoffset=-3     yoffset=1    xadvance=6     page=0  chnl=0 
-char id=107   x=33     y=234     width=18     height=26     xoffset=-3     yoffset=1    xadvance=9     page=0  chnl=0 
-char id=92   x=51     y=234     width=19     height=26     xoffset=-3     yoffset=2    xadvance=11     page=0  chnl=0 
-char id=90   x=70     y=234     width=21     height=26     xoffset=-3     yoffset=2    xadvance=13     page=0  chnl=0 
-char id=89   x=91     y=234     width=21     height=26     xoffset=-3     yoffset=3    xadvance=13     page=0  chnl=0 
-char id=88   x=112     y=234     width=23     height=26     xoffset=-3     yoffset=2    xadvance=14     page=0  chnl=0 
-char id=83   x=135     y=234     width=19     height=26     xoffset=-3     yoffset=2    xadvance=11     page=0  chnl=0 
-char id=82   x=154     y=234     width=20     height=26     xoffset=-3     yoffset=1    xadvance=12     page=0  chnl=0 
-char id=80   x=174     y=234     width=20     height=26     xoffset=-3     yoffset=1    xadvance=12     page=0  chnl=0 
-char id=79   x=194     y=234     width=23     height=26     xoffset=-2     yoffset=2    xadvance=15     page=0  chnl=0 
-char id=75   x=217     y=234     width=20     height=26     xoffset=-3     yoffset=2    xadvance=12     page=0  chnl=0 
-char id=74   x=0     y=260     width=19     height=26     xoffset=-3     yoffset=2    xadvance=11     page=0  chnl=0 
-char id=72   x=19     y=260     width=21     height=26     xoffset=-3     yoffset=1    xadvance=13     page=0  chnl=0 
-char id=70   x=40     y=260     width=19     height=26     xoffset=-3     yoffset=2    xadvance=10     page=0  chnl=0 
-char id=68   x=59     y=260     width=20     height=26     xoffset=-3     yoffset=1    xadvance=13     page=0  chnl=0 
-char id=67   x=79     y=260     width=20     height=26     xoffset=-3     yoffset=2    xadvance=11     page=0  chnl=0 
-char id=65   x=99     y=260     width=21     height=26     xoffset=-3     yoffset=2    xadvance=12     page=0  chnl=0 
-char id=64   x=120     y=260     width=21     height=26     xoffset=-3     yoffset=2    xadvance=13     page=0  chnl=0 
-char id=40   x=141     y=260     width=15     height=26     xoffset=-3     yoffset=2    xadvance=7     page=0  chnl=0 
-char id=57   x=156     y=260     width=18     height=26     xoffset=-2     yoffset=2    xadvance=11     page=0  chnl=0 
-char id=54   x=174     y=260     width=18     height=26     xoffset=-3     yoffset=2    xadvance=10     page=0  chnl=0 
-char id=53   x=192     y=260     width=19     height=26     xoffset=-3     yoffset=2    xadvance=11     page=0  chnl=0 
-char id=52   x=211     y=260     width=19     height=26     xoffset=-3     yoffset=2    xadvance=11     page=0  chnl=0 
-char id=50   x=230     y=260     width=19     height=26     xoffset=-3     yoffset=1    xadvance=11     page=0  chnl=0 
-char id=48   x=0     y=286     width=18     height=26     xoffset=-3     yoffset=2    xadvance=10     page=0  chnl=0 
-char id=105   x=18     y=286     width=13     height=26     xoffset=-3     yoffset=1    xadvance=5     page=0  chnl=0 
-char id=63   x=31     y=286     width=17     height=26     xoffset=-3     yoffset=2    xadvance=9     page=0  chnl=0 
-char id=8364   x=48     y=286     width=23     height=25     xoffset=-4     yoffset=3    xadvance=14     page=0  chnl=0 
-char id=252   x=71     y=286     width=17     height=25     xoffset=-3     yoffset=2    xadvance=11     page=0  chnl=0 
-char id=246   x=88     y=286     width=19     height=25     xoffset=-3     yoffset=3    xadvance=11     page=0  chnl=0 
-char id=238   x=107     y=286     width=16     height=25     xoffset=-4     yoffset=2    xadvance=6     page=0  chnl=0 
-char id=222   x=123     y=286     width=20     height=25     xoffset=-3     yoffset=2    xadvance=12     page=0  chnl=0 
-char id=189   x=143     y=286     width=26     height=25     xoffset=-3     yoffset=3    xadvance=17     page=0  chnl=0 
-char id=188   x=169     y=286     width=25     height=25     xoffset=-3     yoffset=3    xadvance=17     page=0  chnl=0 
-char id=182   x=194     y=286     width=22     height=25     xoffset=-4     yoffset=2    xadvance=13     page=0  chnl=0 
-char id=174   x=216     y=286     width=22     height=25     xoffset=-3     yoffset=2    xadvance=14     page=0  chnl=0 
-char id=169   x=0     y=312     width=22     height=25     xoffset=-3     yoffset=2    xadvance=14     page=0  chnl=0 
-char id=87   x=22     y=312     width=27     height=25     xoffset=-3     yoffset=3    xadvance=18     page=0  chnl=0 
-char id=86   x=49     y=312     width=22     height=25     xoffset=-3     yoffset=2    xadvance=13     page=0  chnl=0 
-char id=85   x=71     y=312     width=21     height=25     xoffset=-3     yoffset=3    xadvance=13     page=0  chnl=0 
-char id=78   x=92     y=312     width=22     height=25     xoffset=-3     yoffset=3    xadvance=14     page=0  chnl=0 
-char id=77   x=114     y=312     width=26     height=25     xoffset=-3     yoffset=2    xadvance=18     page=0  chnl=0 
-char id=73   x=140     y=312     width=17     height=25     xoffset=-3     yoffset=2    xadvance=9     page=0  chnl=0 
-char id=71   x=157     y=312     width=20     height=25     xoffset=-3     yoffset=2    xadvance=13     page=0  chnl=0 
-char id=69   x=177     y=312     width=18     height=25     xoffset=-3     yoffset=2    xadvance=10     page=0  chnl=0 
-char id=66   x=195     y=312     width=20     height=25     xoffset=-3     yoffset=2    xadvance=12     page=0  chnl=0 
-char id=56   x=215     y=312     width=20     height=25     xoffset=-3     yoffset=3    xadvance=12     page=0  chnl=0 
-char id=35   x=0     y=337     width=21     height=25     xoffset=-3     yoffset=1    xadvance=13     page=0  chnl=0 
-char id=49   x=21     y=337     width=15     height=25     xoffset=-3     yoffset=2    xadvance=7     page=0  chnl=0 
-char id=8471   x=36     y=337     width=22     height=24     xoffset=-3     yoffset=2    xadvance=14     page=0  chnl=0 
-char id=8240   x=58     y=337     width=22     height=24     xoffset=-3     yoffset=2    xadvance=14     page=0  chnl=0 
-char id=321   x=80     y=337     width=21     height=24     xoffset=-4     yoffset=3    xadvance=13     page=0  chnl=0 
-char id=248   x=101     y=337     width=19     height=24     xoffset=-3     yoffset=5    xadvance=10     page=0  chnl=0 
-char id=239   x=120     y=337     width=16     height=24     xoffset=-4     yoffset=3    xadvance=5     page=0  chnl=0 
-char id=237   x=136     y=337     width=13     height=24     xoffset=-3     yoffset=3    xadvance=5     page=0  chnl=0 
-char id=236   x=149     y=337     width=14     height=24     xoffset=-4     yoffset=3    xadvance=5     page=0  chnl=0 
-char id=177   x=163     y=337     width=19     height=24     xoffset=-3     yoffset=3    xadvance=11     page=0  chnl=0 
-char id=165   x=182     y=337     width=21     height=24     xoffset=-3     yoffset=3    xadvance=13     page=0  chnl=0 
-char id=84   x=203     y=337     width=21     height=24     xoffset=-3     yoffset=3    xadvance=13     page=0  chnl=0 
-char id=76   x=224     y=337     width=20     height=24     xoffset=-3     yoffset=3    xadvance=12     page=0  chnl=0 
-char id=47   x=0     y=362     width=17     height=24     xoffset=-3     yoffset=3    xadvance=9     page=0  chnl=0 
-char id=37   x=17     y=362     width=19     height=24     xoffset=-3     yoffset=3    xadvance=12     page=0  chnl=0 
-char id=55   x=36     y=362     width=18     height=24     xoffset=-3     yoffset=3    xadvance=10     page=0  chnl=0 
-char id=51   x=54     y=362     width=18     height=24     xoffset=-3     yoffset=3    xadvance=10     page=0  chnl=0 
-char id=109   x=72     y=362     width=22     height=23     xoffset=-2     yoffset=5    xadvance=15     page=0  chnl=0 
-char id=8800   x=94     y=362     width=18     height=22     xoffset=-3     yoffset=6    xadvance=10     page=0  chnl=0 
-char id=8734   x=112     y=362     width=23     height=22     xoffset=-3     yoffset=5    xadvance=15     page=0  chnl=0 
-char id=339   x=135     y=362     width=25     height=22     xoffset=-3     yoffset=6    xadvance=17     page=0  chnl=0 
-char id=247   x=160     y=362     width=18     height=22     xoffset=-3     yoffset=5    xadvance=11     page=0  chnl=0 
-char id=230   x=178     y=362     width=23     height=22     xoffset=-3     yoffset=6    xadvance=15     page=0  chnl=0 
-char id=99   x=201     y=362     width=17     height=22     xoffset=-3     yoffset=5    xadvance=9     page=0  chnl=0 
-char id=43   x=218     y=362     width=19     height=22     xoffset=-3     yoffset=5    xadvance=11     page=0  chnl=0 
-char id=97   x=237     y=362     width=17     height=22     xoffset=-3     yoffset=6    xadvance=9     page=0  chnl=0 
-char id=111   x=0     y=386     width=19     height=22     xoffset=-3     yoffset=6    xadvance=11     page=0  chnl=0 
-char id=115   x=19     y=386     width=17     height=22     xoffset=-3     yoffset=6    xadvance=9     page=0  chnl=0 
-char id=101   x=36     y=386     width=17     height=22     xoffset=-3     yoffset=6    xadvance=9     page=0  chnl=0 
-char id=8308   x=53     y=386     width=15     height=21     xoffset=-3     yoffset=1    xadvance=7     page=0  chnl=0 
-char id=122   x=68     y=386     width=18     height=21     xoffset=-3     yoffset=6    xadvance=10     page=0  chnl=0 
-char id=119   x=86     y=386     width=23     height=21     xoffset=-4     yoffset=6    xadvance=13     page=0  chnl=0 
-char id=117   x=109     y=386     width=17     height=21     xoffset=-3     yoffset=6    xadvance=11     page=0  chnl=0 
-char id=59   x=126     y=386     width=12     height=21     xoffset=-3     yoffset=6    xadvance=4     page=0  chnl=0 
-char id=62   x=138     y=386     width=17     height=21     xoffset=-3     yoffset=6    xadvance=9     page=0  chnl=0 
-char id=110   x=155     y=386     width=19     height=21     xoffset=-4     yoffset=6    xadvance=10     page=0  chnl=0 
-char id=114   x=174     y=386     width=16     height=21     xoffset=-3     yoffset=6    xadvance=8     page=0  chnl=0 
-char id=118   x=190     y=386     width=19     height=21     xoffset=-4     yoffset=6    xadvance=9     page=0  chnl=0 
-char id=120   x=209     y=386     width=20     height=21     xoffset=-3     yoffset=6    xadvance=12     page=0  chnl=0 
-char id=60   x=229     y=386     width=17     height=21     xoffset=-3     yoffset=6    xadvance=9     page=0  chnl=0 
-char id=178   x=0     y=408     width=17     height=20     xoffset=-3     yoffset=3    xadvance=9     page=0  chnl=0 
-char id=58   x=17     y=408     width=12     height=20     xoffset=-3     yoffset=7    xadvance=4     page=0  chnl=0 
-char id=42   x=29     y=408     width=17     height=20     xoffset=-3     yoffset=1    xadvance=9     page=0  chnl=0 
-char id=61   x=46     y=408     width=18     height=20     xoffset=-2     yoffset=6    xadvance=12     page=0  chnl=0 
-char id=185   x=64     y=408     width=12     height=19     xoffset=-3     yoffset=3    xadvance=4     page=0  chnl=0 
-char id=179   x=76     y=408     width=15     height=19     xoffset=-3     yoffset=3    xadvance=8     page=0  chnl=0 
-char id=170   x=91     y=408     width=14     height=19     xoffset=-3     yoffset=1    xadvance=6     page=0  chnl=0 
-char id=305   x=105     y=408     width=12     height=18     xoffset=-3     yoffset=9    xadvance=4     page=0  chnl=0 
-char id=215   x=117     y=408     width=17     height=18     xoffset=-2     yoffset=6    xadvance=11     page=0  chnl=0 
-char id=186   x=134     y=408     width=15     height=18     xoffset=-3     yoffset=2    xadvance=7     page=0  chnl=0 
-char id=176   x=149     y=408     width=15     height=18     xoffset=-2     yoffset=-1    xadvance=8     page=0  chnl=0 
-char id=8250   x=164     y=408     width=14     height=17     xoffset=-3     yoffset=9    xadvance=7     page=0  chnl=0 
-char id=8226   x=178     y=408     width=15     height=17     xoffset=-3     yoffset=8    xadvance=7     page=0  chnl=0 
-char id=8222   x=193     y=408     width=16     height=17     xoffset=-3     yoffset=12    xadvance=8     page=0  chnl=0 
-char id=8221   x=209     y=408     width=16     height=17     xoffset=-3     yoffset=2    xadvance=8     page=0  chnl=0 
-char id=8220   x=225     y=408     width=17     height=17     xoffset=-3     yoffset=2    xadvance=9     page=0  chnl=0 
-char id=8218   x=242     y=408     width=12     height=17     xoffset=-3     yoffset=12    xadvance=5     page=0  chnl=0 
-char id=8217   x=0     y=428     width=12     height=17     xoffset=-3     yoffset=2    xadvance=4     page=0  chnl=0 
-char id=8216   x=12     y=428     width=12     height=17     xoffset=-3     yoffset=2    xadvance=4     page=0  chnl=0 
-char id=187   x=24     y=428     width=21     height=17     xoffset=-3     yoffset=8    xadvance=14     page=0  chnl=0 
-char id=171   x=45     y=428     width=22     height=17     xoffset=-3     yoffset=7    xadvance=14     page=0  chnl=0 
-char id=8482   x=67     y=428     width=20     height=16     xoffset=-3     yoffset=3    xadvance=12     page=0  chnl=0 
-char id=8249   x=87     y=428     width=15     height=16     xoffset=-3     yoffset=9    xadvance=7     page=0  chnl=0 
-char id=184   x=102     y=428     width=13     height=16     xoffset=-1     yoffset=17    xadvance=8     page=0  chnl=0 
-char id=94   x=115     y=428     width=15     height=16     xoffset=-3     yoffset=2    xadvance=7     page=0  chnl=0 
-char id=39   x=130     y=428     width=11     height=16     xoffset=-3     yoffset=2    xadvance=3     page=0  chnl=0 
-char id=34   x=141     y=428     width=16     height=16     xoffset=-3     yoffset=2    xadvance=8     page=0  chnl=0 
-char id=180   x=157     y=428     width=14     height=15     xoffset=-2     yoffset=0    xadvance=8     page=0  chnl=0 
-char id=44   x=171     y=428     width=12     height=15     xoffset=-3     yoffset=14    xadvance=4     page=0  chnl=0 
-char id=8230   x=183     y=428     width=23     height=14     xoffset=-3     yoffset=13    xadvance=15     page=0  chnl=0 
-char id=732   x=206     y=428     width=16     height=14     xoffset=-3     yoffset=1    xadvance=8     page=0  chnl=0 
-char id=126   x=222     y=428     width=18     height=14     xoffset=-3     yoffset=1    xadvance=8     page=0  chnl=0 
-char id=96   x=240     y=428     width=14     height=14     xoffset=-3     yoffset=1    xadvance=7     page=0  chnl=0 
-char id=8722   x=0     y=445     width=18     height=13     xoffset=-3     yoffset=8    xadvance=10     page=0  chnl=0 
-char id=8211   x=18     y=445     width=17     height=13     xoffset=-3     yoffset=10    xadvance=9     page=0  chnl=0 
-char id=183   x=35     y=445     width=12     height=13     xoffset=-2     yoffset=8    xadvance=6     page=0  chnl=0 
-char id=175   x=47     y=445     width=16     height=13     xoffset=-2     yoffset=2    xadvance=10     page=0  chnl=0 
-char id=168   x=63     y=445     width=15     height=13     xoffset=-2     yoffset=1    xadvance=8     page=0  chnl=0 
-char id=95   x=78     y=445     width=18     height=13     xoffset=-4     yoffset=18    xadvance=9     page=0  chnl=0 
-char id=8212   x=96     y=445     width=21     height=12     xoffset=-3     yoffset=11    xadvance=14     page=0  chnl=0 
-char id=173   x=117     y=445     width=15     height=12     xoffset=-3     yoffset=10    xadvance=7     page=0  chnl=0 
-char id=45   x=132     y=445     width=15     height=12     xoffset=-3     yoffset=10    xadvance=7     page=0  chnl=0 
-char id=46   x=147     y=445     width=11     height=12     xoffset=-3     yoffset=15    xadvance=4     page=0  chnl=0 
-char id=172   x=158     y=445     width=20     height=19     xoffset=-2     yoffset=5    xadvance=14     page=0  chnl=0 

BIN
examples/data/fonts/main_0.png


BIN
examples/data/images/anim.png


BIN
examples/data/images/button.png


+ 0 - 11
examples/data/res.xml

@@ -1,11 +0,0 @@
-<?xml version="1.0"?>
-<resources>
-	<set path = "images" />
-	<atlas>
-		<image file="anim.png" cols = "8" />
-		<image file="button.png"/>		
-	</atlas>
-	
-	<set path = "fonts" />
-	<font file="main.fnt" />	
-</resources>

BIN
examples/exported/Knight/Knight.aem


+ 0 - 0
examples/exported/Knight/Knight.aem.log


BIN
examples/exported/Knight/images/Sprite_Player_body.png


BIN
examples/exported/Knight/images/Sprite_Player_head.png


BIN
examples/exported/Knight/images/Sprite_Player_left_apple_eye.png


BIN
examples/exported/Knight/images/Sprite_Player_left_eyebrow.png


BIN
examples/exported/Knight/images/Sprite_Player_left_eyelash.png


BIN
examples/exported/Knight/images/Sprite_Player_left_hand.png


BIN
examples/exported/Knight/images/Sprite_Player_left_hand_bg.png


BIN
examples/exported/Knight/images/Sprite_Player_left_leg.png


BIN
examples/exported/Knight/images/Sprite_Player_left_leg_bg.png


BIN
examples/exported/Knight/images/Sprite_Player_right_apple_eye.png


BIN
examples/exported/Knight/images/Sprite_Player_right_eyebrow.png


BIN
examples/exported/Knight/images/Sprite_Player_right_eyelash.png


BIN
examples/exported/Knight/images/Sprite_Player_right_hand.png


BIN
examples/exported/Knight/images/Sprite_Player_right_hand_bg.png


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