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
+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"?>
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-      package="org.oxygine.HelloAE"
+      package="org.oxygine.HelloViewerAE"
       android:versionCode="1"
       android:versionName="1.0"
       android:installLocation="auto">
@@ -11,7 +11,7 @@
                  android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
                  android:hardwareAccelerated="true" >
 
-        <activity android:name="org.oxygine.HelloAE.MainActivity"
+        <activity android:name="org.oxygine.HelloViewerAE.MainActivity"
                   android:label="@string/app_name"
                   android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
                   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="../../../../"
 call gradlew assembleDebug
 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="../../../../"
 ./gradlew assembleDebug
 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 {
             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
 
 #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 
 

+ 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"?>
 <resources>
-    <string name="app_name">HelloAE</string>
+    <string name="app_name">HelloViewerAE</string>
 </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;
 

+ 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
 
-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
 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
 
-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
 cd build_emsc_release

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

@@ -13,4 +13,4 @@ make
 cd ../../data
 
 #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 */
 
 /* 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; };
 		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; };
@@ -83,9 +83,9 @@
 		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; };
 		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; };
 		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 */ = {
 			isa = PBXGroup;
 			children = (
-				04998CEC17F8A933003441C3 /* HelloAE_ios.app */,
+				04998CEC17F8A933003441C3 /* HelloViewerAE_ios.app */,
 			);
 			name = Products;
 			sourceTree = "<group>";
@@ -233,9 +233,9 @@
 /* End PBXGroup section */
 
 /* Begin PBXNativeTarget section */
-		04998CEB17F8A933003441C3 /* HelloAE_ios */ = {
+		04998CEB17F8A933003441C3 /* HelloViewerAE_ios */ = {
 			isa = PBXNativeTarget;
-			buildConfigurationList = 04998D2117F8A933003441C3 /* Build configuration list for PBXNativeTarget "HelloAE_ios" */;
+			buildConfigurationList = 04998D2117F8A933003441C3 /* Build configuration list for PBXNativeTarget "HelloViewerAE_ios" */;
 			buildPhases = (
 				04998CE817F8A933003441C3 /* Sources */,
 				04998CE917F8A933003441C3 /* Frameworks */,
@@ -247,9 +247,9 @@
 				04998D3817F8A982003441C3 /* 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";
 		};
 /* End PBXNativeTarget section */
@@ -261,7 +261,7 @@
 				LastUpgradeCheck = 0510;
 				ORGANIZATIONNAME = Mac;
 			};
-			buildConfigurationList = 04998CE717F8A933003441C3 /* Build configuration list for PBXProject "HelloAE_ios" */;
+			buildConfigurationList = 04998CE717F8A933003441C3 /* Build configuration list for PBXProject "HelloViewerAE_ios" */;
 			compatibilityVersion = "Xcode 3.2";
 			developmentRegion = English;
 			hasScannedForEncodings = 0;
@@ -284,7 +284,7 @@
 			);
 			projectRoot = "";
 			targets = (
-				04998CEB17F8A933003441C3 /* HelloAE_ios */,
+				04998CEB17F8A933003441C3 /* HelloViewerAE_ios */,
 			);
 		};
 /* End PBXProject section */
@@ -387,7 +387,7 @@
 				ONLY_ACTIVE_ARCH = YES;
 				SDKROOT = iphoneos;
 				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;
 		};
@@ -423,7 +423,7 @@
 				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
 				SDKROOT = iphoneos;
 				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;
 			};
 			name = Release;
@@ -436,18 +436,18 @@
 				CODE_SIGN_IDENTITY = "iPhone Developer";
 				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
 				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_VARIABLE = NO;
 				GCC_INLINES_ARE_PRIVATE_EXTERN = NO;
-				INFOPLIST_FILE = "HelloAE/HelloAE_ios-Info.plist";
+				INFOPLIST_FILE = "HelloViewerAE/HelloViewerAE_ios-Info.plist";
 				LIBRARY_SEARCH_PATHS = (
 					"$(inherited)",
-					"../../../oxygine-framework//oxygine/third_party/ios/libraries",
+					"../../../../oxygine-framework//oxygine/third_party/ios/libraries",
 				);
 				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 = "";
 				TARGETED_DEVICE_FAMILY = "1,2";
 				WRAPPER_EXTENSION = app;
@@ -462,18 +462,18 @@
 				CODE_SIGN_IDENTITY = "iPhone Developer";
 				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
 				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_VARIABLE = NO;
 				GCC_INLINES_ARE_PRIVATE_EXTERN = NO;
-				INFOPLIST_FILE = "HelloAE/HelloAE_ios-Info.plist";
+				INFOPLIST_FILE = "HelloViewerAE/HelloViewerAE_ios-Info.plist";
 				LIBRARY_SEARCH_PATHS = (
 					"$(inherited)",
-					"../../../oxygine-framework//oxygine/third_party/ios/libraries",
+					"../../../../oxygine-framework//oxygine/third_party/ios/libraries",
 				);
 				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 = "";
 				TARGETED_DEVICE_FAMILY = "1,2";
 				WRAPPER_EXTENSION = app;
@@ -483,7 +483,7 @@
 /* End XCBuildConfiguration section */
 
 /* Begin XCConfigurationList section */
-		04998CE717F8A933003441C3 /* Build configuration list for PBXProject "HelloAE_ios" */ = {
+		04998CE717F8A933003441C3 /* Build configuration list for PBXProject "HelloViewerAE_ios" */ = {
 			isa = XCConfigurationList;
 			buildConfigurations = (
 				04998D1F17F8A933003441C3 /* Debug */,
@@ -492,7 +492,7 @@
 			defaultConfigurationIsVisible = 0;
 			defaultConfigurationName = Release;
 		};
-		04998D2117F8A933003441C3 /* Build configuration list for PBXNativeTarget "HelloAE_ios" */ = {
+		04998D2117F8A933003441C3 /* Build configuration list for PBXNativeTarget "HelloViewerAE_ios" */ = {
 			isa = XCConfigurationList;
 			buildConfigurations = (
 				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 */
 		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; };
-		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; };
 		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; };
 		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; };
 		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>"; };
@@ -98,8 +98,8 @@
 		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>"; };
 
-		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 */
 
 /* Begin PBXFrameworksBuildPhase section */
@@ -144,7 +144,7 @@
 		049B572F1871FBE900EF3C66 /* Products */ = {
 			isa = PBXGroup;
 			children = (
-				049B572E1871FBE900EF3C66 /* HelloAE_macosx.app */,
+				049B572E1871FBE900EF3C66 /* HelloViewerAE_macosx.app */,
 			);
 			name = Products;
 			sourceTree = "<group>";
@@ -189,7 +189,7 @@
 				04FE4D4FB640E0DF92DFB865 /* images */, 
 				7F3B12E3C9D554D9FE28101D /* res.xml */, 
 
-				049B57391871FBE900EF3C66 /* HelloAE_macosx-Info.plist */,
+				049B57391871FBE900EF3C66 /* HelloViewerAE_macosx-Info.plist */,
 			);
 			name = "Supporting Files";
 			sourceTree = "<group>";
@@ -219,9 +219,9 @@
 /* End PBXGroup section */
 
 /* Begin PBXNativeTarget section */
-		049B572D1871FBE900EF3C66 /* HelloAE_macosx */ = {
+		049B572D1871FBE900EF3C66 /* HelloViewerAE_macosx */ = {
 			isa = PBXNativeTarget;
-			buildConfigurationList = 049B575F1871FBE900EF3C66 /* Build configuration list for PBXNativeTarget "HelloAE_macosx" */;
+			buildConfigurationList = 049B575F1871FBE900EF3C66 /* Build configuration list for PBXNativeTarget "HelloViewerAE_macosx" */;
 			buildPhases = (
 				049B572A1871FBE900EF3C66 /* Sources */,
 				049B572B1871FBE900EF3C66 /* Frameworks */,
@@ -233,9 +233,9 @@
 				04059FE91872027200BA6557 /* 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";
 		};
 /* End PBXNativeTarget section */
@@ -247,7 +247,7 @@
 				LastUpgradeCheck = 0610;
 				ORGANIZATIONNAME = oxygine;
 			};
-			buildConfigurationList = 049B57291871FBE900EF3C66 /* Build configuration list for PBXProject "HelloAE_macosx" */;
+			buildConfigurationList = 049B57291871FBE900EF3C66 /* Build configuration list for PBXProject "HelloViewerAE_macosx" */;
 			compatibilityVersion = "Xcode 3.2";
 			developmentRegion = English;
 			hasScannedForEncodings = 0;
@@ -270,7 +270,7 @@
 			);
 			projectRoot = "";
 			targets = (
-				049B572D1871FBE900EF3C66 /* HelloAE_macosx */,
+				049B572D1871FBE900EF3C66 /* HelloViewerAE_macosx */,
 			);
 		};
 /* End PBXProject section */
@@ -390,7 +390,7 @@
 				MACOSX_DEPLOYMENT_TARGET = 10.8;
 				ONLY_ACTIVE_ARCH = YES;
 				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";
 			};
 			name = Debug;
@@ -425,7 +425,7 @@
 				MACOSX_DEPLOYMENT_TARGET = 10.8;
 				ONLY_ACTIVE_ARCH = YES;
 				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";
 			};
 			name = Release;
@@ -436,14 +436,14 @@
 				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
 				COMBINE_HIDPI_IMAGES = 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 = (
 					"$(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;
 			};
 			name = Debug;
@@ -454,14 +454,14 @@
 				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
 				COMBINE_HIDPI_IMAGES = 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 = (
 					"$(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;
 			};
 			name = Release;
@@ -469,7 +469,7 @@
 /* End XCBuildConfiguration section */
 
 /* Begin XCConfigurationList section */
-		049B57291871FBE900EF3C66 /* Build configuration list for PBXProject "HelloAE_macosx" */ = {
+		049B57291871FBE900EF3C66 /* Build configuration list for PBXProject "HelloViewerAE_macosx" */ = {
 			isa = XCConfigurationList;
 			buildConfigurations = (
 				049B575D1871FBE900EF3C66 /* Debug */,
@@ -478,7 +478,7 @@
 			defaultConfigurationIsVisible = 0;
 			defaultConfigurationName = Release;
 		};
-		049B575F1871FBE900EF3C66 /* Build configuration list for PBXNativeTarget "HelloAE_macosx" */ = {
+		049B575F1871FBE900EF3C66 /* Build configuration list for PBXNativeTarget "HelloViewerAE_macosx" */ = {
 			isa = XCConfigurationList;
 			buildConfigurations = (
 				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
 # 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
-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
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution

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

@@ -13,8 +13,8 @@
   <PropertyGroup Label="Globals">
     <ProjectGuid>{2B4D7491-A4F8-4606-B0E3-2A1FCE3C46C4}</ProjectGuid>
     <Keyword>Win32Proj</Keyword>
-    <RootNamespace>HelloAE</RootNamespace>
-    <ProjectName>HelloAE</ProjectName>
+    <RootNamespace>HelloViewerAE</RootNamespace>
+    <ProjectName>HelloViewerAE</ProjectName>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
 
@@ -84,13 +84,13 @@
       <WarningLevel>Level3</WarningLevel>
       <Optimization>Disabled</Optimization>
       <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>
     <Link>
       <SubSystem>Windows</SubSystem>
       <GenerateDebugInformation>true</GenerateDebugInformation>
       <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>
     </Link>
   </ItemDefinitionGroup>
@@ -103,20 +103,20 @@
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <IntrinsicFunctions>true</IntrinsicFunctions>
       <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>
     <Link>
       <SubSystem>Windows</SubSystem>
       <GenerateDebugInformation>true</GenerateDebugInformation>
       <EnableCOMDATFolding>true</EnableCOMDATFolding>
       <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>
       <AdditionalOptions>/ignore:4099 %(AdditionalOptions)</AdditionalOptions>
     </Link>
   </ItemDefinitionGroup>
   <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>
     </ProjectReference>
   </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_init();
 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/DebugActor.hpp"
 #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 std;
+
 
 // This function is called each frame
 int mainloop()
@@ -48,11 +70,14 @@ void run()
 
     // Initialize Oxygine's internal stuff
     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();
@@ -60,7 +85,7 @@ void run()
 
 
     // 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();
     getStage()->setSize(size);
 
@@ -82,7 +107,7 @@ void run()
 
 #if TARGET_OS_IPHONE || TARGET_OS_SIMULATOR
     // On iPhone mainloop is called automatically by CADisplayLink, see int main() below
-    //return;
+    return;
 #endif
 
     // This is the main game loop.
@@ -92,6 +117,9 @@ void run()
         if (done)
             break;
     }
+
+
+
     /*
      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
@@ -120,13 +148,29 @@ void run()
 
     ObjectBase::__stopTracingLeaks();
     //end
+
+
+	std::quick_exit(1);
 }
 
+#ifdef __S3E__
+int main(int argc, char* argv[])
+{
+    run();
+    return 0;
+}
+#endif
+
+
 #ifdef OXYGINE_SDL
 
 #include "SDL_main.h"
 #include "SDL.h"
 
+std::string aeProject;
+std::string aeCurrent;
+Vector2 aeWorkArea(0,0);
+
 extern "C"
 {
     void one(void* param) { mainloop(); }
@@ -134,12 +178,23 @@ extern "C"
 
     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();
 
 #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.
-        //SDL_iPhoneSetAnimationCallback(core::getWindow(), 1, one, nullptr);
+        SDL_iPhoneSetAnimationCallback(core::getWindow(), 1, one, nullptr);
 #endif
 
 #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